diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 678012eef3e..b4bb1640443 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,10 +15,10 @@ jobs: uses: actions/checkout@v4 - name: Install Requirements for Coverage Testing run: | - apt update && apt install -y lcov + apt update && apt install -y lcov gpg - name: Building run: | - cmake -B build -DENABLE_DEEPKS=ON -DENABLE_LIBXC=ON -DBUILD_TESTING=ON -DENABLE_COVERAGE=ON + cmake -B build -DENABLE_COVERAGE=ON -DBUILD_TESTING=ON -DENABLE_DEEPKS=ON -DENABLE_LIBXC=ON -DENABLE_LIBRI=ON -DENABLE_PAW=ON -DENABLE_GOOGLEBENCH=ON -DENABLE_RAPIDJSON=ON cmake --build build -j`nproc` cmake --install build - name: Testing diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f72220205b..62dfd410738 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ option(ENABLE_RAPIDJSON "Enable rapid-json usage." OFF) option(ENABLE_CNPY "Enable cnpy usage." OFF) option(ENABLE_PEXSI "Enable support for PEXSI." OFF) option(ENABLE_CUSOLVERMP "Enable cusolvermp." OFF) +option(USE_DSP "Enable DSP usage." OFF) # enable json support if(ENABLE_RAPIDJSON) @@ -119,6 +120,12 @@ elseif(ENABLE_LCAO AND NOT ENABLE_MPI) set(ABACUS_BIN_NAME abacus_serial) endif() +if (USE_DSP) + set(USE_ELPA OFF) + set(ENABLE_LCAO OFF) + set(ABACUS_BIN_NAME abacus_dsp) +endif() + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) if(ENABLE_COVERAGE) @@ -240,6 +247,11 @@ if(ENABLE_MPI) list(APPEND math_libs MPI::MPI_CXX) endif() +if (USE_DSP) + target_link_libraries(${ABACUS_BIN_NAME} ${DIR_MTBLAS_LIBRARY}) + add_compile_definitions(__DSP) +endif() + find_package(Threads REQUIRED) target_link_libraries(${ABACUS_BIN_NAME} Threads::Threads) @@ -436,22 +448,6 @@ if(ENABLE_FLOAT_FFTW) endif() if(ENABLE_DEEPKS) - # Torch uses outdated components to detect CUDA arch, causing failure on - # latest CUDA kits. Set CMake variable TORCH_CUDA_ARCH_LIST in the form of - # "major.minor" if required. - find_package(Torch REQUIRED) - if(NOT Torch_VERSION VERSION_LESS "2.1.0") - set_if_higher(CMAKE_CXX_STANDARD 17) - elseif(NOT Torch_VERSION VERSION_LESS "1.5.0") - set_if_higher(CMAKE_CXX_STANDARD 14) - endif() - include_directories(${TORCH_INCLUDE_DIRS}) - if(MKL_FOUND) - list(PREPEND math_libs ${TORCH_LIBRARIES}) - else() - list(APPEND math_libs ${TORCH_LIBRARIES}) - endif() - add_compile_options(${TORCH_CXX_FLAGS}) target_link_libraries(${ABACUS_BIN_NAME} deepks) find_path(libnpy_SOURCE_DIR npy.hpp HINTS ${libnpy_INCLUDE_DIR}) @@ -470,6 +466,25 @@ if(ENABLE_DEEPKS) add_compile_definitions(__DEEPKS) endif() +# Torch uses outdated components to detect CUDA arch, causing failure on +# latest CUDA kits. Set CMake variable TORCH_CUDA_ARCH_LIST in the form of +# "major.minor" if required. +if(ENABLE_DEEPKS OR DEFINED Torch_DIR) + find_package(Torch REQUIRED) + if(NOT Torch_VERSION VERSION_LESS "2.1.0") + set_if_higher(CMAKE_CXX_STANDARD 17) + elseif(NOT Torch_VERSION VERSION_LESS "1.5.0") + set_if_higher(CMAKE_CXX_STANDARD 14) + endif() + include_directories(${TORCH_INCLUDE_DIRS}) + if(MKL_FOUND) + list(PREPEND math_libs ${TORCH_LIBRARIES}) + else() + list(APPEND math_libs ${TORCH_LIBRARIES}) + endif() + add_compile_options(${TORCH_CXX_FLAGS}) +endif() + if (ENABLE_CNPY) find_path(cnpy_SOURCE_DIR cnpy.h @@ -590,13 +605,14 @@ if(DEFINED DeePMD_DIR) add_compile_definitions(__DPMDC) else() target_link_libraries(${ABACUS_BIN_NAME} DeePMD::deepmd_cc) - if(NOT DEFINED TensorFlow_DIR) - set(TensorFlow_DIR ${DeePMD_DIR}) - endif() - find_package(TensorFlow REQUIRED) - if(TensorFlow_FOUND) - target_link_libraries(${ABACUS_BIN_NAME} TensorFlow::tensorflow_cc) - endif() + endif() +endif() + +if(DEFINED TensorFlow_DIR) + find_package(TensorFlow REQUIRED) + include_directories(${TensorFlow_DIR}/include) + if(TensorFlow_FOUND) + target_link_libraries(${ABACUS_BIN_NAME} TensorFlow::tensorflow_cc) endif() endif() diff --git a/README.md b/README.md index ef9ebff38cd..31857eeac99 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ # About ABACUS -ABACUS (Atomic-orbital Based Ab-initio Computation at UStc) is an open-source package based on density functional theory (DFT). The package utilizes both plane wave and numerical atomic basis sets with the usage of norm-conserving pseudopotentials to describe the interactions between nuclear ions and valence electrons. ABACUS supports LDA, GGA, meta-GGA, and hybrid functionals. Apart from single-point calculations, the package allows geometry optimizations and ab-initio molecular dynamics with various ensembles. The package also provides a variety of advanced functionalities for simulating materials, including the DFT+U, VdW corrections, and implicit solvation model, etc. In addition, ABACUS strives to provide a general infrastructure to facilitate the developments and applications of novel machine-learning-assisted DFT methods (DeePKS, DP-GEN, DeepH, etc.) in molecular and material simulations. +ABACUS (Atomic-orbital Based Ab-initio Computation at UStc) is an open-source package based on density functional theory (DFT). The package utilizes both plane wave and numerical atomic basis sets with the usage of norm-conserving pseudopotentials to describe the interactions between nuclear ions and valence electrons. ABACUS supports LDA, GGA, meta-GGA, and hybrid functionals. Apart from single-point calculations, the package allows geometry optimizations and ab-initio molecular dynamics with various ensembles. The package also provides a variety of advanced functionalities for simulating materials, including the DFT+U, VdW corrections, and implicit solvation model, etc. In addition, ABACUS strives to provide a general infrastructure to facilitate the developments and applications of novel machine-learning-assisted DFT methods (DeePKS, DP-GEN, DeepH, DeePTB etc.) in molecular and material simulations. # Online Documentation For detailed documentation, please refer to [our documentation website](https://abacus.deepmodeling.com/). + +See our [Github Pages](https://mcresearch.github.io/abacus-user-guide/) for more tutorials and developer guides. \ No newline at end of file diff --git a/docs/CITATIONS.md b/docs/CITATIONS.md index 2294404f537..d54627292d7 100644 --- a/docs/CITATIONS.md +++ b/docs/CITATIONS.md @@ -26,7 +26,7 @@ The following references are required to be cited when using ABACUS. Specificall - **If DeePKS is used:** - Wenfei Li, Qi Ou, et al. "DeePKS+ABACUS as a Bridge between Expensive Quantum Mechanical Models and Machine Learning Potentials." . + Wenfei Li, Qi Ou, et al. "DeePKS+ABACUS as a Bridge between Expensive Quantum Mechanical Models and Machine Learning Potentials." J. Phys. Chem. A 126.49 (2022): 9154-9164. - **If hybrid functional is used:** diff --git a/docs/advanced/acceleration/cuda.md b/docs/advanced/acceleration/cuda.md index 0200e98e78d..32319617669 100644 --- a/docs/advanced/acceleration/cuda.md +++ b/docs/advanced/acceleration/cuda.md @@ -29,12 +29,14 @@ To compile and use ABACUS in CUDA mode, you currently need to have an NVIDIA GPU Check the [Advanced Installation Options](https://abacus-rtd.readthedocs.io/en/latest/advanced/install.html#build-with-cuda-support) for the installation of CUDA version support. -When the compilation parameter USE_ELPA is ON (which is the default value) and USE_CUDA is also set to ON, the ELPA library needs to [enable GPU support](https://github.com/marekandreas/elpa/blob/master/documentation/INSTALL.md) at compile time. +Setting both USE_ELPA and USE_CUDA to ON does not automatically enable ELPA to run on GPUs. ELPA support for GPUs needs to be enabled when ELPA is compiled. [enable GPU support](https://github.com/marekandreas/elpa/blob/master/documentation/INSTALL.md). + +The ABACUS program will automatically determine whether the current ELPA supports GPU based on the elpa/elpa_configured_options.h header file. Users can also check this header file to determine the GPU support of ELPA in their environment. ELPA introduced a new API elpa_setup_gpu in version 2023.11.001. So if you want to enable ELPA GPU in ABACUS, the ELPA version must be greater than or equal to 2023.11.001. ## Run with the GPU support by editing the INPUT script: In `INPUT` file we need to set the input parameter [device](../input_files/input-main.md#device) to `gpu`. If this parameter is not set, ABACUS will try to determine if there are available GPUs. -- Set `ks_solver`: For the PW basis, CG, BPCG and Davidson methods are supported on GPU; set the input parameter [ks_solver](../input_files/input-main.md#ks_solver) to `cg`, `bpcg` or `dav`. For the LCAO basis, `cusolver` and `elpa` is supported on GPU. +- Set `ks_solver`: For the PW basis, CG, BPCG and Davidson methods are supported on GPU; set the input parameter [ks_solver](../input_files/input-main.md#ks_solver) to `cg`, `bpcg` or `dav`. For the LCAO basis, `cusolver`, `cusolvermp` and `elpa` is supported on GPU. - **multi-card**: ABACUS allows for multi-GPU acceleration. If you have multiple GPU cards, you can run ABACUS with several MPI processes, and each process will utilize one GPU card. For example, the command `mpirun -n 2 abacus` will by default launch two GPUs for computation. If you only have one card, this command will only start one GPU. ## Examples diff --git a/docs/advanced/elec_properties/Berry_phase.md b/docs/advanced/elec_properties/Berry_phase.md index 9dbe47ba904..7f85689a5ff 100644 --- a/docs/advanced/elec_properties/Berry_phase.md +++ b/docs/advanced/elec_properties/Berry_phase.md @@ -23,7 +23,7 @@ pseudo_dir ../../../tests/PP_ORB //the path to locate the pesudopotential orbital_dir ../../../tests/PP_ORB //the path to locate the numerical orbital files ntype 3 ecutwfc 50 // Ry -symmetry 0 // turn off symmetry +symmetry -1 // turn off symmetry calculation nscf // non-self-consistent calculation basis_type lcao // atomic basis init_chg file // read charge from files @@ -70,4 +70,6 @@ The results are shown as follows: P = 0.8906925 (mod 2.1748536) ( 0.0000000, 0.0000000, 0.8906925) C/m^2 ``` -The electric polarization **P** is multivalued, which modulo a quantum e**R**/V~cell~. Note: the values in parentheses are the components of the **P** along the c axis in the x, y, z Cartesian coordinates when set gdir = 3 in INPUT file. \ No newline at end of file +The electric polarization **P** is multivalued, which modulo a quantum e**R**/V~cell~. + +Note: The vectors R1, R2, and R3 refer to the three lattice vectors of the unit cell. When gdir=3, the calculated polarization is along the R3 direction. The three values in parentheses represent the re-projection of the polarization along the R3 direction onto the Cartesian coordinate system (i.e., the xyz coordinate system). To obtain the full polarization components in the Cartesian system, you need to calculate the polarization for R1, R2, and R3 separately, and then sum their respective x, y, and z components. diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index f6cb7639d7c..92f8e11f1fc 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -39,7 +39,6 @@ - [pw\_diag\_thr](#pw_diag_thr) - [pw\_diag\_nmax](#pw_diag_nmax) - [pw\_diag\_ndim](#pw_diag_ndim) - - [diago\_full\_acc](#diago_full_acc) - [erf\_ecut](#erf_ecut) - [fft\_mode](#fft_mode) - [erf\_height](#erf_height) @@ -89,6 +88,9 @@ - [scf\_thr](#scf_thr) - [scf\_ene\_thr](#scf_ene_thr) - [scf\_thr\_type](#scf_thr_type) + - [scf\_os\_stop](#scf_os_stop) + - [scf\_os\_thr](#scf_os_thr) + - [scf\_os\_ndim](#scf_os_ndim) - [chg\_extrap](#chg_extrap) - [lspinorb](#lspinorb) - [noncolin](#noncolin) @@ -161,6 +163,7 @@ - [nbands\_istate](#nbands_istate) - [bands\_to\_print](#bands_to_print) - [if\_separate\_k](#if_separate_k) + - [out\_elf](#out_elf) - [Density of states](#density-of-states) - [dos\_edelta\_ev](#dos_edelta_ev) - [dos\_sigma](#dos_sigma) @@ -243,8 +246,8 @@ - [exx\_opt\_orb\_ecut](#exx_opt_orb_ecut) - [exx\_opt\_orb\_tolerence](#exx_opt_orb_tolerence) - [exx\_real\_number](#exx_real_number) - - [exx\_symmetry\_realspace](#exx_symmetry_realspace) - [rpa\_ccp\_rmesh\_times](#rpa_ccp_rmesh_times) + - [exx\_symmetry\_realspace](#exx_symmetry_realspace) - [out\_ri\_cv](#out_ri_cv) - [Molecular dynamics](#molecular-dynamics) - [md\_type](#md_type) @@ -273,6 +276,9 @@ - [lj\_epsilon](#lj_epsilon) - [lj\_sigma](#lj_sigma) - [pot\_file](#pot_file) + - [dp\_rescaling](#dp_rescaling) + - [dp\_fparam](#dp_fparam) + - [dp\_aparam](#dp_aparam) - [msst\_direction](#msst_direction) - [msst\_vel](#msst_vel) - [msst\_vis](#msst_vis) @@ -422,11 +428,12 @@ - [nocc](#nocc) - [nvirt](#nvirt) - [lr\_nstates](#lr_nstates) + - [lr\_unrestricted](#lr_unrestricted) - [abs\_wavelen\_range](#abs_wavelen_range) - [out\_wfc\_lr](#out_wfc_lr) - [abs\_broadening](#abs_broadening) - [ri\_hartree\_benchmark](#ri_hartree_benchmark) - - [aims_nbasis](#aims_nbasis) + - [aims\_nbasis](#aims_nbasis) [back to top](#full-list-of-input-keywords) ## System variables @@ -666,6 +673,7 @@ These variables are used to control parameters related to input files. - **Type**: String - **Description**: the name of the structure file - Containing various information about atom species, including pseudopotential files, local orbitals files, cell information, atom positions, and whether atoms should be allowed to move. + - When [calculation](#calculation) is set to `md` and [md_restart](#md_restart) is set to `true`, this keyword will NOT work. - Refer to [Doc](https://github.com/deepmodeling/abacus-develop/blob/develop/docs/advanced/input_files/stru.md) - **Default**: STRU @@ -727,7 +735,7 @@ These variables are used to control the plane wave related parameters. - **Type**: Real - **Description**: Energy cutoff for plane wave functions, the unit is **Rydberg**. Note that even for localized orbitals basis, you still need to setup an energy cutoff for this system. Because our local pseudopotential parts and the related force are calculated from plane wave basis set, etc. Also, because our orbitals are generated by matching localized orbitals to a chosen set of wave functions from a certain energy cutoff, this set of localize orbitals is most accurate under this same plane wave energy cutoff. -- **Default**: 50 +- **Default**: 50 Ry (PW basis), 100 Ry (LCAO basis) ### ecutrho @@ -777,12 +785,6 @@ These variables are used to control the plane wave related parameters. - **Description**: Only useful when you use `ks_solver = dav` or `ks_solver = dav_subspace`. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization. - **Default**: 4 -### diago_full_acc - -- **Type**: bool -- **Description**: Only useful when you use `ks_solver = dav_subspace`. If `TRUE`, all the empty states are diagonalized at the same level of accuracy of the occupied ones. Otherwise the empty states are diagonalized using a larger threshold (10-5) (this should not affect total energy, forces, and other ground-state properties). -- **Default**: false - ### erf_ecut - **Type**: Real @@ -923,7 +925,7 @@ calculations. - **cg**: cg method. - **bpcg**: bpcg method, which is a block-parallel Conjugate Gradient (CG) method, typically exhibits higher acceleration in a GPU environment. - **dav**: the Davidson algorithm. - - **dav_subspace**: subspace Davidson algorithm + - **dav_subspace**: Davidson algorithm without orthogonalization operation, this method is the most recommended for efficiency. `pw_diag_ndim` can be set to 2 for this method. For atomic orbitals basis, @@ -931,6 +933,8 @@ calculations. - **genelpa**: This method should be used if you choose localized orbitals. - **scalapack_gvx**: Scalapack can also be used for localized orbitals. - **cusolver**: This method needs building with CUDA and at least one gpu is available. + - **cusolvermp**: This method supports multi-GPU acceleration and needs building with CUDA。 Note that when using cusolvermp, you should set the number of MPI processes to be equal to the number of GPUs. + - **elpa**: The ELPA solver supports both CPU and GPU. By setting the `device` to GPU, you can launch the ELPA solver with GPU acceleration (provided that you have installed a GPU-supported version of ELPA, which requires you to manually compile and install ELPA, and the ABACUS should be compiled with -DUSE_ELPA=ON and -DUSE_CUDA=ON). The ELPA solver also supports multi-GPU acceleration. If you set ks_solver=`genelpa` for basis_type=`pw`, the program will be stopped with an error message: @@ -939,7 +943,13 @@ calculations. ``` Then the user has to correct the input file and restart the calculation. -- **Default**: cg (plane-wave basis), or genelpa (localized atomic orbital basis, if compiling option `USE_ELPA` has been set),lapack (localized atomic orbital basis, if compiling option `ENABLE_MPI` has not been set), scalapack_gvx, (localized atomic orbital basis, if compiling option `USE_ELPA` has not been set and if compiling option `ENABLE_MPI` has been set) +- **Default**: + - **PW basis**: cg. + - **LCAO basis**: + - genelpa (if compiling option `USE_ELPA` has been set) + - lapack (if compiling option `ENABLE_MPI` has not been set) + - scalapack_gvx (if compiling option `USE_ELPA` has not been set and compiling option `ENABLE_MPI` has been set) + - cusolver (if compiling option `USE_CUDA` has been set) ### nbands @@ -1198,6 +1208,29 @@ Note: In new angle mixing, you should set `mixing_beta_mag >> mixing_beta`. The - **Default**: 1 (plane-wave basis), or 2 (localized atomic orbital basis). +### scf_os_stop + +- **Type**: bool +- **Description**: For systems that are difficult to converge, the SCF process may exhibit oscillations in charge density, preventing further progress toward the specified convergence criteria and resulting in continuous oscillation until the maximum number of steps is reached; this greatly wastes computational resources. To address this issue, this function allows ABACUS to terminate the SCF process early upon detecting oscillations, thus reducing subsequent meaningless calculations. The detection of oscillations is based on the slope of the logarithm of historical drho values.. To this end, Least Squares Method is used to calculate the slope of the logarithmically taken drho for the previous `scf_os_ndim` iterations. If the calculated slope is larger than `scf_os_thr`, stop the SCF. + + - **0**: The SCF will continue to run regardless of whether there is oscillation or not. + - **1**: If the calculated slope is larger than `scf_os_thr`, stop the SCF. + +- **Default**: false + +### scf_os_thr + +- **Type**: double +- **Description**: The slope threshold to determine if the SCF is stuck in a charge density oscillation. If the calculated slope is larger than `scf_os_thr`, stop the SCF. + +- **Default**: -0.01 + +### scf_os_ndim + +- **Type**: int +- **Description**: To determine the number of old iterations' `drho` used in slope calculations. +- **Default**: `mixing_ndim` + ### chg_extrap - **Type**: String @@ -1520,7 +1553,7 @@ These variables are used to control the output of properties. - **Type**: Integer \[Integer\](optional) - **Description**: The first integer controls whether to output the charge density on real space grids: - - 1. Output the charge density (in Bohr^-3) on real space grids into the density files in the folder `OUT.${suffix}`. The files are named as: + - 1: Output the charge density (in Bohr^-3) on real space grids into the density files in the folder `OUT.${suffix}`. The files are named as: - nspin = 1: SPIN1_CHG.cube; - nspin = 2: SPIN1_CHG.cube, and SPIN2_CHG.cube; - nspin = 4: SPIN1_CHG.cube, SPIN2_CHG.cube, SPIN3_CHG.cube, and SPIN4_CHG.cube. @@ -1800,6 +1833,23 @@ The band (KS orbital) energy for each (k-point, spin, band) will be printed in t - **Description**: Specifies whether to write the partial charge densities for all k-points to individual files or merge them. **Warning**: Enabling symmetry may produce incorrect results due to incorrect k-point weights. Therefore, when calculating partial charge densities, it is strongly recommended to set `symmetry = -1`. - **Default**: false +### out_elf + +- **Type**: Integer \[Integer\](optional) +- **Availability**: Only for Kohn-Sham DFT and Orbital Free DFT. +- **Description**: Whether to output the electron localization function (ELF) in the folder `OUT.${suffix}`. The files are named as + - nspin = 1: + - ELF.cube: ${\rm{ELF}} = \frac{1}{1+\chi^2}$, $\chi = \frac{\frac{1}{2}\sum_{i}{f_i |\nabla\psi_{i}|^2} - \frac{|\nabla\rho|^2}{8\rho}}{\frac{3}{10}(3\pi^2)^{2/3}\rho^{5/3}}$; + - nspin = 2: + - ELF_SPIN1.cube, ELF_SPIN2.cube: ${\rm{ELF}}_\sigma = \frac{1}{1+\chi_\sigma^2}$, $\chi_\sigma = \frac{\frac{1}{2}\sum_{i}{f_i |\nabla\psi_{i,\sigma}|^2} - \frac{|\nabla\rho_\sigma|^2}{8\rho_\sigma}}{\frac{3}{10}(6\pi^2)^{2/3}\rho_\sigma^{5/3}}$; + - ELF.cube: ${\rm{ELF}} = \frac{1}{1+\chi^2}$, $\chi = \frac{\frac{1}{2}\sum_{i,\sigma}{f_i |\nabla\psi_{i,\sigma}|^2} - \sum_{\sigma}{\frac{|\nabla\rho_\sigma|^2}{8\rho_\sigma}}}{\sum_{\sigma}{\frac{3}{10}(6\pi^2)^{2/3}\rho_\sigma^{5/3}}}$; + + The second integer controls the precision of the kinetic energy density output, if not given, will use `3` as default. For purpose restarting from this file and other high-precision involved calculation, recommend to use `10`. + + --- + In molecular dynamics calculations, the output frequency is controlled by [out_interval](#out_interval). +- **Default**: 0 3 + [back to top](#full-list-of-input-keywords) ## Density of states @@ -2888,46 +2938,38 @@ These variables are used to control vdW-corrected related parameters. - **Type**: String - **Description**: Specifies the method used for Van der Waals (VdW) correction. Available options are: - `d2`: [Grimme's D2](https://onlinelibrary.wiley.com/doi/abs/10.1002/jcc.20495) dispersion correction method - - `d3_0`: [Grimme's DFT-D3(0)](https://aip.scitation.org/doi/10.1063/1.3382344) dispersion correction method - - `d3_bj`: [Grimme's DFTD3(BJ)](https://onlinelibrary.wiley.com/doi/abs/10.1002/jcc.21759) dispersion correction method + - `d3_0`: [Grimme's DFT-D3(0)](https://aip.scitation.org/doi/10.1063/1.3382344) dispersion correction method (zero-damping) + - `d3_bj`: [Grimme's DFTD3(BJ)](https://onlinelibrary.wiley.com/doi/abs/10.1002/jcc.21759) dispersion correction method (BJ-damping) - `none`: no vdW correction - **Default**: none +- **Note**: ABACUS supports automatic setting on DFT-D3 parameters for common functionals after version 3.8.3 (and several develop versions earlier). To benefit from this feature, please specify the parameter `dft_functional` explicitly (for more details on this parameter, please see [dft_functional](#dft_functional)), otherwise the autoset procedure will crash with error message like `cannot find DFT-D3 parameter for XC(***)`. If not satisfied with those in-built parameters, any manually setting on `vdw_s6`, `vdw_s8`, `vdw_a1` and `vdw_a2` will overwrite. +- **Special**: There are special cases for functional family wB97 (Omega-B97): if want to use the functional wB97X-D3BJ, one needs to specify the `dft_functional` as `HYB_GGA_WB97X_V` and `vdw_method` as `d3_bj`. If want to use the functional wB97X-D3, specify `dft_functional` as `HYB_GGA_WB97X_D3` and `vdw_method` as `d3_0`. ### vdw_s6 - **Type**: Real - **Availability**: `vdw_method` is set to `d2`, `d3_0`, or `d3_bj` -- **Description**: This scale factor is used to optimize the interaction energy deviations in van der Waals (vdW) corrected calculations. The recommended values of this parameter are dependent on the chosen vdW correction method and the DFT functional being used. For DFT-D2, the recommended values are 0.75 (PBE), 1.2 (BLYP), 1.05 (B-P86), 1.0 (TPSS), and 1.05 (B3LYP). For DFT-D3, recommended values with different DFT functionals can be found on the [here](https://www.chemiebn.uni-bonn.de/pctc/mulliken-center/software/dft-d3/dft-d3). The default value of this parameter in ABACUS is set to be the recommended value for PBE. +- **Description**: This scale factor is used to optimize the interaction energy deviations in van der Waals (vdW) corrected calculations. The recommended values of this parameter are dependent on the chosen vdW correction method and the DFT functional being used. For DFT-D2, the recommended values are 0.75 (PBE), 1.2 (BLYP), 1.05 (B-P86), 1.0 (TPSS), and 1.05 (B3LYP). If not set, will use values of PBE functional. For DFT-D3, recommended values with different DFT functionals can be found on the [here](https://github.com/dftd3/simple-dftd3/blob/main/assets/parameters.toml). If not set, will search in ABACUS built-in dataset based on the `dft_functional` keywords. User set value will overwrite the searched value. - **Default**: - 0.75: if `vdw_method` is set to `d2` - - 1.0: if `vdw_method` is set to `d3_0` or `d3_bj` ### vdw_s8 - **Type**: Real - **Availability**: `vdw_method` is set to `d3_0` or `d3_bj` -- **Description**: This scale factor is relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://www.chemiebn.uni-bonn.de/pctc/mulliken-center/software/dft-d3/dft-d3). The default value of this parameter in ABACUS is set to be the recommended value for PBE. -- **Default**: - - 0.722: if `vdw_method` is set to `d3_0` - - 0.7875: if `vdw_method` is set to `d3_bj` +- **Description**: This scale factor is relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://github.com/dftd3/simple-dftd3/blob/main/assets/parameters.toml). If not set, will search in ABACUS built-in dataset based on the `dft_functional` keywords. User set value will overwrite the searched value. ### vdw_a1 - **Type**: Real - **Availability**: `vdw_method` is set to `d3_0` or `d3_bj` -- **Description**: This damping function parameter is relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://www.chemiebn.uni-bonn.de/pctc/mulliken-center/software/dft-d3/dft-d3). The default value of this parameter in ABACUS is set to be the recommended value for PBE. -- **Default**: - - 1.217: if `vdw_method` is set to `d3_0` - - 0.4289: if `vdw_method` is set to `d3_bj` +- **Description**: This damping function parameter is relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://github.com/dftd3/simple-dftd3/blob/main/assets/parameters.toml). If not set, will search in ABACUS built-in dataset based on the `dft_functional` keywords. User set value will overwrite the searched value. ### vdw_a2 - **Type**: Real - **Availability**: `vdw_method` is set to `d3_0` or `d3_bj` -- **Description**: This damping function parameter is only relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://www.chemiebn.uni-bonn.de/pctc/mulliken-center/software/dft-d3/dft-d3). The default value of this parameter in ABACUS is set to be the recommended value for PBE. -- **Default**: - - 1.0: if `vdw_method` is set to `d3_0` - - 4.4407: if `vdw_method` is set to `d3_bj` +- **Description**: This damping function parameter is only relevant for D3(0) and D3(BJ) van der Waals (vdW) correction methods. The recommended values of this parameter with different DFT functionals can be found on the [webpage](https://github.com/dftd3/simple-dftd3/blob/main/assets/parameters.toml). If not set, will search in ABACUS built-in dataset based on the `dft_functional` keywords. User set value will overwrite the searched value. ### vdw_d @@ -3905,7 +3947,7 @@ Currently supported: `RPA`, `LDA`, `PBE`, `HSE`, `HF`. - **Type**: String - **Description**: The method to solve the Casida equation $AX=\Omega X$ in LR-TDDFT under Tamm-Dancoff approximation (TDA), where $A_{ai,bj}=(\epsilon_a-\epsilon_i)\delta_{ij}\delta_{ab}+(ai|f_{Hxc}|bj)+\alpha_{EX}(ab|ij)$ is the particle-hole excitation matrix and $X$ is the transition amplitude. - - `dav`: Construct $AX$ and diagonalize the Hamiltonian matrix iteratively with Davidson algorithm. + - `dav`/`dav_subspace`/ `cg`: Construct $AX$ and diagonalize the Hamiltonian matrix iteratively with Davidson/Non-ortho-Davidson/CG algorithm. - `lapack`: Construct the full $A$ matrix and directly diagonalize with LAPACK. - `spectrum`: Calculate absorption spectrum only without solving Casida equation. The `OUT.${suffix}/` directory should contain the files for LR-TDDFT eigenstates and eigenvalues, i.e. `Excitation_Energy.dat` and `Excitation_Amplitude_${processor_rank}.dat` @@ -3937,6 +3979,13 @@ Currently supported: `RPA`, `LDA`, `PBE`, `HSE`, `HF`. - **Description**: The number of 2-particle states to be solved - **Default**: 0 +### lr_unrestricted +- **Type**: Boolean +- **Description**: Whether to use unrestricted construction for LR-TDDFT (the matrix size will be doubled). + - True: Always use unrestricted LR-TDDFT. + - False: Use unrestricted LR-TDDFT only when the system is open-shell. +- **Default**: False + ### abs_wavelen_range - **Type**: Real Real diff --git a/docs/advanced/input_files/kpt.md b/docs/advanced/input_files/kpt.md index 9c0eb336b1d..853a3dc3403 100644 --- a/docs/advanced/input_files/kpt.md +++ b/docs/advanced/input_files/kpt.md @@ -8,7 +8,7 @@ ABACUS uses periodic boundary conditions for both crystals and finite systems. F ## Gamma-only Calculations -In ABACUS, we offer th option of running gamma-only calculations for LCAO basis by setting [gamma_only](./input-main.md#gamma_only) to be 1. Due to details of implementation, gamma-only calculation will be slightly faster than running a non gamma-only calculation and explicitly setting gamma point to be the only the k-point, but the results should be consistent. +In ABACUS, we offer the option of running gamma-only calculations for LCAO basis by setting [gamma_only](./input-main.md#gamma_only) to be 1. Due to details of implementation, gamma-only calculation will be slightly faster than running a non gamma-only calculation and explicitly setting gamma point to be the only the k-point, but the results should be consistent. > If gamma_only is set to 1, the KPT file will be overwritten. So make sure to turn off gamma_only for multi-k calculations. @@ -23,7 +23,7 @@ method to generate k-mesh, and the following is an example input k-point (`KPT`) K_POINTS //keyword for start 0 //total number of k-point, `0' means generate automatically Gamma //which kind of Monkhorst-Pack method, `Gamma' or `MP' -2 2 2 0 0 0 //first three number: subdivisions along recpri. vectors +2 2 2 0 0 0 //first three number: subdivisions along reciprocal vectors //last three number: shift of the mesh ``` @@ -63,8 +63,8 @@ Direct //`Direct' or `Cartesian' coordinate ## Band structure calculations ABACUS uses specified high-symmetry directions of the Brillouin zone for band structure -calculations. The third line of k-point file should start with ‘Line’ or ‘Line_Cartesian’ for -line mode. ‘Line’ means the positions below are in Direct coordinates, while ‘Line_Cartesian’ +calculations. The third line of k-point file should start with 'Line' or 'Line_Cartesian' for +line mode. 'Line' means the positions below are in Direct coordinates, while 'Line_Cartesian' means in Cartesian coordinates: ``` diff --git a/docs/advanced/install.md b/docs/advanced/install.md index 6c31229070c..4fa6b906c48 100644 --- a/docs/advanced/install.md +++ b/docs/advanced/install.md @@ -38,13 +38,22 @@ cmake -B build -DENABLE_DEEPKS=1 -DTorch_DIR=~/libtorch/share/cmake/Torch/ -Dlib If the Deep Potential model is employed in Molecule Dynamics calculations, the following prerequisites and steps are needed: - [DeePMD-kit](https://github.com/deepmodeling/deepmd-kit) -- [TensorFlow](https://www.tensorflow.org/) +- [TensorFlow](https://www.tensorflow.org/) (optional) +- [LibTorch](https://pytorch.org/) (optional) +In the simplest case, the `tensorflow_cc` and `torch` libraries are in the same directory as the `deepmd_c`/`deepmd_cc` libraries, then ```bash -cmake -B build -DDeePMD_DIR=~/deepmd-kit -DTensorFlow_DIR=~/tensorflow +cmake -B build -DDeePMD_DIR=/dir_to_deepmd-kit ``` +DeePMD-kit supports TensorFlow backend but its libraries are placed at another directory, then -> `deepmd_c`/`deepmd_cc` and `tensorflow_cc` libraries would be called according to `DeePMD_DIR` and `TensorFlow_DIR`, which is showed in detail in [this page](https://github.com/deepmodeling/deepmd-kit/blob/master/doc/inference/cxx.md). If `TensorFlow_DIR` is not defined, it will be the same as `DeePMD_DIR`. Note that `tensorflow_cc` is not required if `deepmd_c` is found. +```bash +cmake -B build -DDeePMD_DIR=/dir_to_deepmd-kit -DTensorFlow_DIR=/dir_to_tensorflow +``` +Similarly, DeePMD-kit supports PyTorch backend but its libraries are placed at another directory, then +```bash +cmake -B build -DDeePMD_DIR=/dir_to_deepmd-kit -DTorch_DIR=/dir_to_pytorch +``` ## Build with LibRI and LibComm @@ -93,9 +102,9 @@ cmake -B build -DUSE_CUDA=1 -DCMAKE_CUDA_COMPILER=${path to cuda toolkit}/bin/nv ## Build math library from source -> Note: This flag is **enabled by default**. It will get better performance than the standard implementation on `gcc` and `clang`. But it **will be disabled** when using `Intel Compiler` since the math functions will get wrong results and the performance is also unexpectly poor. +> Note: We recommend using the latest available compiler sets, since they offer faster implementations of math functions. -To build math functions from source code, instead of using c++ standard implementation, define `USE_ABACUS_LIBM` flag. +This flag is disabled by default. To build math functions from source code, define `USE_ABACUS_LIBM` flag. It is expected to get a better performance on legacy versions of `gcc` and `clang`. Currently supported math functions: `sin`, `cos`, `sincos`, `exp`, `cexp` @@ -282,15 +291,21 @@ directly. > Note: This part is only required if you want to load a trained DeeP Potential and run molecular dynamics with that. To train the DeeP Potential with DP-GEN, no extra prerequisite is needed and please refer to [this page](http://abacus.deepmodeling.com/en/latest/advanced/interface/dpgen.html) for ABACUS interface with DP-GEN. -To compile ABACUS with DeePMD-kit, you need to define `DeePMD_DIR` and `TensorFlow_DIR` in the file `Makefile.vars` or use +To compile ABACUS with DeePMD-kit, you need to define `DeePMD_DIR` and `TensorFlow_DIR` (TensorFlow Backend, optional) and/or `LIBTORCH_DIR` (PyTorch Backend, optional) in the file `Makefile.vars`. +Or the `tensorflow_cc` and `torch` libraries are in the same directory as the `deepmd_c`/`deepmd_cc` libraries, then ```makefile -make DeePMD_DIR=~/deepmd-kit TensorFlow_DIR=~/tensorflow +make DeePMD_DIR=/dir_to_deepmd-kit ``` +DeePMD-kit supports TensorFlow backend but its libraries are placed at another directory, then -directly. - -> `deepmd_c`/`deepmd_cc` and `tensorflow_cc` libraries would be called according to `DeePMD_DIR` and `TensorFlow_DIR`, which is showed in detail in [this page](https://github.com/deepmodeling/deepmd-kit/blob/master/doc/inference/cxx.md). If `TensorFlow_DIR` is not defined, it will be the same as `DeePMD_DIR`. Note that `tensorflow_cc` is not required if `deepmd_c` is found. +```makefile +make DeePMD_DIR=/dir_to_deepmd-kit TensorFlow_DIR=/dir_to_tensorflow +``` +Similarly, DeePMD-kit supports PyTorch backend but its libraries are placed at another directory, then +```makefile +make DeePMD_DIR=/dir_to_deepmd-kit Torch_DIR=/dir_to_pytorch +``` ### Add LibRI Support To use new EXX, you need two libraries: [LibRI](https://github.com/abacusmodeling/LibRI) and [LibComm](https://github.com/abacusmodeling/LibComm) and need to define `LIBRI_DIR` and `LIBCOMM_DIR` in the file `Makefile.vars` or use diff --git a/docs/advanced/interface/deepks.md b/docs/advanced/interface/deepks.md index be2cfafa975..3fb2cb5b4ce 100644 --- a/docs/advanced/interface/deepks.md +++ b/docs/advanced/interface/deepks.md @@ -1,9 +1,14 @@ # DeePKS -[DeePKS](https://pubs.acs.org/doi/10.1021/acs.jctc.0c00872) is a machine-learning aided density funcitonal model that fits the energy difference between highly accurate but computationally demanding method and effcient but less accurate method via neural-network. As such, the trained DeePKS model can provide highly accurate energetics (and forces) with relatively low computational cost, and can therefore act as a bridge to connect expensive quantum mechanic data and machine-learning-based potentials. While the original framework of DeePKS is for molecular systems, please refer to this [reference](https://arxiv.org/abs/2206.10093) for the application of DeePKS in periodic systems. +[DeePKS](https://pubs.acs.org/doi/10.1021/acs.jctc.0c00872) is a machine-learning (ML) aided density funcitonal model that fits the energy difference between highly accurate but computationally demanding method and effcient but less accurate method via neural-network. Common high-precision methods include hybrid functionals or CCSD-T, while common low-precision methods are LDA/GGA. -Detailed instructions on installing and running DeePKS can be found on this [website](https://deepks-kit.readthedocs.io/en/latest/index.html). An [example](https://github.com/deepmodeling/deepks-kit/tree/abacus/examples/water_single_lda2pbe_abacus) for training DeePKS model with ABACUS is also provided. The DeePKS-related keywords in `INPUT` file can be found [here](http://abacus.deepmodeling.com/en/latest/advanced/input_files/input-main.html#deepks). +As such, the trained DeePKS model can provide highly accurate energetics (and forces/band gap/density) with relatively low computational cost, and can therefore act as a bridge to connect expensive quantum mechanic data and machine-learning-based potentials. +While the original framework of DeePKS is for molecular systems, please refer to this [J. Phys. Chem. A 126.49 (2022): 9154-9164](https://pubs.acs.org/doi/abs/10.1021/acs.jpca.2c05000) for the application of DeePKS in periodic systems. -> Note: Use the LCAO basis for DeePKS-related calculations +Detailed instructions on installing and running DeePKS can be found on this [website](https://deepks-kit.readthedocs.io/en/latest/index.html). The DeePKS-related keywords in `INPUT` file can be found [here](http://abacus.deepmodeling.com/en/latest/advanced/input_files/input-main.html#deepks). An [example](https://github.com/deepmodeling/deepks-kit/tree/abacus/examples/water_single_lda2pbe_abacus) for training DeePKS model with ABACUS is also provided. For practical applications, users can refer to a series of [Notebooks](https://bohrium.dp.tech/collections/1921409690). These Notebooks provide detailed instructions on how to train and use the DeePKS model using perovskite as an example. Currently, these tutorials are available in Chinese, but we plan to release corresponding English versions in the near future. + + + +> Note: DeePKS calculations can only be performed by the LCAO basis. diff --git a/docs/advanced/interface/deeptb.md b/docs/advanced/interface/deeptb.md new file mode 100644 index 00000000000..13cdf406dc2 --- /dev/null +++ b/docs/advanced/interface/deeptb.md @@ -0,0 +1,5 @@ +# DeePTB + +[DeePTB](https://github.com/deepmodeling/DeePTB) is an innovative Python package that uses deep learning to accelerate ab initio electronic structure simulations. It offers versatile, accurate, and efficient simulations for a wide range of materials and phenomena. Trained on small systems, DeePTB can predict electronic structures of large systems, handle structural perturbations, and integrate with molecular dynamics for finite temperature simulations, providing comprehensive insights into atomic and electronic behavior. See more details in [DeePTB-SK: Nat Commun 15, 6772 (2024)](https://www.nature.com/articles/s41467-024-51006-4) and [DeePTB-E3: arXiv:2407.06053](https://arxiv.org/pdf/2407.06053). + +DeePTB trains the model based on the Structure, Eigenvalues, Hamiltonian, Density matrix, and Overlap matrix from first-principles calcualtions. DeePTB team provides the interfaces [dftio](https://github.com/deepmodeling/dftio) with other first-principles softwares. [dftio](https://github.com/deepmodeling/dftio) fully supports the interfaces with ABACUS, and can transfer the Structure, Eigenvalues, Hamiltonian, Density matrix, and Overlap matrix from ABACUS into the format used in [DeePTB](https://github.com/deepmodeling/DeePTB). diff --git a/docs/advanced/interface/index.rst b/docs/advanced/interface/index.rst index 4bb8704727a..99d656885f0 100644 --- a/docs/advanced/interface/index.rst +++ b/docs/advanced/interface/index.rst @@ -9,6 +9,7 @@ Interfaces to Other Softwares deepks dpgen deeph + deeptb Hefei-NAMD phonopy Wannier90 diff --git a/docs/advanced/pp_orb.md b/docs/advanced/pp_orb.md index 734e8bf6414..953ddc85aa6 100644 --- a/docs/advanced/pp_orb.md +++ b/docs/advanced/pp_orb.md @@ -19,7 +19,20 @@ Inside ABACUS, orbitals in LCAO basis are arranged lexicographically by species- ## Generating atomic orbital bases -Users may also choose to generate their own atomic obitals. In ABACUS, the atomic orbital bases are generated using a scheme developed in the [paper](https://iopscience.iop.org/article/10.1088/0953-8984/22/44/445501). A detailed description of the procedure for generating orbitals will be provided later. +Users may also generate ABACUS numerical atomic obitals based on their own flavor. The theoretical background of orbital generation can be found in following works: + +- Spillage: [Chen M, Guo G C, He L. Systematically improvable optimized atomic basis sets for ab initio calculations[J]. Journal of Physics: Condensed Matter, 2010, 22(44): 445501.](https://iopscience.iop.org/article/10.1088/0953-8984/22/44/445501) +- PTG DPSI: [Lin P, Ren X, He L. Strategy for constructing compact numerical atomic orbital basis sets by incorporating the gradients of reference wavefunctions[J]. Physical Review B, 2021, 103(23): 235131.](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.103.235131) + +Guidelines for generating atomic orbital bases are as follows: + +- [Numerical Atomic Orbitals 1: the nomenclature and usage of numerical atomic orbitals in ABACUS](https://mcresearch.github.io/abacus-user-guide/abacus-nac1.html) (Chinese) +- [Numerical Atomic Orbitals 2: generate numerical atomic orbitals based on given norm-conserving pseudopotential](https://mcresearch.github.io/abacus-user-guide/abacus-nac1.html) (Chinese) +- [Numerical Atomic Orbitals 3: generate high-precision numerical atomic orbitals](https://mcresearch.github.io/abacus-user-guide/abacus-nac1.html) (Chinese) + +Stable orbital generation programs can be found in guidelines above, there is also another developing version of orbital generation program, in which algorithms are consecutively improved: [Github repository of ABACUS ORBGEN project](https://github.com/kirk0830/ABACUS-ORBGEN), the usage of which can be found in README (in English) file. + +*NOTE*: users are encouraged to cite the above works when numerical atomic orbitals and its generation codes are used in their research. ## BSSE Correction @@ -51,16 +64,46 @@ $$ $$ ## Pseudopotentials - -In ABACUS, we support norm-conserving and ultrasoft pseudopotentials. -For norm-conserving pseudopotentials, we support four different formats of the pseudopotential files: UPF, UPF2, VWR, and BLPS. -For ultrasoft pseudopotentials, currently we support only one format of the pseudopotential files: UPF2. - -For more information, check the `ATOMIC_SPECIES` section in the specification of the [STRU file](./input_files/stru.md). - -Here we list some common sources of the pseudopotential files: - -1. [Quantum ESPRESSO](http://www.quantum-espresso.org/pseudopotentials/). -2. [SG15-ONCV](http://quantum-simulation.org/potentials/sg15_oncv/upf/). -3. [DOJO](http://www.pseudo-dojo.org/). -4. [BLPS](https://github.com/PrincetonUniversity/BLPSLibrary). +### Supported formats +ABACUS supports both norm-conserving and ultrasoft pseudopotentials. For norm-conserving pseudopotentials, UPF, UPF2, VWR, and BLPS formats are supported. For ultrasoft pseudopotentials, UPF and UPF2 formats are supported. + +### Usage +For more information about pseudopotential usage, check the `ATOMIC_SPECIES` section in the specification of the [STRU file](./input_files/stru.md). + +### Download +Users can find pseudopotentials in the following links: + +**Website** +- [Quantum ESPRESSO](https://www.quantum-espresso.org/pseudopotentials): the official website of Quantum ESPRESSO, where you can find a large number of pseudopotential files. +- [Stantard Solid State Pseudopotential library](https://www.materialscloud.org/sssp): a library of **high-quality** pseudopotentials for solid-state calculations, with **a large number of tests on efficiency and precison**. +- [PWmat](http://www.pwmat.com/potential-download): a website that provides a large number of pseudopotential files, various kinds of semi-core constructed pseudopotentials are included. **Several sets (with or without f-electrons/noncolinear core correction) of Lanthanide pseudopotentials are also available**. +- [THEOS](http://theossrv1.epfl.ch/Main/Pseudopotentials): PSlibrary 0.3.1, a library of pseudopotentials for DFT calculations, including ultrasoft, paw, norm-conserving both full-relativistic and scalar-relativistic pseudopotentials. +- [ABACUS@USTC](https://abacus.ustc.edu.cn/pseudo/list.htm): **ABACUS official website** where you can find a large number of pseudopotential files and numerical atomic orbital files. +- [BLPS](https://github.com/PrincetonUniversity/BLPSLibrary): BLPS format pseudopotential library + +**Norm-conserving pseudopotentials** +- [SG15](http://www.quantum-simulation.org/potentials/sg15_oncv/): **vastly used in ABACUS** DFT calculation and numerical atomic orbital generation. +- [PseudoDOJO](http://www.pseudo-dojo.org/): another widely used pseudopotential database, developed by Abinit group, **including Lanthanide pseudopotentials (f-electrons frozen)**. +- [The Rappe group](https://www.sas.upenn.edu/rappegroup/research/pseudo-potential-gga.html): a collection of GGA pseudopotentials which are generated with Opium code, several tests proves that are out-performing in alloy systems. +- [Matteo Giantomassi's Github repo](https://github.com/gmatteo/pseudos_ac_she): a Github repository that contains norm-conserving pseudopotentials for **Actinides and superheavy elements to 120-th element**. + +**Ultrasoft pseudopotentials** +- [Vanderbilt](http://www.physics.rutgers.edu/~dhv/uspp/): a collection of ultrasoft pseudopotentials generated by Vanderbilt group. +- [GBRV](https://www.physics.rutgers.edu/gbrv/) by Kevin F. Garrity, Joseph W. Bennett, Karin M. Rabe, and David Vanderbilt: presently the most popular ultrasoft pseudpotentials in Quantum ESPRESSO user community. + +### Pseudopotential Generation +For pseudopotential generation, please refer to the following links for more information: +- [Quantum ESPRESSO](http://www.quantum-espresso.org/pseudopotentials/) +- [ONCVPSP](http://www.mat-simresearch.com/) +- [Opium](https://opium.sourceforge.net/) + +A Chinese guideline is also available here: [A brief introduction of norm-conserving pseudopotential generation](https://mcresearch.github.io/abacus-user-guide/abacus-upf.html) + +# ABACUS Pseudopotential-Numerical atomic orbital Square (APNS) project +For the purpose of providing high-quality pseudopotentials and numerical atomic orbitals, we have initiated the APNS project. The project is aimed at providing a large number of high-quality pseudopotentials and numerical atomic orbitals, along with diverse test data for the ABACUS user community, reduce the cost of generating and testing pseudopotentials and numerical atomic orbitals by users, and promote the development of ABACUS software. The project is currently in the development stage, and we welcome contributions from the community. For more information, please refer to the following links: +- [APNS website: test data and results](https://kirk0830.github.io/ABACUS-Pseudopot-Nao-Square/) +- [APNS workflow (Github repository): high-throughput test of pseudopotentials and numerical atomic orbitals](https://github.com/kirk0830/ABACUS-Pseudopot-Nao-Square) + +There are also other excellent projects that provide high-quality pseudopotentials along with test data: +- [Solid State Pseudopotential library](https://www.materialscloud.org/sssp) +- [Verification of the precision of DFT implementation via AiiDA common workflows](https://acwf-verification.materialscloud.org/) diff --git a/docs/conf.py b/docs/conf.py index ef845b10c8b..6276db30315 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ # -- Project information ----------------------------------------------------- project = 'ABACUS' -copyright = '2022, ABACUS' +copyright = '2024, ABACUS' author = 'ABACUS' # The full version, including alpha/beta/rc tags @@ -33,7 +33,6 @@ extensions = [ 'myst_parser', 'deepmodeling_sphinx', - 'sphinxcontrib.jquery', ] myst_enable_extensions = [ "amsmath", @@ -66,7 +65,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = 'sphinx_book_theme' html_logo = 'abacus-logo.svg' diff --git a/docs/requirements.txt b/docs/requirements.txt index 34b6c32f45d..d7fef4eb495 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ urllib3 myst_parser[linkify] -sphinx_rtd_theme -deepmodeling_sphinx +sphinx-book-theme +deepmodeling-sphinx>=0.3.0 diff --git a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-a b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-a index 4fe797dadad..97520e857e4 100644 --- a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-a +++ b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-a @@ -3,7 +3,7 @@ pseudo_dir ../../../tests/PP_ORB orbital_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 calculation nscf basis_type lcao init_chg file diff --git a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-b b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-b index 637b9aa5336..22e02eddbab 100644 --- a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-b +++ b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-b @@ -3,7 +3,7 @@ pseudo_dir ../../../tests/PP_ORB orbital_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 calculation nscf basis_type lcao init_chg file diff --git a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-c b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-c index 426b111e61e..b2cdf5958ee 100644 --- a/examples/berryphase/lcao_PbTiO3/INPUT-nscf-c +++ b/examples/berryphase/lcao_PbTiO3/INPUT-nscf-c @@ -3,7 +3,7 @@ pseudo_dir ../../../tests/PP_ORB orbital_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 calculation nscf basis_type lcao init_chg file diff --git a/examples/berryphase/pw_PbTiO3/INPUT-nscf-a b/examples/berryphase/pw_PbTiO3/INPUT-nscf-a index 23fc9549fc6..c344e9ff15e 100644 --- a/examples/berryphase/pw_PbTiO3/INPUT-nscf-a +++ b/examples/berryphase/pw_PbTiO3/INPUT-nscf-a @@ -2,7 +2,7 @@ INPUT_PARAMETERS pseudo_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 pw_diag_thr 1e-10 calculation nscf basis_type pw diff --git a/examples/berryphase/pw_PbTiO3/INPUT-nscf-b b/examples/berryphase/pw_PbTiO3/INPUT-nscf-b index a59e92149cb..ef6c1984c70 100644 --- a/examples/berryphase/pw_PbTiO3/INPUT-nscf-b +++ b/examples/berryphase/pw_PbTiO3/INPUT-nscf-b @@ -2,7 +2,7 @@ INPUT_PARAMETERS pseudo_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 pw_diag_thr 1e-10 calculation nscf basis_type pw diff --git a/examples/berryphase/pw_PbTiO3/INPUT-nscf-c b/examples/berryphase/pw_PbTiO3/INPUT-nscf-c index fdc68d69a33..2242ff889e8 100644 --- a/examples/berryphase/pw_PbTiO3/INPUT-nscf-c +++ b/examples/berryphase/pw_PbTiO3/INPUT-nscf-c @@ -2,7 +2,7 @@ INPUT_PARAMETERS pseudo_dir ../../../tests/PP_ORB ntype 3 ecutwfc 50 -symmetry 0 +symmetry -1 pw_diag_thr 1e-10 calculation nscf basis_type pw diff --git a/examples/lr-tddft/lcao_Si2/INPUT b/examples/lr-tddft/lcao_Si2/INPUT index cac5e5cca35..19ea04fe1a7 100644 --- a/examples/lr-tddft/lcao_Si2/INPUT +++ b/examples/lr-tddft/lcao_Si2/INPUT @@ -37,4 +37,3 @@ out_alllog 1 nvirt 19 abs_wavelen_range 100 175 -#diago_full_acc 1 diff --git a/examples/vdw/si2/INPUT1 b/examples/vdw/si2-vdwd2/INPUT1 similarity index 100% rename from examples/vdw/si2/INPUT1 rename to examples/vdw/si2-vdwd2/INPUT1 diff --git a/examples/vdw/si2/INPUT2 b/examples/vdw/si2-vdwd2/INPUT2 similarity index 62% rename from examples/vdw/si2/INPUT2 rename to examples/vdw/si2-vdwd2/INPUT2 index 8b27ddf50cc..dc3d7801d57 100644 --- a/examples/vdw/si2/INPUT2 +++ b/examples/vdw/si2-vdwd2/INPUT2 @@ -1,5 +1,6 @@ -#INPUT file for applying D3(BJ) correction -#with default VdW parameters +#INPUT file for applying D2 correction +#where I chose to manually set the C6 parameter +#in file c6.txt #in pw basis INPUT_PARAMETERS @@ -12,4 +13,5 @@ ecutwfc 50 scf_nmax 100 scf_thr 1e-6 basis_type pw -vdw_method d3_bj +vdw_method d2 +vdw_C6_file c6.txt diff --git a/examples/vdw/si2/KPT b/examples/vdw/si2-vdwd2/KPT similarity index 100% rename from examples/vdw/si2/KPT rename to examples/vdw/si2-vdwd2/KPT diff --git a/examples/vdw/si2/STRU b/examples/vdw/si2-vdwd2/STRU similarity index 100% rename from examples/vdw/si2/STRU rename to examples/vdw/si2-vdwd2/STRU diff --git a/examples/vdw/si2/c6.txt b/examples/vdw/si2-vdwd2/c6.txt similarity index 100% rename from examples/vdw/si2/c6.txt rename to examples/vdw/si2-vdwd2/c6.txt diff --git a/examples/vdw/si2/run.sh b/examples/vdw/si2-vdwd2/run.sh similarity index 100% rename from examples/vdw/si2/run.sh rename to examples/vdw/si2-vdwd2/run.sh diff --git a/examples/vdw/si2-vdwd3/INPUT1 b/examples/vdw/si2-vdwd3/INPUT1 new file mode 100644 index 00000000000..09c40e8103a --- /dev/null +++ b/examples/vdw/si2-vdwd3/INPUT1 @@ -0,0 +1,15 @@ +#INPUT file for applying D3(BJ) correction +#in lcao basis + +INPUT_PARAMETERS +#Parameters (General) +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +ntype 1 +#Parameters (Accuracy) +ecutwfc 50 +scf_nmax 100 +scf_thr 1e-6 +basis_type lcao +vdw_method d3_bj +dft_functional MGGA_X_SCAN+MGGA_C_SCAN diff --git a/examples/vdw/si2-vdwd3/INPUT2 b/examples/vdw/si2-vdwd3/INPUT2 new file mode 100644 index 00000000000..1e7a68e5b46 --- /dev/null +++ b/examples/vdw/si2-vdwd3/INPUT2 @@ -0,0 +1,15 @@ +#INPUT file for applying D3(BJ) correction +#in pw basis + +INPUT_PARAMETERS +#Parameters (General) +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +ntype 1 +#Parameters (Accuracy) +ecutwfc 50 +scf_nmax 100 +scf_thr 1e-6 +basis_type pw +vdw_method d3_bj +dft_functional pbe diff --git a/examples/vdw/si2-vdwd3/INPUT3 b/examples/vdw/si2-vdwd3/INPUT3 new file mode 100644 index 00000000000..8a5a4e9a2c0 --- /dev/null +++ b/examples/vdw/si2-vdwd3/INPUT3 @@ -0,0 +1,21 @@ +#INPUT file for applying D3(BJ) correction +#in lcao basis. This example illustrates +#the manually setting on vdw parameters + +INPUT_PARAMETERS +#Parameters (General) +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +ntype 1 +#Parameters (Accuracy) +ecutwfc 50 +scf_nmax 100 +scf_thr 1e-6 +basis_type lcao +vdw_method d3_bj +dft_functional pbe +vdw_s6 1.000 +vdw_s8 0.722 +vdw_a1 1.217 +vdw_a2 1.000 + diff --git a/examples/vdw/si2-vdwd3/KPT b/examples/vdw/si2-vdwd3/KPT new file mode 100644 index 00000000000..253d74de39a --- /dev/null +++ b/examples/vdw/si2-vdwd3/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +4 4 4 0 0 0 diff --git a/examples/vdw/si2-vdwd3/STRU b/examples/vdw/si2-vdwd3/STRU new file mode 100644 index 00000000000..ecf106c93d8 --- /dev/null +++ b/examples/vdw/si2-vdwd3/STRU @@ -0,0 +1,24 @@ +#This is the atom file containing all the information +#about the lattice structure. + +ATOMIC_SPECIES +Si 1.000 Si_ONCV_PBE-1.0.upf #Element, Mass, Pseudopotential + +NUMERICAL_ORBITAL +Si_gga_6au_100Ry_2s2p1d.orb + +LATTICE_CONSTANT +10.2 #Lattice constant + +LATTICE_VECTORS +0.5 0.5 0.0 #Lattice vector 1 +0.5 0.0 0.5 #Lattice vector 2 +0.0 0.5 0.5 #Lattice vector 3 + +ATOMIC_POSITIONS +Cartesian #Cartesian(Unit is LATTICE_CONSTANT) +Si #Name of element +0.0 #Magnetic for this element. +2 #Number of atoms +0.00 0.00 0.00 0 0 0 #x,y,z, move_x, move_y, move_z +0.25 0.25 0.25 1 1 1 diff --git a/examples/vdw/si2-vdwd3/run.sh b/examples/vdw/si2-vdwd3/run.sh new file mode 100644 index 00000000000..ab26cc16633 --- /dev/null +++ b/examples/vdw/si2-vdwd3/run.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +ABACUS_PATH=$(awk -F "=" '$1=="ABACUS_PATH"{print $2}' ../../SETENV) +ABACUS_NPROCS=$(awk -F "=" '$1=="ABACUS_NPROCS"{print $2}' ../../SETENV) +ABACUS_THREADS=$(awk -F "=" '$1=="ABACUS_THREADS"{print $2}' ../../SETENV) + +cp INPUT1 INPUT +OMP_NUM_THREADS=${ABACUS_THREADS} mpirun -np ${ABACUS_NPROCS} ${ABACUS_PATH} | tee scf1.output +mv OUT.ABACUS/running_scf.log OUT.ABACUS/running_scf1.log +cp INPUT2 INPUT +OMP_NUM_THREADS=${ABACUS_THREADS} mpirun -np ${ABACUS_NPROCS} ${ABACUS_PATH} | tee scf2.output +mv OUT.ABACUS/running_scf.log OUT.ABACUS/running_scf2.log +cp INPUT3 INPUT +OMP_NUM_THREADS=${ABACUS_THREADS} mpirun -np ${ABACUS_NPROCS} ${ABACUS_PATH} | tee scf3.output +mv OUT.ABACUS/running_scf.log OUT.ABACUS/running_scf3.log +rm INPUT + +if [[ ! -f scf1.output ]] || + [[ ! -f scf2.output ]] || + [[ ! -f scf3.output ]] || + [[ ! -f OUT.ABACUS/running_scf1.log ]] || + [[ ! -f OUT.ABACUS/running_scf2.log ]] || + [[ ! -f OUT.ABACUS/running_scf3.log ]] || + [[ ! ( "$(tail -1 OUT.ABACUS/running_scf1.log)" == " Total Time :"* ) ]] || + [[ ! ( "$(tail -1 OUT.ABACUS/running_scf2.log)" == " Total Time :"* ) ]] || + [[ ! ( "$(tail -1 OUT.ABACUS/running_scf3.log)" == " Total Time :"* ) ]] +then + echo "job is failed!" + exit 1 +else + echo "job is successed!" + exit 0 +fi diff --git a/python/pyabacus/CMakeLists.txt b/python/pyabacus/CMakeLists.txt index e21f5e14463..5baa420ce8f 100644 --- a/python/pyabacus/CMakeLists.txt +++ b/python/pyabacus/CMakeLists.txt @@ -1,18 +1,20 @@ cmake_minimum_required(VERSION 3.15...3.26) +# project settings project( ${SKBUILD_PROJECT_NAME} VERSION ${SKBUILD_PROJECT_VERSION} LANGUAGES CXX) +# find python and pybind11 find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) find_package(pybind11 CONFIG REQUIRED) +# set source path set(ABACUS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../../source") set(BASE_PATH "${ABACUS_SOURCE_DIR}/module_base") set(NAO_PATH "${ABACUS_SOURCE_DIR}/module_basis/module_nao") set(HSOLVER_PATH "${ABACUS_SOURCE_DIR}/module_hsolver") -set(HAMILT_PATH "${ABACUS_SOURCE_DIR}/module_hamilt_general") set(PSI_PATH "${ABACUS_SOURCE_DIR}/module_psi") set(ENABLE_LCAO ON) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../cmake") @@ -63,11 +65,14 @@ else() endif() endif() -include_directories(${BASE_PATH} +# add include directories +include_directories( + ${BASE_PATH} ${ABACUS_SOURCE_DIR} - ${ABACUS_SOURCE_DIR}/module_base/module_container) + ${ABACUS_SOURCE_DIR}/module_base/module_container + ) -# add library +# add basic libraries set(CMAKE_POSITION_INDEPENDENT_CODE ON) # add base set(BASE_BINARY_DIR "${PROJECT_SOURCE_DIR}/build/base") @@ -80,83 +85,6 @@ set(ORB_BINARY_DIR "${PROJECT_SOURCE_DIR}/build/orb") add_subdirectory(${ABACUS_SOURCE_DIR}/module_basis/module_ao ${ORB_BINARY_DIR}) # set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -# add nao shared library -list(APPEND _naos - ${NAO_PATH}/atomic_radials.cpp - ${NAO_PATH}/beta_radials.cpp - ${NAO_PATH}/hydrogen_radials.cpp - ${NAO_PATH}/numerical_radial.cpp - ${NAO_PATH}/pswfc_radials.cpp - ${NAO_PATH}/radial_collection.cpp - ${NAO_PATH}/radial_set.cpp - ${NAO_PATH}/real_gaunt_table.cpp - ${NAO_PATH}/sphbes_radials.cpp - ${NAO_PATH}/two_center_bundle.cpp - ${NAO_PATH}/two_center_integrator.cpp - ${NAO_PATH}/two_center_table.cpp - ${NAO_PATH}/projgen.cpp - # dependency - ${ABACUS_SOURCE_DIR}/module_base/kernels/math_op.cpp - # ${ABACUS_SOURCE_DIR}/module_psi/kernels/psi_memory_op.cpp - ${ABACUS_SOURCE_DIR}/module_base/module_device/memory_op.cpp - ) -add_library(naopack SHARED - ${_naos} - ) -# add diago shared library -list(APPEND _diago - ${HSOLVER_PATH}/diago_dav_subspace.cpp - ${HSOLVER_PATH}/diago_david.cpp - ${HSOLVER_PATH}/diag_const_nums.cpp - ${HSOLVER_PATH}/diago_iter_assist.cpp - - ${HSOLVER_PATH}/kernels/dngvd_op.cpp - ${HSOLVER_PATH}/kernels/math_kernel_op.cpp - # dependency - ${BASE_PATH}/module_device/device.cpp - ${BASE_PATH}/module_device/memory_op.cpp - - ${HAMILT_PATH}/operator.cpp - ${PSI_PATH}/psi.cpp - ) -add_library(diagopack SHARED - ${_diago} - ) -target_link_libraries(diagopack - PRIVATE - ${OpenBLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ) -# link math_libs -if(MKLROOT) - target_link_libraries(naopack - base - parameter - container - orb - ${math_libs} - MPI::MPI_CXX - OpenMP::OpenMP_CXX - ) -else() - target_link_libraries(naopack - base - parameter - container - orb - ${math_libs} - ) -endif() -# list(APPEND _sources ${_naos} ${_bases}) -list(APPEND _sources - ${PROJECT_SOURCE_DIR}/src/py_abacus.cpp - ${PROJECT_SOURCE_DIR}/src/py_base_math.cpp - ${PROJECT_SOURCE_DIR}/src/py_m_nao.cpp - ${PROJECT_SOURCE_DIR}/src/py_hsolver.cpp - ) -pybind11_add_module(_core MODULE ${_sources}) -target_link_libraries(_core PRIVATE pybind11::headers naopack diagopack) -target_compile_definitions(_core PRIVATE VERSION_INFO=${PROJECT_VERSION}) # set RPATH execute_process( COMMAND "${PYTHON_EXECUTABLE}" -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())" @@ -167,9 +95,9 @@ execute_process( # set package name to pyabacus set(TARGET_PACK pyabacus) set(CMAKE_INSTALL_RPATH "${PYTHON_SITE_PACKAGES}/${TARGET_PACK}") -set_target_properties(_core PROPERTIES INSTALL_RPATH "$ORIGIN") -set_target_properties(naopack PROPERTIES INSTALL_RPATH "$ORIGIN") -set_target_properties(diagopack PROPERTIES INSTALL_RPATH "$ORIGIN") -install(TARGETS _core naopack DESTINATION ${TARGET_PACK}) -install(TARGETS _core diagopack DESTINATION ${TARGET_PACK}) + +# add subdirectories for submodules +add_subdirectory(${PROJECT_SOURCE_DIR}/src/hsolver) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleBase) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleNAO) diff --git a/python/pyabacus/CONTRIBUTING.md b/python/pyabacus/CONTRIBUTING.md new file mode 100644 index 00000000000..fbd23ad9ffe --- /dev/null +++ b/python/pyabacus/CONTRIBUTING.md @@ -0,0 +1,376 @@ +# Developer Guide + +## Introduction + +Welcome to the `pyabacus` project! This document provides guidelines and instructions for developers who want to contribute to this project. + +`pyabacus` is a Python interface for the ABACUS package. It provides a high-level Python API for interacting with the ABACUS library, allowing users to perform electronic structure calculations and analyze the results using Python. + + + +- [Project structure](#project-structure) + - [Root CMake Configuration](#root-cmake-configuration) + - [Module CMake Configuration](#module-cmake-configuration) +- [Development Process](#development-process) + + + +**If you are new to the project**, please refer to the [README.md](./README.md) file for an overview of the project and its goals. + +**If you are already familiar with the project and want to contribute**, this guide will help you understand the project structure, development process, and best practices for contributing code. + +**If you have any questions or need help**, feel free to reach out to the maintainers or create an issue in the repository. + +**Please feel free to contribute to this guide** by submitting a pull request with any improvements or additional information. + +Let's get started! + +## Project Structure + +The project is organized as follows: + +``` +pyabacus/ +├── CMakeLists.txt +└── src + ├── pyabacus + │ └── {your_module} + │ ├── {interface}.py + │ └── __init__.py + └── {your_module} + ├── {your_code}.cpp + └── CMakeLists.txt +``` + +Our project is built using [pybind11](https://github.com/pybind/pybind11) and [scikit-build-core](https://scikit-build-core.readthedocs.io/) for facilitating the `CMake` build toolchain. So the `CMakeLists.txt` configuration is the key to thoroughly understanding the project structure. + +### Root CMake Configuration + +The `CMakeLists.txt` in root directory is the main configuration file for the pyabacus project. It sets up the project, finds necessary dependencies, configures build options, and includes subdirectories for different modules. Below is a detailed explanation of each section of the file: + +```cmake +cmake_minimum_required(VERSION 3.15...3.26) + +# Project settings +project( + ${SKBUILD_PROJECT_NAME} + VERSION ${SKBUILD_PROJECT_VERSION} + LANGUAGES CXX) +``` +- This section sets the project name, version, and the programming languages used (C++ in this case). The project name and version are obtained from the `SKBUILD_PROJECT_NAME` and `SKBUILD_PROJECT_VERSION` variables, respectively. + +```cmake +# Find Python and pybind11 +find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) +find_package(pybind11 CONFIG REQUIRED) +``` +- This section finds the required Python and pybind11 packages. + +```cmake +# Set source path +set(ABACUS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../../source") +set(BASE_PATH "${ABACUS_SOURCE_DIR}/module_base") +set(NAO_PATH "${ABACUS_SOURCE_DIR}/module_basis/module_nao") +set(HSOLVER_PATH "${ABACUS_SOURCE_DIR}/module_hsolver") +set(PSI_PATH "${ABACUS_SOURCE_DIR}/module_psi") +set(ENABLE_LCAO ON) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../cmake") +``` +- This section sets various source paths and configuration options. It defines the paths to different modules and appends the custom CMake module path. + +```cmake +# Add math_libs +if(DEFINED ENV{MKLROOT} AND NOT DEFINED MKLROOT) + set(MKLROOT "$ENV{MKLROOT}") +endif() +if(MKLROOT) + set(MKL_INTERFACE lp64) + set(ENABLE_MPI ON) + if (ENABLE_MPI) + find_package(MPI REQUIRED) + include_directories(${MPI_CXX_INCLUDE_PATH}) + endif() + + set(USE_OPENMP ON) + if(USE_OPENMP) + find_package(OpenMP REQUIRED) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + add_link_options(${OpenMP_CXX_LIBRARIES}) + endif() + find_package(MKL REQUIRED) + add_definitions(-D__MKL) + include_directories(${MKL_INCLUDE} ${MKL_INCLUDE}/fftw) + + if(NOT ENABLE_DEEPKS) + list(APPEND math_libs IntelMKL::MKL) + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES Intel) + list(APPEND math_libs -lifcore) + endif() +else() + find_package(FFTW3 REQUIRED) + add_compile_definitions(__FFTW3) + find_package(LAPACK REQUIRED) + include_directories(${FFTW3_INCLUDE_DIRS}) + list(APPEND math_libs FFTW3::FFTW3 LAPACK::LAPACK) + + if(ENABLE_LCAO) + find_package(ScaLAPACK REQUIRED) + list(APPEND math_libs ScaLAPACK::ScaLAPACK) + endif() +endif() +``` +- This section configures the math libraries. It checks for the presence of the Intel Math Kernel Library (MKL) and configures it if available. If MKL is not available, it falls back to using FFTW3 and LAPACK. It also configures MPI and OpenMP if enabled. + +```cmake +# Add include directories +include_directories( + ${BASE_PATH} + ${ABACUS_SOURCE_DIR} + ${ABACUS_SOURCE_DIR}/module_base/module_container + ) +``` +- This section adds the necessary include directories for the project. + +```cmake +# Add basic libraries +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# Add base +set(BASE_BINARY_DIR "${PROJECT_SOURCE_DIR}/build/base") +add_subdirectory(${ABACUS_SOURCE_DIR}/module_base ${BASE_BINARY_DIR}) +# Add parameter +set(PARAMETER_BINARY_DIR "${PROJECT_SOURCE_DIR}/build/parameter") +add_subdirectory(${ABACUS_SOURCE_DIR}/module_parameter ${PARAMETER_BINARY_DIR}) +# Add orb +set(ORB_BINARY_DIR "${PROJECT_SOURCE_DIR}/build/orb") +add_subdirectory(${ABACUS_SOURCE_DIR}/module_basis/module_ao ${ORB_BINARY_DIR}) +``` +- This section sets the position-independent code flag and adds subdirectories for the base, parameter, and orb modules. It specifies the build directories for these modules. + +```cmake +# Set RPATH +execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())" + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES + OUTPUT_STRIP_TRAILING_WHITESPACE +) +``` +- This section sets the runtime search path (RPATH) for the Python site-packages directory. It uses a Python command to get the site-packages path and stores it in the `PYTHON_SITE_PACKAGES` variable. + +```cmake +# Set package name to pyabacus +set(TARGET_PACK pyabacus) +set(CMAKE_INSTALL_RPATH "${PYTHON_SITE_PACKAGES}/${TARGET_PACK}") +``` +- This section sets the package name to `pyabacus` and configures the install RPATH to include the Python site-packages directory. + +```cmake +# Add subdirectories for submodules +add_subdirectory(${PROJECT_SOURCE_DIR}/src/hsolver) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleBase) +add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleNAO) +``` +- This section adds subdirectories for modules. Each subdirectory contains its own `CMakeLists.txt` for further configuration. + +By following this structure, the `CMakeLists.txt` file ensures that all necessary dependencies are found, configured, and included in the build process. It also sets up the project environment and includes submodules for different components of the `pyabacus` project. + +### Module CMake Configuration + +I'll show you a `CMakeLists.txt` for example (pyabacus.hsolver) + +```cmake +# Add diago shared library +list(APPEND _diago + ${HSOLVER_PATH}/diago_dav_subspace.cpp + ${HSOLVER_PATH}/diago_david.cpp + ${HSOLVER_PATH}/diag_const_nums.cpp + ${HSOLVER_PATH}/diago_iter_assist.cpp + ${HSOLVER_PATH}/kernels/dngvd_op.cpp + ${HSOLVER_PATH}/kernels/math_kernel_op.cpp + ${BASE_PATH}/kernels/math_op.cpp + ${BASE_PATH}/module_device/device.cpp + ${BASE_PATH}/module_device/memory_op.cpp + ${PSI_PATH}/psi.cpp +) +add_library(diagopack SHARED ${_diago}) +target_link_libraries(diagopack + base + parameter + container + orb + ${math_libs} + ${OpenBLAS_LIBRARIES} + ${LAPACK_LIBRARIES} +) + +list(APPEND pymodule_hsolver + ${PROJECT_SOURCE_DIR}/src/hsolver/py_hsolver.cpp +) + +# Use pybind11 to add python module +pybind11_add_module(_hsolver_pack MODULE ${pymodule_hsolver}) +# Link your dependencies and pybind11 libraries to your module +target_link_libraries(_hsolver_pack PRIVATE pybind11::headers diagopack) +target_compile_definitions(_hsolver_pack PRIVATE VERSION_INFO=${PROJECT_VERSION}) + +set_target_properties(diagopack PROPERTIES INSTALL_RPATH "$ORIGIN") +set_target_properties(_hsolver_pack PROPERTIES INSTALL_RPATH "$ORIGIN") + +# Install your module package to destination path +install(TARGETS _hsolver_pack diagopack DESTINATION ${TARGET_PACK}/hsolver) +``` + +You can refer to the `CMakeLists.txt` files in other modules for guidance on how to configure your module. + +## Development Process + +To contribute to the `pyabacus` project, follow these steps: + +1. **Check the issues**: + - Look for issues to ensure that you are not working on something that is already in progress. + - If you want to work on a new feature or bug fix, create an issue first to discuss it with the maintainers. + +2. **Create a new folder for your module**: + - If you want to add a new module with pure Python code, create a new folder in the `src/pyabacus` directory. + - If you want to add a new module with C++ code, create a new folder in the `src` directory and a corresponding directory in the `src/pyabacus` directory. + +3. **Write source code using pybind11**: + - Follow the structure of other modules. + - Manage dependencies and installation paths in the `CMakeLists.txt` file. + +3. **Modify `src/pyabacus/__init__.py`**: + - Add the name of your module to the `__submodules__` list and import the module in the `__getattr__` function. + + ```python + from __future__ import annotations + + __submodules__ = ["ModuleBase", "ModuleNAO", "hsolver", "{module_name}"] + + __all__ = list(__submodules__) + + def __getattr__(attr): + if attr == "ModuleBase": + import pyabacus.ModuleBase as ModuleBase + return ModuleBase + elif attr == "ModuleNAO": + import pyabacus.ModuleNAO as ModuleNAO + return ModuleNAO + elif attr == "hsolver": + import pyabacus.hsolver as hsolver + return hsolver + elif attr == '{module_name}': + import pyabacus.{module_name} as {module_name} + return {module_name} + else: + raise AttributeError(f"module {__name__} has no attribute {attr}") + ``` + +4. **Create two files in `src/pyabacus/{module_name}`**: + - `__init__.py`: This file allows Python to recognize the folder as a module. + - `_{module_name}.py`: This file is responsible for designing the Python interface (frontend). + + **Example `__init__.py`**: + + ```python + from __future__ import annotations + from ._{module_name} import * + + __all__ = ["{class_name}", "{func_name}", ...] + ``` + + **Example `_{module_name}.py`**: + + ```python + from .{module_library_name} import {your_class} as _your_class, ... + + """ + Your class should inherit from the corresponding class in the C++ library. + All methods should be overridden to provide type hints and auto-completion. + You can use the `super()` method to call the base class(C++ class) methods. + """ + class {your_class}(_your_class): + def __init__(self) -> None: + super().__init__() + + def foo(self, arg1, arg2, ...) -> RetType: + return super().foo(arg1, arg2, ...) + + def bar(self, arg1, arg2, ...): + super().bar(arg1, arg2, ...) + ``` + + For a class, if you do not declare the interface in the frontend, the IDE will not provide type hints and auto-completion. However, if the interface name matches the name binding in pybind11, it will be overridden. To address this, you can use the method as shown above. + +5. **Handle overloaded functions in C++**: + - Since Python does not support function overloading with different parameters, use the following method: + + ```python + @overload + def foo(self, x: float) -> float: ... + @overload + def foo(self, n: int, x: float, y: float) -> float: ... + + def foo(self, *args, **kwargs): + return super().foo(*args, **kwargs) + ``` + +**Example Python Interface**: + + ```python + class diag_comm_info(_diag_comm_info): + def __init__(self, rank: int, nproc: int): + super().__init__(rank, nproc) + + @property + def rank(self) -> int: + return super().rank + + @property + def nproc(self) -> int: + return super().nproc + + class Sphbes(_Sphbes): + def __init__(self) -> None: + super().__init__() + + @overload + @staticmethod + def sphbesj(l: int, x: float) -> float: ... + @overload + @staticmethod + def sphbesj( + n: int, + r: NDArray[np.float64], + q: int, + l: int, + jl: NDArray[np.float64] + ) -> None: ... + + def sphbesj(self, *args, **kwargs): + return super().sphbesj(*args, **kwargs) + + @overload + @staticmethod + def dsphbesj(l: int, x: float) -> float: ... + @overload + @staticmethod + def dsphbesj( + n: int, + r: NDArray[np.float64], + q: int, + l: int, + djl: NDArray[np.float64] + ) -> None: ... + + def dsphbesj(self, *args, **kwargs): + return super().dsphbesj(*args, **kwargs) + + @staticmethod + def sphbes_zeros(l: int, n: int, zeros: NDArray[np.float64]) -> None: + super().sphbes_zeros(l, n, zeros) + ``` + +## Conclusion + +By following this guide, you can effectively contribute to the `pyabacus` project. Ensure that you follow the structure and conventions outlined here to maintain consistency and readability in the codebase. Happy coding! diff --git a/python/pyabacus/README.md b/python/pyabacus/README.md index f751e52c1bb..5634bf8cf25 100644 --- a/python/pyabacus/README.md +++ b/python/pyabacus/README.md @@ -1,19 +1,32 @@ -Build Example: TwoCenterIntegral Section in ABACUS -================================================== +# pyabacus: a Python interface for the ABACUS package -An example project built with [pybind11](https://github.com/pybind/pybind11) -and scikit-build-core. Python 3.7+ (see older commits for older versions of -Python). +`pyabacus` is a Python interface for the ABACUS package, which provides a high-level Python API for interacting with the `ABACUS` library. -Installation ------------- +This project is built using [pybind11](https://github.com/pybind/pybind11) and [scikit-build-core](https://scikit-build-core.readthedocs.io/), so you can easily build the project and use it in your Python environment. + +Now, `pyabacus` provides the following modules: +- `io`: a module for input/output in pyabacus. +- `Cell`: a module for the cell structure to bridge `ModuleNAO` in python module with users' input. +- `ModuleBase`: a module for basic math functions. +- `ModuleNAO`: a module for numerical atomic orbitals (NAO). +- `hsolver`: a module for solving the Hamiltonian. + + + +- [Installation](#installation) +- [CI Examples](#ci-examples) +- [License](#license) +- [Test call](#test-call) + + + +## Installation - Create and activate a new conda env, e.g. `conda create -n myenv python=3.8 & conda activate myenv`. - Clone ABACUS main repository and `cd abacus-develop/python/pyabacus`. - Build pyabacus by `pip install -v .` or install test dependencies & build pyabacus by `pip install .[test]`. (Use `pip install -v .[test] -i https://pypi.tuna.tsinghua.edu.cn/simple` to accelerate installation process.) -CI Examples ------------ +## CI Examples There are examples for CI in `.github/workflows`. A simple way to produces binary "wheels" for all platforms is illustrated in the "wheels.yml" file, @@ -71,15 +84,13 @@ eigenvalues difference: -8.94295749e-12 4.71351846e-11 5.39378986e-10 1.97244101e-08] ``` -License -------- +## License pybind11 is provided under a BSD-style license that can be found in the LICENSE file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license. -Test call ---------- +## Test call ```python import pyabacus as m diff --git a/python/pyabacus/examples/diago_matrix.py b/python/pyabacus/examples/diago_matrix.py index b7dba3865c5..657a3a679e8 100644 --- a/python/pyabacus/examples/diago_matrix.py +++ b/python/pyabacus/examples/diago_matrix.py @@ -10,10 +10,13 @@ def load_mat(mat_file): return h_mat, nbasis, nband def calc_eig_pyabacus(mat_file, method): - algo = { + dav = { 'dav_subspace': hsolver.dav_subspace, 'davidson': hsolver.davidson } + cg = { + 'cg': hsolver.cg + } h_mat, nbasis, nband = load_mat(mat_file) @@ -22,25 +25,27 @@ def calc_eig_pyabacus(mat_file, method): diag_elem = np.where(np.abs(diag_elem) < 1e-8, 1e-8, diag_elem) precond = 1.0 / np.abs(diag_elem) - def mm_op(x): + def mvv_op(x): return h_mat.dot(x) - e, _ = algo[method]( - mm_op, - v0, - nbasis, - nband, - precond, - dav_ndim=8, - tol=1e-8, - max_iter=1000 - ) + if method in dav: + algo = dav[method] + # args: mvvop, init_v, dim, num_eigs, precondition, dav_ndim, tol, max_iter + args = (mvv_op, v0, nbasis, nband, precond, 8, 1e-12, 5000) + elif method in cg: + algo = cg[method] + # args: mvvop, init_v, dim, num_eigs, precondition, tol, max_iter + args = (mvv_op, v0, nbasis, nband, precond, 1e-12, 5000) + else: + raise ValueError(f"Method {method} not available") + + e, _ = algo(*args) print(f'eigenvalues calculated by pyabacus-{method} is: \n', e) return e -def calc_eig_scipy(mat_file): +def calc_eigsh(mat_file): h_mat, _, nband = load_mat(mat_file) e, _ = scipy.sparse.linalg.eigsh(h_mat, k=nband, which='SA', maxiter=1000) e = np.sort(e) @@ -50,13 +55,12 @@ def calc_eig_scipy(mat_file): if __name__ == '__main__': mat_file = './Si2.mat' - method = ['davidson', 'dav_subspace'] + method = ['dav_subspace', 'davidson', 'cg'] for m in method: print(f'\n====== Calculating eigenvalues using {m} method... ======') e_pyabacus = calc_eig_pyabacus(mat_file, m) - e_scipy = calc_eig_scipy(mat_file) + e_scipy = calc_eigsh(mat_file) print('eigenvalues difference: \n', e_pyabacus - e_scipy) - - \ No newline at end of file + \ No newline at end of file diff --git a/python/pyabacus/pyproject.toml b/python/pyabacus/pyproject.toml index fd3fecc9e9f..7b1c4891a81 100644 --- a/python/pyabacus/pyproject.toml +++ b/python/pyabacus/pyproject.toml @@ -33,6 +33,15 @@ wheel.expand-macos-universal-tags = true cmake.verbose = true logging.level = "INFO" +[tool.scikit-build.cmake.define] +CMAKE_INSTALL_RPATH = "$ORIGIN" + +[tool.setuptools] +package-dir = {"pyabacus" = "src/pyabacus"} + +[tool.setuptools.packages.find] +where = ["src"] +include = ["pyabacus*"] [tool.pytest.ini_options] minversion = "6.0" diff --git a/python/pyabacus/src/ModuleBase/CMakeLists.txt b/python/pyabacus/src/ModuleBase/CMakeLists.txt new file mode 100644 index 00000000000..f150cf1b5e8 --- /dev/null +++ b/python/pyabacus/src/ModuleBase/CMakeLists.txt @@ -0,0 +1,25 @@ +list(APPEND pymodule_base + ${PROJECT_SOURCE_DIR}/src/ModuleBase/py_base_math.cpp + ${BASE_PATH}/kernels/math_op.cpp + ${BASE_PATH}/module_device/memory_op.cpp + ) + +pybind11_add_module(_base_pack MODULE ${pymodule_base}) + +target_link_libraries(_base_pack + PRIVATE + base + parameter + container + orb + ${math_libs} + ${OpenBLAS_LIBRARIES} + ${LAPACK_LIBRARIES} + ) + +target_link_libraries(_base_pack PRIVATE pybind11::headers) +target_compile_definitions(_base_pack PRIVATE VERSION_INFO=${PROJECT_VERSION}) + +set_target_properties(_base_pack PROPERTIES INSTALL_RPATH "$ORIGIN") + +install(TARGETS _base_pack DESTINATION ${TARGET_PACK}/ModuleBase) \ No newline at end of file diff --git a/python/pyabacus/src/py_base_math.cpp b/python/pyabacus/src/ModuleBase/py_base_math.cpp similarity index 97% rename from python/pyabacus/src/py_base_math.cpp rename to python/pyabacus/src/ModuleBase/py_base_math.cpp index 5f87831477e..b9803c81cd2 100644 --- a/python/pyabacus/src/py_base_math.cpp +++ b/python/pyabacus/src/ModuleBase/py_base_math.cpp @@ -12,10 +12,8 @@ using overload_cast_ = pybind11::detail::overload_cast_impl; void bind_base_math(py::module& m) { - py::module module_base = m.def_submodule("ModuleBase"); - // python binding for class Sphbes - py::class_(module_base, "Sphbes") + py::class_(m, "Sphbes") .def(py::init<>()) .def_static("sphbesj", overload_cast_()(&ModuleBase::Sphbes::sphbesj), "l"_a, "x"_a) .def_static("dsphbesj", overload_cast_()(&ModuleBase::Sphbes::dsphbesj), "l"_a, "x"_a) @@ -65,7 +63,7 @@ void bind_base_math(py::module& m) }); // python binding for class Integral - py::class_(module_base, "Integral") + py::class_(m, "Integral") .def(py::init<>()) .def_static("Simpson_Integral", [](const int mesh, py::array_t func, py::array_t rab, double asum) { py::buffer_info func_info = func.request(); @@ -220,6 +218,13 @@ void bind_base_math(py::module& m) static_cast(x_info.ptr), static_cast(w_info.ptr)); }); - py::class_(module_base, "SphericalBesselTransformer") - .def(py::init<>()); + py::class_(m, "SphericalBesselTransformer") + .def(py::init<>()); +} + +PYBIND11_MODULE(_base_pack, m) +{ + m.doc() = "Submodule for pyabacus: ModuleBase"; + + bind_base_math(m); } \ No newline at end of file diff --git a/python/pyabacus/src/ModuleNAO/CMakeLists.txt b/python/pyabacus/src/ModuleNAO/CMakeLists.txt new file mode 100644 index 00000000000..65e209ca403 --- /dev/null +++ b/python/pyabacus/src/ModuleNAO/CMakeLists.txt @@ -0,0 +1,52 @@ +# add nao shared library +list(APPEND _naos + ${NAO_PATH}/atomic_radials.cpp + ${NAO_PATH}/beta_radials.cpp + ${NAO_PATH}/hydrogen_radials.cpp + ${NAO_PATH}/numerical_radial.cpp + ${NAO_PATH}/pswfc_radials.cpp + ${NAO_PATH}/radial_collection.cpp + ${NAO_PATH}/radial_set.cpp + ${NAO_PATH}/real_gaunt_table.cpp + ${NAO_PATH}/sphbes_radials.cpp + ${NAO_PATH}/two_center_bundle.cpp + ${NAO_PATH}/two_center_integrator.cpp + ${NAO_PATH}/two_center_table.cpp + ${NAO_PATH}/projgen.cpp + # dependency + ${ABACUS_SOURCE_DIR}/module_base/kernels/math_op.cpp + # ${ABACUS_SOURCE_DIR}/module_psi/kernels/psi_memory_op.cpp + ${ABACUS_SOURCE_DIR}/module_base/module_device/memory_op.cpp +) +add_library(naopack SHARED + ${_naos} +) + +# link math_libs +if(MKLROOT) + target_link_libraries(naopack + MPI::MPI_CXX + OpenMP::OpenMP_CXX + ) +endif() + +target_link_libraries(naopack + base + parameter + container + orb + ${math_libs} +) + +list(APPEND pymodule_nao + ${PROJECT_SOURCE_DIR}/src/ModuleNAO/py_m_nao.cpp +) + +pybind11_add_module(_nao_pack MODULE ${pymodule_nao}) +target_link_libraries(_nao_pack PRIVATE pybind11::headers naopack) +target_compile_definitions(_nao_pack PRIVATE VERSION_INFO=${PROJECT_VERSION}) + +set_target_properties(naopack PROPERTIES INSTALL_RPATH "$ORIGIN") +set_target_properties(_nao_pack PROPERTIES INSTALL_RPATH "$ORIGIN") + +install(TARGETS _nao_pack naopack DESTINATION ${TARGET_PACK}/ModuleNAO) \ No newline at end of file diff --git a/python/pyabacus/src/py_m_nao.cpp b/python/pyabacus/src/ModuleNAO/py_m_nao.cpp similarity index 98% rename from python/pyabacus/src/py_m_nao.cpp rename to python/pyabacus/src/ModuleNAO/py_m_nao.cpp index d7c72836149..92c5084d44d 100644 --- a/python/pyabacus/src/py_m_nao.cpp +++ b/python/pyabacus/src/ModuleNAO/py_m_nao.cpp @@ -13,12 +13,8 @@ using overload_cast_ = pybind11::detail::overload_cast_impl; void bind_m_nao(py::module& m) { - // Create the submodule for Module NAO - py::module m_nao = m.def_submodule("ModuleNAO"); - m_nao.doc() = "Module for Numerical Atomic Orbitals (NAO) in ABACUS"; - // Bind the RadialCollection class - py::class_(m_nao, "RadialCollection") + py::class_(m, "RadialCollection") .def(py::init<>(), R"pbdoc( A class that holds all numerical radial functions of the same kind. @@ -95,7 +91,7 @@ void bind_m_nao(py::module& m) .def("nchi", overload_cast_()(&RadialCollection::nchi, py::const_), "itype"_a) .def("nchi", overload_cast_<>()(&RadialCollection::nchi, py::const_)); // Bind the TwoCenterIntegrator class - py::class_(m_nao, "TwoCenterIntegrator") + py::class_(m, "TwoCenterIntegrator") .def(py::init<>(), R"pbdoc( A class to compute two-center integrals. @@ -261,7 +257,7 @@ void bind_m_nao(py::module& m) "pvR"_a, "deriv"_a = false); // Bind the NumericalRadial class - py::class_(m_nao, "NumericalRadial") + py::class_(m, "NumericalRadial") .def(py::init<>(), R"pbdoc( A class that represents a numerical radial function. @@ -493,4 +489,11 @@ void bind_m_nao(py::module& m) return py::array_t(self.nk(), kvalue); }) .def_property_readonly("is_fft_compliant", overload_cast_<>()(&NumericalRadial::is_fft_compliant, py::const_)); +} + +PYBIND11_MODULE(_nao_pack, m) +{ + m.doc() = "Module for Numerical Atomic Orbitals (NAO) in ABACUS"; + + bind_m_nao(m); } \ No newline at end of file diff --git a/python/pyabacus/src/hsolver/CMakeLists.txt b/python/pyabacus/src/hsolver/CMakeLists.txt new file mode 100644 index 00000000000..853973e6536 --- /dev/null +++ b/python/pyabacus/src/hsolver/CMakeLists.txt @@ -0,0 +1,42 @@ +# add diago shared library +list(APPEND _diago + ${HSOLVER_PATH}/diago_dav_subspace.cpp + ${HSOLVER_PATH}/diago_david.cpp + ${HSOLVER_PATH}/diago_cg.cpp + ${HSOLVER_PATH}/diag_const_nums.cpp + ${HSOLVER_PATH}/diago_iter_assist.cpp + + ${HSOLVER_PATH}/kernels/dngvd_op.cpp + ${HSOLVER_PATH}/kernels/math_kernel_op.cpp + # dependency + ${BASE_PATH}/kernels/math_op.cpp + ${BASE_PATH}/module_device/device.cpp + ${BASE_PATH}/module_device/memory_op.cpp + + ${PSI_PATH}/psi.cpp + ) +add_library(diagopack SHARED + ${_diago} + ) +target_link_libraries(diagopack + base + parameter + container + orb + ${math_libs} + ${OpenBLAS_LIBRARIES} + ${LAPACK_LIBRARIES} + ) + +list(APPEND pymodule_hsolver + ${PROJECT_SOURCE_DIR}/src/hsolver/py_hsolver.cpp + ) + +pybind11_add_module(_hsolver_pack MODULE ${pymodule_hsolver}) +target_link_libraries(_hsolver_pack PRIVATE pybind11::headers diagopack) +target_compile_definitions(_hsolver_pack PRIVATE VERSION_INFO=${PROJECT_VERSION}) + +set_target_properties(diagopack PROPERTIES INSTALL_RPATH "$ORIGIN") +set_target_properties(_hsolver_pack PROPERTIES INSTALL_RPATH "$ORIGIN") + +install(TARGETS _hsolver_pack diagopack DESTINATION ${TARGET_PACK}/hsolver) \ No newline at end of file diff --git a/python/pyabacus/src/hsolver/py_diago_cg.hpp b/python/pyabacus/src/hsolver/py_diago_cg.hpp new file mode 100644 index 00000000000..2499b96e113 --- /dev/null +++ b/python/pyabacus/src/hsolver/py_diago_cg.hpp @@ -0,0 +1,192 @@ +#ifndef PYTHON_PYABACUS_SRC_PY_DIAGO_CG_HPP +#define PYTHON_PYABACUS_SRC_PY_DIAGO_CG_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "module_hsolver/diago_cg.h" +#include "module_base/module_device/memory_op.h" + +namespace py = pybind11; + +namespace py_hsolver +{ + +class PyDiagoCG +{ +public: + PyDiagoCG(int dim, int num_eigs) : dim{dim}, num_eigs{num_eigs} { } + PyDiagoCG(const PyDiagoCG&) = delete; + PyDiagoCG& operator=(const PyDiagoCG&) = delete; + PyDiagoCG(PyDiagoCG&& other) + { + psi = other.psi; + other.psi = nullptr; + + eig = other.eig; + other.eig = nullptr; + } + + ~PyDiagoCG() + { + if (psi != nullptr) + { + delete psi; + psi = nullptr; + } + + if (eig != nullptr) + { + delete eig; + eig = nullptr; + } + } + + void init_eig() + { + eig = new ct::Tensor(ct::DataType::DT_DOUBLE, {num_eigs}); + eig->zero(); + } + + py::array_t get_eig() + { + py::array_t eig_out(eig->NumElements()); + py::buffer_info eig_buf = eig_out.request(); + double* eig_out_ptr = static_cast(eig_buf.ptr); + + if (eig == nullptr) { + throw std::runtime_error("eig is not initialized"); + } + double* eig_ptr = eig->data(); + + std::copy(eig_ptr, eig_ptr + eig->NumElements(), eig_out_ptr); + return eig_out; + } + + void set_psi(py::array_t> psi_in) + { + py::buffer_info psi_buf = psi_in.request(); + std::complex* psi_ptr = static_cast*>(psi_buf.ptr); + + psi = new ct::TensorMap( + psi_ptr, + ct::DataType::DT_COMPLEX_DOUBLE, + ct::DeviceType::CpuDevice, + ct::TensorShape({num_eigs, dim}) + ); + } + + py::array_t> get_psi() + { + py::array_t> psi_out({num_eigs, dim}); + py::buffer_info psi_buf = psi_out.request(); + std::complex* psi_out_ptr = static_cast*>(psi_buf.ptr); + + if (psi == nullptr) { + throw std::runtime_error("psi is not initialized"); + } + std::complex* psi_ptr = psi->data>(); + + std::copy(psi_ptr, psi_ptr + psi->NumElements(), psi_out_ptr); + return psi_out; + } + + void set_prec(py::array_t prec_in) + { + py::buffer_info prec_buf = prec_in.request(); + double* prec_ptr = static_cast(prec_buf.ptr); + + prec = new ct::TensorMap( + prec_ptr, + ct::DataType::DT_DOUBLE, + ct::DeviceType::CpuDevice, + ct::TensorShape({dim}) + ); + } + + void diag( + std::function>(py::array_t>)> mm_op, + int diag_ndim, + double tol, + bool need_subspace, + bool scf_type, + int nproc_in_pool = 1 + ) { + const std::string basis_type = "pw"; + const std::string calculation = scf_type ? "scf" : "nscf"; + + auto hpsi_func = [mm_op] (const ct::Tensor& psi_in, ct::Tensor& hpsi_out) { + const auto ndim = psi_in.shape().ndim(); + REQUIRES_OK(ndim <= 2, "dims of psi_in should be less than or equal to 2"); + const int nvec = ndim == 1 ? 1 : psi_in.shape().dim_size(0); + const int ld_psi = ndim == 1 ? psi_in.NumElements() : psi_in.shape().dim_size(1); + + // Note: numpy's py::array_t is row-major, and + // our tensor-array is row-major + py::array_t> psi({ld_psi, nvec}); + py::buffer_info psi_buf = psi.request(); + std::complex* psi_ptr = static_cast*>(psi_buf.ptr); + std::copy(psi_in.data>(), psi_in.data>() + nvec * ld_psi, psi_ptr); + + py::array_t> hpsi = mm_op(psi); + + py::buffer_info hpsi_buf = hpsi.request(); + std::complex* hpsi_ptr = static_cast*>(hpsi_buf.ptr); + std::copy(hpsi_ptr, hpsi_ptr + nvec * ld_psi, hpsi_out.data>()); + }; + + auto subspace_func = [] (const ct::Tensor& psi_in, ct::Tensor& psi_out) { /*do nothing*/ }; + + auto spsi_func = [this] (const ct::Tensor& psi_in, ct::Tensor& spsi_out) { + const auto ndim = psi_in.shape().ndim(); + REQUIRES_OK(ndim <= 2, "dims of psi_in should be less than or equal to 2"); + const int nrow = ndim == 1 ? psi_in.NumElements() : psi_in.shape().dim_size(1); + const int nbands = ndim == 1 ? 1 : psi_in.shape().dim_size(0); + syncmem_z2z_h2h_op()( + this->ctx, + this->ctx, + spsi_out.data>(), + psi_in.data>(), + static_cast(nrow * nbands) + ); + }; + + cg = std::make_unique, base_device::DEVICE_CPU>>( + basis_type, + calculation, + need_subspace, + subspace_func, + tol, + diag_ndim, + nproc_in_pool + ); + + cg->diag(hpsi_func, spsi_func, *psi, *eig, *prec); + } + +private: + base_device::DEVICE_CPU* ctx = {}; + + int dim; + int num_eigs; + + ct::Tensor* psi = nullptr; + ct::Tensor* eig = nullptr; + ct::Tensor* prec = nullptr; + + std::unique_ptr, base_device::DEVICE_CPU>> cg; +}; + +} // namespace py_hsolver + +#endif \ No newline at end of file diff --git a/python/pyabacus/src/py_diago_dav_subspace.hpp b/python/pyabacus/src/hsolver/py_diago_dav_subspace.hpp similarity index 86% rename from python/pyabacus/src/py_diago_dav_subspace.hpp rename to python/pyabacus/src/hsolver/py_diago_dav_subspace.hpp index f6cf7e9a5ba..8ef539902e7 100644 --- a/python/pyabacus/src/py_diago_dav_subspace.hpp +++ b/python/pyabacus/src/hsolver/py_diago_dav_subspace.hpp @@ -106,27 +106,28 @@ class PyDiagoDavSubspace double tol, int max_iter, bool need_subspace, - std::vector is_occupied, + std::vector diag_ethr, bool scf_type, hsolver::diag_comm_info comm_info ) { - auto hpsi_func = [mm_op] (std::complex *hpsi_out, - std::complex *psi_in, const int nband_in, - const int nbasis_in, const int band_index1, - const int band_index2) - { + auto hpsi_func = [mm_op] ( + std::complex *psi_in, + std::complex *hpsi_out, + const int ld_psi, + const int nvec + ) { // Note: numpy's py::array_t is row-major, but // our raw pointer-array is column-major - py::array_t, py::array::f_style> psi({nbasis_in, band_index2 - band_index1 + 1}); + py::array_t, py::array::f_style> psi({ld_psi, nvec}); py::buffer_info psi_buf = psi.request(); std::complex* psi_ptr = static_cast*>(psi_buf.ptr); - std::copy(psi_in + band_index1 * nbasis_in, psi_in + (band_index2 + 1) * nbasis_in, psi_ptr); + std::copy(psi_in, psi_in + nvec * ld_psi, psi_ptr); py::array_t, py::array::f_style> hpsi = mm_op(psi); py::buffer_info hpsi_buf = hpsi.request(); std::complex* hpsi_ptr = static_cast*>(hpsi_buf.ptr); - std::copy(hpsi_ptr, hpsi_ptr + (band_index2 - band_index1 + 1) * nbasis_in, hpsi_out); + std::copy(hpsi_ptr, hpsi_ptr + nvec * ld_psi, hpsi_out); }; obj = std::make_unique, base_device::DEVICE_CPU>>( @@ -140,7 +141,7 @@ class PyDiagoDavSubspace comm_info ); - return obj->diag(hpsi_func, psi, nbasis, eigenvalue, is_occupied, scf_type); + return obj->diag(hpsi_func, psi, nbasis, eigenvalue, diag_ethr.data(), scf_type); } private: diff --git a/python/pyabacus/src/py_diago_david.hpp b/python/pyabacus/src/hsolver/py_diago_david.hpp similarity index 89% rename from python/pyabacus/src/py_diago_david.hpp rename to python/pyabacus/src/hsolver/py_diago_david.hpp index a53147f6ce3..2008eb6b858 100644 --- a/python/pyabacus/src/py_diago_david.hpp +++ b/python/pyabacus/src/hsolver/py_diago_david.hpp @@ -109,32 +109,29 @@ class PyDiagoDavid hsolver::diag_comm_info comm_info ) { auto hpsi_func = [mm_op] ( - std::complex *hpsi_out, - std::complex *psi_in, - const int nband_in, - const int nbasis_in, - const int band_index1, - const int band_index2 + std::complex *psi_in, + std::complex *hpsi_out, + const int ld_psi, + const int nvec ) { // Note: numpy's py::array_t is row-major, but // our raw pointer-array is column-major - py::array_t, py::array::f_style> psi({nbasis_in, band_index2 - band_index1 + 1}); + py::array_t, py::array::f_style> psi({ld_psi, nvec}); py::buffer_info psi_buf = psi.request(); std::complex* psi_ptr = static_cast*>(psi_buf.ptr); - std::copy(psi_in + band_index1 * nbasis_in, psi_in + (band_index2 + 1) * nbasis_in, psi_ptr); + std::copy(psi_in, psi_in + nvec * ld_psi, psi_ptr); py::array_t, py::array::f_style> hpsi = mm_op(psi); py::buffer_info hpsi_buf = hpsi.request(); std::complex* hpsi_ptr = static_cast*>(hpsi_buf.ptr); - std::copy(hpsi_ptr, hpsi_ptr + (band_index2 - band_index1 + 1) * nbasis_in, hpsi_out); + std::copy(hpsi_ptr, hpsi_ptr + nvec * ld_psi, hpsi_out); }; auto spsi_func = [this] ( const std::complex *psi_in, std::complex *spsi_out, const int nrow, - const int npw, const int nbands ) { syncmem_op()(this->ctx, this->ctx, spsi_out, psi_in, static_cast(nbands * nrow)); diff --git a/python/pyabacus/src/py_hsolver.cpp b/python/pyabacus/src/hsolver/py_hsolver.cpp similarity index 69% rename from python/pyabacus/src/py_hsolver.cpp rename to python/pyabacus/src/hsolver/py_hsolver.cpp index df8f6782562..7e76d1f874b 100644 --- a/python/pyabacus/src/py_hsolver.cpp +++ b/python/pyabacus/src/hsolver/py_hsolver.cpp @@ -11,20 +11,19 @@ #include "./py_diago_dav_subspace.hpp" #include "./py_diago_david.hpp" +#include "./py_diago_cg.hpp" namespace py = pybind11; using namespace pybind11::literals; void bind_hsolver(py::module& m) { - py::module hsolver = m.def_submodule("hsolver"); - - py::class_(hsolver, "diag_comm_info") + py::class_(m, "diag_comm_info") .def(py::init(), "rank"_a, "nproc"_a) .def_readonly("rank", &hsolver::diag_comm_info::rank) .def_readonly("nproc", &hsolver::diag_comm_info::nproc); - py::class_(hsolver, "diago_dav_subspace") + py::class_(m, "diago_dav_subspace") .def(py::init(), R"pbdoc( Constructor of diago_dav_subspace, a class for diagonalizing a linear operator using the Davidson-Subspace Method. @@ -59,9 +58,8 @@ void bind_hsolver(py::module& m) The maximum number of iterations. need_subspace : bool Whether to use the subspace function. - is_occupied : list[bool] - A list of boolean values indicating whether the band is occupied, - meaning that the corresponding eigenvalue is to be calculated. + diag_ethr : List[float] | None, optional + The list of thresholds of bands, by default None. scf_type : bool Whether to use the SCF type, which is used to determine the convergence criterion. @@ -76,7 +74,7 @@ void bind_hsolver(py::module& m) "tol"_a, "max_iter"_a, "need_subspace"_a, - "is_occupied"_a, + "diag_ethr"_a, "scf_type"_a, "comm_info"_a) .def("set_psi", &py_hsolver::PyDiagoDavSubspace::set_psi, R"pbdoc( @@ -92,7 +90,7 @@ void bind_hsolver(py::module& m) Get the eigenvalues. )pbdoc"); - py::class_(hsolver, "diago_david") + py::class_(m, "diago_david") .def(py::init(), R"pbdoc( Constructor of diago_david, a class for diagonalizing a linear operator using the Davidson Method. @@ -147,4 +145,60 @@ void bind_hsolver(py::module& m) .def("get_eigenvalue", &py_hsolver::PyDiagoDavid::get_eigenvalue, R"pbdoc( Get the eigenvalues. )pbdoc"); + + py::class_(m, "diago_cg") + .def(py::init(), R"pbdoc( + Constructor of diago_cg, a class for diagonalizing + a linear operator using the Conjugate Gradient Method. + + This class serves as a backend computation class. The interface + for invoking this class is a function defined in _hsolver.py, + which uses this class to perform the calculations. + )pbdoc") + .def("diag", &py_hsolver::PyDiagoCG::diag, R"pbdoc( + Diagonalize the linear operator using the Conjugate Gradient Method. + + Parameters + ---------- + mm_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + The operator to be diagonalized, which is a function that takes a matrix as input + and returns a matrix mv_op(X) = H * X as output. + max_iter : int + The maximum number of iterations. + tol : double + The tolerance for the convergence. + need_subspace : bool + Whether to use the subspace function. + scf_type : bool + Whether to use the SCF type, which is used to determine the + convergence criterion. + )pbdoc", + "mm_op"_a, + "max_iter"_a, + "tol"_a, + "need_subspace"_a, + "scf_type"_a, + "nproc_in_pool"_a) + .def("init_eig", &py_hsolver::PyDiagoCG::init_eig, R"pbdoc( + Initialize the eigenvalues. + )pbdoc") + .def("get_eig", &py_hsolver::PyDiagoCG::get_eig, R"pbdoc( + Get the eigenvalues. + )pbdoc") + .def("set_psi", &py_hsolver::PyDiagoCG::set_psi, R"pbdoc( + Set the eigenvectors. + )pbdoc", "psi_in"_a) + .def("get_psi", &py_hsolver::PyDiagoCG::get_psi, R"pbdoc( + Get the eigenvectors. + )pbdoc") + .def("set_prec", &py_hsolver::PyDiagoCG::set_prec, R"pbdoc( + Set the preconditioner. + )pbdoc", "prec_in"_a); } + +PYBIND11_MODULE(_hsolver_pack, m) +{ + m.doc() = "Submodule for pyabacus: hsolver"; + + bind_hsolver(m); +} \ No newline at end of file diff --git a/python/pyabacus/src/py_abacus.cpp b/python/pyabacus/src/py_abacus.cpp deleted file mode 100644 index 5874667761a..00000000000 --- a/python/pyabacus/src/py_abacus.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -namespace py = pybind11; - -void bind_base_math(py::module& m); -void bind_m_nao(py::module& m); -void bind_hsolver(py::module& m); - -PYBIND11_MODULE(_core, m) -{ - m.doc() = "Python extension for ABACUS built with pybind11 and scikit-build."; - bind_base_math(m); - bind_m_nao(m); - bind_hsolver(m); -} \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/ModuleBase/_module_base.py b/python/pyabacus/src/pyabacus/ModuleBase/_module_base.py index fe96247e430..e02b9fea6a7 100644 --- a/python/pyabacus/src/pyabacus/ModuleBase/_module_base.py +++ b/python/pyabacus/src/pyabacus/ModuleBase/_module_base.py @@ -5,12 +5,15 @@ """ import numpy as np - from typing import overload from numpy.typing import NDArray -class Sphbes: - def __init__(self) -> None: ... +from ._base_pack import Sphbes as _Sphbes, Integral as _Integral, SphericalBesselTransformer as _SphericalBesselTransformer + +class Sphbes(_Sphbes): + def __init__(self) -> None: + super().__init__() + @overload @staticmethod def sphbesj(l: int, x: float) -> float: ... @@ -23,6 +26,10 @@ def sphbesj( l: int, jl: NDArray[np.float64] ) -> None: ... + + def sphbesj(self, *args, **kwargs): + return super().sphbesj(*args, **kwargs) + @overload @staticmethod def dsphbesj(l: int, x: float) -> float: ... @@ -35,11 +42,18 @@ def dsphbesj( l: int, djl: NDArray[np.float64] ) -> None: ... - @staticmethod - def sphbes_zeros(l: int, n: int, zeros: NDArray[np.float64]) -> None: ... -class Integral: - def __init__(self) -> None: ... + def dsphbesj(self, *args, **kwargs): + return super().dsphbesj(*args, **kwargs) + + @staticmethod + def sphbes_zeros(l: int, n: int, zeros: NDArray[np.float64]) -> None: + super().sphbes_zeros(l, n, zeros) + +class Integral(_Integral): + def __init__(self) -> None: + super().__init__() + @overload @staticmethod def Simpson_Integral( @@ -56,20 +70,28 @@ def Simpson_Integral( dr: float, asum: float ) -> float: ... + + def Simpson_Integral(self, *args, **kwargs): + return super().Simpson_Integral(*args, **kwargs) + @staticmethod def Simpson_Integral_0toall( mesh: int, func: NDArray[np.float64], rab: NDArray[np.float64], asum: NDArray[np.float64] - ) -> None: ... + ) -> None: + super().Simpson_Integral_0toall(mesh, func, rab, asum) + @staticmethod def Simpson_Integral_alltoinf( mesh: int, func: NDArray[np.float64], rab: NDArray[np.float64], asum: NDArray[np.float64] - ) -> None: ... + ) -> None: + super().Simpson_Integral_alltoinf(mesh, func, rab, asum) + @overload @staticmethod def simpson( @@ -84,6 +106,10 @@ def simpson( f: NDArray[np.float64], h: NDArray[np.float64], ) -> float: ... + + def simpson(self, *args, **kwargs): + return super().simpson(*args, **kwargs) + @overload @staticmethod def Gauss_Legendre_grid_and_weight( @@ -100,6 +126,10 @@ def Gauss_Legendre_grid_and_weight( x: NDArray[np.float64], w: NDArray[np.float64], ) -> None: ... + + def Gauss_Legendre_grid_and_weight(self, *args, **kwargs): + return super().Gauss_Legendre_grid_and_weight(*args, **kwargs) -class SphericalBesselTransformer: - def __init__(self) -> None: ... \ No newline at end of file +class SphericalBesselTransformer(_SphericalBesselTransformer): + def __init__(self) -> None: + super().__init__() diff --git a/python/pyabacus/src/pyabacus/ModuleNAO/__init__.py b/python/pyabacus/src/pyabacus/ModuleNAO/__init__.py index 6c43ea250f9..b12dddb3051 100644 --- a/python/pyabacus/src/pyabacus/ModuleNAO/__init__.py +++ b/python/pyabacus/src/pyabacus/ModuleNAO/__init__.py @@ -1 +1,4 @@ -from __future__ import annotations \ No newline at end of file +from __future__ import annotations +from ._module_nao import * + +__all__ = ["RadialCollection", "TwoCenterIntegrator", "NumericalRadial"] \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/ModuleNAO/_module_nao.py b/python/pyabacus/src/pyabacus/ModuleNAO/_module_nao.py index c27f2ffe5ec..b8ed03a1a4d 100644 --- a/python/pyabacus/src/pyabacus/ModuleNAO/_module_nao.py +++ b/python/pyabacus/src/pyabacus/ModuleNAO/_module_nao.py @@ -5,13 +5,13 @@ """ import numpy as np - from numpy.typing import NDArray from pyabacus.ModuleBase import SphericalBesselTransformer -from typing import overload, List +from typing import overload, List, Tuple +from ._nao_pack import RadialCollection as _RadialCollection, TwoCenterIntegrator as _TwoCenterIntegrator, NumericalRadial as _NumericalRadial -class RadialCollection: +class RadialCollection(_RadialCollection): def __init__(self) -> None: """ A class that holds all numerical radial functions of the same kind. @@ -20,7 +20,7 @@ def __init__(self) -> None: of numerical atomic orbitals, or all Kleinman-Bylander beta functions from all elements involved in a calculation. """ - pass + super().__init__() def build( self, @@ -31,7 +31,7 @@ def build( """ Builds the collection from (orbital) files. """ - pass + super().build(nfile, file_list, ftype) def set_transformer( self, @@ -41,7 +41,7 @@ def set_transformer( """ Sets a spherical Bessel transformers for all RadialSet objects. """ - pass + super().set_transformer(sbt, update) def set_uniform_grid( self, @@ -54,7 +54,7 @@ def set_uniform_grid( """ Sets a common uniform grid for all RadialSet objects. """ - pass + super().set_uniform_grid(for_r_space, ngrid, cutoff, mode, enable_fft) def set_grid( self, @@ -66,33 +66,408 @@ def set_grid( """ Sets a common grid for all RadialSet objects """ - pass + super().set_grid(for_r_space, ngrid, grid, mode) + + def __call__( + self, + itype: int, + l: int, + izeta: int + ) -> 'NumericalRadial': + return super().__call__(itype, l, izeta) + + def symbol(self, itype: int) -> str: + return super().symbol(itype) - def __call__(self, itype: int, l: int, izeta: int) -> 'NumericalRadial': ... - def symbol(self, itype: int) -> str: ... @property - def ntype(self) -> int: ... - @overload - def lmax(self, itype: int) -> int: ... + def ntype(self) -> int: + return super().ntype + + def lmax(self, itype: int) -> int: + return super().lmax(itype) + @property - def lmax(self) -> int: ... - @overload - def rcut_max(self, itype: int) -> float: ... + def lmax(self) -> int: + return super().lmax + + def rcut_max(self, itype: int) -> float: + return super().rcut_max(itype) + @property - def rcut_max(self) -> float: ... - def nzeta(self, itype: int, l: int) -> int: ... + def rcut_max(self) -> float: + return super().rcut_max + + def nzeta(self, itype: int, l: int) -> int: + return super().nzeta(itype, l) + @overload def nzeta_max(self, itype: int) -> int: ... @overload def nzeta_max(self) -> int: ... + + def nzeta_max(self, *args, **kwargs): + return super().nzeta_max(*args, **kwargs) + @overload def nchi(self, itype: int) -> int: ... @overload def nchi(self) -> int: ... -class TwoCenterIntegrator: ... + def nchi(self, *args, **kwargs): + return super().nchi(*args, **kwargs) + +class TwoCenterIntegrator(_TwoCenterIntegrator): + def __init__(self) -> None: + """ + A class to compute two-center integrals. + + This class computes two-center integrals of the form: + + / + I(R) = | dr phi1(r) (op) phi2(r - R) + / + + as well as their gradients, where op is 1 (overlap) or minus Laplacian (kinetic), and phi1, + phi2 are "atomic-orbital-like" functions of the form: + + phi(r) = chi(|r|) * Ylm(r/|r|) + + where chi is some numerical radial function and Ylm is some real spherical harmonics. + + This class is designed to efficiently compute the two-center integrals + between two "collections" of the above functions with various R, e.g., the + overlap integrals between all numerical atomic orbitals and all + Kleinman-Bylander nonlocal projectors, the overlap & kinetic integrals between all numerical atomic orbitals, etc. + This is done by tabulating the radial part of the integrals on an r-space grid and the real Gaunt coefficients in advance. + """ + super().__init__() + + def tabulate( + self, + bra: 'RadialCollection', + ket: 'RadialCollection', + op: str, + nr: int, + cutoff: float + ) -> None: + """ + Tabulates the radial part of a two-center integral. + + Parameters: + bra (RadialFunctions): The radial functions of the first collection. + ket (RadialFunctions): The radial functions of the second collection. + op (char): Operator, could be 'S' (overlap) or 'T' (kinetic). + nr (int): Number of r-space grid points. + cutoff (float): r-space cutoff radius. + """ + super().tabulate(bra, ket, op, nr, cutoff) + + def calculate( + self, + itype1: int, + l1: int, + izeta1: int, + m1: int, + itype2: int, + l2: int, + izeta2: int, + m2: int, + pvR: NDArray[np.float64], + cal_grad: bool = False + ) -> Tuple[NDArray[np.float64], NDArray[np.float64]]: + """ + Compute the two-center integrals. + + This function calculates the two-center integral + + / + I(R) = | dr phi1(r) (op_) phi2(r - R) + / + + or its gradient by using the tabulated radial part and real Gaunt coefficients. + + Parameters + ---------- + itype1 : int + Element index of orbital 1. + l1 : int + Angular momentum of orbital 1. + izeta1 : int + Zeta number of orbital 1. + m1 : int + Magnetic quantum number of orbital 1. + itype2 : int + Element index of orbital 2. + l2 : int + Angular momentum of orbital 2. + izeta2 : int + Zeta number of orbital 2. + m2 : int + Magnetic quantum number of orbital 2. + pvR : array_like + R2 - R1, the displacement vector between the two centers. + cal_grad : bool, optional + The gradient will not be computed if cal_grad is false. + + Returns + ------- + out_array : array_like + The two-center integral. + grad_out_array : array_like + Gradient of the two-center integral. + """ + return super().calculate(itype1, l1, izeta1, m1, itype2, l2, izeta2, m2, pvR, cal_grad) + + def snap( + self, + itype1: int, + l1: int, + izeta1: int, + m1: int, + itype2: int, + pvR: NDArray[np.float64], + deriv: bool + ) -> List[List[float]]: + """ + Compute a batch of two-center integrals. + + This function calculates the two-center integrals (and optionally their gradients) + between one orbital and all orbitals of a certain type from the other collection. + """ + return super().snap(itype1, l1, izeta1, m1, itype2, pvR, deriv) + +class NumericalRadial(_NumericalRadial): + def __init__(self) -> None: + """ + A class that represents a numerical radial function. + + This class is designed to be the container for the radial part of numerical atomic orbitals, Kleinman-Bylander beta functions, and all other similar numerical radial functions in three-dimensional space, each of which is associated with some angular momentum l and whose r and k space values are related by an l-th order spherical Bessel transform. + + A NumericalRadial object can be initialized by "build", which requires the angular momentum, the number of grid points, the grid and the corresponding values. Grid does not have to be uniform. One can initialize the object in either r or k space. After initialization, one can set the + grid in the other space via set_grid or set_uniform_grid. Values in the other space are automatically computed by a spherical Bessel transform. + """ + super().__init__() + + def build( + self, + l: int, + for_r_space: bool, + ngrid: int, + grid: NDArray[np.float64], + value: NDArray[np.float64], + p: int = 0, + izeta: int = 0, + symbol: str = "", + itype: int = 0, + init_sbt: bool = True + ) -> None: + """ + Initializes the object by providing the grid & values in one space. + + Parameters + ---------- + l : int + Angular momentum. + for_r_space : bool + Specifies whether the input corresponds to r or k space. + ngrid : int + Number of grid points. + grid : array_like + Grid points, must be positive & strictly increasing. + value : array_like + Values on the grid. + p : float + Implicit exponent in input values, see pr_ & pk_. + izeta : int + Multiplicity index of radial functions of the same itype and l. + symbol : str + Chemical symbol. + itype : int + Index for the element in calculation. + init_sbt : bool + If true, internal SphericalBesselTransformer will be initialized. + + Notes + ----- + init_sbt is only useful when the internal SphericalBesselTransformer (sbt_) is null-initialized; The function will NOT reset sbt_ if it is already usable. + """ + super().build(l, for_r_space, ngrid, grid, value, p, izeta, symbol, itype, init_sbt) + + def set_transformer( + self, + sbt: SphericalBesselTransformer, + update: int = 0 + ) -> None: + """ + Sets a SphericalBesselTransformer. + + By default, the class uses an internal SphericalBesselTransformer, but one can optionally use a shared one. This could be beneficial when there are a lot of NumericalRadial objects whose grids have the same size. + + Parameters + ---------- + sbt : SphericalBesselTransformer + An external transformer. + update : int + Specifies whether and how values are recomputed with the new transformer. + Accepted values are: + * 0: does not recompute values; + * 1: calls a forward transform; + * -1: calls a backward transform. + """ + super().set_transformer(sbt, update) + + def set_grid( + self, + for_r_space: bool, + ngrid: int, + grid: NDArray[np.float64], + mode: str = 'i' + ) -> None: + """ + Sets up a grid. + + This function can be used to set up the grid which is absent in "build" (in which case values on the new grid are automatically computed by a spherical Bessel transform) or interpolate on an existing grid to a new grid. + + Parameters + ---------- + for_r_space : bool + Specifies whether to set grid for the r or k space. + ngrid : int + Number of grid points. + grid : array_like + Grid points, must be positive & strictly increasing. + mode : char + Specifies how values are updated, could be 'i' or 't': + - 'i': New values are obtained by interpolating and zero-padding + the existing values from current space. With this option, + it is an error if the designated space does not have a grid; + - 't': New values are obtained via transform from the other space. + With this option, it is an error if the other space does not + have a grid. + """ + super().set_grid(for_r_space, ngrid, grid, mode) + + def set_uniform_grid( + self, + for_r_space: bool, + ngrid: int, + cutoff: float, + mode: str = 'i', + enable_fft: bool = False + ) -> None: + """ + Sets up a uniform grid. + + The functionality of this function is similar to set_grid, except that the new grid is a uniform grid specified by the cutoff and the number of grid points, which are calculated as: + + grid[i] = i * (cutoff / (ngrid - 1)) + + Parameters + ---------- + for_r_space : bool + Specifies whether to set grid for the r or k space. + ngrid : int + Number of grid points. + cutoff : float + The maximum value of the grid, which determines the grid spacing. + enable_fft : bool + If true, this function will not only set up the grid & values in the designated space, but also sets the grid in the other space such that the r & k grids are FFT-compliant (and updates values via a FFT-based spherical Bessel transform). + mode : char + Specifies how values are updated, could be 'i' or 't'. + """ + super().set_uniform_grid(for_r_space, ngrid, cutoff, mode, enable_fft) + + def set_value( + self, + for_r_space: bool, + value: NDArray[np.float64], + p: int + ) -> None: + """ + Updates values on an existing grid. + + This function does not alter the grid; it merely updates values on the existing grid. The number of values to read from "value" is determined by the current number of points in the r or k space (nr_ or nk_). Values of the other space will be automatically updated if they exist. + + Warning + ------- + This function does not check the index bound; use with care! + """ + super().set_value(for_r_space, value, p) + + def wipe( + self, + r_space: bool = True, + k_space: bool = True + ) -> None: + super().wipe(r_space, k_space) + + def normalize(self, for_r_space: bool = True) -> None: + """ + Normalizes the radial function. + + The radial function is normalized such that the integral of the square of the function multiplied by the square of the radial coordinate over the entire space is equal to one: + + ∫ from 0 to +∞ of (x^2 * f(x)^2) dx = 1 + + where x is r or k. The integral is evaluated with Simpson's rule. Values in the other space are updated automatically via a spherical Bessel transform. + """ + super().normalize(for_r_space) -class NumericalRadial: ... + @property + def symbol(self) -> str: + return super().symbol + @property + def itype(self) -> int: + return super().itype + @property + def izeta(self) -> int: + return super().izeta + @property + def l(self) -> int: + return super().l + @property + def nr(self) -> int: + return super().nr + @property + def nk(self) -> int: + return super().nk + @property + def rcut(self) -> float: + return super().rcut + @property + def kcut(self) -> float: + return super().kcut + @property + def rmax(self) -> float: + return super().rmax + @property + def kmax(self) -> float: + return super().kmax + @property + def pr(self) -> float: + return super().pr + @property + def pk(self) -> float: + return super().pk + @property + def sbt(self) -> SphericalBesselTransformer: + return super().sbt + @property + def rgrid(self) -> NDArray[np.float64]: + return super().rgrid + @property + def kgrid(self) -> NDArray[np.float64]: + return super().kgrid + @property + def rvalue(self) -> NDArray[np.float64]: + return super().rvalue + @property + def kvalue(self) -> NDArray[np.float64]: + return super().kvalue + @property + def is_fft_compliant(self) -> bool: + return super().is_fft_compliant + diff --git a/python/pyabacus/src/pyabacus/__init__.py b/python/pyabacus/src/pyabacus/__init__.py index d73557a7d4d..d8a6e22b722 100644 --- a/python/pyabacus/src/pyabacus/__init__.py +++ b/python/pyabacus/src/pyabacus/__init__.py @@ -1,16 +1,23 @@ from __future__ import annotations -__submodules__ = ["ModuleBase", "ModuleNAO", "hsolver"] - +__submodules__ = ["ModuleBase", "ModuleNAO", "hsolver", "Cell", "IntegralCalculator", "io"] __all__ = list(__submodules__) def __getattr__(attr): if attr == "ModuleBase": - from ._core import ModuleBase + import pyabacus.ModuleBase as ModuleBase return ModuleBase elif attr == "ModuleNAO": - from ._core import ModuleNAO + import pyabacus.ModuleNAO as ModuleNAO return ModuleNAO elif attr == "hsolver": import pyabacus.hsolver as hsolver - return hsolver \ No newline at end of file + return hsolver + elif attr == "Cell": + from .cell import Cell + return Cell + elif attr == "io": + import pyabacus.io as io + return io + else: + raise AttributeError(f"module {__name__} has no attribute {attr}") \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/cell.py b/python/pyabacus/src/pyabacus/cell.py new file mode 100644 index 00000000000..3b22fde5689 --- /dev/null +++ b/python/pyabacus/src/pyabacus/cell.py @@ -0,0 +1,387 @@ +""" +Module for handling atomic structure and calculation parameters in ABACUS. +""" + +from __future__ import annotations +import numpy as np +from typing import List, Union, Optional, Dict, Any, Tuple +import os + +from pyabacus.io import read_stru, write_stru, read_xyz, write_xyz +from pyabacus.io.utils import cart_to_direct, direct_to_cart + +class Cell: + """ + A class representing an atomic cell structure for ABACUS calculations. + + This class handles atomic structures, lattice parameters, and calculation settings. + It supports both STRU and XYZ file formats and provides a comprehensive interface + for managing atomic systems in ABACUS calculations. + + Attributes: + atoms: List of atoms with their properties + lattice: Lattice vectors (3x3 numpy array) + unit: Unit system ('Angstrom' or 'Bohr') + spin: Spin configuration + charge: Total charge + lattice_constant: Scaling factor for lattice vectors + basis_type: Type of basis set (e.g., 'lcao', 'pw') + orbitals: List of orbital files + pseudo_potentials: Dict of pseudopotential settings per element + pseudo_dir: Directory containing pseudopotential files + orbital_dir: Directory containing orbital files + precision: Numerical precision for calculations + ecutwfc: Energy cutoff for wavefunctions in Ry + """ + + def __init__(self): + """Initialize an empty Cell object with default values.""" + # Structure attributes + self._atoms = [] # List of [symbol, position, properties] + self._lattice = np.eye(3) # Default to unit cell + self._lattice_constant = 1.0 + self._coord_type = 'Cartesian' + + # Physical properties + self._unit = 'Angstrom' + self._spin = 0 + self._charge = 0 + + # Calculation settings + self._basis_type = '' + self._ecutwfc = 100.0 # Default cutoff energy in Ry + self._precision = 1e-8 + self._mesh = None + self._kspace = None + + # File paths and settings + self.pseudo_dir = '' + self.orbital_dir = '' + self.pseudo_potentials = {} + self.orbitals = [] + + self._built = False + + def build(self) -> None: + """ + Build the cell structure and set automatic parameters. + + This method ensures all necessary components are properly initialized + and sets automatic parameters based on the current configuration. + + Raises: + ValueError: If essential components are missing or invalid + """ + if not self._atoms: + raise ValueError("No atoms defined in the cell") + + self._set_auto_parameters() + self._built = True + + def _set_auto_parameters(self) -> None: + """ + Set automatic calculation parameters based on structure and precision. + + This method determines appropriate mesh settings based on the lattice + vectors and precision requirements. It should be called whenever the + lattice vectors or precision settings change significantly. + """ + if self._lattice is not None: + # Calculate mesh size based on lattice vectors and precision + scaled_lattice = self._lattice * self._lattice_constant + # Get lengths of lattice vectors + lengths = np.sqrt(np.sum(scaled_lattice**2, axis=1)) + # Set mesh points inversely proportional to lattice vector lengths + # and scaled by precision + self._mesh = [max(1, int(np.ceil(length / self._precision))) + for length in lengths] + else: + self._mesh = [10, 10, 10] # Default mesh if no lattice is defined + + @classmethod + def from_file(cls, file_path: str) -> 'Cell': + """ + Create a Cell object from a structure file. + + Args: + file_path: Path to either a STRU or XYZ file + + Returns: + A new Cell object initialized from the file + + Raises: + ValueError: If the file format is not supported + FileNotFoundError: If the file doesn't exist + """ + if not os.path.exists(file_path): + raise FileNotFoundError(f"File not found: {file_path}") + + cell = cls() + + if file_path.lower().endswith('.xyz'): + cell._load_xyz(file_path) + elif os.path.basename(file_path).upper() == 'STRU': + cell._load_stru(file_path) + else: + raise ValueError("Unsupported file format. Use .xyz or STRU files.") + + # Build the cell after loading the structure + cell.build() + return cell + + def to_file(self, file_path: str, file_type: Optional[str] = None) -> None: + """ + Write the cell structure to a file. + + Args: + file_path: Path where the file should be written + file_type: Type of file to write ('xyz' or 'stru'). If None, inferred from file_path. + + Raises: + ValueError: If the file type is not supported or cannot be determined + """ + if file_type is None: + if file_path.lower().endswith('.xyz'): + file_type = 'xyz' + elif os.path.basename(file_path).upper() == 'STRU': + file_type = 'stru' + else: + raise ValueError("Cannot determine file type from file name") + + if file_type.lower() == 'xyz': + species = [atom[0] for atom in self._atoms] + positions = [atom[1] for atom in self._atoms] + write_xyz(file_path, species, positions) + elif file_type.lower() == 'stru': + self._save_stru(file_path) + else: + raise ValueError(f"Unsupported file type: {file_type}") + + def _load_stru(self, stru_file: str) -> None: + """Load structure from a STRU file.""" + stru_dict = read_stru(stru_file) + + # Set lattice information + self.lattice_constant = stru_dict['lat']['const'] + if 'vec' in stru_dict['lat']: + self.lattice = np.array(stru_dict['lat']['vec']) + + # Set coordinate type + self._coord_type = stru_dict['coord_type'] + + # Process atomic species and positions + self._atoms = [] + self.orbitals = [] + + for species in stru_dict['species']: + # Clean the pseudopotential filename before storing + pp_file = species['pp_file'] + if pp_file.startswith('./'): + pp_file = pp_file[2:] # Remove './' prefix if present + + # Store pseudopotential information + self.pseudo_potentials[species['symbol']] = { + 'mass': species['mass'], + 'pseudo_file': pp_file + } + if 'pp_type' in species: + self.pseudo_potentials[species['symbol']]['pp_type'] = species['pp_type'] + + # Store orbital information if present + if 'orb_file' in species: + self.orbitals.append(species['orb_file']) + + # Process atoms + for atom in species['atom']: + pos = np.array(atom['coord']) + # Convert position to Cartesian if it's in Direct coordinates + if self._coord_type.lower() == 'direct': + pos = direct_to_cart(pos, self.lattice * self.lattice_constant) + + # Create atom entry with all properties + properties = {k: v for k, v in atom.items() if k != 'coord'} + self._atoms.append([species['symbol'], pos, properties]) + + def _save_stru(self, file_path: str) -> None: + """Save structure to a STRU file.""" + # Build STRU dictionary + species_dict = {} + for symbol, pos, props in self._atoms: + if symbol not in species_dict: + pp_info = self.pseudo_potentials.get(symbol, {}) + + # Ensure we have a clean filename (remove './' if present) + pp_file = pp_info.get('pseudo_file', f"{symbol}.UPF") + if pp_file.startswith('./'): + pp_file = pp_file[2:] + + species_dict[symbol] = { + 'symbol': symbol, + 'mass': pp_info.get('mass', 1.0), + 'pp_file': pp_file, # Store clean filename + 'natom': 1, + 'mag_each': props.get('mag', 0.0), + 'atom': [] + } + if 'pp_type' in pp_info: + species_dict[symbol]['pp_type'] = pp_info['pp_type'] + else: + species_dict[symbol]['natom'] += 1 + + # Convert coordinates if needed + coord = pos + if self._coord_type.lower() == 'direct': + coord = cart_to_direct(pos, self.lattice * self.lattice_constant) + + # Add atom with its properties + atom_entry = {'coord': coord} + atom_entry.update(props) + species_dict[symbol]['atom'].append(atom_entry) + + # Add orbital information + if self.orbitals: + for symbol, orb in zip(species_dict.keys(), self.orbitals): + species_dict[symbol]['orb_file'] = orb + + + stru_dict = { + 'lat': { + 'const': self.lattice_constant, + 'vec': self.lattice.tolist() + }, + 'coord_type': self._coord_type, + 'species': list(species_dict.values()) + } + + # Write to file + write_stru(os.path.dirname(file_path), stru_dict, os.path.basename(file_path)) + + def _load_xyz(self, xyz_file: str) -> None: + """Load structure from an XYZ file.""" + species, coords = read_xyz(xyz_file) + self._atoms = [[s, p, {}] for s, p in zip(species, coords)] + + def add_atom(self, + symbol: str, + position: Union[List[float], np.ndarray], + properties: Optional[Dict[str, Any]] = None) -> None: + """ + Add an atom to the cell. + + Args: + symbol: Chemical symbol of the atom + position: Position vector [x, y, z] + properties: Additional properties (magnetic moment, constraints, etc.) + """ + position = np.asarray(position) + if properties is None: + properties = {} + self._atoms.append([symbol, position, properties]) + self._built = False # Require rebuild after adding atoms + + @property + def lattice(self) -> np.ndarray: + """Get the lattice vectors.""" + return self._lattice + + @lattice.setter + def lattice(self, value: Union[List[List[float]], np.ndarray]) -> None: + """Set the lattice vectors.""" + self._lattice = np.asarray(value) + if self._lattice.shape != (3, 3): + raise ValueError("Lattice must be a 3x3 array") + self._built = False # Require rebuild after changing lattice + + @property + def atoms(self) -> List[Tuple[str, np.ndarray, Dict[str, Any]]]: + """Get the list of atoms with their properties.""" + return self._atoms.copy() + + @property + def positions(self) -> np.ndarray: + """Get atomic positions as a numpy array.""" + return np.array([atom[1] for atom in self._atoms]) + + @property + def species(self) -> List[str]: + """Get list of atomic species symbols.""" + return [atom[0] for atom in self._atoms] + + @property + def unit(self) -> str: + """Get the unit system.""" + return self._unit + + @unit.setter + def unit(self, value: str) -> None: + """Set the unit system.""" + if value.lower() in ['angstrom', 'a']: + self._unit = 'Angstrom' + elif value.lower() in ['bohr', 'b', 'au']: + self._unit = 'Bohr' + else: + raise ValueError("Unit must be 'Angstrom' or 'Bohr'") + + @property + def ecutwfc(self) -> float: + """Get the plane wave energy cutoff in Ry.""" + return self._ecutwfc + + @ecutwfc.setter + def ecutwfc(self, value: float) -> None: + """Set the plane wave energy cutoff in Ry.""" + if value <= 0: + raise ValueError("Energy cutoff must be positive") + self._ecutwfc = value + + @property + def precision(self) -> float: + """Get the numerical precision.""" + return self._precision + + @precision.setter + def precision(self, value: float) -> None: + """Set the numerical precision.""" + if value <= 0: + raise ValueError("Precision must be a positive number") + self._precision = value + if self._built: + self._set_auto_parameters() # Update mesh when precision changes + + def get_scaled_positions(self) -> np.ndarray: + """Get atomic positions in fractional coordinates.""" + if not self._built: + raise RuntimeError("Cell has not been built. Call build() first.") + return cart_to_direct(self.positions, self.lattice * self.lattice_constant) + + def make_kpts(self, mesh: List[int], with_gamma_point: bool = True) -> np.ndarray: + """ + Generate k-points mesh in reciprocal space. + + Args: + mesh: List of 3 integers specifying the k-point mesh + with_gamma_point: Whether to include the gamma point + + Returns: + Array of k-points in reciprocal space + """ + if not self._built: + raise RuntimeError("Cell has not been built. Call build() first.") + if self.lattice is None: + raise ValueError("Lattice vectors must be set before generating k-points.") + + kpts = [] + for i in range(mesh[0]): + for j in range(mesh[1]): + for k in range(mesh[2]): + if with_gamma_point: + kpt = np.array([i/mesh[0], j/mesh[1], k/mesh[2]]) + else: + kpt = np.array([(i+0.5)/mesh[0], (j+0.5)/mesh[1], (k+0.5)/mesh[2]]) + kpts.append(kpt) + + # Convert to cartesian coordinates in reciprocal space + recip_lattice = 2 * np.pi * np.linalg.inv(self.lattice.T) + kpts = np.dot(kpts, recip_lattice) + + return np.array(kpts) \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/hsolver/__init__.py b/python/pyabacus/src/pyabacus/hsolver/__init__.py index e6a2da7ea63..207fcd785f7 100644 --- a/python/pyabacus/src/pyabacus/hsolver/__init__.py +++ b/python/pyabacus/src/pyabacus/hsolver/__init__.py @@ -1,4 +1,4 @@ from __future__ import annotations from ._hsolver import * -__all__ = ["dav_subspace"] \ No newline at end of file +__all__ = ["diag_comm_info", "dav_subspace", "davidson", "cg"] \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/hsolver/_hsolver.py b/python/pyabacus/src/pyabacus/hsolver/_hsolver.py index 5f5875a0554..d1cebad5ddc 100644 --- a/python/pyabacus/src/pyabacus/hsolver/_hsolver.py +++ b/python/pyabacus/src/pyabacus/hsolver/_hsolver.py @@ -1,47 +1,56 @@ -# pyabacus.hsolver +""" +pyabacus.hsolver +================== +Module for Solver for Hamiltonian in ABACUS +""" import numpy as np from numpy.typing import NDArray from typing import Tuple, List, Union, Callable -from .._core import hsolver +from ._hsolver_pack import diag_comm_info as _diag_comm_info +from ._hsolver_pack import diago_dav_subspace, diago_david, diago_cg -class diag_comm_info: - def __init__(self, rank: int, nproc: int) -> None: ... +class diag_comm_info(_diag_comm_info): + def __init__(self, rank: int, nproc: int): + super().__init__(rank, nproc) @property - def rank(self) -> int: ... + def rank(self) -> int: + return super().rank @property - def nproc(self) -> int: ... - + def nproc(self) -> int: + return super().nproc + def dav_subspace( - mm_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + mvv_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]], init_v: NDArray[np.complex128], dim: int, num_eigs: int, - pre_condition: NDArray[np.float64], + precondition: NDArray[np.float64], dav_ndim: int = 2, tol: float = 1e-2, max_iter: int = 1000, need_subspace: bool = False, - is_occupied: Union[List[bool], None] = None, + diag_ethr: Union[List[float], None] = None, scf_type: bool = False ) -> Tuple[NDArray[np.float64], NDArray[np.complex128]]: """ A function to diagonalize a matrix using the Davidson-Subspace method. Parameters ---------- - mm_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], - The operator to be diagonalized, which is a function that takes a matrix as input - and returns a matrix mv_op(X) = H * X as output. + mvv_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + The operator to be diagonalized, which is a function that takes a set of + vectors X = [x1, ..., xN] as input and returns a matrix(vector block) + mvv_op(X) = H * X ([Hx1, ..., HxN]) as output. init_v : NDArray[np.complex128] The initial guess for the eigenvectors. dim : int The number of basis, i.e. the number of rows/columns in the matrix. num_eigs : int The number of bands to calculate, i.e. the number of eigenvalues to calculate. - pre_condition : NDArray[np.float64] + precondition : NDArray[np.float64] The preconditioner. dav_ndim : int, optional The number of vectors in the subspace, by default 2. @@ -51,10 +60,8 @@ def dav_subspace( The maximum number of iterations, by default 1000. need_subspace : bool, optional Whether to use subspace function, by default False. - is_occupied : List[bool] | None, optional - The list of occupied bands, by default None. This indicates how many eigenvalues - need to be calculated, starting from the smallest eigenvalue. Only the energy levels - occupied by electrons (occupied) need to be calculated. + diag_ethr : List[float] | None, optional + The list of thresholds of bands, by default None. scf_type : bool, optional Indicates whether the calculation is a self-consistent field (SCF) calculation. If True, the initial precision of eigenvalue calculation can be coarse. @@ -68,31 +75,31 @@ def dav_subspace( v : NDArray[np.complex128] The eigenvectors corresponding to the eigenvalues. """ - if not callable(mm_op): - raise TypeError("mm_op must be a callable object.") + if not callable(mvv_op): + raise TypeError("mvv_op must be a callable object.") - if is_occupied is None: - is_occupied = [True] * num_eigs + if diag_ethr is None: + diag_ethr = [tol] * num_eigs if init_v.ndim != 1 or init_v.dtype != np.complex128: init_v = init_v.flatten().astype(np.complex128, order='C') - _diago_obj_dav_subspace = hsolver.diago_dav_subspace(dim, num_eigs) + _diago_obj_dav_subspace = diago_dav_subspace(dim, num_eigs) _diago_obj_dav_subspace.set_psi(init_v) _diago_obj_dav_subspace.init_eigenvalue() - comm_info = hsolver.diag_comm_info(0, 1) + comm_info = diag_comm_info(0, 1) assert dav_ndim > 1, "dav_ndim must be greater than 1." assert dav_ndim * num_eigs < dim * comm_info.nproc, "dav_ndim * num_eigs must be less than dim * comm_info.nproc." _ = _diago_obj_dav_subspace.diag( - mm_op, - pre_condition, + mvv_op, + precondition, dav_ndim, tol, max_iter, need_subspace, - is_occupied, + diag_ethr, scf_type, comm_info ) @@ -103,32 +110,32 @@ def dav_subspace( return e, v def davidson( - mm_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + mvv_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]], init_v: NDArray[np.complex128], dim: int, num_eigs: int, - pre_condition: NDArray[np.float64], + precondition: NDArray[np.float64], dav_ndim: int = 2, tol: float = 1e-2, max_iter: int = 1000, use_paw: bool = False, - # is_occupied: Union[List[bool], None] = None, # scf_type: bool = False ) -> Tuple[NDArray[np.float64], NDArray[np.complex128]]: """ A function to diagonalize a matrix using the Davidson-Subspace method. Parameters ---------- - mm_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], - The operator to be diagonalized, which is a function that takes a matrix as input - and returns a matrix mv_op(X) = H * X as output. + mvv_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + The operator to be diagonalized, which is a function that takes a set of + vectors X = [x1, ..., xN] as input and returns a matrix(vector block) + mvv_op(X) = H * X ([Hx1, ..., HxN]) as output. init_v : NDArray[np.complex128] The initial guess for the eigenvectors. dim : int The number of basis, i.e. the number of rows/columns in the matrix. num_eigs : int The number of bands to calculate, i.e. the number of eigenvalues to calculate. - pre_condition : NDArray[np.float64] + precondition : NDArray[np.float64] The preconditioner. dav_ndim : int, optional The number of vectors in the subspace, by default 2. @@ -146,21 +153,21 @@ def davidson( v : NDArray[np.complex128] The eigenvectors corresponding to the eigenvalues. """ - if not callable(mm_op): - raise TypeError("mm_op must be a callable object.") + if not callable(mvv_op): + raise TypeError("mvv_op must be a callable object.") if init_v.ndim != 1 or init_v.dtype != np.complex128: init_v = init_v.flatten().astype(np.complex128, order='C') - _diago_obj_dav_subspace = hsolver.diago_david(dim, num_eigs) - _diago_obj_dav_subspace.set_psi(init_v) - _diago_obj_dav_subspace.init_eigenvalue() + _diago_obj_david = diago_david(dim, num_eigs) + _diago_obj_david.set_psi(init_v) + _diago_obj_david.init_eigenvalue() - comm_info = hsolver.diag_comm_info(0, 1) + comm_info = diag_comm_info(0, 1) - _ = _diago_obj_dav_subspace.diag( - mm_op, - pre_condition, + _ = _diago_obj_david.diag( + mvv_op, + precondition, dav_ndim, tol, max_iter, @@ -168,8 +175,85 @@ def davidson( comm_info ) - e = _diago_obj_dav_subspace.get_eigenvalue() - v = _diago_obj_dav_subspace.get_psi() + e = _diago_obj_david.get_eigenvalue() + v = _diago_obj_david.get_psi() return e, v - \ No newline at end of file + +def cg( + mvv_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + init_v: NDArray[np.complex128], + dim: int, + num_eigs: int, + precondition: NDArray[np.float64], + tol: float = 1e-2, + max_iter: int = 1000, + need_subspace: bool = False, + scf_type: bool = False, + nproc_in_pool: int = 1 +) -> Tuple[NDArray[np.float64], NDArray[np.complex128]]: + """ A function to diagonalize a matrix using the Conjugate Gradient method. + + Parameters + ---------- + mvv_op : Callable[[NDArray[np.complex128]], NDArray[np.complex128]], + The operator to be diagonalized, which is a function that takes a set of + vectors X = [x1, ..., xN] as input and returns a matrix(vector block) + mvv_op(X) = H * X ([Hx1, ..., HxN]) as output. + init_v : NDArray[np.complex128] + The initial guess for the eigenvectors. + dim : int + The number of basis, i.e. the number of rows/columns in the matrix. + num_eigs : int + The number of bands to calculate, i.e. the number of eigenvalues to calculate. + precondition : NDArray[np.float64] + The preconditioner. + max_iter : int, optional + The maximum number of iterations, by default 1000. + tol : float, optional + The tolerance for the convergence, by default 1e-2. + need_subspace : bool, optional + Whether to use subspace function, by default False. + scf_type : bool, optional + Indicates whether the calculation is a self-consistent field (SCF) calculation. + If True, the initial precision of eigenvalue calculation can be coarse. + If False, it indicates a non-self-consistent field (non-SCF) calculation, + where high precision in eigenvalue calculation is required from the start. + nproc_in_pool : int, optional + The number of processes in the pool, by default 1. + + Returns + ------- + e : NDArray[np.float64] + The eigenvalues. + v : NDArray[np.complex128] + The eigenvectors corresponding to the eigenvalues. + """ + if not callable(mvv_op): + raise TypeError("mvv_op must be a callable object.") + + if init_v.ndim != 1 or init_v.dtype != np.complex128: + # the shape of init_v is (num_eigs, dim) = (dim, num_eigs).T + if init_v.ndim == 2: + init_v = init_v.T + init_v = init_v.flatten().astype(np.complex128, order='C') + + _diago_obj_cg = diago_cg(dim, num_eigs) + _diago_obj_cg.set_psi(init_v) + _diago_obj_cg.init_eig() + + _diago_obj_cg.set_prec(precondition) + + _diago_obj_cg.diag( + mvv_op, + max_iter, + tol, + need_subspace, + scf_type, + nproc_in_pool + ) + + e = _diago_obj_cg.get_eig() + v = _diago_obj_cg.get_psi() + + return e, v \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/io/__init__.py b/python/pyabacus/src/pyabacus/io/__init__.py new file mode 100644 index 00000000000..0d1a887939b --- /dev/null +++ b/python/pyabacus/src/pyabacus/io/__init__.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +from .stru import read_stru, write_stru +from .xyz import read_xyz, write_xyz + +__all__ = [ + "read_stru", + "write_stru", + "read_xyz", + "write_xyz", +] \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/io/stru.py b/python/pyabacus/src/pyabacus/io/stru.py new file mode 100644 index 00000000000..1b337e74a79 --- /dev/null +++ b/python/pyabacus/src/pyabacus/io/stru.py @@ -0,0 +1,262 @@ +""" +Module for reading and writing ABACUS STRU files. + +This module provides functions to read from and write to STRU files used by ABACUS. +It supports various formats and features including different coordinate types, +magnetic moments, movement constraints, and initial velocities. +""" + +from typing import Dict, Any +import numpy as np +import os + +# Move the content from struio.py here +# Add type hints and improve documentation + +def _parse_coord_line(line): + """ + Parses a coordinate line in the ATOMIC_POSITIONS block. + + Args: + line: String containing atomic coordinates and optional parameters + + Returns: + Dictionary containing parsed coordinate data and optional parameters + """ + fields = line.strip().split() + if len(fields) < 3: + raise ValueError(f"Invalid coordinate line: '{line}'. Expected at least 3 coordinates.") + + result = {'coord': [float(x) for x in fields[0:3]]} + + idx = 3 + while idx < len(fields): + if fields[idx].isdigit(): # no keyword, 0/1 -> frozen atom + result['m'] = [int(x) for x in fields[idx:idx+3]] + idx += 3 + elif fields[idx] == 'm': # frozen atom + result['m'] = [int(x) for x in fields[idx+1:idx+4]] + idx += 4 + elif fields[idx] in ['v', 'vel', 'velocity']: # initial velocity + result['v'] = [float(x) for x in fields[idx+1:idx+4]] + idx += 4 + elif fields[idx] in ['mag', 'magmom']: + if idx + 2 < len(fields) and fields[idx+2] == 'angle1': + result['mag'] = ('Spherical', + [float(fields[idx+1]), float(fields[idx+3]), float(fields[idx+5])]) + idx += 6 + elif idx + 2 < len(fields) and fields[idx+2][0].isdigit(): + result['mag'] = ('Cartesian', + [float(x) for x in fields[idx+1:idx+4]]) + idx += 4 + else: # collinear + result['mag'] = float(fields[idx+1]) + idx += 2 + else: + raise ValueError(f'Unknown keyword: {fields[idx]} in line: {line}') + + return result + + +def _atomic_positions_gen(lines): + """ + Iteratively generates info per species from the ATOMIC_POSITIONS block. + + Args: + lines: List of lines from the ATOMIC_POSITIONS block + + Yields: + Dictionary containing species information and atomic positions + """ + current_pos = 0 + while current_pos < len(lines): + # Read species symbol + symbol = lines[current_pos].strip() + + # Read magnetic moment and number of atoms + try: + mag_each = float(lines[current_pos + 1]) + natom = int(lines[current_pos + 2]) + except (IndexError, ValueError) as e: + raise ValueError(f"Error reading atomic positions for {symbol}: {e}") + + # Read atomic positions + pos_start = current_pos + 3 + pos_end = pos_start + natom + if pos_end > len(lines): + raise ValueError(f"Not enough coordinate lines for {symbol}. Expected {natom}, found {len(lines) - pos_start}") + + # Parse coordinates for each atom + try: + atoms = [_parse_coord_line(line) for line in lines[pos_start:pos_end]] + except Exception as e: + raise ValueError(f"Error parsing coordinates for {symbol}: {e}") + + # Yield the species information + yield { + 'symbol': symbol, + 'mag_each': mag_each, + 'natom': natom, + 'atom': atoms + } + + # Move to next species block + current_pos = pos_end + +def read_stru(fpath: str) -> Dict[str, Any]: + """Read an ABACUS STRU file and return its content as a dictionary.""" + block_title = ['ATOMIC_SPECIES', + 'NUMERICAL_ORBITAL', + 'LATTICE_CONSTANT', + 'LATTICE_PARAMETER', + 'LATTICE_VECTORS', + 'ATOMIC_POSITIONS'] + + def _trim(line): + return line.split('#')[0].split('//')[0].strip(' \t\n') + + with open(fpath, 'r') as f: + lines = [_trim(line).replace('\t', ' ') + for line in f.readlines() if len(_trim(line)) > 0] + + # break the content into blocks + delim = [i for i, line in enumerate(lines) if line in block_title] \ + + [len(lines)] + blocks = {lines[delim[i]] : lines[delim[i]+1:delim[i+1]] + for i in range(len(delim) - 1)} + + stru = {} + #============ LATTICE_CONSTANT/PARAMETER/VECTORS ============ + stru['lat'] = {'const': float(blocks['LATTICE_CONSTANT'][0])} + if 'LATTICE_VECTORS' in blocks: + stru['lat']['vec'] = [[float(x) for x in line.split()] + for line in blocks['LATTICE_VECTORS']] + elif 'LATTICE_PARAMETER' in blocks: + stru['lat']['param'] = [float(x) + for x in blocks['LATTICE_PARAMETERS'].split()] + + #============ ATOMIC_SPECIES ============ + stru['species'] = [_atomic_species_from_file(line) + for line in blocks['ATOMIC_SPECIES']] + + #============ NUMERICAL_ORBITAL ============ + if 'NUMERICAL_ORBITAL' in blocks: + for i, s in enumerate(stru['species']): + s['orb_file'] = blocks['NUMERICAL_ORBITAL'][i].strip() + + #============ ATOMIC_POSITIONS ============ + stru['coord_type'] = blocks['ATOMIC_POSITIONS'][0] + index = {s['symbol']: i for i, s in enumerate(stru['species'])} + try: + for ap in _atomic_positions_gen(blocks['ATOMIC_POSITIONS'][1:]): + stru['species'][index[ap['symbol']]].update(ap) + except Exception as e: + raise ValueError(f"Error processing ATOMIC_POSITIONS: {e}") + + return stru + +def _atomic_species_from_file(line): + """ + Process ATOMIC_SPECIES line to handle paths correctly. + Stores clean filename but preserves original format for writing. + """ + fields = line.split() + # Remove './' prefix if present and extract just the filename + pp_file = fields[2].replace('./', '', 1) if fields[2] else '' + return { + 'symbol': fields[0], + 'mass': float(fields[1]), + 'pp_file': pp_file, # Store clean filename without './' + 'pp_type': fields[3] if len(fields) > 3 else None + } + +def write_stru(job_dir: str, stru: Dict[str, Any], fname: str = 'STRU') -> None: + """ + Write structure information to an ABACUS STRU file. + + Args: + job_dir: Directory where the file should be written + stru: Dictionary containing the structure information + fname: Name of the output file (default: 'STRU') + + Raises: + ValueError: If the structure dictionary is invalid + OSError: If there are problems writing the file + """ + # Copy the write_stru implementation from struio.py + with open(os.path.join(job_dir, fname), 'w') as f: + + #============ ATOMIC_SPECIES ============ + f.write('ATOMIC_SPECIES\n') + # Calculate width based on actual format that will be written + width = { + 'symbol_w': max(len(s['symbol']) for s in stru['species']), + 'mass_w': max(len(str(s['mass'])) for s in stru['species']), + 'pp_file_w': max(len('./' + s['pp_file']) for s in stru['species']) + } + for s in stru['species']: + # Ensure clean filename and add './' prefix + pp_file = s['pp_file'] + if pp_file.startswith('./'): + pp_file = pp_file[2:] + pp_path = './' + pp_file + + f.write('{symbol:<{symbol_w}} {mass:>{mass_w}} {pp_file:>{pp_file_w}}'.format( + symbol=s['symbol'], + mass=s['mass'], + pp_file=pp_path, + **width)) + if 'pp_type' in s and s['pp_type']: + f.write(f" {s['pp_type']}") + f.write('\n') + + #============ NUMERICAL_ORBITAL ============ + if 'orb_file' in stru['species'][0]: + f.write('\nNUMERICAL_ORBITAL\n') + for s in stru['species']: + f.write(f"{s['orb_file']}\n") + + #============ LATTICE_CONSTANT/PARAMETER/VECTORS ============ + f.write('\nLATTICE_CONSTANT\n') + f.write(f"{stru['lat']['const']}\n") + + if 'vec' in stru['lat']: + f.write('\nLATTICE_VECTORS\n') + for v in stru['lat']['vec']: + f.write(f'{v[0]} {v[1]} {v[2]}\n') + + if 'param' in stru['lat']: + f.write('\nLATTICE_PARAMETER\n') + for param in stru['lat']['param']: + f.write(f'{param} ') + f.write('\n') + + #============ ATOMIC_POSITIONS ============ + f.write('\nATOMIC_POSITIONS\n') + f.write(f"{stru['coord_type']}\n") + + for s in stru['species']: + f.write(f"\n{s['symbol']}\n") + f.write(f"{s['mag_each']}\n") + f.write(f"{s['natom']}\n") + + for atom in s['atom']: + f.write(' '.join(f'{x}' for x in atom['coord'])) + + for key in ['m', 'v']: # frozen atom / initial velocity + if key in atom: + f.write(f' {key}' + + ''.join(f' {x}' for x in atom[key])) + + if 'mag' in atom: + if not isinstance(atom['mag'], tuple): # collinear + f.write(f" mag {atom['mag']}") + else: # non-collinear + mag_coord_type, mag = atom['mag'] + assert mag_coord_type in ['Cartesian', 'Spherical'] + if mag_coord_type == 'Cartesian': + f.write(f' mag {mag[0]} {mag[1]} {mag[2]}') + else: + f.write(f' mag {mag[0]} angle1 {mag[1]} angle2 {mag[2]}') + + f.write('\n') \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/io/utils.py b/python/pyabacus/src/pyabacus/io/utils.py new file mode 100644 index 00000000000..c1f9e3884c5 --- /dev/null +++ b/python/pyabacus/src/pyabacus/io/utils.py @@ -0,0 +1,49 @@ +""" +Utility functions for input/output operations. + +This module provides common utility functions used across different IO modules. +""" + +from typing import List +import numpy as np + +def cart_to_direct(cart_coords: np.ndarray, lattice: np.ndarray) -> np.ndarray: + """ + Convert Cartesian coordinates to direct (fractional) coordinates. + + Args: + cart_coords: Cartesian coordinates + lattice: Lattice vectors (3x3 matrix) + + Returns: + Direct coordinates + """ + return np.dot(cart_coords, np.linalg.inv(lattice)) + +def direct_to_cart(direct_coords: np.ndarray, lattice: np.ndarray) -> np.ndarray: + """ + Convert direct (fractional) coordinates to Cartesian coordinates. + + Args: + direct_coords: Direct coordinates + lattice: Lattice vectors (3x3 matrix) + + Returns: + Cartesian coordinates + """ + return np.dot(direct_coords, lattice) + +def parse_bool_vector(vector_str: str) -> List[bool]: + """ + Parse a string of 1s and 0s into a list of booleans. + + Args: + vector_str: String containing 1s and 0s + + Returns: + List of boolean values + + Raises: + ValueError: If the string contains invalid characters + """ + return [bool(int(x)) for x in vector_str.split()] \ No newline at end of file diff --git a/python/pyabacus/src/pyabacus/io/xyz.py b/python/pyabacus/src/pyabacus/io/xyz.py new file mode 100644 index 00000000000..71aa54ed031 --- /dev/null +++ b/python/pyabacus/src/pyabacus/io/xyz.py @@ -0,0 +1,66 @@ +""" +Module for reading and writing XYZ format files. + +This module provides functions to read from and write to XYZ format files, +which are simple coordinate files used to specify molecular geometries. +""" + +from typing import List, Tuple, Union +import numpy as np + +def read_xyz(filepath: str) -> Tuple[List[str], np.ndarray]: + """ + Read an XYZ format file. + + Args: + filepath: Path to the XYZ file + + Returns: + Tuple containing: + - List of atomic symbols + - Numpy array of atomic coordinates + + Raises: + FileNotFoundError: If the file doesn't exist + ValueError: If the file format is invalid + """ + species = [] + coords = [] + + with open(filepath, 'r') as f: + lines = f.readlines() + num_atoms = int(lines[0]) + # Skip comment line + for line in lines[2:2+num_atoms]: + parts = line.split() + species.append(parts[0]) + coords.append([float(x) for x in parts[1:4]]) + + return species, np.array(coords) + +def write_xyz(filepath: str, + species: List[str], + coords: Union[List[List[float]], np.ndarray], + comment: str = '') -> None: + """ + Write structure information to an XYZ file. + + Args: + filepath: Path where the file should be written + species: List of atomic symbols + coords: Array of atomic coordinates + comment: Optional comment for the second line + + Raises: + ValueError: If the input data is invalid + OSError: If there are problems writing the file + """ + coords = np.asarray(coords) + if len(species) != len(coords): + raise ValueError("Number of species must match number of coordinate sets") + + with open(filepath, 'w') as f: + f.write(f"{len(species)}\n") + f.write(f"{comment}\n") + for sym, pos in zip(species, coords): + f.write(f"{sym:2s} {pos[0]:15.8f} {pos[1]:15.8f} {pos[2]:15.8f}\n") \ No newline at end of file diff --git a/python/pyabacus/tests/test_base_math.py b/python/pyabacus/tests/test_base_math.py index 1d5190521f0..1ff52059817 100644 --- a/python/pyabacus/tests/test_base_math.py +++ b/python/pyabacus/tests/test_base_math.py @@ -11,6 +11,7 @@ def test_sphbes(): # test for sphbesj assert s.sphbesj(1, 0.0) == 0.0 assert s.sphbesj(0, 0.0) == 1.0 + assert s.sphbesj(1, np.array([0.0]), 1, 1, np.zeros(1)) == None def test_sbt(): sbt = base.SphericalBesselTransformer() diff --git a/python/pyabacus/tests/test_cell.py b/python/pyabacus/tests/test_cell.py new file mode 100644 index 00000000000..a664af4fa35 --- /dev/null +++ b/python/pyabacus/tests/test_cell.py @@ -0,0 +1,207 @@ +import unittest +import numpy as np +import os +import tempfile +import shutil +from pyabacus import Cell + +class TestCell(unittest.TestCase): + """Test suite for the Cell class.""" + + def setUp(self): + """Set up test fixtures.""" + # Get the absolute path to the test directory + self.test_dir = os.path.dirname(os.path.abspath(__file__)) + self.test_cell_dir = os.path.join(self.test_dir, 'test_cell') + + # Set paths for test files + self.lcao_dir = os.path.join(self.test_cell_dir, 'lcao_ZnO') + self.stru_file = os.path.join(self.lcao_dir, 'STRU') + self.xyz_file = os.path.join(self.test_cell_dir, 'h2o.xyz') + + # Create a temporary directory for output files + self.temp_dir = tempfile.mkdtemp() + + # Verify test files exist + if not os.path.exists(self.stru_file): + raise FileNotFoundError(f"STRU file not found at {self.stru_file}") + if not os.path.exists(self.xyz_file): + raise FileNotFoundError(f"XYZ file not found at {self.xyz_file}") + + def tearDown(self): + """Clean up test fixtures.""" + shutil.rmtree(self.temp_dir) + + def test_initialization(self): + """Test cell initialization.""" + cell = Cell() + self.assertFalse(cell._built) + self.assertEqual(cell.unit, 'Angstrom') + self.assertEqual(cell.ecutwfc, 100.0) + self.assertEqual(cell.precision, 1e-8) + np.testing.assert_array_equal(cell.lattice, np.eye(3)) + + + def test_from_stru_file(self): + """Test loading structure from STRU file.""" + cell = Cell.from_file(self.stru_file) + self.assertTrue(cell._built) + + # Verify basic structure information + self.assertEqual(len(cell.species), 2) + self.assertEqual(cell.species, ['Zn', 'O']) + + # Check lattice parameters and vectors from the actual STRU file + self.assertEqual(cell.lattice_constant, 6.1416) # From STRU file + + scaled_lattice = cell.lattice * cell.lattice_constant + expected_lattice = np.array([ + [6.1416, 0.0, 0.0], + [-3.0708, 5.3186256, 0.0], + [0.0, 0.0, 9.82656] + ]) + np.testing.assert_array_almost_equal(scaled_lattice, expected_lattice) + + def test_from_xyz_file(self): + """Test loading structure from XYZ file.""" + cell = Cell.from_file(self.xyz_file) + self.assertTrue(cell._built) + + # Check basic structure + self.assertEqual(len(cell.species), 3) + self.assertEqual(cell.species, ['O', 'H', 'H']) + + # Check positions match the h2o.xyz file content + positions = cell.positions + self.assertEqual(len(positions), 3) + + def test_build_status(self): + """Test build status management.""" + cell = Cell() + self.assertFalse(cell._built) + + # Adding atoms should keep cell unbuilt + cell.add_atom('H', [0, 0, 0]) + self.assertFalse(cell._built) + + # Building should set the flag + cell.build() + self.assertTrue(cell._built) + + def test_auto_parameters(self): + """Test automatic parameter setting.""" + cell = Cell() + cell.add_atom('H', [0, 0, 0]) + cell.lattice = [[5.0, 0.0, 0.0], + [0.0, 5.0, 0.0], + [0.0, 0.0, 5.0]] + cell.build() + + # Check mesh generation + self.assertIsNotNone(cell._mesh) + self.assertEqual(len(cell._mesh), 3) + + def test_stru_pseudopotentials(self): + """Test pseudopotential information from STRU file.""" + cell = Cell.from_file(self.stru_file) + + # Check pseudopotential information + self.assertIn('Zn', cell.pseudo_potentials) + self.assertIn('O', cell.pseudo_potentials) + + # Verify specific pseudopotential files from STRU + self.assertEqual(cell.pseudo_potentials['Zn']['pseudo_file'], 'Zn.LDA.UPF') + self.assertEqual(cell.pseudo_potentials['O']['pseudo_file'], 'O.LDA.100.UPF') + + def test_stru_orbital_files(self): + """Test orbital information from STRU file.""" + cell = Cell.from_file(self.stru_file) + + # Check orbital files + self.assertEqual(len(cell.orbitals), 2) + self.assertIn('Zn_lda_8.0au_120Ry_2s2p2d', cell.orbitals) + self.assertIn('O_lda_7.0au_50Ry_2s2p1d', cell.orbitals) + + def test_stru_coordinates(self): + """Test coordinate system and positions from STRU file.""" + cell = Cell.from_file(self.stru_file) + + # Check coordinate type + self.assertEqual(cell._coord_type, 'Direct') + + # Get scaled positions + scaled_positions = cell.get_scaled_positions() + + # Expected positions from STRU file + expected_scaled = np.array([ + [0.00, 0.00, 0.00], # Zn + [0.33333, 0.66667, 0.50] # O + ]) + + np.testing.assert_array_almost_equal(scaled_positions, expected_scaled, decimal=4) + + def test_file_operations(self): + """Test file reading and writing operations.""" + # Load from STRU + original_cell = Cell.from_file(self.stru_file) + + # Save to new STRU + new_stru = os.path.join(self.temp_dir, 'STRU') + original_cell.to_file(new_stru, 'stru') + + # Load back and compare + new_cell = Cell.from_file(new_stru) + + # Compare structures + np.testing.assert_array_almost_equal(original_cell.positions, new_cell.positions) + np.testing.assert_array_almost_equal(original_cell.lattice, new_cell.lattice) + self.assertEqual(original_cell.species, new_cell.species) + self.assertEqual(original_cell.pseudo_potentials, new_cell.pseudo_potentials) + self.assertEqual(original_cell.orbitals, new_cell.orbitals) + + # Test XYZ file operations + xyz_cell = Cell.from_file(self.xyz_file) + new_xyz = os.path.join(self.temp_dir, 'test.xyz') + xyz_cell.to_file(new_xyz, 'xyz') + new_xyz_cell = Cell.from_file(new_xyz) + np.testing.assert_array_almost_equal(xyz_cell.positions, new_xyz_cell.positions) + self.assertEqual(xyz_cell.species, new_xyz_cell.species) + + def test_add_atom(self): + """Test atom addition functionality.""" + cell = Cell() + + # Add atom with properties + properties = {"mag": 0.5, "constraint": [1, 1, 1]} + cell.add_atom("Fe", [0, 0, 0], properties) + + self.assertEqual(len(cell.atoms), 1) + self.assertEqual(cell.species[0], "Fe") + atom_data = cell.atoms[0] + self.assertEqual(atom_data[2], properties) + + # Check if adding atom unsets built status + cell.build() + self.assertTrue(cell._built) + cell.add_atom("Fe", [1, 1, 1]) + self.assertFalse(cell._built) + + def test_k_points(self): + """Test k-points generation.""" + cell = Cell() + cell.add_atom('H', [0, 0, 0]) + cell.lattice = [[5.0, 0.0, 0.0], + [0.0, 5.0, 0.0], + [0.0, 0.0, 5.0]] + cell.build() + + # Test k-points generation + kpts = cell.make_kpts([2, 2, 2]) + self.assertEqual(kpts.shape, (8, 3)) + + # Test k-points with non-gamma + kpts_nogamma = cell.make_kpts([2, 2, 2], with_gamma_point=False) + self.assertEqual(kpts_nogamma.shape, (8, 3)) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/python/pyabacus/tests/test_cell/h2o.xyz b/python/pyabacus/tests/test_cell/h2o.xyz new file mode 100644 index 00000000000..829bc1efd1b --- /dev/null +++ b/python/pyabacus/tests/test_cell/h2o.xyz @@ -0,0 +1,5 @@ +3 +H2O molecule +O 0.000000 0.000000 0.000000 +H 0.758602 0.000000 0.504284 +H 0.758602 0.000000 -0.504284 \ No newline at end of file diff --git a/python/pyabacus/tests/test_cell/lcao_ZnO/INPUT b/python/pyabacus/tests/test_cell/lcao_ZnO/INPUT new file mode 100644 index 00000000000..2d13bae3b59 --- /dev/null +++ b/python/pyabacus/tests/test_cell/lcao_ZnO/INPUT @@ -0,0 +1,19 @@ +INPUT_PARAMETERS +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +nbands 24 + +calculation scf +ecutwfc 120 +scf_thr 1.0e-8 +scf_nmax 100 + +smearing_method gaussian +smearing_sigma 0.02 + +mixing_type broyden +mixing_beta 0.4 + +basis_type lcao +gamma_only 0 +symmetry 1 diff --git a/python/pyabacus/tests/test_cell/lcao_ZnO/KPT b/python/pyabacus/tests/test_cell/lcao_ZnO/KPT new file mode 100644 index 00000000000..253d74de39a --- /dev/null +++ b/python/pyabacus/tests/test_cell/lcao_ZnO/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +4 4 4 0 0 0 diff --git a/python/pyabacus/tests/test_cell/lcao_ZnO/STRU b/python/pyabacus/tests/test_cell/lcao_ZnO/STRU new file mode 100644 index 00000000000..b6f121afa8f --- /dev/null +++ b/python/pyabacus/tests/test_cell/lcao_ZnO/STRU @@ -0,0 +1,28 @@ +ATOMIC_SPECIES +Zn 1.000 ./Zn.LDA.UPF +O 1.000 ./O.LDA.100.UPF + +NUMERICAL_ORBITAL +Zn_lda_8.0au_120Ry_2s2p2d +O_lda_7.0au_50Ry_2s2p1d + +LATTICE_CONSTANT +6.1416 + +LATTICE_VECTORS +1.00 0.00 0.00 +-0.5 0.866 0.00 +0.00 0.00 1.6 + +ATOMIC_POSITIONS +Direct + +Zn +0.0 +1 +0.00 0.00 0.00 1 1 1 + +O +0.0 +1 +0.33333 0.66667 0.50 1 1 1 diff --git a/python/pyabacus/tests/test_cell/lcao_ZnO/run.sh b/python/pyabacus/tests/test_cell/lcao_ZnO/run.sh new file mode 100644 index 00000000000..6e2bcc954dd --- /dev/null +++ b/python/pyabacus/tests/test_cell/lcao_ZnO/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +ABACUS_PATH=$(awk -F "=" '$1=="ABACUS_PATH"{print $2}' ../../SETENV) +ABACUS_NPROCS=$(awk -F "=" '$1=="ABACUS_NPROCS"{print $2}' ../../SETENV) +ABACUS_THREADS=$(awk -F "=" '$1=="ABACUS_THREADS"{print $2}' ../../SETENV) + +OMP_NUM_THREADS=${ABACUS_THREADS} mpirun -np ${ABACUS_NPROCS} ${ABACUS_PATH} | tee scf.output + +if [[ ! -f scf.output ]] || + [[ ! -f OUT.ABACUS/running_scf.log ]] || + [[ ! ( "$(tail -1 OUT.ABACUS/running_scf.log)" == " Total Time :"* ) ]] +then + echo "job is failed!" + exit 1 +else + echo "job is successed!" + exit 0 +fi \ No newline at end of file diff --git a/python/pyabacus/tests/test_hsolver.py b/python/pyabacus/tests/test_hsolver.py index 9106bdbf7e2..82b54c5a3ae 100644 --- a/python/pyabacus/tests/test_hsolver.py +++ b/python/pyabacus/tests/test_hsolver.py @@ -6,10 +6,13 @@ import scipy def diag_pyabacus(h_sparse, nband, method): - algo = { + dav = { 'dav_subspace': hsolver.dav_subspace, 'davidson': hsolver.davidson } + cg = { + 'cg': hsolver.cg + } def mm_op(x): return h_sparse.dot(x) @@ -21,16 +24,16 @@ def mm_op(x): diag_elem = np.where(np.abs(diag_elem) < 1e-8, 1e-8, diag_elem) precond = 1.0 / np.abs(diag_elem) - e, _ = algo[method]( - mm_op, - v0, - nbasis, - nband, - precond, - dav_ndim=8, - tol=1e-12, - max_iter=5000 - ) + if method in dav: + algo = dav[method] + args = (mm_op, v0, nbasis, nband, precond, 8, 1e-12, 5000) + elif method in cg: + algo = cg[method] + args = (mm_op, v0, nbasis, nband, precond, 1e-12, 5000) + else: + raise ValueError(f"Method {method} not available") + + e, _ = algo(*args) return e @@ -40,7 +43,8 @@ def diag_eigsh(h_sparse, nband): @pytest.mark.parametrize("method", [ ('dav_subspace'), - ('davidson') + ('davidson'), + ('cg') ]) def test_random_matrix_diag(method): np.random.seed(12) @@ -55,8 +59,10 @@ def test_random_matrix_diag(method): @pytest.mark.parametrize("file_name, nband, atol, method", [ ('./test_diag/Si2.mat', 16, 1e-8, 'dav_subspace'), ('./test_diag/Si2.mat', 16, 1e-8, 'davidson'), + ('./test_diag/Si2.mat', 16, 1e-8, 'cg'), ('./test_diag/Na5.mat', 16, 1e-8, 'dav_subspace'), ('./test_diag/Na5.mat', 16, 1e-8, 'davidson'), + ('./test_diag/Na5.mat', 16, 1e-8, 'cg'), ]) def test_diag(file_name, nband, atol, method): h_sparse = scipy.io.loadmat(file_name)['Problem']['A'][0, 0] diff --git a/source/Makefile b/source/Makefile index a6bfc3efdd8..ee71b453633 100644 --- a/source/Makefile +++ b/source/Makefile @@ -135,16 +135,17 @@ ifdef LIBRI_DIR HONG += -D__EXX -DEXX_H_COMM=2 -DEXX_DM=3 -DTEST_EXX_LCAO=0 -DTEST_EXX_RADIAL=1 endif +ifdef LIBNPY_DIR + CNPY_INCLUDE_DIR = -I${LIBNPY_DIR}/include + HONG += -D__DEEPKS + INCLUDES += $(CNPY_INCLUDE_DIR) +endif + ifdef LIBTORCH_DIR - ifdef LIBNPY_DIR - LIBTORCH_INCLUDE_DIR = -I${LIBTORCH_DIR}/include -I${LIBTORCH_DIR}/include/torch/csrc/api/include - LIBTORCH_LIB_DIR= ${LIBTORCH_DIR}/lib - LIBTORCH_LIB = -L${LIBTORCH_LIB_DIR} -ltorch -lc10 -Wl,-rpath,${LIBTORCH_LIB_DIR} -Wl,--no-as-needed,"${LIBTORCH_LIB_DIR}/libtorch_cpu.so" -Wl,--as-needed ${LIBTORCH_LIB_DIR}/libc10.so -lpthread -Wl,--no-as-needed,"${LIBTORCH_LIB_DIR}/libtorch.so" -Wl,--as-needed - CNPY_INCLUDE_DIR = -I${LIBNPY_DIR}/include - HONG += -D__DEEPKS - INCLUDES += $(LIBTORCH_INCLUDE_DIR) $(CNPY_INCLUDE_DIR) - LIBS += $(LIBTORCH_LIB) - endif + LIBTORCH_INCLUDE_DIR = -I${LIBTORCH_DIR}/include -I${LIBTORCH_DIR}/include/torch/csrc/api/include + INCLUDES += $(LIBTORCH_INCLUDE_DIR) + LIBTORCH_LIB_DIR= ${LIBTORCH_DIR}/lib + LIBS += -L${LIBTORCH_LIB_DIR} -ltorch -lc10 -Wl,-rpath,${LIBTORCH_LIB_DIR} -Wl,--no-as-needed,"${LIBTORCH_LIB_DIR}/libtorch_cpu.so" -Wl,--as-needed ${LIBTORCH_LIB_DIR}/libc10.so -lpthread -Wl,--no-as-needed,"${LIBTORCH_LIB_DIR}/libtorch.so" -Wl,--as-needed endif ifdef DeePMD_DIR @@ -162,20 +163,19 @@ ifdef DeePMD_DIR LIBS += -L${DeeP_LIB_DIR} -ldeepmd_c -Wl,-rpath=${DeeP_LIB_DIR} else LIBS += -L${DeeP_LIB_DIR} -ldeepmd_cc -Wl,-rpath=${DeeP_LIB_DIR} - - #========================== - # TensorFlow package - #========================== - ifndef TensorFlow_DIR - TensorFlow_DIR = ${DeePMD_DIR} - endif - TensorFlow_LIB_DIR = ${TensorFlow_DIR}/lib - LIBS += -L${TensorFlow_LIB_DIR} -ltensorflow_cc -Wl,-rpath=${TensorFlow_LIB_DIR} - TensorFlow_INCLUDE_DIR = ${TensorFlow_DIR}/include - INCLUDES += -I${TensorFlow_INCLUDE_DIR} endif endif +ifdef TensorFlow_DIR + #========================== + # TensorFlow package + #========================== + TensorFlow_LIB_DIR = ${TensorFlow_DIR}/lib + LIBS += -L${TensorFlow_LIB_DIR} -ltensorflow_cc -Wl,-rpath=${TensorFlow_LIB_DIR} + TensorFlow_INCLUDE_DIR = ${TensorFlow_DIR}/include + INCLUDES += -I${TensorFlow_INCLUDE_DIR} +endif + ifdef PEXSI_DIR OBJS_ABACUS += ${OBJS_HSOLVER_PEXSI} INCLUDES += -I${PEXSI_DIR}/include -I${PARMETIS_DIR}/include -I${DSUPERLU_DIR}/include diff --git a/source/Makefile.Objects b/source/Makefile.Objects index e723eef0bcc..d97ee9f5bc7 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -121,6 +121,7 @@ OBJS_MAIN=main.o\ OBJS_BASE=abfs-vector3_order.o\ assoc_laguerre.o\ + blas_connector.o\ complexarray.o\ complexmatrix.o\ clebsch_gordan_coeff.o\ @@ -213,6 +214,7 @@ OBJS_ELECSTAT=elecstate.o\ elecstate_print.o\ elecstate_pw.o\ elecstate_pw_sdft.o\ + elecstate_pw_cal_tau.o\ elecstate_op.o\ efield.o\ gatefield.o\ @@ -226,6 +228,7 @@ OBJS_ELECSTAT=elecstate.o\ OBJS_ELECSTAT_LCAO=elecstate_lcao.o\ elecstate_lcao_tddft.o\ + elecstate_lcao_cal_tau.o\ density_matrix.o\ cal_dm_psi.o\ @@ -240,7 +243,6 @@ OBJS_ESOLVER=esolver.o\ esolver_of.o\ esolver_of_tool.o\ esolver_of_interface.o\ - print_funcs.o\ pw_fun.o\ pw_init_after_vc.o\ pw_init_globalc.o\ @@ -288,6 +290,7 @@ OBJS_GINT=gint.o\ init_orb.o\ OBJS_HAMILT=hamilt_pw.o\ + hamilt_sdft_pw.o\ operator.o\ operator_pw.o\ ekinetic_pw.o\ @@ -454,7 +457,12 @@ OBJS_XC=xc_functional.o\ xc_functional_gradcorr.o\ xc_functional_wrapper_xc.o\ xc_functional_wrapper_gcxc.o\ - xc_functional_wrapper_tauxc.o\ + xc_functional_libxc.o\ + xc_functional_libxc_tools.o\ + xc_functional_libxc_vxc.o\ + xc_functional_libxc_wrapper_xc.o\ + xc_functional_libxc_wrapper_gcxc.o\ + xc_functional_libxc_wrapper_tauxc.o\ xc_funct_exch_lda.o\ xc_funct_corr_lda.o\ xc_funct_exch_gga.o\ @@ -476,7 +484,6 @@ OBJS_IO=input_conv.o\ output.o\ print_info.o\ read_cube.o\ - read_rho.o\ rhog_io.o\ read_exit_file.o\ read_wfc_pw.o\ @@ -496,6 +503,7 @@ OBJS_IO=input_conv.o\ winput.o\ write_cube.o\ write_elecstat_pot.o\ + write_elf.o\ write_dipole.o\ td_current_io.o\ write_wfc_r.o\ @@ -523,6 +531,7 @@ OBJS_IO=input_conv.o\ read_input_item_other.o\ read_input_item_output.o\ read_set_globalv.o\ + orb_io.o\ OBJS_IO_LCAO=cal_r_overlap_R.o\ write_orb_info.o\ @@ -559,12 +568,9 @@ OBJS_LCAO=evolve_elec.o\ FORCE_STRESS.o\ FORCE_gamma.o\ FORCE_k.o\ - fvl_dphi_gamma.o\ - fvl_dphi_k.o\ - fedm_gamma.o\ - fedm_k.o\ - ftvnl_dphi_gamma.o\ - ftvnl_dphi_k.o\ + stress_tools.o\ + edm.o\ + pulay_force_stress_center2.o\ fvnl_dbeta_gamma.o\ fvnl_dbeta_k.o\ grid_init.o\ @@ -605,6 +611,8 @@ OBJS_MODULE_RI=conv_coulomb_pot_k.o\ Mix_Matrix.o\ symmetry_rotation.o\ symmetry_irreducible_sector.o\ + auxiliary_func.o\ + ewald_Vq_tools.o\ OBJS_PARALLEL=parallel_common.o\ parallel_global.o\ @@ -642,7 +650,6 @@ OBJS_SRCPW=H_Ewald_pw.o\ structure_factor_k.o\ soc.o\ sto_iter.o\ - sto_hchi.o\ sto_che.o\ sto_wf.o\ sto_func.o\ @@ -722,7 +729,6 @@ OBJS_TENSOR=tensor.o\ operator_lr_exx.o\ kernel_xc.o\ pot_hxc_lrtd.o\ - hsolver_lrtd.o\ lr_spectrum.o\ hamilt_casida.o\ esolver_lrtd_lcao.o\ diff --git a/source/Makefile.vars b/source/Makefile.vars index f00eca8ea31..c542d3811ba 100644 --- a/source/Makefile.vars +++ b/source/Makefile.vars @@ -57,7 +57,7 @@ CEREAL_DIR = /usr/local/include/cereal ##------------------- OPTIONAL LIBS --------------------------------- ## To use DEEPKS: set LIBTORCH_DIR and LIBNPY_DIR ## To use LIBXC: set LIBXC_DIR which contains include and lib/libxc.a (>5.1.7) -## To use DeePMD: set DeePMD_DIR and TensorFlow_DIR +## To use DeePMD: set DeePMD_DIR LIBTORCH_DIR and TensorFlow_DIR ## To use LibRI: set LIBRI_DIR and LIBCOMM_DIR ## To use PEXSI: set PEXSI_DIR DSUPERLU_DIR and PARMETIS_DIR ##--------------------------------------------------------------------- diff --git a/source/driver.cpp b/source/driver.cpp index db5d6425850..c4490da8624 100644 --- a/source/driver.cpp +++ b/source/driver.cpp @@ -41,7 +41,7 @@ void Driver::init() // (3) output information time_t time_finish = std::time(nullptr); - Print_Info::print_time(time_start, time_finish); + ModuleIO::print_time(time_start, time_finish); // (4) close all of the running logs ModuleBase::Global_File::close_all_log(GlobalV::MY_RANK, PARAM.inp.out_alllog,PARAM.inp.calculation); diff --git a/source/driver_run.cpp b/source/driver_run.cpp index 5bf9eb49c5a..451c4025b11 100644 --- a/source/driver_run.cpp +++ b/source/driver_run.cpp @@ -40,7 +40,7 @@ void Driver::driver_run() { // the life of ucell should begin here, mohan 2024-05-12 // delete ucell as a GlobalC in near future - GlobalC::ucell.setup_cell(PARAM.inp.stru_file, GlobalV::ofs_running); + GlobalC::ucell.setup_cell(PARAM.globalv.global_in_stru, GlobalV::ofs_running); Check_Atomic_Stru::check_atomic_stru(GlobalC::ucell, PARAM.inp.min_dist_coef); diff --git a/source/main.cpp b/source/main.cpp index 18e717a6143..345445f1343 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -27,13 +27,14 @@ int main(int argc, char** argv) */ int nproc = 1; int my_rank = 0; - Parallel_Global::read_mpi_parameters(argc, argv, nproc, my_rank); + int nthread_per_proc = 1; + Parallel_Global::read_pal_param(argc, argv, nproc, nthread_per_proc, my_rank); #ifdef _OPENMP // ref: https://www.fftw.org/fftw3_doc/Usage-of-Multi_002dthreaded-FFTW.html fftw_init_threads(); fftw_plan_with_nthreads(omp_get_max_threads()); #endif - PARAM.set_rank_nproc(my_rank, nproc); + PARAM.set_pal_param(my_rank, nproc, nthread_per_proc); /* main program for doing electronic structure calculations. diff --git a/source/module_base/CMakeLists.txt b/source/module_base/CMakeLists.txt index dde98f915f3..e11141208cc 100644 --- a/source/module_base/CMakeLists.txt +++ b/source/module_base/CMakeLists.txt @@ -11,6 +11,7 @@ add_library( base OBJECT assoc_laguerre.cpp + blas_connector.cpp clebsch_gordan_coeff.cpp complexarray.cpp complexmatrix.cpp diff --git a/source/module_base/blas_connector.cpp b/source/module_base/blas_connector.cpp new file mode 100644 index 00000000000..30b3b93d403 --- /dev/null +++ b/source/module_base/blas_connector.cpp @@ -0,0 +1,225 @@ +#include "blas_connector.h" + +#ifdef __DSP +#include "module_base/kernels/dsp/dsp_connector.h" +#include "module_base/global_variable.h" +#endif + +void BlasConnector::axpy( const int n, const float alpha, const float *X, const int incX, float *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + saxpy_(&n, &alpha, X, &incX, Y, &incY); +} +} + +void BlasConnector::axpy( const int n, const double alpha, const double *X, const int incX, double *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + daxpy_(&n, &alpha, X, &incX, Y, &incY); +} +} + +void BlasConnector::axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + caxpy_(&n, &alpha, X, &incX, Y, &incY); +} +} + +void BlasConnector::axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + zaxpy_(&n, &alpha, X, &incX, Y, &incY); +} +} + + +// x=a*x +void BlasConnector::scal( const int n, const float alpha, float *X, const int incX, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + sscal_(&n, &alpha, X, &incX); +} +} + +void BlasConnector::scal( const int n, const double alpha, double *X, const int incX, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + dscal_(&n, &alpha, X, &incX); +} +} + +void BlasConnector::scal( const int n, const std::complex alpha, std::complex *X, const int incX, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + cscal_(&n, &alpha, X, &incX); +} +} + +void BlasConnector::scal( const int n, const std::complex alpha, std::complex *X, const int incX, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + zscal_(&n, &alpha, X, &incX); +} +} + + +// d=x*y +float BlasConnector::dot( const int n, const float *X, const int incX, const float *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + return sdot_(&n, X, &incX, Y, &incY); + return sdot_(&n, X, &incX, Y, &incY); +} +} + +double BlasConnector::dot( const int n, const double *X, const int incX, const double *Y, const int incY, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + return ddot_(&n, X, &incX, Y, &incY); + return ddot_(&n, X, &incX, Y, &incY); +} +} + +// C = a * A.? * B.? + b * C +void BlasConnector::gemm(const char transa, const char transb, const int m, const int n, const int k, + const float alpha, const float *a, const int lda, const float *b, const int ldb, + const float beta, float *c, const int ldc, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + sgemm_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc); + } + #ifdef __DSP + else if (device_type == base_device::AbacusDevice_t::DspDevice){ + sgemm_mth_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc, GlobalV::MY_RANK); + } + #endif +} + +void BlasConnector::gemm(const char transa, const char transb, const int m, const int n, const int k, + const double alpha, const double *a, const int lda, const double *b, const int ldb, + const double beta, double *c, const int ldc, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + dgemm_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc); + } + #ifdef __DSP + else if (device_type == base_device::AbacusDevice_t::DspDevice){ + dgemm_mth_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc, GlobalV::MY_RANK); + } + #endif +} + +void BlasConnector::gemm(const char transa, const char transb, const int m, const int n, const int k, + const std::complex alpha, const std::complex *a, const int lda, const std::complex *b, const int ldb, + const std::complex beta, std::complex *c, const int ldc, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + cgemm_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc); + } + #ifdef __DSP + else if (device_type == base_device::AbacusDevice_t::DspDevice) { + cgemm_mth_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc, GlobalV::MY_RANK); + } + #endif +} + +void BlasConnector::gemm(const char transa, const char transb, const int m, const int n, const int k, + const std::complex alpha, const std::complex *a, const int lda, const std::complex *b, const int ldb, + const std::complex beta, std::complex *c, const int ldc, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + zgemm_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc); + } + #ifdef __DSP + else if (device_type == base_device::AbacusDevice_t::DspDevice) { + zgemm_mth_(&transb, &transa, &n, &m, &k, + &alpha, b, &ldb, a, &lda, + &beta, c, &ldc, GlobalV::MY_RANK); + } + #endif +} + +void BlasConnector::gemv(const char trans, const int m, const int n, + const double alpha, const double* A, const int lda, const double* X, const int incx, + const double beta, double* Y, const int incy, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + dgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); +} +} + +void BlasConnector::gemv(const char trans, const int m, const int n, + const std::complex alpha, const std::complex *A, const int lda, const std::complex *X, const int incx, + const std::complex beta, std::complex *Y, const int incy, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + cgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); +} +} + +void BlasConnector::gemv(const char trans, const int m, const int n, + const std::complex alpha, const std::complex *A, const int lda, const std::complex *X, const int incx, + const std::complex beta, std::complex *Y, const int incy, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + zgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); +} +} + + +// out = ||x||_2 +float BlasConnector::nrm2( const int n, const float *X, const int incX, base_device::AbacusDevice_t device_type ) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + return snrm2_( &n, X, &incX ); + return snrm2_( &n, X, &incX ); +} +} + + +double BlasConnector::nrm2( const int n, const double *X, const int incX, base_device::AbacusDevice_t device_type ) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + return dnrm2_( &n, X, &incX ); + return dnrm2_( &n, X, &incX ); +} +} + + +double BlasConnector::nrm2( const int n, const std::complex *X, const int incX, base_device::AbacusDevice_t device_type ) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + return dznrm2_( &n, X, &incX ); + return dznrm2_( &n, X, &incX ); +} +} + +// copies a into b +void BlasConnector::copy(const long n, const double *a, const int incx, double *b, const int incy, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + dcopy_(&n, a, &incx, b, &incy); +} +} + +void BlasConnector::copy(const long n, const std::complex *a, const int incx, std::complex *b, const int incy, base_device::AbacusDevice_t device_type) +{ + if (device_type == base_device::AbacusDevice_t::CpuDevice) { + zcopy_(&n, a, &incx, b, &incy); +} +} \ No newline at end of file diff --git a/source/module_base/blas_connector.h b/source/module_base/blas_connector.h index 90f1efae533..b819b6852ed 100644 --- a/source/module_base/blas_connector.h +++ b/source/module_base/blas_connector.h @@ -2,6 +2,10 @@ #define BLAS_CONNECTOR_H #include +#include "module_base/module_device/types.h" + +// These still need to be linked in the header file +// Because quite a lot of code will directly use the original cblas kernels. extern "C" { @@ -115,152 +119,99 @@ class BlasConnector // Peize Lin add 2016-08-04 // y=a*x+y - static inline - void axpy( const int n, const float alpha, const float *X, const int incX, float *Y, const int incY) - { - saxpy_(&n, &alpha, X, &incX, Y, &incY); - } - static inline - void axpy( const int n, const double alpha, const double *X, const int incX, double *Y, const int incY) - { - daxpy_(&n, &alpha, X, &incX, Y, &incY); - } - static inline - void axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY) - { - caxpy_(&n, &alpha, X, &incX, Y, &incY); - } - static inline - void axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY) - { - zaxpy_(&n, &alpha, X, &incX, Y, &incY); - } + static + void axpy( const int n, const float alpha, const float *X, const int incX, float *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void axpy( const int n, const double alpha, const double *X, const int incX, double *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void axpy( const int n, const std::complex alpha, const std::complex *X, const int incX, std::complex *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + // Peize Lin add 2016-08-04 // x=a*x - static inline - void scal( const int n, const float alpha, float *X, const int incX) - { - sscal_(&n, &alpha, X, &incX); - } - static inline - void scal( const int n, const double alpha, double *X, const int incX) - { - dscal_(&n, &alpha, X, &incX); - } - static inline - void scal( const int n, const std::complex alpha, std::complex *X, const int incX) - { - cscal_(&n, &alpha, X, &incX); - } - static inline - void scal( const int n, const std::complex alpha, std::complex *X, const int incX) - { - zscal_(&n, &alpha, X, &incX); - } + static + void scal( const int n, const float alpha, float *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void scal( const int n, const double alpha, double *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void scal( const int n, const std::complex alpha, std::complex *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void scal( const int n, const std::complex alpha, std::complex *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + // Peize Lin add 2017-10-27 // d=x*y - static inline - float dot( const int n, const float *X, const int incX, const float *Y, const int incY) - { - return sdot_(&n, X, &incX, Y, &incY); - } - static inline - double dot( const int n, const double *X, const int incX, const double *Y, const int incY) - { - return ddot_(&n, X, &incX, Y, &incY); - } + static + float dot( const int n, const float *X, const int incX, const float *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + double dot( const int n, const double *X, const int incX, const double *Y, const int incY, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + // Peize Lin add 2017-10-27, fix bug trans 2019-01-17 // C = a * A.? * B.? + b * C - static inline + static void gemm(const char transa, const char transb, const int m, const int n, const int k, const float alpha, const float *a, const int lda, const float *b, const int ldb, - const float beta, float *c, const int ldc) - { - sgemm_(&transb, &transa, &n, &m, &k, - &alpha, b, &ldb, a, &lda, - &beta, c, &ldc); - } - static inline + const float beta, float *c, const int ldc, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static void gemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, - const double beta, double *c, const int ldc) - { - dgemm_(&transb, &transa, &n, &m, &k, - &alpha, b, &ldb, a, &lda, - &beta, c, &ldc); - } - static inline + const double beta, double *c, const int ldc, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static void gemm(const char transa, const char transb, const int m, const int n, const int k, const std::complex alpha, const std::complex *a, const int lda, const std::complex *b, const int ldb, - const std::complex beta, std::complex *c, const int ldc) - { - cgemm_(&transb, &transa, &n, &m, &k, - &alpha, b, &ldb, a, &lda, - &beta, c, &ldc); - } - static inline + const std::complex beta, std::complex *c, const int ldc, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static void gemm(const char transa, const char transb, const int m, const int n, const int k, const std::complex alpha, const std::complex *a, const int lda, const std::complex *b, const int ldb, - const std::complex beta, std::complex *c, const int ldc) - { - zgemm_(&transb, &transa, &n, &m, &k, - &alpha, b, &ldb, a, &lda, - &beta, c, &ldc); - } - static inline + const std::complex beta, std::complex *c, const int ldc, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static void gemv(const char trans, const int m, const int n, const double alpha, const double* A, const int lda, const double* X, const int incx, - const double beta, double* Y, const int incy) - { - dgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); - } - static inline - void gemv(const char trans, const int m, const int n, - const std::complex alpha, const std::complex *A, const int lda, const std::complex *X, const int incx, - const std::complex beta, std::complex *Y, const int incy) - { - cgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); - } - static inline + const double beta, double* Y, const int incy, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void gemv(const char trans, const int m, const int n, + const std::complex alpha, const std::complex *A, const int lda, const std::complex *X, const int incx, + const std::complex beta, std::complex *Y, const int incy, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static void gemv(const char trans, const int m, const int n, const std::complex alpha, const std::complex *A, const int lda, const std::complex *X, const int incx, - const std::complex beta, std::complex *Y, const int incy) - { - zgemv_(&trans, &m, &n, &alpha, A, &lda, X, &incx, &beta, Y, &incy); - } + const std::complex beta, std::complex *Y, const int incy, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + // Peize Lin add 2018-06-12 // out = ||x||_2 - static inline - float nrm2( const int n, const float *X, const int incX ) - { - return snrm2_( &n, X, &incX ); - } - static inline - double nrm2( const int n, const double *X, const int incX ) - { - return dnrm2_( &n, X, &incX ); - } - static inline - double nrm2( const int n, const std::complex *X, const int incX ) - { - return dznrm2_( &n, X, &incX ); - } + static + float nrm2( const int n, const float *X, const int, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice ); + + static + double nrm2( const int n, const double *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice ); + + static + double nrm2( const int n, const std::complex *X, const int incX, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice ); + // copies a into b - static inline - void copy(const long n, const double *a, const int incx, double *b, const int incy) - { - dcopy_(&n, a, &incx, b, &incy); - } - static inline - void copy(const long n, const std::complex *a, const int incx, std::complex *b, const int incy) - { - zcopy_(&n, a, &incx, b, &incy); - } + static + void copy(const long n, const double *a, const int incx, double *b, const int incy, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); + + static + void copy(const long n, const std::complex *a, const int incx, std::complex *b, const int incy, base_device::AbacusDevice_t device_type = base_device::AbacusDevice_t::CpuDevice); }; // If GATHER_INFO is defined, the original function is replaced with a "i" suffix, @@ -308,4 +259,4 @@ void zgemv_i(const char *trans, */ #endif // GATHER_INFO -#endif // BLAS_CONNECTOR_H +#endif // BLAS_CONNECTOR_H \ No newline at end of file diff --git a/source/module_base/global_file.cpp b/source/module_base/global_file.cpp index c2cb6ad0f12..b912996f4ed 100644 --- a/source/module_base/global_file.cpp +++ b/source/module_base/global_file.cpp @@ -274,30 +274,4 @@ void ModuleBase::Global_File::close_all_log(const int rank, const bool out_alllo #endif return; } - -void ModuleBase::Global_File::delete_tmp_files() -{ - if (GlobalV::MY_RANK == 0) - { - for (int is = 0; is < PARAM.inp.nspin; ++is) - { - std::string tmp_chg_1 = PARAM.globalv.global_out_dir + "NOW_SPIN" + std::to_string(is + 1) + "_CHG.cube"; - std::string tmp_chg_2 = PARAM.globalv.global_out_dir + "OLD1_SPIN" + std::to_string(is + 1) + "_CHG.cube"; - std::string tmp_chg_3 = PARAM.globalv.global_out_dir + "OLD2_SPIN" + std::to_string(is + 1) + "_CHG.cube"; - - if (access(tmp_chg_1.c_str(), 0) == 0) - { - std::remove(tmp_chg_1.c_str()); - } - if (access(tmp_chg_2.c_str(), 0) == 0) - { - std::remove(tmp_chg_2.c_str()); - } - if (access(tmp_chg_3.c_str(), 0) == 0) - { - std::remove(tmp_chg_3.c_str()); - } - } - } -} } diff --git a/source/module_base/global_file.h b/source/module_base/global_file.h index 1db9a0a4b65..9b6895388cd 100644 --- a/source/module_base/global_file.h +++ b/source/module_base/global_file.h @@ -30,13 +30,7 @@ namespace Global_File void make_dir_atom(const std::string &label); void open_log ( std::ofstream &ofs, const std::string &fn, const std::string &calculation, const bool &restart); void close_log( std::ofstream &ofs, const std::string &fn); - void close_all_log(const int rank, const bool out_alllog = false,const std::string &calculation = "md"); - - /** - * @brief delete tmperary files - * - */ - void delete_tmp_files(); + void close_all_log(const int rank, const bool out_alllog = false, const std::string& calculation = "md"); } } #endif diff --git a/source/module_base/global_variable.cpp b/source/module_base/global_variable.cpp index caa75cee7cf..616e8c36569 100644 --- a/source/module_base/global_variable.cpp +++ b/source/module_base/global_variable.cpp @@ -12,25 +12,6 @@ #include namespace GlobalV { - -//---------------------------------------------------------- -// EXPLAIN : Basic Global Variables -// In practice calculation, these values are set in -// input.cpp. -//---------------------------------------------------------- -int NBANDS = 0; -int NLOCAL = 0; // total number of local basis. - -int NSPIN = 1; // LDA -double nupdown = 0.0; - -bool use_uspp = false; -std::string KS_SOLVER = "cg"; // xiaohui add 2013-09-01 -double SEARCH_RADIUS = -1.0; - -int NB2D = 1; - - //---------------------------------------------------------- // EXPLAIN : Parallel information //---------------------------------------------------------- @@ -53,23 +34,11 @@ int GRANK = MY_RANK; int GSIZE = DSIZE; //---------------------------------------------------------- -// EXPLAIN : The input file name and directory +// EXPLAIN : ofstream for output //---------------------------------------------------------- -std::string stru_file = "STRU"; - std::ofstream ofs_running; std::ofstream ofs_warning; std::ofstream ofs_info; // output math lib info std::ofstream ofs_device; // output device info - -//========================================================== -// device flags added by denghui -//========================================================== -std::string device_flag = "unknown"; - -double nelec = 0; - - -// on-site orbitals } // namespace GlobalV diff --git a/source/module_base/global_variable.h b/source/module_base/global_variable.h index 83b6b3faf98..9063298947a 100644 --- a/source/module_base/global_variable.h +++ b/source/module_base/global_variable.h @@ -13,27 +13,6 @@ namespace GlobalV { -//========================================================== -// EXPLAIN : Basic Global Variables -//========================================================== - -extern int NBANDS; -extern int NLOCAL; // 1.1 // mohan add 2009-05-29 - - -extern int NSPIN; // 7 -extern double nupdown; -extern bool use_uspp; - -extern std::string KS_SOLVER; // xiaohui add 2013-09-01 -extern double SEARCH_RADIUS; // 11.1 // mohan add 2011-03-10 - - -extern int NB2D; // 16.5 dividsion of 2D_matrix. - - // pw, 2: real drho for lcao - - //======================================================================== // EXPLAIN : Parallel information // GLOBAL VARIABLES : @@ -80,37 +59,11 @@ extern int KPAR_LCAO; // NAME : ofs_running( contain information during runnnig) // NAME : ofs_warning( contain warning information, including error) //========================================================== -extern std::string stru_file; // extern std::string global_pseudo_type; // mohan add 2013-05-20 (xiaohui add // 2013-06-23) extern std::ofstream ofs_running; extern std::ofstream ofs_warning; extern std::ofstream ofs_info; extern std::ofstream ofs_device; - - -// mixing parameters - -//========================================================== -// device flags added by denghui -//========================================================== -extern std::string device_flag; -//========================================================== -// precision flags added by denghui -//========================================================== - - // "out_chg" elec step. -/// @brief method to initialize wavefunction -/// @author kirk0830, 20230920 -/// @brief whether use the new psi initializer to initialize psi -/// @author ykhuang, 20230920 - -extern double nelec; - -// Deltaspin related - -// Quasiatomic orbital related - -// radius of on-site orbitals } // namespace GlobalV #endif diff --git a/source/module_base/grid/delley.cpp b/source/module_base/grid/delley.cpp index 1e0b6c703e2..c24aa6ffbbf 100644 --- a/source/module_base/grid/delley.cpp +++ b/source/module_base/grid/delley.cpp @@ -1,12 +1,13 @@ #include "module_base/grid/delley.h" +#include #include #include #include namespace { -struct Table { +struct DelleyTable { const int lmax_; const int ngrid_; const int ntype_[6]; @@ -14,7 +15,7 @@ struct Table { }; // Delley's table from the original article -const std::vector table = { +const std::vector delley_table = { { 17, 110, {1, 1, 0, 3, 1, 0}, { @@ -209,7 +210,7 @@ const std::vector
table = { 0.63942796347491023, 0.06424549224220589, 0.0009158016174693465, } } -}; // end of the definition of "table" +}; // end of the definition of "delley_table" // size of each group of points with octahedral symmetry // 6: (1, 0, 0) x sign x permutation (vertices) @@ -324,15 +325,15 @@ const std::vector fill = { }, }; // end of the definition of "fill" -const Table* _find_table(int& lmax) { - // NOTE: this function assumes elements in "Delley::table_" are +const DelleyTable* _find_delley(int& lmax) { + // NOTE: this function assumes elements in "delley_table" are // arranged such that their members "lmax_" are in ascending order. - auto tab = std::find_if(table.begin(), table.end(), - [lmax](const Table& t) { return t.lmax_ >= lmax; }); - return tab == table.end() ? nullptr : (lmax = tab->lmax_, &(*tab)); + auto tab = std::find_if(delley_table.begin(), delley_table.end(), + [lmax](const DelleyTable& t) { return t.lmax_ >= lmax; }); + return tab == delley_table.end() ? nullptr : (lmax = tab->lmax_, &(*tab)); } -void _get(const Table* tab, double* grid, double* weight) { +void _delley(const DelleyTable* tab, double* grid, double* weight) { assert(tab); const double* ptr = &tab->data_[0]; for (int itype = 0; itype < 6; ++itype) { @@ -348,29 +349,29 @@ void _get(const Table* tab, double* grid, double* weight) { } // end of anonymous namespace -int Grid::Delley::ngrid(int& lmax) { - auto tab = _find_table(lmax); +int Grid::Angular::ngrid_delley(int& lmax) { + auto tab = _find_delley(lmax); return tab ? tab->ngrid_ : -1; } -int Grid::Delley::get(int& lmax, double* grid, double* weight) { - auto tab = _find_table(lmax); - return tab ? _get(tab, grid, weight), 0 : -1; +int Grid::Angular::delley(int& lmax, double* grid, double* weight) { + auto tab = _find_delley(lmax); + return tab ? _delley(tab, grid, weight), 0 : -1; } -int Grid::Delley::get( +int Grid::Angular::delley( int& lmax, std::vector& grid, std::vector& weight ) { - auto tab = _find_table(lmax); + auto tab = _find_delley(lmax); if (!tab) { return -1; } grid.resize(3 * tab->ngrid_); weight.resize(tab->ngrid_); - _get(tab, grid.data(), weight.data()); + _delley(tab, grid.data(), weight.data()); return 0; } diff --git a/source/module_base/grid/delley.h b/source/module_base/grid/delley.h index 4f68a2168af..25f5fd35bed 100644 --- a/source/module_base/grid/delley.h +++ b/source/module_base/grid/delley.h @@ -1,19 +1,10 @@ -#ifndef GRID_DELLEY_H -#define GRID_DELLEY_H +#ifndef GRID_ANGULAR_DELLEY_H +#define GRID_ANGULAR_DELLEY_H #include -#include -/** - * @brief Delley's grid for quadrature on the unit sphere. - * - * Reference: - * Delley, B. (1996). High order integration schemes on the unit sphere. - * Journal of computational chemistry, 17(9), 1152-1155. - * - */ namespace Grid { -namespace Delley { +namespace Angular { /** * @brief Number of Delley's grid points for a certain order of accuracy. @@ -27,7 +18,7 @@ namespace Delley { * lmax will be set to 23. * */ -int ngrid(int& lmax); +int ngrid_delley(int& lmax); /** @@ -45,13 +36,16 @@ int ngrid(int& lmax); * ngrid(lmax) elements, respectively. The function will return 0 if * successful, or -1 if the requested order cannot be fulfilled. * + * Reference: + * Delley, B. (1996). High order integration schemes on the unit sphere. + * Journal of computational chemistry, 17(9), 1152-1155. */ -int get(int& lmax, double* grid, double* weight); +int delley(int& lmax, double* grid, double* weight); // a handy wrapper doing the same as above -int get(int& lmax, std::vector& grid, std::vector& weight); +int delley(int& lmax, std::vector& grid, std::vector& weight); -} // end of namespace Delley +} // end of namespace Angular } // end of namespace Grid #endif diff --git a/source/module_base/grid/partition.cpp b/source/module_base/grid/partition.cpp new file mode 100644 index 00000000000..20ce3edb265 --- /dev/null +++ b/source/module_base/grid/partition.cpp @@ -0,0 +1,142 @@ +#include "module_base/grid/partition.h" +#include "module_base/constants.h" + +#include +#include +#include +#include +#include +#include + +namespace Grid { +namespace Partition { + +const double stratmann_a = 0.64; + +double w_becke( + int nR0, + const double* drR, + const double* dRR, + int nR, + const int* iR, + int c +) { + assert(nR > 0 && nR0 >= nR); + std::vector P(nR, 1.0); + for (int i = 0; i < nR; ++i) { + int I = iR[i]; + for (int j = i + 1; j < nR; ++j) { + int J = iR[j]; + double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J]; + double s = s_becke(mu); + P[I] *= s; + P[J] *= (1.0 - s); // s(-mu) = 1 - s(mu) + } + } + return P[c] / std::accumulate(P.begin(), P.end(), 0.0); +} + + +double s_becke(double mu) { + /* + * Becke's iterated polynomials (3rd order) + * + * s(mu) = 0.5 * (1 - p(p(p(mu)))) + * + * p(x) = 0.5 * x * (3 - x^2) + * + */ + double p = 0.5 * mu * (3.0 - mu*mu); + p = 0.5 * p * (3.0 - p*p); + p = 0.5 * p * (3.0 - p*p); + return 0.5 * (1.0 - p); +} + + +double w_stratmann( + int nR0, + const double* drR, + const double* dRR, + const double* drR_thr, + int nR, + int* iR, + int c +) { + assert(nR > 0 && nR0 >= nR); + int I = iR[c], J = 0; + + // If r falls within the exclusive zone of a center, return immediately. + for (int j = 0; j < nR; ++j) { + J = iR[j]; + if (drR[J] <= drR_thr[J]) { + return static_cast(I == J); + } + } + + // Even if the grid point does not fall within the exclusive zone of any + // center, the normalized weight could still be 0 or 1, and this can be + // figured out by examining the unnormalized weight alone. + + // Swap the grid center to the first position in iteration for convenience. + // Restore the original order before return. + std::swap(iR[0], iR[c]); + + std::vector P(nR); + for (int j = 1; j < nR; ++j) { + J = iR[j]; + double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J]; + P[j] = s_stratmann(mu); + } + P[0] = std::accumulate(P.begin() + 1, P.end(), 1.0, + std::multiplies()); + + if (P[0] == 0.0 || P[0] == 1.0) { + std::swap(iR[0], iR[c]); // restore the original order + return P[0]; + } + + // If it passes all the screening above, all unnormalized weights + // have to be calculated in order to get the normalized weight. + + std::for_each(P.begin() + 1, P.end(), [](double& s) { s = 1.0 - s; }); + for (int i = 1; i < nR; ++i) { + I = iR[i]; + for (int j = i + 1; j < nR; ++j) { + J = iR[j]; + double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J]; + double s = s_stratmann(mu); + P[i] *= s; + P[j] *= (1.0 - s); // s(-mu) = 1 - s(mu) + } + } + + std::swap(iR[0], iR[c]); // restore the original order + return P[0] / std::accumulate(P.begin(), P.end(), 0.0); +} + + +double s_stratmann(double mu) { + /* + * Stratmann's piecewise cell function + * + * s(mu) = 0.5 * (1 - g(mu/a)) + * + * / -1 x <= -1 + * | + * g(x) = | (35x - 35x^3 + 21x^5 - 5x^7) / 16 |x| < 1 + * | + * \ +1 x >= +1 + * + */ + double x = mu / stratmann_a; + double x2 = x * x; + double h = 0.0625 * x * (35 + x2 * (-35 + x2 * (21 - 5 * x2))); + + bool mid = std::abs(x) < 1; + double g = !mid * (1 - 2 * std::signbit(x)) + mid * h; + return 0.5 * (1.0 - g); +} + + +} // end of namespace Partition +} // end of namespace Grid diff --git a/source/module_base/grid/partition.h b/source/module_base/grid/partition.h new file mode 100644 index 00000000000..cc4879e3a0d --- /dev/null +++ b/source/module_base/grid/partition.h @@ -0,0 +1,84 @@ +#ifndef GRID_PARTITION_H +#define GRID_PARTITION_H + +namespace Grid { +namespace Partition { + +enum class Type { + Becke, + Stratmann, +}; + +extern const double stratmann_a; + +/** + * @brief Becke's partition weight. + * + * This function computes the normalized Becke's partition weight + * for a grid point associated with a selected set of centers, given + * the grid point's distance to centers and inter-center distance. + * + * @param nR0 Total number of centers given by drR & dRR. + * @param drR Distance between the grid point and centers. + * @param dRR Distance between centers. dRR[I*nR0 + J] is the + * distance between center I and J. + * @param nR Number of centers involved in the weight calculation. + * nR <= nR0. Length of iR. + * @param iR Indices of centers involved. + * Each element is a distinctive index in [0, nR0). + * @param c iR[c] is the index of the center whom this grid point + * belongs to. + * + * Reference: + * Becke, A. D. (1988). + * A multicenter numerical integration scheme for polyatomic molecules. + * The Journal of chemical physics, 88(4), 2547-2553. + * + */ +double w_becke( + int nR0, + const double* drR, + const double* dRR, + int nR, + const int* iR, + int c +); + +// Becke's cell function (iterated polynomial) +double s_becke(double mu); + + +/** + * @brief Becke's partition weight with Stratmann's scheme. + * + * This function is similar to w_becke, but the cell function adopts + * the one proposed by Stratmann et al, which enables some screening. + * + * @see w_becke + * + * @param drR_thr Radius of exclusive zone of each center. + * + * Reference: + * Stratmann, R. E., Scuseria, G. E., & Frisch, M. J. (1996). + * Achieving linear scaling in exchange-correlation density functional + * quadratures. + * Chemical physics letters, 257(3-4), 213-223. + * + */ +double w_stratmann( + int nR0, + const double* drR, + const double* dRR, + const double* drR_thr, + int nR, + int* iR, + int c +); + +// Stratmann's piecewise cell function +double s_stratmann(double mu); + +} // end of namespace Partition +} // end of namespace Grid + +#endif diff --git a/source/module_base/grid/radial.cpp b/source/module_base/grid/radial.cpp new file mode 100644 index 00000000000..6b34ec953dc --- /dev/null +++ b/source/module_base/grid/radial.cpp @@ -0,0 +1,64 @@ +#include "module_base/grid/radial.h" + +#include + +namespace Grid { +namespace Radial { + +void baker(int nbase, double R, double* r, double* w, int mult) { + int n = (nbase+1) * mult - 1; + double r0 = -R / std::log((2.0 * nbase + 1.0) / ((nbase+1)*(nbase+1))); + for (int i = 1; i <= n; ++i) { + r[i-1] = -r0 * std::log(1.0 - static_cast(i)*i/((n+1)*(n+1))); + w[i-1] = 2.0 * i * r0 * r[i-1] * r[i-1] / ((n+1+i)*(n+1-i)); + } +} + + +void baker(int nbase, double R, std::vector& r, + std::vector& w, int mult) { + int n = (nbase+1) * mult - 1; + r.resize(n); + w.resize(n); + baker(nbase, R, r.data(), w.data(), mult); +} + + +void murray(int n, double R, double* r, double* w) { + for (int i = 1; i <= n; ++i) { + double x = static_cast(i) / (n + 1); + r[i-1] = std::pow(x / (1.0 - x), 2) * R; + w[i-1] = 2.0 / (n + 1) * std::pow(R, 3) * std::pow(x, 5) + / std::pow(1.0 - x, 7); + } +} + + +void treutler_m4(int n, double R, double* r, double* w, double alpha) { + const double pi = std::acos(-1.0); + const double inv_ln2 = 1.0 / std::log(2.0); + + for (int i = 1; i <= n; ++i) { + double x = std::cos(i * pi / (n + 1)); + double beta = std::sqrt((1.0 + x) / (1.0 - x)); + double gamma = std::log((1.0 - x) / 2.0); + double delta = std::pow(1.0 + x, alpha); + r[i-1] = -R * inv_ln2 * delta * gamma; + w[i-1] = pi / (n + 1) * std::pow(delta * R * inv_ln2, 3) + * gamma * gamma * (beta - alpha / beta * gamma); + } +} + + +void mura(int n, double R, double* r, double* w) { + for (int i = 1; i <= n; ++i) { + double x = static_cast(i) / (n + 1); + double alpha = 1.0 - x * x * x; + r[i-1] = -R * std::log(alpha); + w[i-1] = 3.0 * R * std::pow(x * r[i-1], 2) / ((n+1) * alpha); + } +} + + +} // end of namespace Radial +} // end of namespace Grid diff --git a/source/module_base/grid/radial.h b/source/module_base/grid/radial.h new file mode 100644 index 00000000000..b8378f58340 --- /dev/null +++ b/source/module_base/grid/radial.h @@ -0,0 +1,70 @@ +#ifndef GRID_RADIAL_H +#define GRID_RADIAL_H + +#include + +namespace Grid { +namespace Radial { + +/** + * @brief Radial quadratures. + * + * This namespace contains functions that generate grids and weights + * for numerical integration + * + * / inf 2 + * | dr r g(r) ~ \sum_i w[i] g(r[i]) + * / 0 + * + */ + +/** + * Baker, J., Andzelm, J., Scheiner, A., & Delley, B. (1994). + * The effect of grid quality and weight derivatives in + * density functional calculations. + * The Journal of chemical physics, 101(10), 8894-8902. + * + * Zhang, I. Y., Ren, X., Rinke, P., Blum, V., & Scheffler, M. (2013). + * Numeric atom-centered-orbital basis sets with valence-correlation + * consistency from H to Ar. + * New Journal of Physics, 15(12), 123033. + * + * @note nbase is the number of points of the "base" grid, i.e., + * before applying the "radial multiplier" introduced by Zhang et al. + * The true number of grid points is (nbase+1) * mult - 1. + */ +void baker(int nbase, double R, double* r, double* w, int mult = 1); +void baker(int nbase, double R, std::vector& r, + std::vector& w, int mult = 1); + + +/** + * Murray, C. W., Handy, N. C., & Laming, G. J. (1993). + * Quadrature schemes for integrals of density functional theory. + * Molecular Physics, 78(4), 997-1014. + */ +void murray(int n, double R, double* r, double* w); + + +/** + * Treutler, O., & Ahlrichs, R. (1995). + * Efficient molecular numerical integration schemes. + * The Journal of Chemical Physics, 102(1), 346-354. + * + * @note M4 reduces to M3 at alpha = 0. + */ +void treutler_m4(int n, double R, double* r, double* w, double alpha = 0.6); + + +/** + * Mura, M. E., & Knowles, P. J. (1996). + * Improved radial grids for quadrature in molecular + * density‐functional calculations. + * The Journal of chemical physics, 104(24), 9848-9858. + */ +void mura(int n, double R, double* r, double* w); + +} // end of namespace Radial +} // end of namespace Grid + +#endif diff --git a/source/module_base/grid/test/CMakeLists.txt b/source/module_base/grid/test/CMakeLists.txt index 0f77a425fee..e403c8c2c6f 100644 --- a/source/module_base/grid/test/CMakeLists.txt +++ b/source/module_base/grid/test/CMakeLists.txt @@ -7,3 +7,16 @@ AddTest( ../../ylm.cpp ) +AddTest( + TARGET test_radial + SOURCES test_radial.cpp + ../radial.cpp +) + +AddTest( + TARGET test_partition + SOURCES test_partition.cpp + ../partition.cpp + ../radial.cpp + ../delley.cpp +) diff --git a/source/module_base/grid/test/test_delley.cpp b/source/module_base/grid/test/test_delley.cpp index 2b892cd5322..2aa9b38df0f 100644 --- a/source/module_base/grid/test/test_delley.cpp +++ b/source/module_base/grid/test/test_delley.cpp @@ -7,7 +7,7 @@ #include #endif -using namespace Grid; +using namespace Grid::Angular; // mock the function to prevent unnecessary dependency namespace ModuleBase { @@ -47,27 +47,27 @@ void DelleyTest::randgen(int lmax, std::vector& coef) { TEST_F(DelleyTest, NumGrid) { int lmax = 5; - int ngrid = Delley::ngrid(lmax); + int ngrid = ngrid_delley(lmax); EXPECT_EQ(lmax, 17); EXPECT_EQ(ngrid, 110); lmax = 17; - ngrid = Delley::ngrid(lmax); + ngrid = ngrid_delley(lmax); EXPECT_EQ(lmax, 17); EXPECT_EQ(ngrid, 110); lmax = 20; - ngrid = Delley::ngrid(lmax); + ngrid = ngrid_delley(lmax); EXPECT_EQ(lmax, 23); EXPECT_EQ(ngrid, 194); lmax = 59; - ngrid = Delley::ngrid(lmax); + ngrid = ngrid_delley(lmax); EXPECT_EQ(lmax, 59); EXPECT_EQ(ngrid, 1202); lmax = 60; - ngrid = Delley::ngrid(lmax); + ngrid = ngrid_delley(lmax); EXPECT_EQ(lmax, 60); EXPECT_EQ(ngrid, -1); } @@ -91,7 +91,7 @@ TEST_F(DelleyTest, Accuracy) { std::vector grid, weight, coef; for (int grid_lmax = 17; grid_lmax < 60; grid_lmax +=6) { - Delley::get(grid_lmax, grid, weight); + delley(grid_lmax, grid, weight); int func_lmax = grid_lmax / 2; randgen(func_lmax, coef); @@ -101,8 +101,8 @@ TEST_F(DelleyTest, Accuracy) { ModuleBase::Ylm::sph_harm(func_lmax, grid[3*i], grid[3*i+1], grid[3*i+2], ylm_real); double tmp = 0.0; - for (size_t i = 0; i < coef.size(); ++i) { - tmp += coef[i] * ylm_real[i]; + for (size_t j = 0; j < coef.size(); ++j) { + tmp += coef[j] * ylm_real[j]; } val += weight[i] * tmp * tmp; } diff --git a/source/module_base/grid/test/test_partition.cpp b/source/module_base/grid/test/test_partition.cpp new file mode 100644 index 00000000000..057f4c43da4 --- /dev/null +++ b/source/module_base/grid/test/test_partition.cpp @@ -0,0 +1,295 @@ +#include "module_base/grid/partition.h" +#include "module_base/grid/radial.h" +#include "module_base/grid/delley.h" +#include "module_base/constants.h" + +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include + +#ifdef __MPI +#include +#endif + +using ModuleBase::PI; +using Vec3 = std::array; + +using iclock = std::chrono::high_resolution_clock; +iclock::time_point start; +std::chrono::duration dur; + +double norm(const Vec3& v) { + return std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + +Vec3 operator-(const Vec3& v1, const Vec3& v2) { + return {v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]}; +} + +Vec3 operator+(const Vec3& v1, const Vec3& v2) { + return {v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]}; +} + +// |r|^n * exp(-a*|r|^2) +double func_core(const Vec3& r, double a, double n) { + double rabs = norm(r); + return std::pow(rabs, n) * std::exp(-a * rabs * rabs); +} + +// func_core integrated over all space +double ref_core(double a, double n) { + double p = 0.5 * (n + 3); + return 2.0 * PI * std::pow(a, -p) * std::tgamma(p); +} + +// the test function is a combination of several func_core +double func( + const Vec3& r, + const std::vector& R, + const std::vector& a, + const std::vector& n +) { + double val = 0.0; + for (size_t i = 0; i < R.size(); i++) { + val += func_core(r - R[i], a[i], n[i]); + } + return val; +} + +double ref(const std::vector& a, const std::vector& n) { + double val = 0.0; + for (size_t i = 0; i < a.size(); i++) { + val += ref_core(a[i], n[i]); + } + return val; +} + +// A Param object specifies a test function +struct Param { + std::vector R; + std::vector a; + std::vector n; +}; + +std::vector test_params = { + { + { + {0.0, 0.0, 0.0}, + {0.0, 0.0, 2.0}, + }, + {0.5, 2.0}, + {0, 0} + }, + { + { + {0.0, 0.0, 0.0}, + {0.0, 0.0, 2.0}, + {0.0, 3.0, 0.0}, + }, + {0.5, 2.0, 1.5}, + {1, 2, 0.5} + }, + { + { + {0.0, 0.0, 0.0}, + {0.0, 0.0, 3.0}, + {0.0, 3.0, 0.0}, + {9.0, 0.0, 0.0}, + }, + {1.0, 2.0, 1.5, 2.0}, + {2.5, 2, 0.5, 1} + }, + { + { + {0.0, 0.0, 0.0}, + {0.0, 0.0, 3.0}, + {0.0, 3.0, 0.0}, + {9.0, 0.0, 0.0}, + {1.0, 1.0, 1.0}, + {2.0, 2.0, 2.0}, + {3.0, 3.0, 3.0}, + {4.0, 4.0, 4.0}, + {5.0, 5.0, 5.0}, + {6.0, 6.0, 6.0}, + }, + {1.0, 2.0, 1.5, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0}, + {2.5, 2.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} + }, +}; + +std::vector dist_R_R(const std::vector& R) { + // tabulate dRR[I,J] = || R[I] - R[J] || + size_t nR = R.size(); + std::vector dRR(nR*nR, 0.0); + for (size_t I = 0; I < nR; I++) { + for (size_t J = I + 1; J < nR; J++) { + double d = norm(R[I] - R[J]); + dRR[I*nR + J] = d; + dRR[J*nR + I] = d; + } + } + return dRR; +} + +class PartitionTest: public ::testing::Test { +protected: + PartitionTest(); + + // grid & weight for one-center integration + std::vector r; + std::vector w; + + const double tol = 1e-5; +}; + +PartitionTest::PartitionTest() { + // angular grid & weight + std::vector r_ang, w_ang; + int lmax = 25; + Grid::Angular::delley(lmax, r_ang, w_ang); + + // radial grid & weight + std::vector r_rad, w_rad; + int nrad = 60; + int Rcut = 7.0; + int mult = 2; + Grid::Radial::baker(nrad, Rcut, r_rad, w_rad, mult); + + // complete grid & weight for one-center integration + size_t ngrid = w_rad.size() * w_ang.size(); + r.resize(3*ngrid); + w.resize(ngrid); + + size_t ir = 0; + for (size_t i = 0; i < w_rad.size(); i++) { + for (size_t j = 0; j < w_ang.size(); j++) { + r[3*ir] = r_rad[i] * r_ang[3*j]; + r[3*ir+1] = r_rad[i] * r_ang[3*j+1]; + r[3*ir+2] = r_rad[i] * r_ang[3*j+2]; + w[ir] = w_rad[i] * w_ang[j] * 4.0 * PI; + ++ir; + } + } +} + + +TEST_F(PartitionTest, Becke) { + dur = dur.zero(); + for (const Param& param : test_params) { + double val = 0.0; + double val_ref = ref(param.a, param.n); + + // tabulate || R[I] - R[J] || + std::vector dRR(dist_R_R(param.R)); + + // all centers are involved + size_t nR = param.R.size(); + std::vector iR(nR); + std::iota(iR.begin(), iR.end(), 0); + + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(iR.begin(), iR.end(), g); + + for (size_t I = 0; I < nR; ++I) { // for each center + for (size_t i = 0; i < w.size(); i++) { + Vec3 ri = Vec3{r[3*i], r[3*i+1], r[3*i+2]} + param.R[I]; + + // tabulate || r - R[J] || + std::vector drR(nR); + for (size_t J = 0; J < nR; ++J) { + drR[J] = norm(ri - param.R[J]); + } + + // partition weight for this grid point + start = iclock::now(); + double w_part = Grid::Partition::w_becke( + drR.size(), drR.data(), dRR.data(), + iR.size(), iR.data(), I + ); + dur += iclock::now() - start; + + val += w_part * w[i] * func(ri, param.R, param.a, param.n); + } + } + + EXPECT_NEAR(val, val_ref, tol); + } + printf("time elapsed = %8.3e seconds\n", dur.count()); +} + + +TEST_F(PartitionTest, Stratmann) { + dur = dur.zero(); + + for (const Param& param : test_params) { + double val = 0.0; + double val_ref = ref(param.a, param.n); + + // tabulate || R[I] - R[J] || + std::vector dRR(dist_R_R(param.R)); + + // all centers are involved + size_t nR = param.R.size(); + std::vector iR(nR); + std::iota(iR.begin(), iR.end(), 0); + + // radii of exclusive zone + std::vector drR_thr(nR); + for (size_t I = 0; I < nR; ++I) { + double dRRmin = 1e100; + for (size_t J = 0; J < nR; ++J) { + if (J != I) { + dRRmin = std::min(dRRmin, dRR[I*nR + J]); + } + } + drR_thr[I] = 0.5 * (1.0 - Grid::Partition::stratmann_a) * dRRmin; + } + + for (size_t I = 0; I < nR; ++I) { // for each center + for (size_t i = 0; i < w.size(); i++) { + Vec3 ri = Vec3{r[3*i], r[3*i+1], r[3*i+2]} + param.R[I]; + + // tabulate || r - R[J] || + std::vector drR(nR); + for (size_t J = 0; J < nR; ++J) { + drR[J] = norm(ri - param.R[J]); + } + + // partition weight for this grid point + start = iclock::now(); + double w_part = Grid::Partition::w_stratmann( + drR.size(), drR.data(), dRR.data(), drR_thr.data(), + iR.size(), iR.data(), I + ); + dur += iclock::now() - start; + + val += w_part * w[i] * func(ri, param.R, param.a, param.n); + } + } + + EXPECT_NEAR(val, val_ref, tol); + } + printf("time elapsed = %8.3e seconds\n", dur.count()); +} + + +int main(int argc, char** argv) +{ +#ifdef __MPI + MPI_Init(&argc, &argv); +#endif + + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef __MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/source/module_base/grid/test/test_radial.cpp b/source/module_base/grid/test/test_radial.cpp new file mode 100644 index 00000000000..6cdd4c4841a --- /dev/null +++ b/source/module_base/grid/test/test_radial.cpp @@ -0,0 +1,136 @@ +#include "module_base/grid/radial.h" + +#include "gtest/gtest.h" +#include +#include +#ifdef __MPI +#include +#endif + +using namespace Grid::Radial; +using Func_t = std::function; + +/** + * This test briefly checks various radial quadrature schemes by comparing + * their numerical results with analytical values on a few simple functions. + * + * The number of grid points and scaling factor are not carefully selected + * and the test is not exhaustive. It is just a sanity check. + * + */ + +const double pi = std::acos(-1.0); + +// test functions f(r) and their analytical integrals +// +// / inf 2 +// | dr r f(r) +// / 0 +// +std::vector> test_func_ref = { + { + [](double r) { + return std::exp(-0.3 * r * r) + std::exp(-3.0 * r * r); + }, + 0.25 * std::sqrt(pi) * (std::pow(0.3, -1.5) + std::pow(3.0, -1.5)) + }, + { + [](double r) { + return r * (std::exp(-0.3 * r * r) + std::exp(-3.0 * r * r)); + }, + 0.5 / (0.3 * 0.3) + 0.5 / (3.0 * 3.0) + }, + { + [](double r) { + return r * r * (std::exp(-0.3 * r * r) + std::exp(-3.0 * r * r)); + }, + 0.375 * std::sqrt(pi) * (std::pow(0.3, -2.5) + std::pow(3.0, -2.5)) + }, +}; + + +double quadrature(const Func_t& f, int n, double* r, double* w) { + double res = 0.0; + for (int i = 0; i < n; i++) { + res += w[i] * f(r[i]); + } + return res; +} + + +TEST(RadialTest, Baker) { + // R should be large enough to cover the range of the function. + // For mult = 1, R is the cutoff radius; for mult > 1, there + // are (mult - 1) grid points extend beyond R. + int nbase = 20; + int mult = 2; + double R = 7.0; + std::vector r, w; + baker(nbase, R, r, w, mult); + + EXPECT_EQ(r.size(), (nbase + 1) * mult - 1); + + for (auto& t : test_func_ref) { + double res = quadrature(t.first, r.size(), r.data(), w.data()); + EXPECT_NEAR(res, t.second, 1.0e-6); + } +} + + +TEST(RadialTest, Murray) { + int n = 40; + double R = 7.0; + std::vector r(n), w(n); + murray(n, R, r.data(), w.data()); + + for (auto& t : test_func_ref) { + double res = quadrature(t.first, r.size(), r.data(), w.data()); + EXPECT_NEAR(res, t.second, 1.0e-6); + } +} + + +TEST(RadialTest, Treutler) { + int n = 40; + double R = 7.0; + std::vector r(n), w(n); + + for (auto alpha : {0.0, 0.6, 1.0}) { + treutler_m4(n, R, r.data(), w.data(), alpha); + + for (auto& t : test_func_ref) { + double res = quadrature(t.first, r.size(), r.data(), w.data()); + EXPECT_NEAR(res, t.second, 1.0e-6); + } + } +} + + +TEST(RadialTest, Mura) { + int n = 40; + double R = 7.0; + std::vector r(n), w(n); + mura(n, R, r.data(), w.data()); + + for (auto& t : test_func_ref) { + double res = quadrature(t.first, r.size(), r.data(), w.data()); + EXPECT_NEAR(res, t.second, 1.0e-6); + } +} + + +int main(int argc, char** argv) +{ +#ifdef __MPI + MPI_Init(&argc, &argv); +#endif + + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef __MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/source/module_base/kernels/dsp/dsp_connector.h b/source/module_base/kernels/dsp/dsp_connector.h new file mode 100644 index 00000000000..b51c67663ee --- /dev/null +++ b/source/module_base/kernels/dsp/dsp_connector.h @@ -0,0 +1,131 @@ +#ifndef DSP_CONNECTOR_H +#define DSP_CONNECTOR_H +#ifdef __DSP + +#include "module_base/module_device/device.h" +#include "module_base/module_device/memory_op.h" +#include "module_hsolver/diag_comm_info.h" + +// Base dsp functions +void dspInitHandle(int id); +void dspDestoryHandle(int id); +void *malloc_ht(size_t bytes, int cluster_id); +void free_ht(void* ptr); + + +// mtblas functions + +void sgemm_mt_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const float *alpha, const float *a, const int *lda, + const float *b, const int *ldb, const float *beta, + float *c, const int *ldc, int cluster_id); + +void dgemm_mt_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const double *alpha,const double *a, const int *lda, + const double *b, const int *ldb, const double *beta, + double *c, const int *ldc, int cluster_id); + +void zgemm_mt_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const std::complex *alpha, const std::complex *a, const int *lda, + const std::complex *b, const int *ldb, const std::complex *beta, + std::complex *c, const int *ldc, int cluster_id); + +void cgemm_mt_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const std::complex *alpha, const std::complex *a, const int *lda, + const std::complex *b, const int *ldb, const std::complex *beta, + std::complex *c, const int *ldc, int cluster_id); + + +void sgemm_mth_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const float *alpha, const float *a, const int *lda, + const float *b, const int *ldb, const float *beta, + float *c, const int *ldc, int cluster_id); + +void dgemm_mth_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const double *alpha,const double *a, const int *lda, + const double *b, const int *ldb, const double *beta, + double *c, const int *ldc, int cluster_id); + +void zgemm_mth_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const std::complex *alpha, const std::complex *a, const int *lda, + const std::complex *b, const int *ldb, const std::complex *beta, + std::complex *c, const int *ldc, int cluster_id); + +void cgemm_mth_(const char *transa, const char *transb, + const int *m, const int *n, const int *k, + const std::complex *alpha, const std::complex *a, const int *lda, + const std::complex *b, const int *ldb, const std::complex *beta, + std::complex *c, const int *ldc, int cluster_id); + +//#define zgemm_ zgemm_mt + +// The next is dsp utils. It may be moved to other files if this file get too huge + +template +void dsp_dav_subspace_reduce(T* hcc, T* scc, int nbase, int nbase_x, int notconv, MPI_Comm diag_comm){ + + using syncmem_complex_op = base_device::memory::synchronize_memory_op; + + auto* swap = new T[notconv * nbase_x]; + auto* target = new T[notconv * nbase_x]; + syncmem_complex_op()(cpu_ctx, cpu_ctx, swap, hcc + nbase * nbase_x, notconv * nbase_x); + if (base_device::get_current_precision(swap) == "single") + { + MPI_Reduce(swap, + target, + notconv * nbase_x, + MPI_COMPLEX, + MPI_SUM, + 0, + diag_comm); + } + else + { + MPI_Reduce(swap, + target, + notconv * nbase_x, + MPI_DOUBLE_COMPLEX, + MPI_SUM, + 0, + diag_comm); + } + + syncmem_complex_op()(cpu_ctx, cpu_ctx, hcc + nbase * nbase_x, target, notconv * nbase_x); + syncmem_complex_op()(cpu_ctx, cpu_ctx, swap, scc + nbase * nbase_x, notconv * nbase_x); + + if (base_device::get_current_precision(swap) == "single") + { + MPI_Reduce(swap, + target, + notconv * nbase_x, + MPI_COMPLEX, + MPI_SUM, + 0, + diag_comm); + } + else + { + MPI_Reduce(swap, + target, + notconv * nbase_x, + MPI_DOUBLE_COMPLEX, + MPI_SUM, + 0, + diag_comm); + } + + syncmem_complex_op()(cpu_ctx, cpu_ctx, scc + nbase * nbase_x, target, notconv * nbase_x); + delete[] swap; + delete[] target; +} + + +#endif +#endif \ No newline at end of file diff --git a/source/module_base/math_chebyshev.cpp b/source/module_base/math_chebyshev.cpp index 9de052382dc..76400ab6308 100644 --- a/source/module_base/math_chebyshev.cpp +++ b/source/module_base/math_chebyshev.cpp @@ -575,6 +575,7 @@ bool Chebyshev::checkconverge( std::function* in, std::complex* out, const int)> funA, std::complex* wavein, const int N, + const int LDA, REAL& tmax, REAL& tmin, REAL stept) @@ -584,9 +585,9 @@ bool Chebyshev::checkconverge( std::complex* arrayn; std::complex* arrayn_1; - arraynp1 = new std::complex[N]; - arrayn = new std::complex[N]; - arrayn_1 = new std::complex[N]; + arraynp1 = new std::complex[LDA]; + arrayn = new std::complex[LDA]; + arrayn_1 = new std::complex[LDA]; ModuleBase::GlobalFunc::DCOPY(wavein, arrayn_1, N); diff --git a/source/module_base/math_chebyshev.h b/source/module_base/math_chebyshev.h index 973cf7481b2..a62a5520d27 100644 --- a/source/module_base/math_chebyshev.h +++ b/source/module_base/math_chebyshev.h @@ -191,6 +191,7 @@ class Chebyshev bool checkconverge(std::function* in, std::complex* out, const int)> funA, std::complex* wavein, const int N, + const int LDA, REAL& tmax, // trial number for upper bound REAL& tmin, // trial number for lower bound REAL stept); // tmax = max() + stept, tmin = min() - stept diff --git a/source/module_base/module_device/device.cpp b/source/module_base/module_device/device.cpp index 4b739fd7a3d..4897ef1e8ae 100644 --- a/source/module_base/module_device/device.cpp +++ b/source/module_base/module_device/device.cpp @@ -148,13 +148,12 @@ int set_device_by_rank(const MPI_Comm mpi_comm) { #endif std::string get_device_flag(const std::string &device, - const std::string &ks_solver, const std::string &basis_type) { if (device == "cpu") { return "cpu"; // no extra checks required } std::string error_message; -if (device != "" and device != "gpu") +if (device != "auto" and device != "gpu") { error_message += "Parameter \"device\" can only be set to \"cpu\" or \"gpu\"!"; ModuleBase::WARNING_QUIT("device", error_message); diff --git a/source/module_base/module_device/device.h b/source/module_base/module_device/device.h index d0ed3325559..6be4952f149 100644 --- a/source/module_base/module_device/device.h +++ b/source/module_base/module_device/device.h @@ -44,10 +44,9 @@ int get_device_kpar(const int& kpar); /** * @brief Get the device flag object - * for module_io PARAM.globalv.device_flag + * for module_io PARAM.inp.device */ std::string get_device_flag(const std::string& device, - const std::string& ks_solver, const std::string& basis_type); #if __MPI diff --git a/source/module_base/module_device/memory_op.cpp b/source/module_base/module_device/memory_op.cpp index 1edc05b8fd9..f989924d303 100644 --- a/source/module_base/module_device/memory_op.cpp +++ b/source/module_base/module_device/memory_op.cpp @@ -2,6 +2,10 @@ #include "module_base/memory.h" #include "module_base/tool_threading.h" +#ifdef __DSP +#include "module_base/kernels/dsp/dsp_connector.h" +#include "module_base/global_variable.h" +#endif #include #include @@ -342,5 +346,57 @@ template struct delete_memory_op, base_device::DEVICE_GPU>; template struct delete_memory_op, base_device::DEVICE_GPU>; #endif +#ifdef __DSP + +template +struct resize_memory_op_mt +{ + void operator()(const base_device::DEVICE_CPU* dev, FPTYPE*& arr, const size_t size, const char* record_in) + { + if (arr != nullptr) + { + free_ht(arr); + } + arr = (FPTYPE*)malloc_ht(sizeof(FPTYPE) * size, GlobalV::MY_RANK); + std::string record_string; + if (record_in != nullptr) + { + record_string = record_in; + } + else + { + record_string = "no_record"; + } + + if (record_string != "no_record") + { + ModuleBase::Memory::record(record_string, sizeof(FPTYPE) * size); + } + } +}; + +template +struct delete_memory_op_mt +{ + void operator()(const base_device::DEVICE_CPU* dev, FPTYPE* arr) + { + free_ht(arr); + } +}; + + +template struct resize_memory_op_mt; +template struct resize_memory_op_mt; +template struct resize_memory_op_mt; +template struct resize_memory_op_mt, base_device::DEVICE_CPU>; +template struct resize_memory_op_mt, base_device::DEVICE_CPU>; + +template struct delete_memory_op_mt; +template struct delete_memory_op_mt; +template struct delete_memory_op_mt; +template struct delete_memory_op_mt, base_device::DEVICE_CPU>; +template struct delete_memory_op_mt, base_device::DEVICE_CPU>; +#endif + } // namespace memory } // namespace base_device \ No newline at end of file diff --git a/source/module_base/module_device/memory_op.h b/source/module_base/module_device/memory_op.h index d1b49959379..49ca788d0a1 100644 --- a/source/module_base/module_device/memory_op.h +++ b/source/module_base/module_device/memory_op.h @@ -146,6 +146,36 @@ struct delete_memory_op }; #endif // __CUDA || __UT_USE_CUDA || __ROCM || __UT_USE_ROCM +#ifdef __DSP + +template +struct resize_memory_op_mt +{ + /// @brief Allocate memory for a given pointer. Note this op will free the pointer first. + /// + /// Input Parameters + /// \param dev : the type of computing device + /// \param size : array size + /// \param record_string : label for memory record + /// + /// Output Parameters + /// \param arr : allocated array + void operator()(const Device* dev, FPTYPE*& arr, const size_t size, const char* record_in = nullptr); +}; + +template +struct delete_memory_op_mt +{ + /// @brief free memory for multi-device + /// + /// Input Parameters + /// \param dev : the type of computing device + /// \param arr : the input array + void operator()(const Device* dev, FPTYPE* arr); +}; + +#endif // __DSP + } // end of namespace memory } // end of namespace base_device @@ -233,5 +263,4 @@ using castmem_z2c_d2h_op = base_device::memory:: static base_device::DEVICE_CPU* cpu_ctx = {}; static base_device::DEVICE_GPU* gpu_ctx = {}; - #endif // MODULE_DEVICE_MEMORY_H_ \ No newline at end of file diff --git a/source/module_base/module_device/types.h b/source/module_base/module_device/types.h index dfa960a1e31..81413006f43 100644 --- a/source/module_base/module_device/types.h +++ b/source/module_base/module_device/types.h @@ -6,12 +6,14 @@ namespace base_device struct DEVICE_CPU; struct DEVICE_GPU; +struct DEVICE_DSP; enum AbacusDevice_t { UnKnown, CpuDevice, GpuDevice, + DspDevice }; } // namespace base_device diff --git a/source/module_base/parallel_global.cpp b/source/module_base/parallel_global.cpp index 8d15db036d4..b4ce7016aae 100644 --- a/source/module_base/parallel_global.cpp +++ b/source/module_base/parallel_global.cpp @@ -14,6 +14,8 @@ #include "module_base/global_function.h" #include "module_base/parallel_common.h" #include "module_base/parallel_reduce.h" +#include "module_parameter/parameter.h" +// #include "module_base/tool_quit.h" #include "version.h" #include @@ -85,7 +87,12 @@ void Parallel_Global::split_grid_world(const int diag_np, const int& nproc, cons return; } -void Parallel_Global::read_mpi_parameters(int argc, char** argv, int& NPROC, int& MY_RANK) +// changed from read_mpi_parameters in 2024-1018 +void Parallel_Global::read_pal_param(int argc, + char** argv, + int& NPROC, + int& NTHREAD_PER_PROC, + int& MY_RANK) { #ifdef __MPI #ifdef _OPENMP @@ -150,6 +157,10 @@ void Parallel_Global::read_mpi_parameters(int argc, char** argv, int& NPROC, int // the user may take their own risk by set the OMP_NUM_THREADS env var. if (std::getenv("OMP_NUM_THREADS") == nullptr) { + // usage of WARNING_QUIT need module_base/tool_quit.cpp + // lead to undefined error in unit_test building + // ModuleBase::WARNING_QUIT( "Parallel_Global::read_pal_param","OMP_NUM_THREADS setting is invalid. Please set it to a proper value."); + std::cerr << "ERROR: OMP_NUM_THREADS setting is invalid. Please set it to a proper value." << std::endl; exit(1); } } @@ -162,6 +173,8 @@ void Parallel_Global::read_mpi_parameters(int argc, char** argv, int& NPROC, int << "Local thread limit: " << max_thread_num << std::endl; } + NTHREAD_PER_PROC = current_thread_num; + if (MY_RANK == 0) { #ifdef VERSION @@ -192,7 +205,7 @@ void Parallel_Global::read_mpi_parameters(int argc, char** argv, int& NPROC, int << std::endl << " Commit: " << commit << std::endl << std::endl; - time_t time_now = time(NULL); + time_t time_now = time(nullptr); std::cout << " " << ctime(&time_now); } diff --git a/source/module_base/parallel_global.h b/source/module_base/parallel_global.h index 525b4cacd0f..b87aae5b5da 100644 --- a/source/module_base/parallel_global.h +++ b/source/module_base/parallel_global.h @@ -18,7 +18,9 @@ extern int omp_number; //--------------------------- // call at the very first. //--------------------------- -void read_mpi_parameters(int argc, char** argv, int& NPROC, int& MY_RANK); + +// changed from read_mpi_parameters in 2024-1018 +void read_pal_param(int argc, char** argv, int& NPROC, int& NTHREAD_PER_PROC, int& MY_RANK); #ifdef __MPI void myProd(std::complex* in, std::complex* inout, int* len, MPI_Datatype* dptr); #endif diff --git a/source/module_base/sph_bessel_recursive.h b/source/module_base/sph_bessel_recursive.h index a74b0987e30..e11af5127df 100644 --- a/source/module_base/sph_bessel_recursive.h +++ b/source/module_base/sph_bessel_recursive.h @@ -7,7 +7,7 @@ #define SPH_BESSEL_RECURSIVE_H #include -#include"stddef.h" +#include namespace ModuleBase { @@ -32,7 +32,7 @@ class Sph_Bessel_Recursive::D1 private: std::vector> jlx; // jlx[l][x] - double dx; + double dx = 0.0; bool finish_set_dx = false; void cal_jlx_0( const int l_size ); @@ -56,7 +56,7 @@ class Sph_Bessel_Recursive::D2 private: std::vector>> jlx; // jlx[l][x1][x2] - double dx; + double dx = 0.0; bool finish_set_dx = false; void cal_jlx_0( const int l_size, const size_t ix1_size, const size_t ix2_size ); diff --git a/source/module_base/test/CMakeLists.txt b/source/module_base/test/CMakeLists.txt index 6ada3dec29a..86e05d94786 100644 --- a/source/module_base/test/CMakeLists.txt +++ b/source/module_base/test/CMakeLists.txt @@ -3,7 +3,7 @@ install(DIRECTORY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) AddTest( TARGET base_blas_connector LIBS parameter ${math_libs} - SOURCES blas_connector_test.cpp + SOURCES blas_connector_test.cpp ../blas_connector.cpp ) AddTest( TARGET base_atom_in @@ -18,7 +18,7 @@ AddTest( AddTest( TARGET base_tool_quit LIBS parameter - SOURCES tool_quit_test.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES tool_quit_test.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ) AddTest( TARGET base_tool_check @@ -32,7 +32,7 @@ AddTest( ADDTest( TARGET base_global_function LIBS parameter ${math_libs} - SOURCES global_function_test.cpp ../global_function.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../memory.cpp ../timer.cpp + SOURCES global_function_test.cpp ../blas_connector.cpp ../global_function.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../memory.cpp ../timer.cpp ) AddTest( TARGET base_vector3 @@ -42,7 +42,7 @@ AddTest( AddTest( TARGET base_matrix3 LIBS parameter ${math_libs} - SOURCES matrix3_test.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES matrix3_test.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ../blas_connector.cpp ) AddTest( TARGET base_intarray @@ -57,17 +57,17 @@ AddTest( AddTest( TARGET base_matrix LIBS parameter ${math_libs} - SOURCES matrix_test.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES matrix_test.cpp ../blas_connector.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ) AddTest( TARGET base_complexarray LIBS parameter - SOURCES complexarray_test.cpp ../complexarray.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES complexarray_test.cpp ../complexarray.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ) AddTest( TARGET base_complexmatrix LIBS parameter ${math_libs} - SOURCES complexmatrix_test.cpp ../complexmatrix.cpp ../matrix.cpp + SOURCES complexmatrix_test.cpp ../blas_connector.cpp ../complexmatrix.cpp ../matrix.cpp ) AddTest( TARGET base_integral @@ -82,34 +82,34 @@ AddTest( AddTest( TARGET base_ylmreal LIBS parameter ${math_libs} device - SOURCES math_ylmreal_test.cpp ../math_ylmreal.cpp ../complexmatrix.cpp ../global_variable.cpp ../ylm.cpp ../realarray.cpp ../timer.cpp ../matrix.cpp ../vector3.h + SOURCES math_ylmreal_test.cpp ../blas_connector.cpp ../math_ylmreal.cpp ../complexmatrix.cpp ../global_variable.cpp ../ylm.cpp ../realarray.cpp ../timer.cpp ../matrix.cpp ../vector3.h ../parallel_reduce.cpp ../parallel_global.cpp ../parallel_comm.cpp ../parallel_common.cpp ../memory.cpp ../libm/branred.cpp ../libm/sincos.cpp ) AddTest( TARGET base_math_sphbes LIBS parameter - SOURCES math_sphbes_test.cpp ../math_sphbes.cpp ../timer.cpp + SOURCES math_sphbes_test.cpp ../math_sphbes.cpp ../timer.cpp ) AddTest( TARGET base_mathzone LIBS parameter ${math_libs} - SOURCES mathzone_test.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES mathzone_test.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ../blas_connector.cpp ) AddTest( TARGET base_mathzone_add1 LIBS parameter ${math_libs} - SOURCES mathzone_add1_test.cpp ../mathzone_add1.cpp ../math_sphbes.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES mathzone_add1_test.cpp ../blas_connector.cpp ../mathzone_add1.cpp ../math_sphbes.cpp ../matrix3.cpp ../matrix.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp ) AddTest( TARGET base_math_polyint LIBS parameter - SOURCES math_polyint_test.cpp ../math_polyint.cpp ../realarray.cpp ../timer.cpp + SOURCES math_polyint_test.cpp ../math_polyint.cpp ../realarray.cpp ../timer.cpp ) AddTest( TARGET base_gram_schmidt_orth LIBS parameter ${math_libs} - SOURCES gram_schmidt_orth_test.cpp ../gram_schmidt_orth.h ../gram_schmidt_orth-inl.h ../global_function.h ../math_integral.cpp + SOURCES gram_schmidt_orth_test.cpp ../blas_connector.cpp ../gram_schmidt_orth.h ../gram_schmidt_orth-inl.h ../global_function.h ../math_integral.cpp ) AddTest( TARGET base_math_bspline @@ -119,12 +119,12 @@ AddTest( AddTest( TARGET base_inverse_matrix LIBS parameter ${math_libs} - SOURCES inverse_matrix_test.cpp ../inverse_matrix.cpp ../complexmatrix.cpp ../matrix.cpp ../timer.cpp + SOURCES inverse_matrix_test.cpp ../blas_connector.cpp ../inverse_matrix.cpp ../complexmatrix.cpp ../matrix.cpp ../timer.cpp ) AddTest( TARGET base_mymath LIBS parameter - SOURCES mymath_test.cpp ../mymath.cpp ../timer.cpp + SOURCES mymath_test.cpp ../mymath.cpp ../timer.cpp ) AddTest( TARGET base_container @@ -135,31 +135,31 @@ AddTest( AddTest( TARGET base_math_chebyshev LIBS parameter ${math_libs} - SOURCES math_chebyshev_test.cpp ../math_chebyshev.cpp ../tool_quit.cpp ../global_variable.cpp ../timer.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp + SOURCES math_chebyshev_test.cpp ../blas_connector.cpp ../math_chebyshev.cpp ../tool_quit.cpp ../global_variable.cpp ../timer.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ) AddTest( TARGET base_lapack_connector LIBS parameter ${math_libs} - SOURCES lapack_connector_test.cpp ../lapack_connector.h + SOURCES lapack_connector_test.cpp ../blas_connector.cpp ../lapack_connector.h ) AddTest( TARGET base_opt_CG LIBS parameter ${math_libs} - SOURCES opt_CG_test.cpp opt_test_tools.cpp ../opt_CG.cpp ../opt_DCsrch.cpp ../global_variable.cpp ../parallel_reduce.cpp + SOURCES opt_CG_test.cpp opt_test_tools.cpp ../blas_connector.cpp ../opt_CG.cpp ../opt_DCsrch.cpp ../global_variable.cpp ../parallel_reduce.cpp ) AddTest( TARGET base_opt_TN LIBS parameter ${math_libs} - SOURCES opt_TN_test.cpp opt_test_tools.cpp ../opt_CG.cpp ../opt_DCsrch.cpp ../global_variable.cpp ../parallel_reduce.cpp + SOURCES opt_TN_test.cpp opt_test_tools.cpp ../blas_connector.cpp ../opt_CG.cpp ../opt_DCsrch.cpp ../global_variable.cpp ../parallel_reduce.cpp ) AddTest( TARGET base_ylm LIBS parameter - SOURCES ylm_test.cpp ../ylm.cpp ../timer.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp + SOURCES ylm_test.cpp ../ylm.cpp ../timer.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ) AddTest( @@ -171,7 +171,7 @@ AddTest( AddTest( TARGET base_global_file LIBS parameter - SOURCES global_file_test.cpp ../global_file.cpp ../global_function.cpp ../tool_quit.cpp ../global_variable.cpp ../memory.cpp ../timer.cpp + SOURCES global_file_test.cpp ../global_file.cpp ../global_function.cpp ../tool_quit.cpp ../global_variable.cpp ../memory.cpp ../timer.cpp ) AddTest( @@ -194,19 +194,19 @@ AddTest( AddTest( TARGET spherical_bessel_transformer - SOURCES spherical_bessel_transformer_test.cpp ../spherical_bessel_transformer.cpp ../math_sphbes.cpp ../math_integral.cpp ../timer.cpp + SOURCES spherical_bessel_transformer_test.cpp ../blas_connector.cpp ../spherical_bessel_transformer.cpp ../math_sphbes.cpp ../math_integral.cpp ../timer.cpp LIBS parameter ${math_libs} ) AddTest( TARGET cubic_spline - SOURCES cubic_spline_test.cpp ../cubic_spline.cpp + SOURCES cubic_spline_test.cpp ../blas_connector.cpp ../cubic_spline.cpp LIBS parameter ${math_libs} ) AddTest( TARGET clebsch_gordan_coeff_test - SOURCES clebsch_gordan_coeff_test.cpp ../clebsch_gordan_coeff.cpp ../intarray.cpp ../realarray.cpp ../complexmatrix.cpp ../matrix.cpp ../timer.cpp + SOURCES clebsch_gordan_coeff_test.cpp ../blas_connector.cpp ../clebsch_gordan_coeff.cpp ../intarray.cpp ../realarray.cpp ../complexmatrix.cpp ../matrix.cpp ../timer.cpp ../math_ylmreal.cpp ../global_variable.cpp ../ylm.cpp ../timer.cpp ../vector3.h ../parallel_reduce.cpp ../parallel_global.cpp ../parallel_comm.cpp ../parallel_common.cpp ../memory.cpp ../libm/branred.cpp ../libm/sincos.cpp ../inverse_matrix.cpp ../lapack_connector.h LIBS parameter ${math_libs} device @@ -214,7 +214,7 @@ AddTest( AddTest( TARGET assoc_laguerre_test - SOURCES assoc_laguerre_test.cpp ../assoc_laguerre.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp + SOURCES assoc_laguerre_test.cpp ../blas_connector.cpp ../assoc_laguerre.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp LIBS parameter ${math_libs} ) @@ -234,6 +234,6 @@ if(ENABLE_GOOGLEBENCH) AddTest( TARGET perf_sphbes LIBS parameter - SOURCES perf_sphbes_test.cpp ../math_sphbes.cpp ../timer.cpp + SOURCES perf_sphbes_test.cpp ../math_sphbes.cpp ../timer.cpp ) endif() diff --git a/source/module_base/test/global_file_test.cpp b/source/module_base/test/global_file_test.cpp index 9d06349bbc9..adc7f30fc72 100644 --- a/source/module_base/test/global_file_test.cpp +++ b/source/module_base/test/global_file_test.cpp @@ -157,26 +157,4 @@ TEST_F(GlobalFile,closealllog) } remove("running.log"); remove("warning.log"); -} - -TEST_F(GlobalFile, DeleteTmpFiles) -{ - - std::string tmp_chg_1 = PARAM.sys.global_out_dir + "NOW_SPIN1_CHG.cube"; - std::string tmp_chg_2 = PARAM.sys.global_out_dir + "OLD1_SPIN1_CHG.cube"; - std::string tmp_chg_3 = PARAM.sys.global_out_dir + "OLD2_SPIN1_CHG.cube"; - std::ofstream ofs1(tmp_chg_1.c_str()); - std::ofstream ofs2(tmp_chg_2.c_str()); - std::ofstream ofs3(tmp_chg_3.c_str()); - ofs1.close(); - ofs2.close(); - ofs3.close(); - EXPECT_TRUE(access(tmp_chg_1.c_str(), 0) == 0); - EXPECT_TRUE(access(tmp_chg_2.c_str(), 0) == 0); - EXPECT_TRUE(access(tmp_chg_3.c_str(), 0) == 0); - - ModuleBase::Global_File::delete_tmp_files(); - EXPECT_TRUE(access(tmp_chg_1.c_str(), 0) == -1); - EXPECT_TRUE(access(tmp_chg_2.c_str(), 0) == -1); - EXPECT_TRUE(access(tmp_chg_3.c_str(), 0) == -1); } \ No newline at end of file diff --git a/source/module_base/test/math_chebyshev_test.cpp b/source/module_base/test/math_chebyshev_test.cpp index 3d2a015880d..7e7caef2a3c 100644 --- a/source/module_base/test/math_chebyshev_test.cpp +++ b/source/module_base/test/math_chebyshev_test.cpp @@ -346,15 +346,15 @@ TEST_F(MathChebyshevTest, checkconverge) double tmin = -1.1; double tmax = 1.1; bool converge; - converge = p_chetest->checkconverge(fun_sigma_y, v, 2, tmax, tmin, 0.2); + converge = p_chetest->checkconverge(fun_sigma_y, v, 2, 2, tmax, tmin, 0.2); EXPECT_TRUE(converge); - converge = p_chetest->checkconverge(fun_sigma_y, v + 2, 2, tmax, tmin, 0.2); + converge = p_chetest->checkconverge(fun_sigma_y, v + 2, 2, 2, tmax, tmin, 0.2); EXPECT_TRUE(converge); EXPECT_NEAR(tmin, -1.1, 1e-8); EXPECT_NEAR(tmax, 1.1, 1e-8); tmax = -1.1; - converge = p_chetest->checkconverge(fun_sigma_y, v, 2, tmax, tmin, 2.2); + converge = p_chetest->checkconverge(fun_sigma_y, v, 2, 2, tmax, tmin, 2.2); EXPECT_TRUE(converge); EXPECT_NEAR(tmin, -1.1, 1e-8); EXPECT_NEAR(tmax, 1.1, 1e-8); @@ -363,12 +363,12 @@ TEST_F(MathChebyshevTest, checkconverge) v[0] = std::complex(0, 1), v[1] = 1; fun.factor = 1.5; tmin = -1.1, tmax = 1.1; - converge = p_chetest->checkconverge(fun_sigma_y, v, 2, tmax, tmin, 0.2); + converge = p_chetest->checkconverge(fun_sigma_y, v, 2, 2, tmax, tmin, 0.2); EXPECT_FALSE(converge); fun.factor = -1.5; tmin = -1.1, tmax = 1.1; - converge = p_chetest->checkconverge(fun_sigma_y, v, 2, tmax, tmin, 0.2); + converge = p_chetest->checkconverge(fun_sigma_y, v, 2, 2, tmax, tmin, 0.2); EXPECT_FALSE(converge); fun.factor = 1; @@ -632,9 +632,9 @@ TEST_F(MathChebyshevTest, checkconverge_float) auto fun_sigma_yf = [&](std::complex* in, std::complex* out, const int m = 1) { fun.sigma_y(in, out, m); }; - converge = p_fchetest->checkconverge(fun_sigma_yf, v, 2, tmax, tmin, 0.2); + converge = p_fchetest->checkconverge(fun_sigma_yf, v, 2, 2, tmax, tmin, 0.2); EXPECT_TRUE(converge); - converge = p_fchetest->checkconverge(fun_sigma_yf, v + 2, 2, tmax, tmin, 0.2); + converge = p_fchetest->checkconverge(fun_sigma_yf, v + 2, 2, 2, tmax, tmin, 0.2); EXPECT_TRUE(converge); EXPECT_NEAR(tmin, -1.1, 1e-6); EXPECT_NEAR(tmax, 1.1, 1e-6); diff --git a/source/module_basis/module_ao/parallel_2d.h b/source/module_basis/module_ao/parallel_2d.h index d3c88d57836..8aeea9792f7 100644 --- a/source/module_basis/module_ao/parallel_2d.h +++ b/source/module_basis/module_ao/parallel_2d.h @@ -15,6 +15,7 @@ class Parallel_2D ~Parallel_2D() = default; Parallel_2D& operator=(Parallel_2D&& rhs) = default; + Parallel_2D(Parallel_2D&& rhs) = default; /// number of local rows int get_row_size() const diff --git a/source/module_basis/module_ao/test/CMakeLists.txt b/source/module_basis/module_ao/test/CMakeLists.txt index db9c648b122..c1708eef856 100644 --- a/source/module_basis/module_ao/test/CMakeLists.txt +++ b/source/module_basis/module_ao/test/CMakeLists.txt @@ -7,6 +7,7 @@ list(APPEND depend_files ../../../module_base/math_ylmreal.cpp ../../../module_base/ylm.cpp ../../../module_base/memory.cpp + ../../../module_base/blas_connector.cpp ../../../module_base/complexarray.cpp ../../../module_base/complexmatrix.cpp ../../../module_base/matrix.cpp diff --git a/source/module_basis/module_nao/atomic_radials.cpp b/source/module_basis/module_nao/atomic_radials.cpp index 2391d471db9..7d095e70cda 100644 --- a/source/module_basis/module_nao/atomic_radials.cpp +++ b/source/module_basis/module_nao/atomic_radials.cpp @@ -3,11 +3,16 @@ #include "module_base/math_integral.h" #include "module_base/parallel_common.h" #include "module_base/tool_quit.h" + +// FIXME: should update with pyabacus +// #include "module_io/orb_io.h" + #include "projgen.h" #include #include #include +#include AtomicRadials& AtomicRadials::operator=(const AtomicRadials& rhs) { @@ -207,7 +212,6 @@ void AtomicRadials::read_abacus_orb(std::ifstream& ifs, std::ofstream* ptr_log, { rgrid[ir] = ir * dr; } - chi_ = new NumericalRadial[nchi_]; // record whether an orbital has been read or not @@ -269,116 +273,47 @@ void AtomicRadials::read_abacus_orb(std::ifstream& ifs, std::ofstream* ptr_log, delete[] rgrid; } -void AtomicRadials::read_abacus_orb(std::ifstream& ifs, - std::string& elem, - double& ecut, - int& nr, - double& dr, - std::vector& nzeta, - std::vector>& radials, - const int rank) -{ - nr = 0; // number of grid points - dr = 0; // grid spacing - int lmax, nchi = 0; // number of radial functions - std::vector> radial_map_; // build a map from [l][izeta] to 1-d array index - std::string tmp; - // first read the header - if (rank == 0) - { - if (!ifs.is_open()) - { - ModuleBase::WARNING_QUIT("AtomicRadials::read_abacus_orb", "Couldn't open orbital file."); - } - while (ifs >> tmp) - { - if (tmp == "Element") - { - ifs >> elem; - } - else if (tmp == "Cutoff(Ry)") - { - ifs >> ecut; - } - else if (tmp == "Lmax") - { - ifs >> lmax; - nzeta.resize(lmax + 1); - for (int l = 0; l <= lmax; ++l) - { - ifs >> tmp >> tmp >> tmp >> nzeta[l]; - } - } - else if (tmp == "Mesh") - { - ifs >> nr; - continue; - } - else if (tmp == "dr") - { - ifs >> dr; - break; - } - } - radial_map_.resize(lmax + 1); - for (int l = 0; l <= lmax; ++l) - { - radial_map_[l].resize(nzeta[l]); - } - int ichi = 0; - for (int l = 0; l <= lmax; ++l) - { - for (int iz = 0; iz < nzeta[l]; ++iz) - { - radial_map_[l][iz] = ichi++; // return the value of ichi, then increment - } - } - nchi = ichi; // total number of radial functions - radials.resize(nchi); - std::for_each(radials.begin(), radials.end(), [nr](std::vector& v) { v.resize(nr); }); - } - - // broadcast the header information -#ifdef __MPI - Parallel_Common::bcast_string(elem); - Parallel_Common::bcast_double(ecut); - Parallel_Common::bcast_int(lmax); - Parallel_Common::bcast_int(nchi); - Parallel_Common::bcast_int(nr); - Parallel_Common::bcast_double(dr); -#endif - - // then adjust the size of the vectors - if (rank != 0) - { - nzeta.resize(lmax + 1); - radials.resize(nchi); - std::for_each(radials.begin(), radials.end(), [nr](std::vector& v) { v.resize(nr); }); - } - // broadcast the number of zeta functions for each angular momentum -#ifdef __MPI - Parallel_Common::bcast_int(nzeta.data(), lmax + 1); -#endif - - // read the radial functions by rank0 - int ichi = 0; - for (int i = 0; i != nchi; ++i) - { - if (rank == 0) - { - int l, izeta; - ifs >> tmp >> tmp >> tmp; - ifs >> tmp >> l >> izeta; - ichi = radial_map_[l][izeta]; - for (int ir = 0; ir != nr; ++ir) - { - ifs >> radials[ichi][ir]; - } - } - // broadcast the radial functions -#ifdef __MPI - Parallel_Common::bcast_int(ichi); // let other ranks know where to store the radial function - Parallel_Common::bcast_double(radials[ichi].data(), nr); -#endif - } -} \ No newline at end of file +// FIXME: should update with pyabacus +// void AtomicRadials::read_abacus_orb(std::ifstream& ifs, std::ofstream* ptr_log, const int rank) +// { +// /* +// * Read the orbital file. +// * +// * For orbital file format, see +// * (new) abacus-develop/tools/SIAB/PyTorchGradient/source/IO/print_orbital.py +// * (old) abacus-develop/tools/SIAB/SimulatedAnnealing/source/src_spillage/Plot_Psi.cpp +// * */ +// int ngrid = 0; // number of grid points +// double dr = 0; // grid spacing +// std::string tmp; + +// int nr; +// std::vector nzeta; +// std::vector> radials; + +// ModuleIO::read_abacus_orb(ifs, symbol_, orb_ecut_, nr, dr, nzeta, radials, rank); + +// lmax_ = nzeta.size() - 1; +// nzeta_ = new int[lmax_ + 1]; +// std::copy(nzeta.begin(), nzeta.end(), nzeta_); + +// nchi_ = std::accumulate(nzeta.begin(), nzeta.end(), 0); +// nzeta_max_ = *std::max_element(nzeta.begin(), nzeta.end()); + +// indexing(); + +// std::vector rgrid(nr); +// std::iota(rgrid.begin(), rgrid.end(), 0); +// std::for_each(rgrid.begin(), rgrid.end(), [dr](double& r) { r *= dr; }); +// chi_ = new NumericalRadial[nchi_]; +// int ichi = 0; +// for (int l = 0; l <= lmax_; ++l) +// { +// for (int izeta = 0; izeta < nzeta[l]; ++izeta) +// { +// chi_[index(l, izeta)].build(l, true, nr, rgrid.data(), radials[ichi].data(), 0, izeta, symbol_, itype_, false); +// chi_[index(l, izeta)].normalize(); +// ++ichi; +// } +// } +// } diff --git a/source/module_basis/module_nao/atomic_radials.h b/source/module_basis/module_nao/atomic_radials.h index 874f56897f3..51b17e02cc7 100644 --- a/source/module_basis/module_nao/atomic_radials.h +++ b/source/module_basis/module_nao/atomic_radials.h @@ -43,28 +43,6 @@ class AtomicRadials : public RadialSet //! Get the energy cutoff as given by the orbital file double orb_ecut() const { return orb_ecut_; } - /** - * @brief static version of read_abacus_orb. A delete-new operation may cause the memory leak, - * it is better to use std::vector to replace the raw pointer. - * - * @param ifs [in] ifstream from the orbital file, via `std::ifstream ifs(forb);` - * @param elem [out] element symbol - * @param ecut [out] planewave energy cutoff - * @param nr [out] number of radial grid points - * @param dr [out] radial grid spacing - * @param nzeta [out] number of zeta functions for each angular momentum - * @param radials [out] radial orbitals - * @param rank [in] MPI rank - */ - static void read_abacus_orb(std::ifstream& ifs, - std::string& elem, - double& ecut, - int& nr, - double& dr, - std::vector& nzeta, - std::vector>& radials, - const int rank = 0); - private: double orb_ecut_; //!< energy cutoff as given by the orbital file diff --git a/source/module_basis/module_nao/radial_set.cpp b/source/module_basis/module_nao/radial_set.cpp index 259f7928915..3b00ba679a3 100644 --- a/source/module_basis/module_nao/radial_set.cpp +++ b/source/module_basis/module_nao/radial_set.cpp @@ -7,6 +7,9 @@ #include "module_base/spherical_bessel_transformer.h" +// FIXME: should update with pyabacus +// #include "module_io/orb_io.h" + RadialSet::~RadialSet() { delete[] nzeta_; @@ -252,3 +255,28 @@ void RadialSet::write_abacus_orb(const std::string& file_name, const int rank) c } file_to.close(); } + +// FIXME: should update with pyabacus +// void RadialSet::write_abacus_orb(const std::string& forb, const int rank) const +// { +// std::ofstream ofs; +// ofs.open(forb, std::ios::out); + +// const double dr = 0.01; +// const int nr = static_cast(rcut_max_ / dr) + 1; +// std::vector nzeta(lmax_ + 1); +// std::copy(nzeta_, nzeta_ + lmax_ + 1, nzeta.begin()); +// std::vector> radials(nchi_, std::vector(nr, 0.0)); +// int ichi = 0; +// for (int l = 0; l <= lmax_; l++) +// { +// for (int izeta = 0; izeta < nzeta[l]; izeta++) +// { +// std::copy(chi_[index(l, izeta)].rvalue(), chi_[index(l, izeta)].rvalue() + nr, radials[ichi].begin()); +// ichi++; +// } +// } + +// ModuleIO::write_abacus_orb(ofs, symbol_, 100, nr, dr, nzeta, radials, rank); +// ofs.close(); +// } diff --git a/source/module_basis/module_nao/test/CMakeLists.txt b/source/module_basis/module_nao/test/CMakeLists.txt index ac58199df47..0759f334352 100644 --- a/source/module_basis/module_nao/test/CMakeLists.txt +++ b/source/module_basis/module_nao/test/CMakeLists.txt @@ -17,6 +17,7 @@ AddTest( ../projgen.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -29,6 +30,7 @@ AddTest( ../numerical_radial.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -41,6 +43,7 @@ AddTest( ../numerical_radial.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -53,6 +56,7 @@ AddTest( ../numerical_radial.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -65,6 +69,7 @@ AddTest( ../numerical_radial.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -83,6 +88,7 @@ AddTest( ../sphbes_radials.cpp ../../module_ao/ORB_atomic_lm.cpp ../../module_ao/ORB_atomic.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base ) @@ -103,6 +109,7 @@ AddTest( ../two_center_bundle.cpp ../two_center_integrator.cpp ../real_gaunt_table.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base container orb ) @@ -132,6 +139,7 @@ AddTest( ../radial_set.cpp ../numerical_radial.cpp ../two_center_bundle.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base container orb ) @@ -152,6 +160,7 @@ AddTest( ../radial_set.cpp ../projgen.cpp ../numerical_radial.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base container orb ) @@ -172,6 +181,7 @@ AddTest( ../radial_set.cpp ../projgen.cpp ../numerical_radial.cpp + ../../../module_io/orb_io.cpp LIBS parameter ${math_libs} device base container orb ) diff --git a/source/module_basis/module_nao/test/atomic_radials_test.cpp b/source/module_basis/module_nao/test/atomic_radials_test.cpp index 5b201a5f7f4..f1a64c2e074 100644 --- a/source/module_basis/module_nao/test/atomic_radials_test.cpp +++ b/source/module_basis/module_nao/test/atomic_radials_test.cpp @@ -36,10 +36,6 @@ using ModuleBase::SphericalBesselTransformer; * * - to_numerical_orbital * - Overwrites the content of a Numerical_Orbital object with the current object. - * - * - read_abacus_orb - * - The static version, reads the radial functions from an abacus file. - * * */ class AtomicRadialsTest : public ::testing::Test { @@ -268,44 +264,6 @@ TEST_F(AtomicRadialsTest, ToNumericalOrbital) } } -TEST_F(AtomicRadialsTest, ReadAbacusOrb) -{ - std::ifstream ifs(file); - std::string elem; - double ecut, dr; - int nr; - std::vector nzeta; - std::vector> radials; - AtomicRadials::read_abacus_orb(ifs, elem, ecut, nr, dr, nzeta, radials); - EXPECT_EQ(elem, "Ti"); - EXPECT_DOUBLE_EQ(ecut, 100.0); - EXPECT_EQ(nr, 1001); - EXPECT_DOUBLE_EQ(dr, 0.01); - EXPECT_EQ(nzeta.size(), 4); // l from 0 to 3 - EXPECT_EQ(nzeta[0], 4); - EXPECT_EQ(nzeta[1], 2); - EXPECT_EQ(nzeta[2], 2); - EXPECT_EQ(nzeta[3], 1); - EXPECT_EQ(radials.size(), 9); // 4 + 2 + 2 + 1 - for(auto& radial: radials) - { - EXPECT_EQ(radial.size(), 1001); - } - EXPECT_EQ(radials[0][0], -1.581711853170e-01); - EXPECT_EQ(radials[0][4], -1.583907030513e-01); - EXPECT_EQ(radials[0][996], -4.183526380009e-05); - EXPECT_EQ(radials[0][1000], 0); - EXPECT_EQ(radials[3][0], -1.166292682541e+00); - EXPECT_EQ(radials[3][4], -1.164223359672e+00); - EXPECT_EQ(radials[3][996], -3.183325576529e-04); - EXPECT_EQ(radials[3][1000], 0); - EXPECT_EQ(radials[8][0], 0); - EXPECT_EQ(radials[8][4], 3.744878535962e-05); - EXPECT_EQ(radials[8][996], 7.495357740660e-05); - EXPECT_EQ(radials[8][1000], 0); - ifs.close(); -} - int main(int argc, char** argv) { diff --git a/source/module_basis/module_pw/kernels/test/CMakeLists.txt b/source/module_basis/module_pw/kernels/test/CMakeLists.txt index 48188f269a9..c190ded73d3 100644 --- a/source/module_basis/module_pw/kernels/test/CMakeLists.txt +++ b/source/module_basis/module_pw/kernels/test/CMakeLists.txt @@ -8,5 +8,5 @@ AddTest( ../../../../module_base/parallel_global.cpp ../../../../module_base/parallel_reduce.cpp ../../../../module_base/parallel_comm.cpp ../../../../module_base/complexmatrix.cpp ../../../../module_base/matrix.cpp ../../../../module_base/memory.cpp - ../../../../module_base/libm/branred.cpp ../../../../module_base/libm/sincos.cpp + ../../../../module_base/libm/branred.cpp ../../../../module_base/libm/sincos.cpp ../../../../module_base/blas_connector.cpp ) \ No newline at end of file diff --git a/source/module_basis/module_pw/test/CMakeLists.txt b/source/module_basis/module_pw/test/CMakeLists.txt index 1306a5f7ba4..e1ce122d073 100644 --- a/source/module_basis/module_pw/test/CMakeLists.txt +++ b/source/module_basis/module_pw/test/CMakeLists.txt @@ -3,7 +3,7 @@ AddTest( TARGET pw_test LIBS parameter ${math_libs} planewave device SOURCES ../../../module_base/matrix.cpp ../../../module_base/complexmatrix.cpp ../../../module_base/matrix3.cpp ../../../module_base/tool_quit.cpp - ../../../module_base/mymath.cpp ../../../module_base/timer.cpp ../../../module_base/memory.cpp + ../../../module_base/mymath.cpp ../../../module_base/timer.cpp ../../../module_base/memory.cpp ../../../module_base/blas_connector.cpp ../../../module_base/libm/branred.cpp ../../../module_base/libm/sincos.cpp # ../../../module_psi/kernels/psi_memory_op.cpp ../../../module_base/module_device/memory_op.cpp diff --git a/source/module_cell/cal_atoms_info.h b/source/module_cell/cal_atoms_info.h new file mode 100644 index 00000000000..c4aa70fb3a7 --- /dev/null +++ b/source/module_cell/cal_atoms_info.h @@ -0,0 +1,74 @@ +#ifndef CAL_ATOMS_INFO_H +#define CAL_ATOMS_INFO_H +#include "module_parameter/parameter.h" +#include "unitcell.h" +class CalAtomsInfo +{ + public: + CalAtomsInfo(){}; + ~CalAtomsInfo(){}; + + /** + * @brief Calculate the atom information from pseudopotential to set Parameter + * + * @param atoms [in] Atom pointer + * @param ntype [in] number of atom types + * @param para [out] Parameter object + */ + void cal_atoms_info(const Atom* atoms, const int& ntype, Parameter& para) + { + // calculate initial total magnetization when NSPIN=2 + if (para.inp.nspin == 2 && !para.globalv.two_fermi) + { + for (int it = 0; it < ntype; ++it) + { + for (int ia = 0; ia < atoms[it].na; ++ia) + { + para.input.nupdown += atoms[it].mag[ia]; + } + } + GlobalV::ofs_running << " The readin total magnetization is " << para.inp.nupdown << std::endl; + } + + if (!para.inp.use_paw) + { + // decide whether to be USPP + for (int it = 0; it < ntype; ++it) + { + if (atoms[it].ncpp.tvanp) + { + para.sys.use_uspp = true; + } + } + + // calculate the total number of local basis + para.sys.nlocal = 0; + for (int it = 0; it < ntype; ++it) + { + const int nlocal_it = atoms[it].nw * atoms[it].na; + if (para.inp.nspin != 4) + { + para.sys.nlocal += nlocal_it; + } + else + { + para.sys.nlocal += nlocal_it * 2; // zhengdy-soc + } + } + } + + // calculate the total number of electrons + cal_nelec(atoms, ntype, para.input.nelec); + + // autoset and check GlobalV::NBANDS + std::vector nelec_spin(2, 0.0); + if (para.inp.nspin == 2) + { + nelec_spin[0] = (para.inp.nelec + para.inp.nupdown ) / 2.0; + nelec_spin[1] = (para.inp.nelec - para.inp.nupdown ) / 2.0; + } + cal_nbands(para.inp.nelec, para.sys.nlocal, nelec_spin, para.input.nbands); + return; + } +}; +#endif \ No newline at end of file diff --git a/source/module_cell/klist.cpp b/source/module_cell/klist.cpp index ec1e3e37b02..6286f8e4eca 100644 --- a/source/module_cell/klist.cpp +++ b/source/module_cell/klist.cpp @@ -106,6 +106,17 @@ void K_Vectors::set(const ModuleSymmetry::Symmetry& symm, std::string skpt1; std::string skpt2; + if (!this->kc_done && this->kd_done) + { + for (size_t ik = 0; ik!=this->nkstot_full; ++ik) + this->kvec_c_full[ik] = this->kvec_d[ik] * reciprocal_vec; + } + else if(this->kc_done && !this->kd_done) + { + for (size_t ik = 0; ik!=this->nkstot_full; ++ik) + this->kvec_c_full[ik] = this->kvec_c[ik]; + } + // (2) // only berry phase need all kpoints including time-reversal symmetry! // if symm_flag is not set, only time-reversal symmetry would be considered. @@ -193,6 +204,7 @@ void K_Vectors::set(const ModuleSymmetry::Symmetry& symm, void K_Vectors::renew(const int& kpoint_number) { kvec_c.resize(kpoint_number); + kvec_c_full.resize(kpoint_number); kvec_d.resize(kpoint_number); wk.resize(kpoint_number); isk.resize(kpoint_number); diff --git a/source/module_cell/klist.h b/source/module_cell/klist.h index edc20446dc7..06650127b3c 100644 --- a/source/module_cell/klist.h +++ b/source/module_cell/klist.h @@ -13,6 +13,7 @@ class K_Vectors public: std::vector> kvec_c; /// Cartesian coordinates of k points std::vector> kvec_d; /// Direct coordinates of k points + std::vector> kvec_c_full; // Cartesian coordinates of full k mesh match with nkstot_full std::vector wk; /// wk, weight of k points diff --git a/source/module_cell/module_neighbor/test/prepare_unitcell.h b/source/module_cell/module_neighbor/test/prepare_unitcell.h index 5f217aadf2a..a92f15842fc 100644 --- a/source/module_cell/module_neighbor/test/prepare_unitcell.h +++ b/source/module_cell/module_neighbor/test/prepare_unitcell.h @@ -252,8 +252,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_cell/module_paw/paw_cell_libpaw.cpp b/source/module_cell/module_paw/paw_cell_libpaw.cpp index aac0b4474af..7abdafa3ca6 100644 --- a/source/module_cell/module_paw/paw_cell_libpaw.cpp +++ b/source/module_cell/module_paw/paw_cell_libpaw.cpp @@ -204,9 +204,11 @@ void Paw_Cell::mix_dij(const int iat, double*dij_paw) const int size_dij = nproj * (nproj+1) / 2; for(int i = 0; i < size_dij * nspden; i ++) { - if(!first_iter) dij_paw[i] = dij_save[iat][i] * (1.0 - mixing_beta) + dij_paw[i] * mixing_beta; + if(!first_iter) { dij_paw[i] = dij_save[iat][i] * (1.0 - mixing_beta) + dij_paw[i] * mixing_beta; +} - if(count > 30) dij_paw[i] = dij_save[iat][i]; + if(count > 30) { dij_paw[i] = dij_save[iat][i]; +} dij_save[iat][i] = dij_paw[i]; } @@ -224,7 +226,7 @@ void Paw_Cell::set_libpaw_files() filename_list = new char[ntypat*264]; if(GlobalV::MY_RANK == 0) { - std::ifstream ifa(PARAM.inp.stru_file.c_str(), std::ios::in); + std::ifstream ifa(PARAM.globalv.global_in_stru.c_str(), std::ios::in); if (!ifa) { ModuleBase::WARNING_QUIT("set_libpaw_files", "can not open stru file"); @@ -234,7 +236,8 @@ void Paw_Cell::set_libpaw_files() while(!ifa.eof()) { getline(ifa,line); - if (line.find("PAW_FILES") != std::string::npos) break; + if (line.find("PAW_FILES") != std::string::npos) { break; +} } for(int i = 0; i < ntypat*264; i++) @@ -681,7 +684,8 @@ void Paw_Cell::set_sij() double* sij = new double[nproj * nproj]; #ifdef __MPI - if(GlobalV::RANK_IN_POOL == 0) extract_sij(it,size_sij,sij_libpaw); + if(GlobalV::RANK_IN_POOL == 0) { extract_sij(it,size_sij,sij_libpaw); +} Parallel_Common::bcast_double(sij_libpaw,size_sij*nspden); #else extract_sij(it,size_sij,sij_libpaw); diff --git a/source/module_cell/module_symmetry/run_symmetry.cpp b/source/module_cell/module_symmetry/run_symmetry.cpp index f6604ac72e1..2eff5fb0ae8 100644 --- a/source/module_cell/module_symmetry/run_symmetry.cpp +++ b/source/module_cell/module_symmetry/run_symmetry.cpp @@ -14,7 +14,7 @@ int main(int argc, char **argv) std::cout << "Hello, this is the 'symmetry' module of ABACUS." << std::endl; std::cout << "The module does symmetry analysis for an input geometry." << std::endl; - Parallel_Global::read_mpi_parameters(argc,argv); + Parallel_Global::read_pal_param(argc,argv); //std::cout << "Right now, the module is still empty, soon we will have more tests." << std::endl; calculate(); diff --git a/source/module_cell/module_symmetry/symmetry.cpp b/source/module_cell/module_symmetry/symmetry.cpp index 4cc925fedb2..743f2156aad 100644 --- a/source/module_cell/module_symmetry/symmetry.cpp +++ b/source/module_cell/module_symmetry/symmetry.cpp @@ -1001,7 +1001,7 @@ bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3 trans(2.0, 2.0, 2.0); - bool s_flag = 0; + bool s_flag = false; for (int it = 0; it < ntype; it++) { @@ -1123,7 +1123,7 @@ bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3 *rhogtot, assert(nrotk <=48 ); //map the gmatrix to inv - int* invmap = new int[nrotk]; - this->gmatrix_invmap(kgmatrix, nrotk, invmap); + std::vectorinvmap(this->nrotk, -1); + this->gmatrix_invmap(kgmatrix, nrotk, invmap.data()); // --------------------------------------------------- /* This code defines a lambda function called "rotate_recip" that takes @@ -1629,6 +1629,7 @@ ModuleBase::timer::tick("Symmetry","group fft grids"); int rot_count=0; for (int isym = 0; isym < nrotk; ++isym) { + if (invmap[isym] < 0 || invmap[isym] > nrotk) { continue; } //tmp variables int ii, jj, kk=0; rotate_recip(kgmatrix[invmap[isym]], tmp_gdirect0, ii, jj, kk); @@ -1750,7 +1751,6 @@ for (int g_index = 0; g_index < group_index; g_index++) delete[] symflag; delete[] isymflag; delete[] table_xyz; - delete[] invmap; delete[] count_xyz; ModuleBase::timer::tick("Symmetry","rhog_symmetry"); } diff --git a/source/module_cell/test/prepare_unitcell.h b/source/module_cell/test/prepare_unitcell.h index a02eafdbb5f..f6692ae8f7e 100644 --- a/source/module_cell/test/prepare_unitcell.h +++ b/source/module_cell/test/prepare_unitcell.h @@ -251,8 +251,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_cell/test/support/mock_unitcell.cpp b/source/module_cell/test/support/mock_unitcell.cpp index 23b4df39092..b91430987a2 100644 --- a/source/module_cell/test/support/mock_unitcell.cpp +++ b/source/module_cell/test/support/mock_unitcell.cpp @@ -124,5 +124,5 @@ void UnitCell::setup(const std::string& latname_in, const int& lmaxmax_in, const bool& init_vel_in, const std::string& fixed_axes_in) {} -void UnitCell::cal_nelec(double& nelec) {} +void cal_nelec(const Atom* atoms, const int& ntype, double& nelec) {} void UnitCell::compare_atom_labels(std::string label1, std::string label2) {} \ No newline at end of file diff --git a/source/module_cell/test/unitcell_test_readpp.cpp b/source/module_cell/test/unitcell_test_readpp.cpp index b2b01c05595..34e5c71b3b2 100644 --- a/source/module_cell/test/unitcell_test_readpp.cpp +++ b/source/module_cell/test/unitcell_test_readpp.cpp @@ -71,7 +71,7 @@ Magnetism::~Magnetism() { delete[] this->start_magnetization; } * - cal_nwfc(): calcuate the total number of local basis: NSPIN != 4 * - this corresponds to number_of_proj, PP_BETA in pp file, and * atoms[it].l_nchi[nw], nw from orb file - * - setup GlobalV::NLOCAL + * - setup PARAM.sys.nlocal * - interfaces initialed in this function: * - itia2iat * - iat2iwt @@ -89,6 +89,8 @@ Magnetism::~Magnetism() { delete[] this->start_magnetization; } * possible of an element * - CalNelec: UnitCell::cal_nelec * - calculate the total number of valence electrons from psp files + * - CalNbands: elecstate::ElecState::cal_nbands() + * - calculate the number of bands */ // mock function @@ -114,9 +116,16 @@ class UcellTest : public ::testing::Test { pp_dir = "./support/"; PARAM.input.pseudo_rcut = 15.0; PARAM.input.dft_functional = "default"; + PARAM.input.esolver_type = "ksdft"; PARAM.input.test_pseudo_cell = true; PARAM.input.nspin = 1; PARAM.input.basis_type = "pw"; + PARAM.input.nelec = 10.0; + PARAM.input.nupdown = 0.0; + PARAM.sys.two_fermi = false; + PARAM.input.nbands = 6; + PARAM.sys.nlocal = 6; + PARAM.input.lspinorb = false; } void TearDown() { ofs.close(); } }; @@ -256,6 +265,7 @@ TEST_F(UcellTest, CalNwfc1) { ucell->read_cell_pseudopots(pp_dir, ofs); EXPECT_FALSE(ucell->atoms[0].ncpp.has_so); EXPECT_FALSE(ucell->atoms[1].ncpp.has_so); + PARAM.sys.nlocal = 3 * 9; ucell->cal_nwfc(ofs); EXPECT_EQ(ucell->atoms[0].iw2l[8], 2); EXPECT_EQ(ucell->atoms[0].iw2n[8], 0); @@ -282,7 +292,6 @@ TEST_F(UcellTest, CalNwfc1) { EXPECT_EQ(ucell->atoms[0].nw, 9); EXPECT_EQ(ucell->atoms[1].nw, 9); EXPECT_EQ(ucell->nwmax, 9); - EXPECT_EQ(GlobalV::NLOCAL, 3 * 9); // check itia2iat EXPECT_EQ(ucell->itia2iat.getSize(), 4); EXPECT_EQ(ucell->itia2iat(0, 0), 0); @@ -322,8 +331,8 @@ TEST_F(UcellTest, CalNwfc2) { ucell->read_cell_pseudopots(pp_dir, ofs); EXPECT_FALSE(ucell->atoms[0].ncpp.has_so); EXPECT_FALSE(ucell->atoms[1].ncpp.has_so); - ucell->cal_nwfc(ofs); - EXPECT_EQ(GlobalV::NLOCAL, 3 * 9 * 2); + PARAM.sys.nlocal = 3 * 9 * 2; + EXPECT_NO_THROW(ucell->cal_nwfc(ofs)); } TEST_F(UcellDeathTest, CheckStructure) { @@ -396,10 +405,163 @@ TEST_F(UcellTest, CalNelec) { EXPECT_EQ(1, ucell->atoms[0].na); EXPECT_EQ(2, ucell->atoms[1].na); double nelec = 0; - ucell->cal_nelec(nelec); + cal_nelec(ucell->atoms, ucell->ntype, nelec); EXPECT_DOUBLE_EQ(6, nelec); } +TEST_F(UcellTest, CalNbands) +{ + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 6); +} + +TEST_F(UcellTest, CalNbandsFractionElec) +{ + PARAM.input.nelec = 9.5; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 6); +} + +TEST_F(UcellTest, CalNbandsSOC) +{ + PARAM.input.lspinorb = true; + PARAM.input.nbands = 0; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 20); +} + +TEST_F(UcellTest, CalNbandsSDFT) +{ + PARAM.input.esolver_type = "sdft"; + std::vector nelec_spin(2, 5.0); + EXPECT_NO_THROW(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands)); +} + +TEST_F(UcellTest, CalNbandsLCAO) +{ + PARAM.input.basis_type = "lcao"; + std::vector nelec_spin(2, 5.0); + EXPECT_NO_THROW(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands)); +} + +TEST_F(UcellTest, CalNbandsLCAOINPW) +{ + PARAM.input.basis_type = "lcao_in_pw"; + PARAM.sys.nlocal = PARAM.input.nbands - 1; + std::vector nelec_spin(2, 5.0); + testing::internal::CaptureStdout(); + EXPECT_EXIT(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("NLOCAL < NBANDS")); +} + +TEST_F(UcellTest, CalNbandsWarning1) +{ + PARAM.input.nbands = PARAM.input.nelec / 2 - 1; + std::vector nelec_spin(2, 5.0); + testing::internal::CaptureStdout(); + EXPECT_EXIT(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("Too few bands!")); +} + +TEST_F(UcellTest, CalNbandsWarning2) +{ + PARAM.input.nspin = 2; + PARAM.input.nupdown = 4.0; + std::vector nelec_spin(2); + nelec_spin[0] = (PARAM.input.nelec + PARAM.input.nupdown ) / 2.0; + nelec_spin[1] = (PARAM.input.nelec - PARAM.input.nupdown ) / 2.0; + testing::internal::CaptureStdout(); + EXPECT_EXIT(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("Too few spin up bands!")); +} + +TEST_F(UcellTest, CalNbandsWarning3) +{ + PARAM.input.nspin = 2; + PARAM.input.nupdown = -4.0; + std::vector nelec_spin(2); + nelec_spin[0] = (PARAM.input.nelec + PARAM.input.nupdown ) / 2.0; + nelec_spin[1] = (PARAM.input.nelec - PARAM.input.nupdown ) / 2.0; + testing::internal::CaptureStdout(); + EXPECT_EXIT(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("Too few spin down bands!")); +} + +TEST_F(UcellTest, CalNbandsSpin1) +{ + PARAM.input.nspin = 1; + PARAM.input.nbands = 0; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 15); +} + +TEST_F(UcellTest, CalNbandsSpin1LCAO) +{ + PARAM.input.nspin = 1; + PARAM.input.nbands = 0; + PARAM.input.basis_type = "lcao"; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 6); +} + +TEST_F(UcellTest, CalNbandsSpin4) +{ + PARAM.input.nspin = 4; + PARAM.input.nbands = 0; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 30); +} + +TEST_F(UcellTest, CalNbandsSpin4LCAO) +{ + PARAM.input.nspin = 4; + PARAM.input.nbands = 0; + PARAM.input.basis_type = "lcao"; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 6); +} + +TEST_F(UcellTest, CalNbandsSpin2) +{ + PARAM.input.nspin = 2; + PARAM.input.nbands = 0; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 16); +} + +TEST_F(UcellTest, CalNbandsSpin2LCAO) +{ + PARAM.input.nspin = 2; + PARAM.input.nbands = 0; + PARAM.input.basis_type = "lcao"; + std::vector nelec_spin(2, 5.0); + cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands); + EXPECT_EQ(PARAM.input.nbands, 6); +} + +TEST_F(UcellTest, CalNbandsGaussWarning) +{ + PARAM.input.nbands = 5; + std::vector nelec_spin(2, 5.0); + PARAM.input.smearing_method = "gaussian"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(cal_nbands(PARAM.input.nelec, PARAM.sys.nlocal, nelec_spin, PARAM.input.nbands), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("for smearing, num. of bands > num. of occupied bands")); +} + #ifdef __MPI #include "mpi.h" int main(int argc, char** argv) { diff --git a/source/module_cell/unitcell.cpp b/source/module_cell/unitcell.cpp old mode 100644 new mode 100755 index 08c68aa259e..c68ab860093 --- a/source/module_cell/unitcell.cpp +++ b/source/module_cell/unitcell.cpp @@ -8,6 +8,7 @@ #include "module_base/global_variable.h" #include "unitcell.h" #include "module_parameter/parameter.h" +#include "cal_atoms_info.h" #ifdef __LCAO #include "../module_basis/module_ao/ORB_read.h" // to use 'ORB' -- mohan 2021-01-30 @@ -594,17 +595,6 @@ void UnitCell::setup_cell(const std::string& fn, std::ofstream& log) { this->bcast_unitcell(); #endif - // after read STRU, calculate initial total magnetization when NSPIN=2 - if (PARAM.inp.nspin == 2 && !PARAM.globalv.two_fermi) { - for (int it = 0; it < this->ntype; it++) { - for (int ia = 0; ia < this->atoms[it].na; ia++) { - GlobalV::nupdown += this->atoms[it].mag[ia]; - } - } - GlobalV::ofs_running << " The readin total magnetization is " - << GlobalV::nupdown << std::endl; - } - //======================================================== // Calculate unit cell volume // the reason to calculate volume here is @@ -831,15 +821,16 @@ void UnitCell::read_pseudo(std::ofstream& ofs) { ModuleBase::WARNING_QUIT("setup_cell", "All DFT functional must consistent."); } - if (atoms[it].ncpp.tvanp) { - GlobalV::use_uspp = true; - } } // setup the total number of PAOs cal_natomwfc(ofs); - // setup GlobalV::NLOCAL + // Calculate the information of atoms from the pseudopotential to set PARAM + CalAtomsInfo ca; + ca.cal_atoms_info(this->atoms, this->ntype, PARAM); + + // setup PARAM.globalv.nlocal cal_nwfc(ofs); // Check whether the number of valence is minimum @@ -919,7 +910,7 @@ void UnitCell::read_pseudo(std::ofstream& ofs) { // calculate the total number of local basis // Target : nwfc, lmax, // atoms[].stapos_wf -// GlobalV::NBANDS +// PARAM.inp.nbands //=========================================== void UnitCell::cal_nwfc(std::ofstream& log) { ModuleBase::TITLE("UnitCell", "cal_nwfc"); @@ -950,14 +941,14 @@ void UnitCell::cal_nwfc(std::ofstream& log) { //=========================== // (3) set nwfc and stapos_wf //=========================== - GlobalV::NLOCAL = 0; + int nlocal_tmp = 0; for (int it = 0; it < ntype; it++) { - atoms[it].stapos_wf = GlobalV::NLOCAL; + atoms[it].stapos_wf = nlocal_tmp; const int nlocal_it = atoms[it].nw * atoms[it].na; if (PARAM.inp.nspin != 4) { - GlobalV::NLOCAL += nlocal_it; + nlocal_tmp += nlocal_it; } else { - GlobalV::NLOCAL += nlocal_it * 2; // zhengdy-soc + nlocal_tmp += nlocal_it * 2; // zhengdy-soc } // for tests @@ -966,19 +957,20 @@ void UnitCell::cal_nwfc(std::ofstream& log) { //orbitals",atoms[it].stapos_wf); } - // OUT(GlobalV::ofs_running,"NLOCAL",GlobalV::NLOCAL); + // OUT(GlobalV::ofs_running,"NLOCAL",PARAM.globalv.nlocal); log << " " << std::setw(40) << "NLOCAL" - << " = " << GlobalV::NLOCAL << std::endl; + << " = " << nlocal_tmp << std::endl; //======================================================== // (4) set index for itia2iat, itiaiw2iwt //======================================================== // mohan add 2010-09-26 - assert(GlobalV::NLOCAL > 0); + assert(nlocal_tmp > 0); + assert(nlocal_tmp == PARAM.globalv.nlocal); delete[] iwt2iat; delete[] iwt2iw; - this->iwt2iat = new int[GlobalV::NLOCAL]; - this->iwt2iw = new int[GlobalV::NLOCAL]; + this->iwt2iat = new int[nlocal_tmp]; + this->iwt2iw = new int[nlocal_tmp]; this->itia2iat.create(ntype, namax); // this->itiaiw2iwt.create(ntype, namax, nwmax*PARAM.globalv.npol); @@ -1050,14 +1042,14 @@ void UnitCell::cal_nwfc(std::ofstream& log) { && (PARAM.inp.init_wfc.substr(0, 3) == "nao") && (PARAM.inp.esolver_type == "ksdft"))) // xiaohui add 2013-09-02 { - ModuleBase::GlobalFunc::AUTO_SET("NBANDS", GlobalV::NBANDS); + ModuleBase::GlobalFunc::AUTO_SET("NBANDS", PARAM.inp.nbands); } else // plane wave basis { // if(winput::after_iter && winput::sph_proj) //{ - // if(GlobalV::NBANDS < GlobalV::NLOCAL) + // if(PARAM.inp.nbands < PARAM.globalv.nlocal) // { - // ModuleBase::WARNING_QUIT("cal_nwfc","NBANDS must > GlobalV::NLOCAL + // ModuleBase::WARNING_QUIT("cal_nwfc","NBANDS must > PARAM.globalv.nlocal //!"); // } // } @@ -1582,65 +1574,160 @@ void UnitCell::remake_cell() { } } -void UnitCell::cal_nelec(double& nelec) { +void cal_nelec(const Atom* atoms, const int& ntype, double& nelec) +{ ModuleBase::TITLE("UnitCell", "cal_nelec"); GlobalV::ofs_running << "\n SETUP THE ELECTRONS NUMBER" << std::endl; - if (nelec == 0) { - if (PARAM.inp.use_paw) { + if (nelec == 0) + { + if (PARAM.inp.use_paw) + { #ifdef USE_PAW - for (int it = 0; it < this->ntype; it++) { + for (int it = 0; it < ntype; it++) + { std::stringstream ss1, ss2; - ss1 << " electron number of element " - << GlobalC::paw_cell.get_zat(it) << std::endl; - const int nelec_it - = GlobalC::paw_cell.get_val(it) * this->atoms[it].na; + ss1 << " electron number of element " << GlobalC::paw_cell.get_zat(it) << std::endl; + const int nelec_it = GlobalC::paw_cell.get_val(it) * atoms[it].na; nelec += nelec_it; - ss2 << "total electron number of element " - << GlobalC::paw_cell.get_zat(it); - - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, - ss1.str(), - GlobalC::paw_cell.get_val(it)); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, - ss2.str(), - nelec_it); + ss2 << "total electron number of element " << GlobalC::paw_cell.get_zat(it); + + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, ss1.str(), GlobalC::paw_cell.get_val(it)); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, ss2.str(), nelec_it); } #endif - } else { - for (int it = 0; it < this->ntype; it++) { + } + else + { + for (int it = 0; it < ntype; it++) + { std::stringstream ss1, ss2; - ss1 << "electron number of element " << this->atoms[it].label; - const double nelec_it - = this->atoms[it].ncpp.zv * this->atoms[it].na; + ss1 << "electron number of element " << atoms[it].label; + const double nelec_it = atoms[it].ncpp.zv * atoms[it].na; nelec += nelec_it; - ss2 << "total electron number of element " - << this->atoms[it].label; - - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, - ss1.str(), - this->atoms[it].ncpp.zv); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, - ss2.str(), - nelec_it); + ss2 << "total electron number of element " << atoms[it].label; + + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, ss1.str(), atoms[it].ncpp.zv); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, ss2.str(), nelec_it); } - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, - "AUTOSET number of electrons: ", - nelec); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "AUTOSET number of electrons: ", nelec); } } - if (PARAM.inp.nelec_delta != 0) { - ModuleBase::GlobalFunc::OUT( - GlobalV::ofs_running, - "nelec_delta is NOT zero, please make sure you know what you are " - "doing! nelec_delta: ", - PARAM.inp.nelec_delta); + if (PARAM.inp.nelec_delta != 0) + { + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, + "nelec_delta is NOT zero, please make sure you know what you are " + "doing! nelec_delta: ", + PARAM.inp.nelec_delta); nelec += PARAM.inp.nelec_delta; ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "nelec now: ", nelec); } return; } +void cal_nbands(const int& nelec, const int& nlocal, const std::vector& nelec_spin, int& nbands) +{ + if (PARAM.inp.esolver_type == "sdft") // qianrui 2021-2-20 + { + return; + } + //======================================= + // calculate number of bands (setup.f90) + //======================================= + double occupied_bands = static_cast(nelec / ModuleBase::DEGSPIN); + if (PARAM.inp.lspinorb == 1) { + occupied_bands = static_cast(nelec); + } + + if ((occupied_bands - std::floor(occupied_bands)) > 0.0) + { + occupied_bands = std::floor(occupied_bands) + 1.0; // mohan fix 2012-04-16 + } + + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "occupied bands", occupied_bands); + + if (nbands == 0) + { + if (PARAM.inp.nspin == 1) + { + const int nbands1 = static_cast(occupied_bands) + 10; + const int nbands2 = static_cast(1.2 * occupied_bands) + 1; + nbands = std::max(nbands1, nbands2); + if (PARAM.inp.basis_type != "pw") { + nbands = std::min(nbands, nlocal); + } + } + else if (PARAM.inp.nspin == 4) + { + const int nbands3 = nelec + 20; + const int nbands4 = static_cast(1.2 * nelec) + 1; + nbands = std::max(nbands3, nbands4); + if (PARAM.inp.basis_type != "pw") { + nbands = std::min(nbands, nlocal); + } + } + else if (PARAM.inp.nspin == 2) + { + const double max_occ = std::max(nelec_spin[0], nelec_spin[1]); + const int nbands3 = static_cast(max_occ) + 11; + const int nbands4 = static_cast(1.2 * max_occ) + 1; + nbands = std::max(nbands3, nbands4); + if (PARAM.inp.basis_type != "pw") { + nbands = std::min(nbands, nlocal); + } + } + ModuleBase::GlobalFunc::AUTO_SET("NBANDS", nbands); + } + // else if ( PARAM.inp.calculation=="scf" || PARAM.inp.calculation=="md" || PARAM.inp.calculation=="relax") //pengfei + // 2014-10-13 + else + { + if (nbands < occupied_bands) { + ModuleBase::WARNING_QUIT("unitcell", "Too few bands!"); + } + if (PARAM.inp.nspin == 2) + { + if (nbands < nelec_spin[0]) + { + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "nelec_up", nelec_spin[0]); + ModuleBase::WARNING_QUIT("ElecState::cal_nbands", "Too few spin up bands!"); + } + if (nbands < nelec_spin[1]) + { + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "nelec_down", nelec_spin[1]); + ModuleBase::WARNING_QUIT("ElecState::cal_nbands", "Too few spin down bands!"); + } + } + } + + // mohan add 2010-09-04 + // std::cout << "nbands(this-> = " < num. of occupied bands"); + } + } + + // mohan update 2021-02-19 + // mohan add 2011-01-5 + if (PARAM.inp.basis_type == "lcao" || PARAM.inp.basis_type == "lcao_in_pw") + { + if (nbands > nlocal) + { + ModuleBase::WARNING_QUIT("ElecState::cal_nbandsc", "NLOCAL < NBANDS"); + } + else + { + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NLOCAL", nlocal); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NBANDS", nbands); + } + } + + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NBANDS", nbands); +} + void UnitCell::compare_atom_labels(std::string label1, std::string label2) { if (label1 != label2) //'!( "Ag" == "Ag" || "47" == "47" || "Silver" == Silver" )' diff --git a/source/module_cell/unitcell.h b/source/module_cell/unitcell.h index 9a8e54ce3d0..4657d97b629 100644 --- a/source/module_cell/unitcell.h +++ b/source/module_cell/unitcell.h @@ -307,10 +307,6 @@ class UnitCell { const bool& init_vel_in, const std::string& fixed_axes_in); - /// @brief calculate the total number of electrons in system - /// (GlobalV::nelec) - void cal_nelec(double& nelec); - /// @brief check consistency between two atom labels from STRU and pseudo or /// orb file void compare_atom_labels(std::string label1, std::string label2); @@ -334,4 +330,23 @@ class UnitCell { std::vector> get_lnchiCounts() const; }; +/** + * @brief calculate the total number of electrons in system + * + * @param atoms [in] atom pointer + * @param ntype [in] number of atom types + * @param nelec [out] total number of electrons + */ +void cal_nelec(const Atom* atoms, const int& ntype, double& nelec); + +/** + * @brief Calculate the number of bands. + * + * @param nelec [in] total number of electrons + * @param nlocal [in] total number of local basis + * @param nelec_spin [in] number of electrons for each spin + * @param nbands [out] number of bands + */ +void cal_nbands(const int& nelec, const int& nlocal, const std::vector& nelec_spin, int& nbands); + #endif // unitcell class diff --git a/source/module_elecstate/CMakeLists.txt b/source/module_elecstate/CMakeLists.txt index 5f24e9db5da..40b43a7b99a 100644 --- a/source/module_elecstate/CMakeLists.txt +++ b/source/module_elecstate/CMakeLists.txt @@ -7,6 +7,7 @@ list(APPEND objects elecstate_print.cpp elecstate_pw.cpp elecstate_pw_sdft.cpp + elecstate_pw_cal_tau.cpp potentials/gatefield.cpp potentials/efield.cpp potentials/H_Hartree_pw.cpp @@ -31,6 +32,7 @@ if(ENABLE_LCAO) list(APPEND objects elecstate_lcao.cpp elecstate_lcao_tddft.cpp + elecstate_lcao_cal_tau.cpp potentials/H_TDDFT_pw.cpp module_dm/density_matrix.cpp module_dm/cal_dm_psi.cpp diff --git a/source/module_elecstate/elecstate.cpp b/source/module_elecstate/elecstate.cpp index 720d920ed5b..3a31f7433c5 100644 --- a/source/module_elecstate/elecstate.cpp +++ b/source/module_elecstate/elecstate.cpp @@ -61,9 +61,8 @@ void ElecState::init_nelec_spin() this->nelec_spin.resize(PARAM.inp.nspin); if (PARAM.inp.nspin == 2) { - // in fact, when TWO_EFERMI(nupdown in INPUT is not 0.0), nelec_spin will be fixed. - this->nelec_spin[0] = (GlobalV::nelec + GlobalV::nupdown) / 2.0; - this->nelec_spin[1] = (GlobalV::nelec - GlobalV::nupdown) / 2.0; + this->nelec_spin[0] = (PARAM.inp.nelec + PARAM.inp.nupdown) / 2.0; + this->nelec_spin[1] = (PARAM.inp.nelec - PARAM.inp.nupdown) / 2.0; } } @@ -108,7 +107,7 @@ void ElecState::calculate_weights() Occupy::iweights(nks, this->klist->wk, nbands, - GlobalV::nelec, + PARAM.inp.nelec, this->ekb, this->eferm.ef, this->wg, @@ -154,7 +153,7 @@ void ElecState::calculate_weights() Occupy::gweights(nks, this->klist->wk, nbands, - GlobalV::nelec, + PARAM.inp.nelec, Occupy::gaussian_parameter, Occupy::gaussian_type, this->ekb, @@ -248,141 +247,11 @@ void ElecState::init_ks(Charge* chg_in, // pointer for class Charge this->bigpw = bigpw_in; // init nelec_spin with nelec and nupdown this->init_nelec_spin(); - // autoset and check GlobalV::NBANDS, nelec_spin is used when NSPIN==2 - this->cal_nbands(); // initialize ekb and wg - this->ekb.create(nk_in, GlobalV::NBANDS); - this->wg.create(nk_in, GlobalV::NBANDS); + this->ekb.create(nk_in, PARAM.inp.nbands); + this->wg.create(nk_in, PARAM.inp.nbands); } -void ElecState::cal_nbands() -{ - if (PARAM.inp.esolver_type == "sdft") // qianrui 2021-2-20 - { - return; - } - //======================================= - // calculate number of bands (setup.f90) - //======================================= - double occupied_bands = static_cast(GlobalV::nelec / ModuleBase::DEGSPIN); - if (PARAM.inp.lspinorb == 1) { - occupied_bands = static_cast(GlobalV::nelec); - } - - if ((occupied_bands - std::floor(occupied_bands)) > 0.0) - { - occupied_bands = std::floor(occupied_bands) + 1.0; // mohan fix 2012-04-16 - } - - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "occupied bands", occupied_bands); - - if (GlobalV::NBANDS == 0) - { - if (PARAM.inp.nspin == 1) - { - const int nbands1 = static_cast(occupied_bands) + 10; - const int nbands2 = static_cast(1.2 * occupied_bands) + 1; - GlobalV::NBANDS = std::max(nbands1, nbands2); - if (PARAM.inp.basis_type != "pw") { - GlobalV::NBANDS = std::min(GlobalV::NBANDS, GlobalV::NLOCAL); - } - } - else if (PARAM.inp.nspin == 4) - { - const int nbands3 = GlobalV::nelec + 20; - const int nbands4 = static_cast(1.2 * GlobalV::nelec) + 1; - GlobalV::NBANDS = std::max(nbands3, nbands4); - if (PARAM.inp.basis_type != "pw") { - GlobalV::NBANDS = std::min(GlobalV::NBANDS, GlobalV::NLOCAL); - } - } - else if (PARAM.inp.nspin == 2) - { - const double max_occ = std::max(this->nelec_spin[0], this->nelec_spin[1]); - const int nbands3 = static_cast(max_occ) + 11; - const int nbands4 = static_cast(1.2 * max_occ) + 1; - GlobalV::NBANDS = std::max(nbands3, nbands4); - if (PARAM.inp.basis_type != "pw") { - GlobalV::NBANDS = std::min(GlobalV::NBANDS, GlobalV::NLOCAL); - } - } - ModuleBase::GlobalFunc::AUTO_SET("NBANDS", GlobalV::NBANDS); - } - // else if ( PARAM.inp.calculation=="scf" || PARAM.inp.calculation=="md" || PARAM.inp.calculation=="relax") //pengfei - // 2014-10-13 - else - { - if (GlobalV::NBANDS < occupied_bands) { - ModuleBase::WARNING_QUIT("unitcell", "Too few bands!"); - } - if (PARAM.inp.nspin == 2) - { - if (GlobalV::NBANDS < this->nelec_spin[0]) - { - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "nelec_up", this->nelec_spin[0]); - ModuleBase::WARNING_QUIT("ElecState::cal_nbands", "Too few spin up bands!"); - } - if (GlobalV::NBANDS < this->nelec_spin[1]) - { - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "nelec_down", this->nelec_spin[1]); - ModuleBase::WARNING_QUIT("ElecState::cal_nbands", "Too few spin down bands!"); - } - } - } - - // mohan add 2010-09-04 - // std::cout << "nbands(this-> = " < num. of occupied bands"); - } - } - - // mohan update 2021-02-19 - // mohan add 2011-01-5 - if (PARAM.inp.basis_type == "lcao" || PARAM.inp.basis_type == "lcao_in_pw") - { - if (GlobalV::NBANDS > GlobalV::NLOCAL) - { - ModuleBase::WARNING_QUIT("ElecState::cal_nbandsc", "NLOCAL < NBANDS"); - } - else - { - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NLOCAL", GlobalV::NLOCAL); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NBANDS", GlobalV::NBANDS); - } - } - - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "NBANDS", GlobalV::NBANDS); -} - -void set_is_occupied(std::vector& is_occupied, - elecstate::ElecState* pes, - const int i_scf, - const int nk, - const int nband, - const bool diago_full_acc) -{ - if (i_scf != 0 && diago_full_acc == false) - { - for (int i = 0; i < nk; i++) - { - if (pes->klist->wk[i] > 0.0) - { - for (int j = 0; j < nband; j++) - { - if (pes->wg(i, j) / pes->klist->wk[i] < 0.01) - { - is_occupied[i * nband + j] = false; - } - } - } - } - } -}; - } // namespace elecstate diff --git a/source/module_elecstate/elecstate.h b/source/module_elecstate/elecstate.h index 65889bfdea9..8b5d9eac723 100644 --- a/source/module_elecstate/elecstate.h +++ b/source/module_elecstate/elecstate.h @@ -53,6 +53,14 @@ class ElecState } // virtual void updateRhoK(const psi::Psi> &psi) = 0; // virtual void updateRhoK(const psi::Psi &psi)=0 + virtual void cal_tau(const psi::Psi>& psi) + { + return; + } + virtual void cal_tau(const psi::Psi& psi) + { + return; + } // update charge density for next scf step // in this function, 1. input rho for construct Hamilt and 2. calculated rho from Psi will mix to 3. new charge @@ -83,9 +91,6 @@ class ElecState //for NSPIN=4, it will record total number, magnetization for x, y, z direction std::vector nelec_spin; - //calculate nbands and - void cal_nbands(); - virtual void print_psi(const psi::Psi& psi_in, const int istep = -1) { return; @@ -192,13 +197,5 @@ class ElecState bool skip_weights = false; }; -// This is an independent function under the elecstate namespace and does not depend on any class. -void set_is_occupied(std::vector& is_occupied, - elecstate::ElecState* pes, - const int i_scf, - const int nk, - const int nband, - const bool diago_full_acc); - } // namespace elecstate #endif diff --git a/source/module_elecstate/elecstate_energy.cpp b/source/module_elecstate/elecstate_energy.cpp index e2777fa50dc..1b3f0714144 100644 --- a/source/module_elecstate/elecstate_energy.cpp +++ b/source/module_elecstate/elecstate_energy.cpp @@ -21,7 +21,7 @@ void ElecState::cal_bandgap() this->bandgap = 0.0; return; } - int nbands = GlobalV::NBANDS; + int nbands = PARAM.inp.nbands; int nks = this->klist->get_nks(); double homo = this->ekb(0, 0); double lumo = this->ekb(0, nbands - 1); @@ -52,7 +52,7 @@ void ElecState::cal_bandgap_updw() this->bandgap_dw = 0.0; return; } - int nbands = GlobalV::NBANDS; + int nbands = PARAM.inp.nbands; int nks = this->klist->get_nks(); double homo_up = this->ekb(0, 0); double lumo_up = this->ekb(0, nbands - 1); diff --git a/source/module_elecstate/elecstate_exx.cpp b/source/module_elecstate/elecstate_exx.cpp index 8881a74807d..db67fd3e822 100644 --- a/source/module_elecstate/elecstate_exx.cpp +++ b/source/module_elecstate/elecstate_exx.cpp @@ -13,11 +13,15 @@ void ElecState::set_exx(const double& Eexx) if (GlobalC::exx_info.info_global.cal_exx) { - this->f_en.exx = GlobalC::exx_info.info_global.hybrid_alpha * Eexx; + const double coeff = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; + this->f_en.exx = coeff * Eexx; } return; } #endif //__LCAO #endif //__EXX -} \ No newline at end of file +} // namespace elecstate \ No newline at end of file diff --git a/source/module_elecstate/elecstate_lcao.cpp b/source/module_elecstate/elecstate_lcao.cpp index 0650af2ecf1..5a517b23e00 100644 --- a/source/module_elecstate/elecstate_lcao.cpp +++ b/source/module_elecstate/elecstate_lcao.cpp @@ -62,17 +62,12 @@ void ElecStateLCAO>::psiToRho(const psi::Psigint_k->transfer_DM2DtoGrid(this->DM->get_DMR_vector()); // transfer DM2D to DM_grid in gint - Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho); + Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); this->gint_k->cal_gint(&inout); if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { - for (int is = 0; is < PARAM.inp.nspin; is++) - { - ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); - } - Gint_inout inout1(this->charge->kin_r, Gint_Tools::job_type::tau); - this->gint_k->cal_gint(&inout1); + this->cal_tau(psi); } this->charge->renormalize_rho(); @@ -118,18 +113,13 @@ void ElecStateLCAO::psiToRho(const psi::Psi& psi) this->gint_gamma->transfer_DM2DtoGrid(this->DM->get_DMR_vector()); // transfer DM2D to DM_grid in gint - Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho); + Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); this->gint_gamma->cal_gint(&inout); if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { - for (int is = 0; is < PARAM.inp.nspin; is++) - { - ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); - } - Gint_inout inout1(this->charge->kin_r, Gint_Tools::job_type::tau); - this->gint_gamma->cal_gint(&inout1); + this->cal_tau(psi); } this->charge->renormalize_rho(); @@ -141,7 +131,8 @@ void ElecStateLCAO::psiToRho(const psi::Psi& psi) template void ElecStateLCAO::init_DM(const K_Vectors* kv, const Parallel_Orbitals* paraV, const int nspin) { - this->DM = new DensityMatrix(kv, paraV, nspin); + const int nspin_dm = nspin == 2 ? 2 : 1; + this->DM = new DensityMatrix(paraV, nspin_dm, kv->kvec_d, kv->get_nks() / nspin_dm); } template <> @@ -187,7 +178,7 @@ void ElecStateLCAO::dmToRho(std::vector pexsi_DM, std::vectorgint_gamma->transfer_DM2DtoGrid(this->DM->get_DMR_vector()); // transfer DM2D to DM_grid in gint - Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho); + Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); this->gint_gamma->cal_gint(&inout); if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { diff --git a/source/module_elecstate/elecstate_lcao.h b/source/module_elecstate/elecstate_lcao.h index ad7cf64c958..e0fcf6affec 100644 --- a/source/module_elecstate/elecstate_lcao.h +++ b/source/module_elecstate/elecstate_lcao.h @@ -46,6 +46,7 @@ class ElecStateLCAO : public ElecState // virtual void psiToRho(const psi::Psi& psi) override; // return current electronic density rho, as a input for constructing Hamiltonian // const double* getRho(int spin) const override; + virtual void cal_tau(const psi::Psi& psi) override; // update charge density for next scf step // void getNewRho() override; diff --git a/source/module_elecstate/elecstate_lcao_cal_tau.cpp b/source/module_elecstate/elecstate_lcao_cal_tau.cpp new file mode 100644 index 00000000000..e6bd6561a03 --- /dev/null +++ b/source/module_elecstate/elecstate_lcao_cal_tau.cpp @@ -0,0 +1,41 @@ +#include "elecstate_lcao.h" + +#include "module_base/timer.h" + +namespace elecstate +{ + +// calculate the kinetic energy density tau, multi-k case +template <> +void ElecStateLCAO>::cal_tau(const psi::Psi>& psi) +{ + ModuleBase::timer::tick("ElecStateLCAO", "cal_tau"); + + for (int is = 0; is < PARAM.inp.nspin; is++) + { + ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); + } + Gint_inout inout1(this->charge->kin_r, Gint_Tools::job_type::tau, PARAM.inp.nspin); + this->gint_k->cal_gint(&inout1); + + ModuleBase::timer::tick("ElecStateLCAO", "cal_tau"); + return; +} + +// calculate the kinetic energy density tau, gamma-only case +template <> +void ElecStateLCAO::cal_tau(const psi::Psi& psi) +{ + ModuleBase::timer::tick("ElecStateLCAO", "cal_tau"); + + for (int is = 0; is < PARAM.inp.nspin; is++) + { + ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); + } + Gint_inout inout1(this->charge->kin_r, Gint_Tools::job_type::tau, PARAM.inp.nspin); + this->gint_gamma->cal_gint(&inout1); + + ModuleBase::timer::tick("ElecStateLCAO", "cal_tau"); + return; +} +} \ No newline at end of file diff --git a/source/module_elecstate/elecstate_lcao_tddft.cpp b/source/module_elecstate/elecstate_lcao_tddft.cpp index 48ce026e1fe..147b790a955 100644 --- a/source/module_elecstate/elecstate_lcao_tddft.cpp +++ b/source/module_elecstate/elecstate_lcao_tddft.cpp @@ -22,13 +22,8 @@ void ElecStateLCAO_TDDFT::psiToRho_td(const psi::Psi>& psi) // this part for calculating DMK in 2d-block format, not used for charge now // psi::Psi> dm_k_2d(); - - if (PARAM.inp.ks_solver == "genelpa" || PARAM.inp.ks_solver == "scalapack_gvx" - || PARAM.inp.ks_solver == "lapack") // Peize Lin test 2019-05-15 - { - elecstate::cal_dm_psi(this->DM->get_paraV_pointer(), this->wg, psi, *(this->DM)); - this->DM->cal_DMR(); - } + elecstate::cal_dm_psi(this->DM->get_paraV_pointer(), this->wg, psi, *(this->DM)); + this->DM->cal_DMR(); for (int is = 0; is < PARAM.inp.nspin; is++) { @@ -41,7 +36,7 @@ void ElecStateLCAO_TDDFT::psiToRho_td(const psi::Psi>& psi) ModuleBase::GlobalFunc::NOTE("Calculate the charge on real space grid!"); this->gint_k->transfer_DM2DtoGrid(this->DM->get_DMR_vector()); // transfer DM2D to DM_grid in gint - Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho); // rho calculation + Gint_inout inout(this->charge->rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); // rho calculation this->gint_k->cal_gint(&inout); this->charge->renormalize_rho(); @@ -57,7 +52,7 @@ void ElecStateLCAO_TDDFT::calculate_weights_td() if (PARAM.inp.ocp == 1) { int num = 0; - num = this->klist->get_nks() * GlobalV::NBANDS; + num = this->klist->get_nks() * PARAM.inp.nbands; if (num != PARAM.inp.ocp_kb.size()) { ModuleBase::WARNING_QUIT("ElecStateLCAO_TDDFT::calculate_weights_td", @@ -69,7 +64,7 @@ void ElecStateLCAO_TDDFT::calculate_weights_td() { num_elec += PARAM.inp.ocp_kb[i]; } - if (std::abs(num_elec - GlobalV::nelec) > 1.0e-5) + if (std::abs(num_elec - PARAM.inp.nelec) > 1.0e-5) { ModuleBase::WARNING_QUIT("ElecStateLCAO_TDDFT::calculate_weights_td", "total number of occupations is wrong , please check ocp_set"); @@ -77,9 +72,9 @@ void ElecStateLCAO_TDDFT::calculate_weights_td() for (int ik = 0; ik < this->klist->get_nks(); ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { - this->wg(ik, ib) = PARAM.inp.ocp_kb[ik * GlobalV::NBANDS + ib]; + this->wg(ik, ib) = PARAM.inp.ocp_kb[ik * PARAM.inp.nbands + ib]; } } } diff --git a/source/module_elecstate/elecstate_print.cpp b/source/module_elecstate/elecstate_print.cpp index ab4fa47c4d3..2d738345b32 100644 --- a/source/module_elecstate/elecstate_print.cpp +++ b/source/module_elecstate/elecstate_print.cpp @@ -245,7 +245,7 @@ void ElecState::print_band(const int& ik, const int& printe, const int& iter) { // check the band energy. bool wrong = false; - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { if (std::abs(this->ekb(ik, ib)) > 1.0e10) { @@ -267,7 +267,7 @@ void ElecState::print_band(const int& ik, const int& printe, const int& iter) GlobalV::ofs_running << " Energy (eV) & Occupations for spin=" << this->klist->isk[ik] + 1 << " K-point=" << ik + 1 << std::endl; GlobalV::ofs_running << std::setiosflags(std::ios::showpoint); - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { GlobalV::ofs_running << " " << std::setw(6) << ib + 1 << std::setw(15) << this->ekb(ik, ib) * ModuleBase::Ry_to_eV; diff --git a/source/module_elecstate/elecstate_pw.cpp b/source/module_elecstate/elecstate_pw.cpp index 8fa5ee74b7f..aebde68a089 100644 --- a/source/module_elecstate/elecstate_pw.cpp +++ b/source/module_elecstate/elecstate_pw.cpp @@ -34,7 +34,7 @@ ElecStatePW::~ElecStatePW() if (base_device::get_device_type(this->ctx) == base_device::GpuDevice) { delmem_var_op()(this->ctx, this->rho_data); - if (get_xc_func_type() == 3) + if (get_xc_func_type() == 3 || PARAM.inp.out_elf[0] > 0) { delmem_var_op()(this->ctx, this->kin_r_data); } @@ -47,13 +47,13 @@ ElecStatePW::~ElecStatePW() template void ElecStatePW::init_rho_data() { - if (PARAM.globalv.device_flag == "gpu" || PARAM.inp.precision == "single") { + if (PARAM.inp.device == "gpu" || PARAM.inp.precision == "single") { this->rho = new Real*[this->charge->nspin]; resmem_var_op()(this->ctx, this->rho_data, this->charge->nspin * this->charge->nrxx); for (int ii = 0; ii < this->charge->nspin; ii++) { this->rho[ii] = this->rho_data + ii * this->charge->nrxx; } - if (get_xc_func_type() == 3) + if (get_xc_func_type() == 3 || PARAM.inp.out_elf[0] > 0) { this->kin_r = new Real*[this->charge->nspin]; resmem_var_op()(this->ctx, this->kin_r_data, this->charge->nspin * this->charge->nrxx); @@ -64,7 +64,7 @@ void ElecStatePW::init_rho_data() } else { this->rho = reinterpret_cast(this->charge->rho); - if (get_xc_func_type() == 3) + if (get_xc_func_type() == 3 || PARAM.inp.out_elf[0] > 0) { this->kin_r = reinterpret_cast(this->charge->kin_r); } @@ -104,11 +104,11 @@ void ElecStatePW::psiToRho(const psi::Psi& psi) psi.fix_k(ik); this->updateRhoK(psi); } - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { this->add_usrho(psi); } - if (PARAM.globalv.device_flag == "gpu" || PARAM.inp.precision == "single") { + if (PARAM.inp.device == "gpu" || PARAM.inp.precision == "single") { for (int ii = 0; ii < PARAM.inp.nspin; ii++) { castmem_var_d2h_op()(cpu_ctx, this->ctx, this->charge->rho[ii], this->rho[ii], this->charge->nrxx); if (get_xc_func_type() == 3) diff --git a/source/module_elecstate/elecstate_pw.h b/source/module_elecstate/elecstate_pw.h index bdf85597cd4..73cf6c91a29 100644 --- a/source/module_elecstate/elecstate_pw.h +++ b/source/module_elecstate/elecstate_pw.h @@ -33,6 +33,7 @@ class ElecStatePW : public ElecState virtual void psiToRho(const psi::Psi& psi); // return current electronic density rho, as a input for constructing Hamiltonian // const double* getRho(int spin) const override; + virtual void cal_tau(const psi::Psi& psi); // update charge density for next scf step // void getNewRho() override; diff --git a/source/module_elecstate/elecstate_pw_cal_tau.cpp b/source/module_elecstate/elecstate_pw_cal_tau.cpp new file mode 100644 index 00000000000..0662bb44258 --- /dev/null +++ b/source/module_elecstate/elecstate_pw_cal_tau.cpp @@ -0,0 +1,68 @@ +#include "elecstate_pw.h" +#include "elecstate_getters.h" + +namespace elecstate { + +template +void ElecStatePW::cal_tau(const psi::Psi& psi) +{ + ModuleBase::TITLE("ElecStatePW", "cal_tau"); + for(int is=0; isctx, this->kin_r[is], 0, this->charge->nrxx); + } + + for (int ik = 0; ik < psi.get_nk(); ++ik) + { + psi.fix_k(ik); + int npw = psi.get_current_nbas(); + int current_spin = 0; + if (PARAM.inp.nspin == 2) + { + current_spin = this->klist->isk[ik]; + } + int nbands = psi.get_nbands(); + for (int ibnd = 0; ibnd < nbands; ibnd++) + { + this->basis->recip_to_real(this->ctx, &psi(ibnd,0), this->wfcr, ik); + + const auto w1 = static_cast(this->wg(ik, ibnd) / get_ucell_omega()); + + // kinetic energy density + for (int j = 0; j < 3; j++) + { + setmem_complex_op()(this->ctx, this->wfcr, 0, this->charge->nrxx); + + meta_op()(this->ctx, + ik, + j, + npw, + this->basis->npwk_max, + static_cast(get_ucell_tpiba()), + this->basis->template get_gcar_data(), + this->basis->template get_kvec_c_data(), + &psi(ibnd, 0), + this->wfcr); + + this->basis->recip_to_real(this->ctx, this->wfcr, this->wfcr, ik); + + elecstate_pw_op()(this->ctx, current_spin, this->charge->nrxx, w1, this->kin_r, this->wfcr); + } + } + } + if (PARAM.inp.device == "gpu" || PARAM.inp.precision == "single") { + for (int ii = 0; ii < PARAM.inp.nspin; ii++) { + castmem_var_d2h_op()(cpu_ctx, this->ctx, this->charge->kin_r[ii], this->kin_r[ii], this->charge->nrxx); + } + } + this->parallelK(); + ModuleBase::TITLE("ElecStatePW", "cal_tau"); +} + +template class ElecStatePW, base_device::DEVICE_CPU>; +template class ElecStatePW, base_device::DEVICE_CPU>; +#if ((defined __CUDA) || (defined __ROCM)) +template class ElecStatePW, base_device::DEVICE_GPU>; +template class ElecStatePW, base_device::DEVICE_GPU>; +#endif +} // namespace elecstate diff --git a/source/module_elecstate/elecstate_pw_sdft.cpp b/source/module_elecstate/elecstate_pw_sdft.cpp index bb840b0cfc0..c36513c838d 100644 --- a/source/module_elecstate/elecstate_pw_sdft.cpp +++ b/source/module_elecstate/elecstate_pw_sdft.cpp @@ -1,41 +1,47 @@ #include "./elecstate_pw_sdft.h" + +#include "module_base/global_function.h" #include "module_base/global_variable.h" -#include "module_parameter/parameter.h" #include "module_base/timer.h" -#include "module_base/global_function.h" #include "module_hamilt_general/module_xc/xc_functional.h" +#include "module_parameter/parameter.h" namespace elecstate { - void ElecStatePW_SDFT::psiToRho(const psi::Psi>& psi) + +template +void ElecStatePW_SDFT::psiToRho(const psi::Psi& psi) +{ + ModuleBase::TITLE(this->classname, "psiToRho"); + ModuleBase::timer::tick(this->classname, "psiToRho"); + for (int is = 0; is < PARAM.inp.nspin; is++) { - ModuleBase::TITLE(this->classname, "psiToRho"); - ModuleBase::timer::tick(this->classname, "psiToRho"); - for(int is=0; is < PARAM.inp.nspin; is++) - { - ModuleBase::GlobalFunc::ZEROS(this->charge->rho[is], this->charge->nrxx); - if (XC_Functional::get_func_type() == 3) - { - ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); - } - } - - if(GlobalV::MY_STOGROUP == 0) - { - this->calEBand(); + ModuleBase::GlobalFunc::ZEROS(this->charge->rho[is], this->charge->nrxx); + if (XC_Functional::get_func_type() == 3) + { + ModuleBase::GlobalFunc::ZEROS(this->charge->kin_r[is], this->charge->nrxx); + } + } + + if (GlobalV::MY_STOGROUP == 0) + { + this->calEBand(); - for(int is=0; ischarge->rho[is], this->charge->nrxx); - } + for (int is = 0; is < PARAM.inp.nspin; is++) + { + ModuleBase::GlobalFunc::ZEROS(this->charge->rho[is], this->charge->nrxx); + } - for (int ik = 0; ik < psi.get_nk(); ++ik) - { - psi.fix_k(ik); - this->updateRhoK(psi); - } - this->parallelK(); + for (int ik = 0; ik < psi.get_nk(); ++ik) + { + psi.fix_k(ik); + this->updateRhoK(psi); } - ModuleBase::timer::tick(this->classname, "psiToRho"); - return; + this->parallelK(); } -} \ No newline at end of file + ModuleBase::timer::tick(this->classname, "psiToRho"); + return; +} + +// template class ElecStatePW_SDFT, base_device::DEVICE_CPU>; +template class ElecStatePW_SDFT, base_device::DEVICE_CPU>; +} // namespace elecstate \ No newline at end of file diff --git a/source/module_elecstate/elecstate_pw_sdft.h b/source/module_elecstate/elecstate_pw_sdft.h index 2dd312ac08a..eaf92153906 100644 --- a/source/module_elecstate/elecstate_pw_sdft.h +++ b/source/module_elecstate/elecstate_pw_sdft.h @@ -3,22 +3,24 @@ #include "elecstate_pw.h" namespace elecstate { - class ElecStatePW_SDFT : public ElecStatePW> +template +class ElecStatePW_SDFT : public ElecStatePW +{ + public: + ElecStatePW_SDFT(ModulePW::PW_Basis_K* wfc_basis_in, + Charge* chg_in, + K_Vectors* pkv_in, + UnitCell* ucell_in, + pseudopot_cell_vnl* ppcell_in, + ModulePW::PW_Basis* rhodpw_in, + ModulePW::PW_Basis* rhopw_in, + ModulePW::PW_Basis_Big* bigpw_in) + : ElecStatePW(wfc_basis_in, chg_in, pkv_in, ucell_in, ppcell_in, rhodpw_in, rhopw_in, bigpw_in) { - public: - ElecStatePW_SDFT(ModulePW::PW_Basis_K* wfc_basis_in, - Charge* chg_in, - K_Vectors* pkv_in, - UnitCell* ucell_in, - pseudopot_cell_vnl* ppcell_in, - ModulePW::PW_Basis* rhodpw_in, - ModulePW::PW_Basis* rhopw_in, - ModulePW::PW_Basis_Big* bigpw_in) - : ElecStatePW(wfc_basis_in, chg_in, pkv_in, ucell_in, ppcell_in, rhodpw_in, rhopw_in, bigpw_in) - { - this->classname = "ElecStatePW_SDFT"; - } - virtual void psiToRho(const psi::Psi>& psi) override; - }; -} + this->classname = "ElecStatePW_SDFT"; + } + virtual void psiToRho(const psi::Psi& psi) override; +}; +} // namespace elecstate #endif \ No newline at end of file diff --git a/source/module_elecstate/magnetism.cpp b/source/module_elecstate/magnetism.cpp index ee574de6049..89bf71eb384 100644 --- a/source/module_elecstate/magnetism.cpp +++ b/source/module_elecstate/magnetism.cpp @@ -42,8 +42,8 @@ void Magnetism::compute_magnetization(const int& nrxx, const int& nxyz, const do //if TWO_EFERMI, no need to update if(!PARAM.globalv.two_fermi) { - nelec_spin[0] = (GlobalV::nelec + this->tot_magnetization) / 2; - nelec_spin[1] = (GlobalV::nelec - this->tot_magnetization) / 2; + nelec_spin[0] = (PARAM.inp.nelec + this->tot_magnetization) / 2; + nelec_spin[1] = (PARAM.inp.nelec - this->tot_magnetization) / 2; ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running,"nelec for spin up", nelec_spin[0]); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running,"nelec for spin down", nelec_spin[1]); } diff --git a/source/module_elecstate/module_charge/charge.cpp b/source/module_elecstate/module_charge/charge.cpp index f24d55e96df..9003844ca1e 100644 --- a/source/module_elecstate/module_charge/charge.cpp +++ b/source/module_elecstate/module_charge/charge.cpp @@ -80,7 +80,7 @@ void Charge::destroy() delete[] _space_rhog_save; delete[] _space_kin_r; delete[] _space_kin_r_save; - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { delete[] kin_r; delete[] kin_r_save; @@ -121,7 +121,7 @@ void Charge::allocate(const int& nspin_in) _space_rho_save = new double[nspin * nrxx]; _space_rhog = new std::complex[nspin * ngmc]; _space_rhog_save = new std::complex[nspin * ngmc]; - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { _space_kin_r = new double[nspin * nrxx]; _space_kin_r_save = new double[nspin * nrxx]; @@ -130,7 +130,7 @@ void Charge::allocate(const int& nspin_in) rhog = new std::complex*[nspin]; rho_save = new double*[nspin]; rhog_save = new std::complex*[nspin]; - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { kin_r = new double*[nspin]; kin_r_save = new double*[nspin]; @@ -151,7 +151,7 @@ void Charge::allocate(const int& nspin_in) ModuleBase::GlobalFunc::ZEROS(rhog[is], ngmc); ModuleBase::GlobalFunc::ZEROS(rho_save[is], nrxx); ModuleBase::GlobalFunc::ZEROS(rhog_save[is], ngmc); - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { kin_r[is] = _space_kin_r + is * nrxx; ModuleBase::GlobalFunc::ZEROS(kin_r[is], nrxx); @@ -171,7 +171,7 @@ void Charge::allocate(const int& nspin_in) ModuleBase::Memory::record("Chg::rho_save", sizeof(double) * nspin * nrxx); ModuleBase::Memory::record("Chg::rhog", sizeof(double) * nspin * ngmc); ModuleBase::Memory::record("Chg::rhog_save", sizeof(double) * nspin * ngmc); - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { ModuleBase::Memory::record("Chg::kin_r", sizeof(double) * nspin * ngmc); ModuleBase::Memory::record("Chg::kin_r_save", sizeof(double) * nspin * ngmc); @@ -242,7 +242,7 @@ void Charge::renormalize_rho() const double sr = this->sum_rho(); GlobalV::ofs_warning << std::setprecision(15); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "charge before normalized", sr); - const double normalize_factor = GlobalV::nelec / sr; + const double normalize_factor = PARAM.inp.nelec / sr; for (int is = 0; is < nspin; is++) { @@ -299,10 +299,10 @@ void Charge::atomic_rho(const int spin_number_need, ne_tot += ne[is]; } ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "total electron number from rho", ne_tot); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "should be", GlobalV::nelec); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "should be", PARAM.inp.nelec); for (int is = 0; is < spin_number_need; ++is) { for (int ir = 0; ir < this->rhopw->nrxx; ++ir) { - rho_in[is][ir] = rho_in[is][ir] / ne_tot * GlobalV::nelec; + rho_in[is][ir] = rho_in[is][ir] / ne_tot * PARAM.inp.nelec; } } @@ -683,10 +683,10 @@ void Charge::atomic_rho(const int spin_number_need, ne_tot += ne[is]; } ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "total electron number from rho", ne_tot); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "should be", GlobalV::nelec); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_warning, "should be", PARAM.inp.nelec); for (int is = 0; is < spin_number_need; ++is) { for (int ir = 0; ir < this->rhopw->nrxx; ++ir) { - rho_in[is][ir] = rho_in[is][ir] / ne_tot * GlobalV::nelec; + rho_in[is][ir] = rho_in[is][ir] / ne_tot * PARAM.inp.nelec; } } } @@ -733,7 +733,7 @@ void Charge::check_rho() { double ne = 0.0; ne = this->cal_rho2ne(rho[0]); - if (std::abs(ne - GlobalV::nelec) > 1.0e-6) + if (std::abs(ne - PARAM.inp.nelec) > 1.0e-6) { ModuleBase::WARNING("Charge", "Charge is not equal to the number of electrons!"); } @@ -755,7 +755,7 @@ void Charge::check_rho() ModuleBase::WARNING_QUIT("Charge", "Number of spin-up electrons set in starting magnetization exceeds all available."); } // for total charge - if (std::abs(ne_up + ne_dn - GlobalV::nelec) > 1.0e-6) + if (std::abs(ne_up + ne_dn - PARAM.inp.nelec) > 1.0e-6) { ModuleBase::WARNING("Charge", "Charge is not equal to the number of electrons!"); } diff --git a/source/module_elecstate/module_charge/charge.h b/source/module_elecstate/module_charge/charge.h index 6ea9ac5a203..1593c9fa47a 100644 --- a/source/module_elecstate/module_charge/charge.h +++ b/source/module_elecstate/module_charge/charge.h @@ -138,6 +138,7 @@ class Charge int ngmc; // number of g vectors in this processor int nspin; // number of spins ModulePW::PW_Basis* rhopw = nullptr;// When double_grid is used, rhopw = rhodpw (dense grid) + bool cal_elf = false; // whether to calculate electron localization function (ELF) private: void destroy(); // free arrays liuyu 2023-03-12 diff --git a/source/module_elecstate/module_charge/charge_init.cpp b/source/module_elecstate/module_charge/charge_init.cpp index fea69558788..c0806da9377 100644 --- a/source/module_elecstate/module_charge/charge_init.cpp +++ b/source/module_elecstate/module_charge/charge_init.cpp @@ -14,7 +14,7 @@ #include "module_elecstate/magnetism.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" -#include "module_io/rho_io.h" +#include "module_io/cube_io.h" #include "module_io/rhog_io.h" #include "module_io/read_wfc_to_rho.h" #ifdef USE_PAW @@ -53,63 +53,37 @@ void Charge::init_rho(elecstate::efermi& eferm_iout, { std::stringstream ssc; ssc << PARAM.globalv.global_readin_dir << "SPIN" << is + 1 << "_CHG.cube"; - double& ef_tmp = eferm_iout.get_ef(is); - if (ModuleIO::read_rho( -#ifdef __MPI - &(GlobalC::Pgrid), -#endif - GlobalV::MY_RANK, - PARAM.inp.esolver_type, - GlobalV::RANK_IN_STOGROUP, - is, - GlobalV::ofs_running, - PARAM.inp.nspin, - ssc.str(), - this->rho[is], - this->rhopw->nx, - this->rhopw->ny, - this->rhopw->nz, - ef_tmp, - &(GlobalC::ucell), - this->prenspin)) + if (ModuleIO::read_vdata_palgrid(GlobalC::Pgrid, + (PARAM.inp.esolver_type == "sdft" ? GlobalV::RANK_IN_STOGROUP : GlobalV::MY_RANK), + GlobalV::ofs_running, + ssc.str(), + this->rho[is], + GlobalC::ucell.nat)) { GlobalV::ofs_running << " Read in the charge density: " << ssc.str() << std::endl; } - else if (is > 0) + else if (is > 0) // nspin=2 or 4 { - if (prenspin == 1) + if (is == 1) // failed at the second spin { - GlobalV::ofs_running << " Didn't read in the charge density but autoset it for spin " << is + 1 - << std::endl; - for (int ir = 0; ir < this->rhopw->nrxx; ir++) - { - this->rho[is][ir] = 0.0; - } + std::cout << "Incomplete charge density file!" << std::endl; + read_error = true; + break; } - // - else if (prenspin == 2) - { // read up and down , then rearrange them. - if (is == 1) - { - std::cout << "Incomplete charge density file!" << std::endl; - read_error = true; - break; - } - else if (is == 2) - { - GlobalV::ofs_running << " Didn't read in the charge density but would rearrange it later. " - << std::endl; - } - else if (is == 3) + else if (is == 2) // read 2 files when nspin=4 + { + GlobalV::ofs_running << " Didn't read in the charge density but would rearrange it later. " + << std::endl; + } + else if (is == 3) // read 2 files when nspin=4 + { + GlobalV::ofs_running << " rearrange charge density " << std::endl; + for (int ir = 0; ir < this->rhopw->nrxx; ir++) { - GlobalV::ofs_running << " rearrange charge density " << std::endl; - for (int ir = 0; ir < this->rhopw->nrxx; ir++) - { - this->rho[3][ir] = this->rho[0][ir] - this->rho[1][ir]; - this->rho[0][ir] = this->rho[0][ir] + this->rho[1][ir]; - this->rho[1][ir] = 0.0; - this->rho[2][ir] = 0.0; - } + this->rho[3][ir] = this->rho[0][ir] - this->rho[1][ir]; + this->rho[0][ir] = this->rho[0][ir] + this->rho[1][ir]; + this->rho[1][ir] = 0.0; + this->rho[2][ir] = 0.0; } } } @@ -129,24 +103,12 @@ void Charge::init_rho(elecstate::efermi& eferm_iout, GlobalV::ofs_running << " try to read kinetic energy density from file : " << ssc.str() << std::endl; // mohan update 2012-02-10, sunliang update 2023-03-09 - if (ModuleIO::read_rho( -#ifdef __MPI - &(GlobalC::Pgrid), -#endif - GlobalV::MY_RANK, - PARAM.inp.esolver_type, - GlobalV::RANK_IN_STOGROUP, - is, - GlobalV::ofs_running, - PARAM.inp.nspin, - ssc.str(), - this->kin_r[is], - this->rhopw->nx, - this->rhopw->ny, - this->rhopw->nz, - eferm_iout.ef, - &(GlobalC::ucell), - this->prenspin)) + if (ModuleIO::read_vdata_palgrid(GlobalC::Pgrid, + (PARAM.inp.esolver_type == "sdft" ? GlobalV::RANK_IN_STOGROUP : GlobalV::MY_RANK), + GlobalV::ofs_running, + ssc.str(), + this->kin_r[is], + GlobalC::ucell.nat)) { GlobalV::ofs_running << " Read in the kinetic energy density: " << ssc.str() << std::endl; } diff --git a/source/module_elecstate/module_charge/charge_mixing.cpp b/source/module_elecstate/module_charge/charge_mixing.cpp index a139d5dfd13..8f346d3b3da 100644 --- a/source/module_elecstate/module_charge/charge_mixing.cpp +++ b/source/module_elecstate/module_charge/charge_mixing.cpp @@ -1701,4 +1701,60 @@ void Charge_Mixing::clean_data(std::complex*& data_s, std::complex= 0) // close the function + { + return false; + } + + if(this->_drho_history.size() == 0) + { + this->_drho_history.resize(PARAM.inp.scf_nmax); + } + + // add drho into history + this->_drho_history[iteration - 1] = drho; + + // check if the history is long enough + if(iteration < iternum_used) + { + return false; + } + + // calculate the slope of the last iternum_used iterations' drho + double slope = 0.0; + + // Least Squares Method + // this part is too short, so I do not design it as a free function in principle + double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0; + for (int i = iteration - iternum_used; i < iteration; i++) + { + sumX += i; + sumY += std::log10(this->_drho_history[i]); + sumXY += i * std::log10(this->_drho_history[i]); + sumXX += i * i; + } + double numerator = iternum_used * sumXY - sumX * sumY; + double denominator = iternum_used * sumXX - sumX * sumX; + if (denominator == 0) { + return false; + } + slope = numerator / denominator; + + // if the slope is less than the threshold, return true + if(slope > threshold) + { + return true; + } + + return false; + + ModuleBase::timer::tick("Charge_Mixing", "if_scf_oscillate"); + } \ No newline at end of file diff --git a/source/module_elecstate/module_charge/charge_mixing.h b/source/module_elecstate/module_charge/charge_mixing.h index 8317b2fb177..a8638659879 100644 --- a/source/module_elecstate/module_charge/charge_mixing.h +++ b/source/module_elecstate/module_charge/charge_mixing.h @@ -105,6 +105,9 @@ class Charge_Mixing int mixing_restart_step = 0; //which step to restart mixing during SCF int mixing_restart_count = 0; // the number of restart mixing during SCF. Do not set mixing_restart_count as bool since I want to keep some flexibility in the future + // to calculate the slope of drho curve during SCF, which is used to determine if SCF oscillate + bool if_scf_oscillate(const int iteration, const double drho, const int iternum_used, const double threshold); + private: // mixing_data @@ -129,6 +132,8 @@ class Charge_Mixing double mixing_angle = 0.0; ///< mixing angle for nspin=4 bool mixing_dmr = false; ///< whether to mixing real space density matrix + std::vector _drho_history; ///< history of drho used to determine the oscillation, size is scf_nmax + bool new_e_iteration = true; ModulePW::PW_Basis* rhopw = nullptr; ///< smooth grid diff --git a/source/module_elecstate/module_charge/charge_mpi.cpp b/source/module_elecstate/module_charge/charge_mpi.cpp index 70aae3d9b27..76646b78956 100644 --- a/source/module_elecstate/module_charge/charge_mpi.cpp +++ b/source/module_elecstate/module_charge/charge_mpi.cpp @@ -132,7 +132,7 @@ void Charge::rho_mpi() for (int is = 0; is < PARAM.inp.nspin; ++is) { reduce_diff_pools(this->rho[is]); - if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5) + if (elecstate::get_xc_func_type() == 3 || elecstate::get_xc_func_type() == 5 || PARAM.inp.out_elf[0] > 0) { reduce_diff_pools(this->kin_r[is]); } diff --git a/source/module_elecstate/module_charge/symmetry_rho.cpp b/source/module_elecstate/module_charge/symmetry_rho.cpp index d5afdbd4c3a..3455402da5f 100644 --- a/source/module_elecstate/module_charge/symmetry_rho.cpp +++ b/source/module_elecstate/module_charge/symmetry_rho.cpp @@ -33,7 +33,7 @@ void Symmetry_rho::begin(const int& spin_now, psymmg(CHR.rhog[spin_now], rho_basis, symm); // need to modify rho_basis->recip2real(CHR.rhog[spin_now], CHR.rho[spin_now]); - if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) + if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5 || CHR.cal_elf) { // Use std::vector to manage kin_g instead of raw pointer std::vector> kin_g(CHR.ngmc); @@ -97,7 +97,7 @@ void Symmetry_rho::psymm(double* rho_part, rhotot.resize(rho_basis->nxyz); ModuleBase::GlobalFunc::ZEROS(rhotot.data(), rho_basis->nxyz); } - Pgrid.reduce_to_fullrho(rhotot.data(), rho_part); + Pgrid.reduce(rhotot.data(), rho_part); // (2) if (GlobalV::MY_RANK == 0) @@ -127,24 +127,7 @@ void Symmetry_rho::psymm(double* rho_part, } // (3) - const int ncxy = rho_basis->nx * rho_basis->ny; - std::vector zpiece(ncxy); - for (int iz = 0; iz < rho_basis->nz; iz++) - { - ModuleBase::GlobalFunc::ZEROS(zpiece.data(), ncxy); - if (GlobalV::MY_RANK == 0) - { - for (int ix = 0; ix < rho_basis->nx; ix++) - { - for (int iy = 0; iy < rho_basis->ny; iy++) - { - const int ir = ix * rho_basis->ny + iy; - zpiece[ir] = rhotot[ix * rho_basis->ny * rho_basis->nz + iy * rho_basis->nz + iz]; - } - } - } - Pgrid.zpiece_to_all(zpiece.data(), iz, rho_part); - } +Pgrid.bcast(rhotot.data(), rho_part, GlobalV::MY_RANK); #endif return; } \ No newline at end of file diff --git a/source/module_elecstate/module_dm/density_matrix.cpp b/source/module_elecstate/module_dm/density_matrix.cpp index 9cbb19c0f4e..87ec4d3acfd 100644 --- a/source/module_elecstate/module_dm/density_matrix.cpp +++ b/source/module_elecstate/module_dm/density_matrix.cpp @@ -26,62 +26,24 @@ DensityMatrix::~DensityMatrix() } } -// constructor for multi-k template -DensityMatrix::DensityMatrix(const K_Vectors* kv_in, const Parallel_Orbitals* paraV_in, const int nspin) +DensityMatrix::DensityMatrix(const Parallel_Orbitals* paraV_in, const int nspin, const std::vector>& kvec_d, const int nk) + : _paraV(paraV_in), _nspin(nspin), _kvec_d(kvec_d), _nk((nk > 0 && nk <= _kvec_d.size()) ? nk : _kvec_d.size()) { ModuleBase::TITLE("DensityMatrix", "DensityMatrix-MK"); - this->_kv = kv_in; - this->_paraV = paraV_in; - // set this->_nspin - if (nspin == 1 || nspin == 4) - { - this->_nspin = 1; - } - else if (nspin == 2) - { - this->_nspin = 2; -#ifdef __DEBUG - assert(kv_in->get_nks() % 2 == 0); -#endif - } - else - { - throw std::string("nspin must be 1, 2 or 4"); - } - // set this->_nks, which is real number of k-points - this->_nks = kv_in->get_nks() / this->_nspin; - // allocate memory for _DMK - this->_DMK.resize(this->_kv->get_nks()); - for (int ik = 0; ik < this->_kv->get_nks(); ik++) + const int nks = _nk * _nspin; + this->_DMK.resize(nks); + for (int ik = 0; ik < nks; ik++) { this->_DMK[ik].resize(this->_paraV->get_row_size() * this->_paraV->get_col_size()); } ModuleBase::Memory::record("DensityMatrix::DMK", this->_DMK.size() * this->_DMK[0].size() * sizeof(TK)); } -// constructor for Gamma-Only template -DensityMatrix::DensityMatrix(const Parallel_Orbitals* paraV_in, const int nspin) +DensityMatrix::DensityMatrix(const Parallel_Orbitals* paraV_in, const int nspin) :_paraV(paraV_in), _nspin(nspin), _kvec_d({ ModuleBase::Vector3(0,0,0) }), _nk(1) { ModuleBase::TITLE("DensityMatrix", "DensityMatrix-GO"); - this->_paraV = paraV_in; - // set this->_nspin - if (nspin == 1 || nspin == 4) - { - this->_nspin = 1; - } - else if (nspin == 2) - { - this->_nspin = 2; - } - else - { - throw std::string("nspin must be 1, 2 or 4"); - } - // set this->_nks, which is real number of k-points - this->_nks = 1; - // allocate memory for _DMK this->_DMK.resize(_nspin); for (int ik = 0; ik < this->_nspin; ik++) { @@ -276,7 +238,7 @@ template TK* DensityMatrix::get_DMK_pointer(const int ik) const { #ifdef __DEBUG - assert(ik < this->_nks * this->_nspin); + assert(ik < this->_nk * this->_nspin); #endif return const_cast(this->_DMK[ik].data()); } @@ -286,7 +248,7 @@ template void DensityMatrix::set_DMK_pointer(const int ik, TK* DMK_in) { #ifdef __DEBUG - assert(ik < this->_nks * this->_nspin); + assert(ik < this->_nk * this->_nspin); #endif this->_DMK[ik].assign(DMK_in, DMK_in + this->_paraV->nrow * this->_paraV->ncol); } @@ -297,17 +259,17 @@ void DensityMatrix::set_DMK(const int ispin, const int ik, const int i, { #ifdef __DEBUG assert(ispin > 0 && ispin <= this->_nspin); - assert(ik >= 0 && ik < this->_nks); + assert(ik >= 0 && ik < this->_nk); #endif // consider transpose col=>row - this->_DMK[ik + this->_nks * (ispin - 1)][i * this->_paraV->nrow + j] = value; + this->_DMK[ik + this->_nk * (ispin - 1)][i * this->_paraV->nrow + j] = value; } // set _DMK element template void DensityMatrix::set_DMK_zero() { - for (int ik = 0; ik < _nspin * _nks; ik++) + for (int ik = 0; ik < _nspin * _nk; ik++) { ModuleBase::GlobalFunc::ZEROS(this->_DMK[ik].data(), this->_paraV->get_row_size() * this->_paraV->get_col_size()); @@ -322,7 +284,7 @@ TK DensityMatrix::get_DMK(const int ispin, const int ik, const int i, co assert(ispin > 0 && ispin <= this->_nspin); #endif // consider transpose col=>row - return this->_DMK[ik + this->_nks * (ispin - 1)][i * this->_paraV->nrow + j]; + return this->_DMK[ik + this->_nk * (ispin - 1)][i * this->_paraV->nrow + j]; } // get _DMK nks, nrow, ncol @@ -330,10 +292,9 @@ template int DensityMatrix::get_DMK_nks() const { #ifdef __DEBUG - assert(this->_DMK.size() != 0); - assert(this->_kv != nullptr); + assert(this->_DMK.size() == _nk * _nspin); #endif - return this->_kv->get_nks(); + return _nk * _nspin; } template @@ -405,7 +366,7 @@ void DensityMatrix::cal_DMR_test() { for (int is = 1; is <= this->_nspin; ++is) { - int ik_begin = this->_nks * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = this->_nk * (is - 1); // jump this->_nk for spin_down if nspin==2 hamilt::HContainer* tmp_DMR = this->_DMR[is - 1]; // set zero since this function is called in every scf step tmp_DMR->set_zero(); @@ -437,12 +398,12 @@ void DensityMatrix::cal_DMR_test() #endif std::complex tmp_res; // loop over k-points - for (int ik = 0; ik < this->_nks; ++ik) + for (int ik = 0; ik < this->_nk; ++ik) { // cal k_phase // if TK==std::complex, kphase is e^{ikR} const ModuleBase::Vector3 dR(r_index[0], r_index[1], r_index[2]); - const double arg = (this->_kv->kvec_d[ik] * dR) * ModuleBase::TWO_PI; + const double arg = (this->_kvec_d[ik] * dR) * ModuleBase::TWO_PI; double sinp, cosp; ModuleBase::libm::sincos(arg, &sinp, &cosp); std::complex kphase = std::complex(cosp, sinp); @@ -480,7 +441,7 @@ void DensityMatrix, double>::cal_DMR() int ld_hk2 = 2 * ld_hk; for (int is = 1; is <= this->_nspin; ++is) { - int ik_begin = this->_nks * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = this->_nk * (is - 1); // jump this->_nk for spin_down if nspin==2 hamilt::HContainer* tmp_DMR = this->_DMR[is - 1]; // set zero since this function is called in every scf step tmp_DMR->set_zero(); @@ -499,6 +460,11 @@ void DensityMatrix, double>::cal_DMR() { throw std::string("Atom-pair not belong this process"); } + std::vector> tmp_DMR; + if (PARAM.inp.nspin == 4) + { + tmp_DMR.resize(tmp_ap.get_size()); + } for (int ir = 0; ir < tmp_ap.get_R_size(); ++ir) { const ModuleBase::Vector3 r_index = tmp_ap.get_R_index(ir); @@ -573,15 +539,13 @@ void DensityMatrix, double>::cal_DMR() // treat DMR as pauli matrix when NSPIN=4 if (PARAM.inp.nspin == 4) { - std::vector> tmp_DMR(this->_paraV->get_col_size() - * this->_paraV->get_row_size(), - std::complex(0.0, 0.0)); - for (int ik = 0; ik < this->_nks; ++ik) + tmp_DMR.assign(tmp_ap.get_size(), std::complex(0.0, 0.0)); + for (int ik = 0; ik < this->_nk; ++ik) { // cal k_phase // if TK==std::complex, kphase is e^{ikR} const ModuleBase::Vector3 dR(r_index[0], r_index[1], r_index[2]); - const double arg = (this->_kv->kvec_d[ik] * dR) * ModuleBase::TWO_PI; + const double arg = (this->_kvec_d[ik] * dR) * ModuleBase::TWO_PI; double sinp, cosp; ModuleBase::libm::sincos(arg, &sinp, &cosp); std::complex kphase = std::complex(cosp, sinp); @@ -593,35 +557,34 @@ void DensityMatrix, double>::cal_DMR() // jump DMK to fill DMR // DMR is row-major, DMK is column-major tmp_DMK_pointer += col_ap * this->_paraV->nrow + row_ap; - for (int mu = 0; mu < this->_paraV->get_row_size(iat1); ++mu) + for (int mu = 0; mu < tmp_ap.get_row_size(); ++mu) { - BlasConnector::axpy(this->_paraV->get_col_size(iat2), + BlasConnector::axpy(tmp_ap.get_col_size(), kphase, tmp_DMK_pointer, ld_hk, tmp_DMR_pointer, 1); tmp_DMK_pointer += 1; - tmp_DMR_pointer += this->_paraV->get_col_size(iat2); + tmp_DMR_pointer += tmp_ap.get_col_size(); } } int npol = 2; // step_trace = 0 for NSPIN=1,2; ={0, 1, local_col, local_col+1} for NSPIN=4 - std::vector step_trace(npol * npol, 0); + int step_trace[4]; for (int is = 0; is < npol; is++) { for (int is2 = 0; is2 < npol; is2++) { - step_trace[is * npol + is2] = this->_paraV->get_col_size(iat2) * is + is2; - // step_trace[is + is2 * npol] = this->_paraV->get_col_size(iat2) * is + is2; + step_trace[is * npol + is2] = tmp_ap.get_col_size() * is + is2; } } std::complex tmp[4]; double* target_DMR = tmp_matrix->get_pointer(); std::complex* tmp_DMR_pointer = tmp_DMR.data(); - for (int irow = 0; irow < this->_paraV->get_row_size(iat1); irow += 2) + for (int irow = 0; irow < tmp_ap.get_row_size(); irow += 2) { - for (int icol = 0; icol < this->_paraV->get_col_size(iat2); icol += 2) + for (int icol = 0; icol < tmp_ap.get_col_size(); icol += 2) { // catch the 4 spin component value of one orbital pair tmp[0] = tmp_DMR_pointer[icol + step_trace[0]]; @@ -636,8 +599,8 @@ void DensityMatrix, double>::cal_DMR() = -tmp[1].imag() + tmp[2].imag(); // (i * (rho_updown - rho_downup)).real() target_DMR[icol + step_trace[3]] = tmp[0].real() - tmp[3].real(); } - tmp_DMR_pointer += this->_paraV->get_col_size(iat2) * 2; - target_DMR += this->_paraV->get_col_size(iat2) * 2; + tmp_DMR_pointer += tmp_ap.get_col_size() * 2; + target_DMR += tmp_ap.get_col_size() * 2; } } } @@ -662,7 +625,7 @@ void DensityMatrix, double>::cal_DMR(const int ik) int ld_hk2 = 2 * ld_hk; for (int is = 1; is <= this->_nspin; ++is) { - int ik_begin = this->_nks * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = this->_nk * (is - 1); // jump this->_nk for spin_down if nspin==2 hamilt::HContainer* tmp_DMR = this->_DMR[is - 1]; // set zero since this function is called in every scf step tmp_DMR->set_zero(); @@ -769,14 +732,14 @@ void DensityMatrix::cal_DMR() int ld_hk = this->_paraV->nrow; for (int is = 1; is <= this->_nspin; ++is) { - int ik_begin = this->_nks * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = this->_nk * (is - 1); // jump this->_nk for spin_down if nspin==2 hamilt::HContainer* tmp_DMR = this->_DMR[is - 1]; // set zero since this function is called in every scf step tmp_DMR->set_zero(); #ifdef __DEBUG // assert(tmp_DMR->is_gamma_only() == true); - assert(this->_nks == 1); + assert(this->_nk == 1); #endif #ifdef _OPENMP #pragma omp parallel for @@ -892,9 +855,9 @@ void DensityMatrix::read_DMK(const std::string directory, const int ispi // quit the program or not. bool quit = false; - ModuleBase::CHECK_DOUBLE(ifs, this->_kv->kvec_d[ik].x, quit); - ModuleBase::CHECK_DOUBLE(ifs, this->_kv->kvec_d[ik].y, quit); - ModuleBase::CHECK_DOUBLE(ifs, this->_kv->kvec_d[ik].z, quit); + ModuleBase::CHECK_DOUBLE(ifs, this->_kvec_d[ik].x, quit); + ModuleBase::CHECK_DOUBLE(ifs, this->_kvec_d[ik].y, quit); + ModuleBase::CHECK_DOUBLE(ifs, this->_kvec_d[ik].z, quit); ModuleBase::CHECK_INT(ifs, this->_paraV->nrow); ModuleBase::CHECK_INT(ifs, this->_paraV->ncol); } // If file exist, read in data. @@ -904,7 +867,7 @@ void DensityMatrix::read_DMK(const std::string directory, const int ispi { for (int j = 0; j < this->_paraV->ncol; ++j) { - ifs >> this->_DMK[ik + this->_nks * (ispin - 1)][i * this->_paraV->ncol + j]; + ifs >> this->_DMK[ik + this->_nk * (ispin - 1)][i * this->_paraV->ncol + j]; } } ifs.close(); @@ -927,7 +890,7 @@ void DensityMatrix::write_DMK(const std::string directory, const { ModuleBase::WARNING("elecstate::write_dmk", "Can't create DENSITY MATRIX File!"); } - ofs << this->_kv->kvec_d[ik].x << " " << this->_kv->kvec_d[ik].y << " " << this->_kv->kvec_d[ik].z << std::endl; + ofs << this->_kvec_d[ik].x << " " << this->_kvec_d[ik].y << " " << this->_kvec_d[ik].z << std::endl; ofs << "\n " << this->_paraV->nrow << " " << this->_paraV->ncol << std::endl; ofs << std::setprecision(3); @@ -941,7 +904,7 @@ void DensityMatrix::write_DMK(const std::string directory, const { ofs << "\n"; } - ofs << " " << this->_DMK[ik + this->_nks * (ispin - 1)][i * this->_paraV->ncol + j]; + ofs << " " << this->_DMK[ik + this->_nk * (ispin - 1)][i * this->_paraV->ncol + j]; } } @@ -964,7 +927,7 @@ void DensityMatrix, double>::write_DMK(const std::string di { ModuleBase::WARNING("elecstate::write_dmk", "Can't create DENSITY MATRIX File!"); } - ofs << this->_kv->kvec_d[ik].x << " " << this->_kv->kvec_d[ik].y << " " << this->_kv->kvec_d[ik].z << std::endl; + ofs << this->_kvec_d[ik].x << " " << this->_kvec_d[ik].y << " " << this->_kvec_d[ik].z << std::endl; ofs << "\n " << this->_paraV->nrow << " " << this->_paraV->ncol << std::endl; ofs << std::setprecision(3); @@ -978,7 +941,7 @@ void DensityMatrix, double>::write_DMK(const std::string di { ofs << "\n"; } - ofs << " " << this->_DMK[ik + this->_nks * (ispin - 1)][i * this->_paraV->ncol + j].real(); + ofs << " " << this->_DMK[ik + this->_nk * (ispin - 1)][i * this->_paraV->ncol + j].real(); } } diff --git a/source/module_elecstate/module_dm/density_matrix.h b/source/module_elecstate/module_dm/density_matrix.h index 0bc28c6cadb..f712a8e4c3c 100644 --- a/source/module_elecstate/module_dm/density_matrix.h +++ b/source/module_elecstate/module_dm/density_matrix.h @@ -3,7 +3,6 @@ #include -#include "module_cell/klist.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" #include "module_hamilt_lcao/hamilt_lcaodft/record_adj.h" #include "module_hamilt_lcao/module_hcontainer/hcontainer.h" @@ -45,16 +44,20 @@ class DensityMatrix /** * @brief Constructor of class DensityMatrix for multi-k calculation - * @param _kv pointer of K_Vectors object * @param _paraV pointer of Parallel_Orbitals object - * @param nspin spin setting (1 - none spin; 2 - spin; 4 - SOC) + * @param nspin number of spin of the density matrix, set by user according to global nspin + * (usually {nspin_global -> nspin_dm} = {1->1, 2->2, 4->1}, but sometimes 2->1 like in LR-TDDFT) + * @param kvec_d direct coordinates of kpoints + * @param nk number of k-points, not always equal to K_Vectors::get_nks()/nspin_dm. + * it will be set to kvec_d.size() if the value is invalid */ - DensityMatrix(const K_Vectors* _kv, const Parallel_Orbitals* _paraV, const int nspin); + DensityMatrix(const Parallel_Orbitals* _paraV, const int nspin, const std::vector>& kvec_d, const int nk); /** * @brief Constructor of class DensityMatrix for gamma-only calculation, where kvector is not required * @param _paraV pointer of Parallel_Orbitals object - * @param nspin spin setting (1 - none spin; 2 - spin; 4 - SOC) + * @param nspin number of spin of the density matrix, set by user according to global nspin + * (usually {nspin_global -> nspin_dm} = {1->1, 2->2, 4->1}, but sometimes 2->1 like in LR-TDDFT) */ DensityMatrix(const Parallel_Orbitals* _paraV, const int nspin); @@ -169,7 +172,7 @@ class DensityMatrix */ const Parallel_Orbitals* get_paraV_pointer() const {return this->_paraV;} - const K_Vectors* get_kv_pointer() const {return this->_kv;} + const std::vector>& get_kvec_d() const { return this->_kvec_d; } /** * @brief calculate density matrix DMR from dm(k) using blas::axpy @@ -240,8 +243,8 @@ class DensityMatrix /** * @brief density matrix in k space, which is a vector[ik] - * DMK should be a [_nspin][_nks][i][j] matrix, - * whose size is _nspin * _nks * _paraV->get_nrow() * _paraV->get_ncol() + * DMK should be a [_nspin][_nk][i][j] matrix, + * whose size is _nspin * _nk * _paraV->get_nrow() * _paraV->get_ncol() */ // std::vector _DMK; std::vector> _DMK; @@ -249,7 +252,7 @@ class DensityMatrix /** * @brief K_Vectors object, which is used to get k-point information */ - const K_Vectors* _kv; + const std::vector> _kvec_d; /** * @brief Parallel_Orbitals object, which contain all information of 2D block cyclic distribution @@ -265,10 +268,10 @@ class DensityMatrix /** * @brief real number of k-points - * _nks is not equal to _kv->get_nks() when spin-polarization is considered - * _nks = kv->_nks / nspin + * _nk is not equal to _kv->get_nks() when spin-polarization is considered + * _nk = kv->get_nks() / nspin when nspin=2 */ - int _nks = 0; + int _nk = 0; }; diff --git a/source/module_elecstate/module_dm/test/prepare_unitcell.h b/source/module_elecstate/module_dm/test/prepare_unitcell.h index 6b295fc0f22..01f37ddd9cc 100644 --- a/source/module_elecstate/module_dm/test/prepare_unitcell.h +++ b/source/module_elecstate/module_dm/test/prepare_unitcell.h @@ -308,8 +308,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_elecstate/module_dm/test/test_cal_dm_R.cpp b/source/module_elecstate/module_dm/test/test_cal_dm_R.cpp index 8cb0ab7539d..c0802a4942d 100644 --- a/source/module_elecstate/module_dm/test/test_cal_dm_R.cpp +++ b/source/module_elecstate/module_dm/test/test_cal_dm_R.cpp @@ -74,7 +74,7 @@ class DMTest : public testing::Test init_parav(); } - void TearDown() + void TearDown() override { delete paraV; delete[] ucell.atoms[0].tau; @@ -129,7 +129,7 @@ TEST_F(DMTest, cal_DMR_test) kv->set_nks(nks); kv->kvec_d.resize(nks); // construct DM - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); // set this->_DMK for (int is = 1; is <= nspin; is++) { @@ -198,7 +198,7 @@ TEST_F(DMTest, cal_DMR_blas_double) kv->set_nks(nks); kv->kvec_d.resize(nks); // construct DM - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); // set this->_DMK for (int is = 1; is <= nspin; is++) { @@ -269,7 +269,7 @@ TEST_F(DMTest, cal_DMR_blas_complex) kv->kvec_d[1].x = 0.5; kv->kvec_d[3].x = 0.5; // construct DM - elecstate::DensityMatrix, double> DM(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); // set this->_DMK for (int is = 1; is <= nspin; is++) { diff --git a/source/module_elecstate/module_dm/test/test_dm_R_init.cpp b/source/module_elecstate/module_dm/test/test_dm_R_init.cpp index 72aabf01ec2..b917e0ac6c3 100644 --- a/source/module_elecstate/module_dm/test/test_dm_R_init.cpp +++ b/source/module_elecstate/module_dm/test/test_dm_R_init.cpp @@ -74,7 +74,7 @@ class DMTest : public testing::Test init_parav(); } - void TearDown() + void TearDown() override { delete paraV; delete[] ucell.atoms[0].tau; @@ -118,7 +118,7 @@ TEST_F(DMTest, DMInit1) // construct DM std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; std::cout << "nrow: " << paraV->nrow << " ncol:" << paraV->ncol << std::endl; - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, nks); // initialize this->_DMR Grid_Driver gd(0,0); DM.init_DMR(&gd, &ucell); @@ -145,7 +145,7 @@ TEST_F(DMTest, DMInit2) // construct DM std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; std::cout << "nrow: " << paraV->nrow << " ncol:" << paraV->ncol << std::endl; - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, nks); // initialize Record_adj using Grid_Driver Grid_Driver gd(0,0); Record_adj ra; @@ -208,12 +208,12 @@ TEST_F(DMTest, DMInit3) kv->kvec_d[1].x = 0.5; kv->kvec_d[3].x = 0.5; // construct a DM - elecstate::DensityMatrix, double> DM(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); Grid_Driver gd(0, 0); DM.init_DMR(&gd, &ucell); std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; // construct another DM - elecstate::DensityMatrix, double> DM1(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM1(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); DM1.init_DMR(*DM.get_DMR_pointer(1)); // compare EXPECT_EQ(DM1.get_DMR_pointer(2)->size_atom_pairs(), test_size * test_size); @@ -266,7 +266,7 @@ TEST_F(DMTest, DMInit4) } } // construct a DM from this HContainer - elecstate::DensityMatrix, double> DM(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); DM.init_DMR(*tmp_DMR); std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; // compare @@ -292,11 +292,11 @@ TEST_F(DMTest, saveDMR) kv->kvec_d[1].x = 0.5; kv->kvec_d[3].x = 0.5; // construct a DM - elecstate::DensityMatrix, double> DM(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); Grid_Driver gd(0, 0); DM.init_DMR(&gd, &ucell); // construct another DM - elecstate::DensityMatrix, double> DM_test(kv, paraV, nspin); + elecstate::DensityMatrix, double> DM_test(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); DM_test.init_DMR(*DM.get_DMR_pointer(1)); DM_test.save_DMR(); EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM.get_DMR_pointer(1)->get_nnr()); diff --git a/source/module_elecstate/module_dm/test/test_dm_constructor.cpp b/source/module_elecstate/module_dm/test/test_dm_constructor.cpp index f055c8b8def..8b4a9c7a6b7 100644 --- a/source/module_elecstate/module_dm/test/test_dm_constructor.cpp +++ b/source/module_elecstate/module_dm/test/test_dm_constructor.cpp @@ -127,7 +127,7 @@ TEST_F(DMTest, DMConstructor_nspin1) std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; std::cout << "nrow: " << paraV->nrow << " ncol:" << paraV->ncol << std::endl; int nspin = 1; - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, nks); // compare EXPECT_EQ(DM.get_DMK_nks(), kv->get_nks()); EXPECT_EQ(DM.get_DMK_nrow(), paraV->nrow); @@ -196,7 +196,7 @@ TEST_F(DMTest, DMConstructor_nspin2) // construct DM std::cout << "dim0: " << paraV->dim0 << " dim1:" << paraV->dim1 << std::endl; std::cout << "nrow: " << paraV->nrow << " ncol:" << paraV->ncol << std::endl; - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, kv->get_nks() / nspin); // compare EXPECT_EQ(DM.get_DMK_nks(), kv->get_nks()); EXPECT_EQ(DM.get_DMK_nrow(), paraV->nrow); diff --git a/source/module_elecstate/module_dm/test/test_dm_io.cpp b/source/module_elecstate/module_dm/test/test_dm_io.cpp index 87bf29b937a..901ea7bef80 100644 --- a/source/module_elecstate/module_dm/test/test_dm_io.cpp +++ b/source/module_elecstate/module_dm/test/test_dm_io.cpp @@ -142,7 +142,7 @@ TEST_F(DMTest, DMConstructor1) int nspin = 1; // construct DM std::cout << paraV->nrow << paraV->ncol << std::endl; - elecstate::DensityMatrix DM(kv, paraV, nspin); + elecstate::DensityMatrix DM(paraV, nspin, kv->kvec_d, kv->get_nks()); // read DMK std::string directory = "./support/"; for (int is = 1; is <= nspin; ++is) @@ -162,7 +162,7 @@ TEST_F(DMTest, DMConstructor1) } } // construct a new DM - elecstate::DensityMatrix DM1(kv, paraV, nspin); + elecstate::DensityMatrix DM1(paraV, nspin, kv->kvec_d, kv->get_nks()); directory = "./support/output"; for (int is = 1; is <= nspin; ++is) { diff --git a/source/module_elecstate/occupy.cpp b/source/module_elecstate/occupy.cpp index 508b72f2615..c4cc61213d6 100644 --- a/source/module_elecstate/occupy.cpp +++ b/source/module_elecstate/occupy.cpp @@ -228,7 +228,7 @@ void Occupy::gweights(const int nks, if (is != -1 && is != isk[ik]) continue; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { //================================ // Calculate the gaussian weights diff --git a/source/module_elecstate/potentials/efield.cpp b/source/module_elecstate/potentials/efield.cpp index d45cca67ce5..02970150958 100644 --- a/source/module_elecstate/potentials/efield.cpp +++ b/source/module_elecstate/potentials/efield.cpp @@ -159,7 +159,7 @@ double Efield::cal_ion_dipole(const UnitCell &cell, const double &bmod) { ion_charge += cell.atoms[it].na * cell.atoms[it].ncpp.zv; } - ion_dipole += (GlobalV::nelec - ion_charge) * saw_function(efield_pos_max, efield_pos_dec, Gatefield::zgate); + ion_dipole += (PARAM.inp.nelec - ion_charge) * saw_function(efield_pos_max, efield_pos_dec, Gatefield::zgate); } ion_dipole *= cell.lat0 / bmod * ModuleBase::FOUR_PI / cell.omega; diff --git a/source/module_elecstate/potentials/gatefield.cpp b/source/module_elecstate/potentials/gatefield.cpp index 3dd6eaa0120..3a59f54632c 100644 --- a/source/module_elecstate/potentials/gatefield.cpp +++ b/source/module_elecstate/potentials/gatefield.cpp @@ -37,7 +37,7 @@ void Gatefield::add_gatefield(double *vltot, { ion_charge += cell.atoms[it].na * cell.atoms[it].ncpp.zv; } - rho_surface = -(GlobalV::nelec - ion_charge) / area * ModuleBase::TWO_PI; + rho_surface = -(PARAM.inp.nelec - ion_charge) / area * ModuleBase::TWO_PI; double block_size = block_up - block_down; @@ -56,7 +56,7 @@ void Gatefield::add_gatefield(double *vltot, } } etotgatefield - = -ModuleBase::e2 * rho_surface * cell.lat0 / Efield::bmod * (factor + (GlobalV::nelec - ion_charge) / 12.0); + = -ModuleBase::e2 * rho_surface * cell.lat0 / Efield::bmod * (factor + (PARAM.inp.nelec - ion_charge) / 12.0); GlobalV::ofs_running << "\n\n Adding charged plate to compensate the charge of the system" << std::endl; ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "prefactor of the potential (Ry a.u.)", rho_surface); diff --git a/source/module_elecstate/potentials/pot_local.cpp b/source/module_elecstate/potentials/pot_local.cpp index 22061b08629..b387fc0328d 100644 --- a/source/module_elecstate/potentials/pot_local.cpp +++ b/source/module_elecstate/potentials/pot_local.cpp @@ -29,6 +29,12 @@ void PotLocal::cal_fixed_v(double *vl_pseudo // store the local pseudopotential } } + /// save the V_local at G=0 + if(this->rho_basis_->npw > 0) + { + *vl_of_0_ = vg[0].real(); + } + // recip2real should be a const function, but now it isn't // a dangerous usage appears here, which should be fix in the future. const_cast(this->rho_basis_)->recip2real(vg, vl_pseudo); diff --git a/source/module_elecstate/potentials/pot_local.h b/source/module_elecstate/potentials/pot_local.h index 327946bc856..df31ac471b4 100644 --- a/source/module_elecstate/potentials/pot_local.h +++ b/source/module_elecstate/potentials/pot_local.h @@ -12,8 +12,9 @@ class PotLocal : public PotBase public: PotLocal(const ModuleBase::matrix* vloc_in, // local pseduopotentials const ModuleBase::ComplexMatrix* sf_in, - const ModulePW::PW_Basis* rho_basis_in) - : vloc_(vloc_in), sf_(sf_in) + const ModulePW::PW_Basis* rho_basis_in, + double& vl_of_0) + : vloc_(vloc_in), sf_(sf_in), vl_of_0_(&vl_of_0) { assert(this->vloc_->nr == this->sf_->nr); this->rho_basis_ = rho_basis_in; @@ -24,6 +25,11 @@ class PotLocal : public PotBase void cal_fixed_v(double* vl_pseudo) override; + private: + + /// @brief save the value of vloc at G=0; this is a static member because there is only one vl(0) for all instances + double* vl_of_0_ = nullptr; + // std::vector vltot; const ModuleBase::matrix* vloc_ = nullptr; // local pseduopotentials diff --git a/source/module_elecstate/potentials/pot_xc.cpp b/source/module_elecstate/potentials/pot_xc.cpp index e2df13b7d6e..b04370b2f55 100644 --- a/source/module_elecstate/potentials/pot_xc.cpp +++ b/source/module_elecstate/potentials/pot_xc.cpp @@ -3,6 +3,10 @@ #include "module_base/timer.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#ifdef USE_LIBXC +#include "module_hamilt_general/module_xc/xc_functional_libxc.h" +#endif + namespace elecstate { @@ -20,7 +24,7 @@ void PotXC::cal_v_eff(const Charge*const chg, const UnitCell*const ucell, Module { #ifdef USE_LIBXC const std::tuple etxc_vtxc_v - = XC_Functional::v_xc_meta(nrxx_current, ucell->omega, ucell->tpiba, chg); + = XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), nrxx_current, ucell->omega, ucell->tpiba, chg); *(this->etxc_) = std::get<0>(etxc_vtxc_v); *(this->vtxc_) = std::get<1>(etxc_vtxc_v); v_eff += std::get<2>(etxc_vtxc_v); diff --git a/source/module_elecstate/potentials/potential_new.cpp b/source/module_elecstate/potentials/potential_new.cpp index acf402425fc..48b90f65b40 100644 --- a/source/module_elecstate/potentials/potential_new.cpp +++ b/source/module_elecstate/potentials/potential_new.cpp @@ -46,7 +46,7 @@ Potential::~Potential() } this->components.clear(); } - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.basis_type == "pw" && PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { delmem_sd_op()(gpu_ctx, s_veff_smooth); delmem_sd_op()(gpu_ctx, s_vofk_smooth); @@ -129,7 +129,7 @@ void Potential::allocate() this->vofk_smooth.create(PARAM.inp.nspin, nrxx_smooth); ModuleBase::Memory::record("Pot::vofk_smooth", sizeof(double) * PARAM.inp.nspin * nrxx_smooth); } - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.basis_type == "pw" && PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { resmem_sd_op()(gpu_ctx, s_veff_smooth, PARAM.inp.nspin * nrxx_smooth); resmem_sd_op()(gpu_ctx, s_vofk_smooth, PARAM.inp.nspin * nrxx_smooth); @@ -177,7 +177,7 @@ void Potential::update_from_charge(const Charge*const chg, const UnitCell*const } #endif - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.basis_type == "pw" && PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { castmem_d2s_h2d_op()(gpu_ctx, cpu_ctx, diff --git a/source/module_elecstate/potentials/potential_new.h b/source/module_elecstate/potentials/potential_new.h index f3ef3b4841e..d1f8e41f78a 100644 --- a/source/module_elecstate/potentials/potential_new.h +++ b/source/module_elecstate/potentials/potential_new.h @@ -169,6 +169,14 @@ class Potential : public PotBase return this->v_effective_fixed.data(); } + + /// @brief get the value of vloc at G=0; + /// @return vl(0) + double get_vl_of_0() const + { + return this->vl_of_0; + } + private: void cal_v_eff(const Charge*const chg, const UnitCell*const ucell, ModuleBase::matrix& v_eff) override; void cal_fixed_v(double* vl_pseudo) override; @@ -196,6 +204,8 @@ class Potential : public PotBase double* etxc_ = nullptr; double* vtxc_ = nullptr; + double vl_of_0 = 0.0; + std::vector components; const UnitCell* ucell_ = nullptr; diff --git a/source/module_elecstate/potentials/potential_types.cpp b/source/module_elecstate/potentials/potential_types.cpp index 36ac62040dc..bc151107984 100644 --- a/source/module_elecstate/potentials/potential_types.cpp +++ b/source/module_elecstate/potentials/potential_types.cpp @@ -27,7 +27,7 @@ PotBase* Potential::get_pot_type(const std::string& pot_type) { if(!PARAM.inp.use_paw) { - return new PotLocal(this->vloc_, &(this->structure_factors_->strucFac), this->rho_basis_); + return new PotLocal(this->vloc_, &(this->structure_factors_->strucFac), this->rho_basis_, this->vl_of_0); } else { diff --git a/source/module_elecstate/test/CMakeLists.txt b/source/module_elecstate/test/CMakeLists.txt index db0f194d397..98d07d71958 100644 --- a/source/module_elecstate/test/CMakeLists.txt +++ b/source/module_elecstate/test/CMakeLists.txt @@ -53,6 +53,7 @@ AddTest( LIBS parameter ${math_libs} planewave_serial base device SOURCES elecstate_pw_test.cpp ../elecstate_pw.cpp + ../elecstate_pw_cal_tau.cpp ../elecstate.cpp ../occupy.cpp ../../module_psi/psi.cpp diff --git a/source/module_elecstate/test/charge_mixing_test.cpp b/source/module_elecstate/test/charge_mixing_test.cpp index da199d8d10a..907596808cf 100644 --- a/source/module_elecstate/test/charge_mixing_test.cpp +++ b/source/module_elecstate/test/charge_mixing_test.cpp @@ -1024,3 +1024,41 @@ TEST_F(ChargeMixingTest, MixDivCombTest) EXPECT_EQ(datas2, nullptr); EXPECT_EQ(datahf2, nullptr); } + +TEST_F(ChargeMixingTest, SCFOscillationTest) +{ + Charge_Mixing CMtest; + int scf_nmax = 20; + int scf_os_ndim = 3; + double scf_os_thr = -0.05; + bool scf_oscillate = false; + std::vector drho(scf_nmax, 0.0); + std::vector scf_oscillate_ref(scf_nmax, false); + drho = {6.83639633652e-05, + 4.93523029235e-05, + 3.59230097735e-05, + 2.68356403913e-05, + 2.17490806464e-05, + 2.14231642508e-05, + 1.67507494811e-05, + 1.53575889539e-05, + 1.26504511554e-05, + 1.04762016224e-05, + 8.10000162918e-06, + 7.66427917682e-06, + 6.70112820094e-06, + 5.68594436664e-06, + 4.80120233733e-06, + 4.86519757184e-06, + 4.37855804356e-06, + 4.29922703412e-06, + 4.36398486331e-06, + 4.94224615955e-06}; + scf_oscillate_ref = {false,false,false,false,false,true,false,false,false,false, + false,false,true,false,false,true,true,true,true,true}; + for (int i = 1; i <= scf_nmax; ++i) + { + scf_oscillate = CMtest.if_scf_oscillate(i,drho[i-1],scf_os_ndim,scf_os_thr); + EXPECT_EQ(scf_oscillate, scf_oscillate_ref[i-1]); + } +} diff --git a/source/module_elecstate/test/charge_test.cpp b/source/module_elecstate/test/charge_test.cpp index 91a071b3707..f7802854278 100644 --- a/source/module_elecstate/test/charge_test.cpp +++ b/source/module_elecstate/test/charge_test.cpp @@ -48,7 +48,7 @@ void Set_GlobalV_Default() { PARAM.input.nspin = 1; PARAM.input.test_charge = 0; - GlobalV::nelec = 8; + PARAM.input.nelec = 8; } } // namespace elecstate @@ -164,7 +164,7 @@ TEST_F(ChargeTest, RenormalizeRho) charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(GlobalV::nelec, 8); + EXPECT_EQ(PARAM.input.nelec, 8); elecstate::tmp_ucell_omega = ucell->omega; charge->renormalize_rho(); EXPECT_NEAR(charge->sum_rho(), 8.0, 1e-10); @@ -184,7 +184,7 @@ TEST_F(ChargeTest, CheckNe) charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(GlobalV::nelec, 8); + EXPECT_EQ(PARAM.input.nelec, 8); elecstate::tmp_ucell_omega = ucell->omega; charge->renormalize_rho(); EXPECT_NEAR(charge->sum_rho(), 8.0, 1e-10); @@ -205,7 +205,7 @@ TEST_F(ChargeTest, SaveRhoBeforeSumBand) charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(GlobalV::nelec, 8); + EXPECT_EQ(PARAM.input.nelec, 8); elecstate::tmp_xc_func_type = 3; elecstate::tmp_ucell_omega = ucell->omega; charge->renormalize_rho(); diff --git a/source/module_elecstate/test/elecstate_base_test.cpp b/source/module_elecstate/test/elecstate_base_test.cpp index de015315baa..4a0950fb300 100644 --- a/source/module_elecstate/test/elecstate_base_test.cpp +++ b/source/module_elecstate/test/elecstate_base_test.cpp @@ -98,8 +98,6 @@ void Charge::check_rho() * - determine the number of electrons for spin up and down * - Constructor: elecstate::ElecState(charge, rhopw, bigpw) * - constructor ElecState using existing charge, rhopw, bigpw - * - CalNbands: elecstate::ElecState::cal_nbands() - * - calculate the number of bands * - InitKS: elecstate::ElecState::init_ks() * - initialize the elecstate for KS-DFT * - GetRho: elecstate::ElecState::getRho() @@ -128,11 +126,11 @@ class MockElecState : public ElecState void Set_GlobalV_Default() { PARAM.input.nspin = 1; - GlobalV::nelec = 10.0; - GlobalV::nupdown = 0.0; + PARAM.input.nelec = 10.0; + PARAM.input.nupdown = 0.0; PARAM.sys.two_fermi = false; - GlobalV::NBANDS = 6; - GlobalV::NLOCAL = 6; + PARAM.input.nbands = 6; + PARAM.sys.nlocal = 6; PARAM.input.esolver_type = "ksdft"; PARAM.input.lspinorb = false; PARAM.input.basis_type = "pw"; @@ -183,145 +181,6 @@ TEST_F(ElecStateTest, Constructor) delete charge; } -TEST_F(ElecStateTest, CalNbands) -{ - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 6); -} - -TEST_F(ElecStateTest, CalNbandsFractionElec) -{ - GlobalV::nelec = 9.5; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 6); -} - -TEST_F(ElecStateTest, CalNbandsSOC) -{ - PARAM.input.lspinorb = true; - GlobalV::NBANDS = 0; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 20); -} - -TEST_F(ElecStateTest, CalNbandsSDFT) -{ - PARAM.input.esolver_type = "sdft"; - EXPECT_NO_THROW(elecstate->cal_nbands()); -} - -TEST_F(ElecStateTest, CalNbandsLCAO) -{ - PARAM.input.basis_type = "lcao"; - EXPECT_NO_THROW(elecstate->cal_nbands()); -} - -TEST_F(ElecStateDeathTest, CalNbandsLCAOINPW) -{ - PARAM.input.basis_type = "lcao_in_pw"; - GlobalV::NLOCAL = GlobalV::NBANDS - 1; - testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->cal_nbands(), ::testing::ExitedWithCode(0), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("NLOCAL < NBANDS")); -} - -TEST_F(ElecStateDeathTest, CalNbandsWarning1) -{ - GlobalV::NBANDS = GlobalV::nelec / 2 - 1; - testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->cal_nbands(), ::testing::ExitedWithCode(0), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("Too few bands!")); -} - -TEST_F(ElecStateDeathTest, CalNbandsWarning2) -{ - PARAM.input.nspin = 2; - GlobalV::nupdown = 4.0; - elecstate->init_nelec_spin(); - testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->cal_nbands(), ::testing::ExitedWithCode(0), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("Too few spin up bands!")); -} - -TEST_F(ElecStateDeathTest, CalNbandsWarning3) -{ - PARAM.input.nspin = 2; - GlobalV::nupdown = -4.0; - elecstate->init_nelec_spin(); - testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->cal_nbands(), ::testing::ExitedWithCode(0), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("Too few spin down bands!")); -} - -TEST_F(ElecStateTest, CalNbandsSpin1) -{ - PARAM.input.nspin = 1; - GlobalV::NBANDS = 0; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 15); -} - -TEST_F(ElecStateTest, CalNbandsSpin1LCAO) -{ - PARAM.input.nspin = 1; - GlobalV::NBANDS = 0; - PARAM.input.basis_type = "lcao"; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 6); -} - -TEST_F(ElecStateTest, CalNbandsSpin4) -{ - PARAM.input.nspin = 4; - GlobalV::NBANDS = 0; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 30); -} - -TEST_F(ElecStateTest, CalNbandsSpin4LCAO) -{ - PARAM.input.nspin = 4; - GlobalV::NBANDS = 0; - PARAM.input.basis_type = "lcao"; - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 6); -} - -TEST_F(ElecStateTest, CalNbandsSpin2) -{ - PARAM.input.nspin = 2; - GlobalV::NBANDS = 0; - elecstate->init_nelec_spin(); - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 16); -} - -TEST_F(ElecStateTest, CalNbandsSpin2LCAO) -{ - PARAM.input.nspin = 2; - GlobalV::NBANDS = 0; - PARAM.input.basis_type = "lcao"; - elecstate->init_nelec_spin(); - elecstate->cal_nbands(); - EXPECT_EQ(GlobalV::NBANDS, 6); -} - -TEST_F(ElecStateDeathTest, CalNbandsGaussWarning) -{ - Occupy::use_gaussian_broadening = true; - EXPECT_TRUE(Occupy::gauss()); - GlobalV::NBANDS = 5; - testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->cal_nbands(), ::testing::ExitedWithCode(0), ""); - output = testing::internal::GetCapturedStdout(); - EXPECT_THAT(output, testing::HasSubstr("for smearing, num. of bands > num. of occupied bands")); - Occupy::use_gaussian_broadening = false; -} - TEST_F(ElecStateTest, InitKS) { Charge* charge = new Charge; @@ -334,9 +193,9 @@ TEST_F(ElecStateTest, InitKS) EXPECT_EQ(elecstate->bigpw, bigpw); EXPECT_EQ(elecstate->klist, klist); EXPECT_EQ(elecstate->ekb.nr, nk); - EXPECT_EQ(elecstate->ekb.nc, GlobalV::NBANDS); + EXPECT_EQ(elecstate->ekb.nc, PARAM.input.nbands); EXPECT_EQ(elecstate->wg.nr, nk); - EXPECT_EQ(elecstate->wg.nc, GlobalV::NBANDS); + EXPECT_EQ(elecstate->wg.nc, PARAM.input.nbands); delete klist; delete bigpw; delete rhopw; @@ -402,73 +261,73 @@ TEST_F(ElecStateTest, InitSCF) TEST_F(ElecStateTest,FixedWeights) { - EXPECT_EQ(GlobalV::NBANDS, 6); - GlobalV::nelec = 30; + EXPECT_EQ(PARAM.input.nbands, 6); + PARAM.input.nelec = 30; K_Vectors* klist = new K_Vectors; klist->set_nks(5); elecstate->klist = klist; - elecstate->wg.create(klist->get_nks(), GlobalV::NBANDS); + elecstate->wg.create(klist->get_nks(), PARAM.input.nbands); std::vector ocp_kb; - ocp_kb.resize(GlobalV::NBANDS*elecstate->klist->get_nks()); + ocp_kb.resize(PARAM.input.nbands*elecstate->klist->get_nks()); for (int i = 0; i < ocp_kb.size(); ++i) { ocp_kb[i] = 1.0; } - elecstate->fixed_weights(ocp_kb, GlobalV::NBANDS, GlobalV::nelec); + elecstate->fixed_weights(ocp_kb, PARAM.input.nbands, PARAM.input.nelec); EXPECT_EQ(elecstate->wg(0, 0), 1.0); - EXPECT_EQ(elecstate->wg(klist->get_nks()-1, GlobalV::NBANDS-1), 1.0); + EXPECT_EQ(elecstate->wg(klist->get_nks()-1, PARAM.input.nbands-1), 1.0); EXPECT_TRUE(elecstate->skip_weights); } TEST_F(ElecStateDeathTest,FixedWeightsWarning1) { - EXPECT_EQ(GlobalV::NBANDS, 6); - GlobalV::nelec = 30; + EXPECT_EQ(PARAM.input.nbands, 6); + PARAM.input.nelec = 30; K_Vectors* klist = new K_Vectors; klist->set_nks(5); elecstate->klist = klist; - elecstate->wg.create(klist->get_nks(), GlobalV::NBANDS); + elecstate->wg.create(klist->get_nks(), PARAM.input.nbands); std::vector ocp_kb; - ocp_kb.resize(GlobalV::NBANDS*elecstate->klist->get_nks()-1); + ocp_kb.resize(PARAM.input.nbands*elecstate->klist->get_nks()-1); for (int i = 0; i < ocp_kb.size(); ++i) { ocp_kb[i] = 1.0; } testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->fixed_weights(ocp_kb, GlobalV::NBANDS, GlobalV::nelec), ::testing::ExitedWithCode(0), ""); + EXPECT_EXIT(elecstate->fixed_weights(ocp_kb, PARAM.input.nbands, PARAM.input.nelec), ::testing::ExitedWithCode(0), ""); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("size of occupation array is wrong , please check ocp_set")); } TEST_F(ElecStateDeathTest,FixedWeightsWarning2) { - EXPECT_EQ(GlobalV::NBANDS, 6); - GlobalV::nelec = 29; + EXPECT_EQ(PARAM.input.nbands, 6); + PARAM.input.nelec = 29; K_Vectors* klist = new K_Vectors; klist->set_nks(5); elecstate->klist = klist; - elecstate->wg.create(klist->get_nks(), GlobalV::NBANDS); + elecstate->wg.create(klist->get_nks(), PARAM.input.nbands); std::vector ocp_kb; - ocp_kb.resize(GlobalV::NBANDS*elecstate->klist->get_nks()); + ocp_kb.resize(PARAM.input.nbands*elecstate->klist->get_nks()); for (int i = 0; i < ocp_kb.size(); ++i) { ocp_kb[i] = 1.0; } testing::internal::CaptureStdout(); - EXPECT_EXIT(elecstate->fixed_weights(ocp_kb, GlobalV::NBANDS, GlobalV::nelec), ::testing::ExitedWithCode(0), ""); + EXPECT_EXIT(elecstate->fixed_weights(ocp_kb, PARAM.input.nbands, PARAM.input.nelec), ::testing::ExitedWithCode(0), ""); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("total number of occupations is wrong , please check ocp_set")); } TEST_F(ElecStateTest, CalEBand) { - EXPECT_EQ(GlobalV::NBANDS, 6); + EXPECT_EQ(PARAM.input.nbands, 6); int nks = 5; - elecstate->wg.create(nks, GlobalV::NBANDS); - elecstate->ekb.create(nks, GlobalV::NBANDS); + elecstate->wg.create(nks, PARAM.input.nbands); + elecstate->ekb.create(nks, PARAM.input.nbands); for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.input.nbands; ++ib) { elecstate->ekb(ik, ib) = 1.0; elecstate->wg(ik, ib) = 2.0; @@ -514,19 +373,19 @@ TEST_F(ElecStateTest, CalculateWeightsIWeights) } elecstate->eferm.ef = 0.0; elecstate->klist = klist; - elecstate->ekb.create(nks, GlobalV::NBANDS); + elecstate->ekb.create(nks, PARAM.input.nbands); for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.input.nbands; ++ib) { elecstate->ekb(ik, ib) = 100.0; } } - elecstate->wg.create(nks, GlobalV::NBANDS); + elecstate->wg.create(nks, PARAM.input.nbands); elecstate->calculate_weights(); EXPECT_DOUBLE_EQ(elecstate->wg(0, 0), 2.0); - EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, GlobalV::nelec/2-1), 2.0); - EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, GlobalV::NBANDS-1), 0.0); + EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, PARAM.input.nelec/2-1), 2.0); + EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, PARAM.input.nbands-1), 0.0); EXPECT_DOUBLE_EQ(elecstate->eferm.ef, 100.0); delete klist; } @@ -571,10 +430,10 @@ TEST_F(ElecStateTest, CalculateWeightsIWeightsTwoFermi) elecstate->eferm.ef_up = 0.0; elecstate->eferm.ef_dw = 0.0; elecstate->klist = klist; - elecstate->ekb.create(nks, GlobalV::NBANDS); + elecstate->ekb.create(nks, PARAM.input.nbands); for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.input.nbands; ++ib) { if(ik < 5) { @@ -586,11 +445,11 @@ TEST_F(ElecStateTest, CalculateWeightsIWeightsTwoFermi) } } } - elecstate->wg.create(nks, GlobalV::NBANDS); + elecstate->wg.create(nks, PARAM.input.nbands); elecstate->calculate_weights(); EXPECT_DOUBLE_EQ(elecstate->wg(0, 0), 1.1); - EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, GlobalV::nelec/2-1), 1.0); - EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, GlobalV::NBANDS-1), 0.0); + EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, PARAM.input.nelec/2-1), 1.0); + EXPECT_DOUBLE_EQ(elecstate->wg(nks-1, PARAM.input.nbands-1), 0.0); EXPECT_DOUBLE_EQ(elecstate->eferm.ef_up, 100.0); EXPECT_DOUBLE_EQ(elecstate->eferm.ef_dw, 200.0); delete klist; @@ -615,23 +474,23 @@ TEST_F(ElecStateTest, CalculateWeightsGWeights) } elecstate->eferm.ef = 0.0; elecstate->klist = klist; - elecstate->ekb.create(nks, GlobalV::NBANDS); + elecstate->ekb.create(nks, PARAM.input.nbands); for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.input.nbands; ++ib) { elecstate->ekb(ik, ib) = 100.0; } } - elecstate->wg.create(nks, GlobalV::NBANDS); + elecstate->wg.create(nks, PARAM.input.nbands); elecstate->calculate_weights(); - // GlobalV::nelec = 10; - // GlobalV::NBANDS = 6; + // PARAM.input.nelec = 10; + // PARAM.input.nbands = 6; // nks = 5; // wg = 10/(5*6) = 0.33333333333 EXPECT_NEAR(elecstate->wg(0, 0), 0.33333333333, 1e-10); - EXPECT_NEAR(elecstate->wg(nks-1, GlobalV::nelec/2-1), 0.33333333333, 1e-10); - EXPECT_NEAR(elecstate->wg(nks-1, GlobalV::NBANDS-1), 0.33333333333,1e-10); + EXPECT_NEAR(elecstate->wg(nks-1, PARAM.input.nelec/2-1), 0.33333333333, 1e-10); + EXPECT_NEAR(elecstate->wg(nks-1, PARAM.input.nbands-1), 0.33333333333,1e-10); EXPECT_NEAR(elecstate->eferm.ef, 99.993159296503, 1e-10); delete klist; Occupy::use_gaussian_broadening = false; @@ -678,10 +537,10 @@ TEST_F(ElecStateTest, CalculateWeightsGWeightsTwoFermi) elecstate->eferm.ef_up = 0.0; elecstate->eferm.ef_dw = 0.0; elecstate->klist = klist; - elecstate->ekb.create(nks, GlobalV::NBANDS); + elecstate->ekb.create(nks, PARAM.input.nbands); for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.input.nbands; ++ib) { if(ik < 5) { @@ -693,15 +552,15 @@ TEST_F(ElecStateTest, CalculateWeightsGWeightsTwoFermi) } } } - elecstate->wg.create(nks, GlobalV::NBANDS); + elecstate->wg.create(nks, PARAM.input.nbands); elecstate->calculate_weights(); - // GlobalV::nelec = 10; - // GlobalV::NBANDS = 6; + // PARAM.input.nelec = 10; + // PARAM.input.nbands = 6; // nks = 10; // wg = 10/(10*6) = 0.16666666666 EXPECT_NEAR(elecstate->wg(0, 0), 0.16666666666, 1e-10); - EXPECT_NEAR(elecstate->wg(nks-1, GlobalV::nelec/2-1), 0.16666666666, 1e-10); - EXPECT_NEAR(elecstate->wg(nks-1, GlobalV::NBANDS-1), 0.16666666666, 1e-10); + EXPECT_NEAR(elecstate->wg(nks-1, PARAM.input.nelec/2-1), 0.16666666666, 1e-10); + EXPECT_NEAR(elecstate->wg(nks-1, PARAM.input.nbands-1), 0.16666666666, 1e-10); EXPECT_NEAR(elecstate->eferm.ef_up, 99.992717105890961, 1e-10); EXPECT_NEAR(elecstate->eferm.ef_dw, 199.99315929650351, 1e-10); delete klist; diff --git a/source/module_elecstate/test/elecstate_energy_test.cpp b/source/module_elecstate/test/elecstate_energy_test.cpp index a9d0c477c5d..3d145ea187e 100644 --- a/source/module_elecstate/test/elecstate_energy_test.cpp +++ b/source/module_elecstate/test/elecstate_energy_test.cpp @@ -77,11 +77,11 @@ class MockElecState : public ElecState PARAM.input.dft_plus_u = 0; // base class PARAM.input.nspin = 1; - GlobalV::nelec = 10.0; - GlobalV::nupdown = 0.0; + PARAM.input.nelec = 10.0; + PARAM.input.nupdown = 0.0; PARAM.sys.two_fermi = false; - GlobalV::NBANDS = 6; - GlobalV::NLOCAL = 6; + PARAM.input.nbands = 6; + PARAM.sys.nlocal = 6; PARAM.input.esolver_type = "ksdft"; PARAM.input.lspinorb = false; PARAM.input.basis_type = "pw"; @@ -193,10 +193,10 @@ TEST_F(ElecStateEnergyTest, CalBandgap) K_Vectors* klist = new K_Vectors; klist->set_nks(5); elecstate->klist = klist; - elecstate->ekb.create(klist->get_nks(), GlobalV::NBANDS); + elecstate->ekb.create(klist->get_nks(), PARAM.input.nbands); for (int ik = 0; ik < klist->get_nks(); ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.input.nbands; ib++) { elecstate->ekb(ik, ib) = ib; } @@ -230,10 +230,10 @@ TEST_F(ElecStateEnergyTest, CalBandgapUpDw) } } elecstate->klist = klist; - elecstate->ekb.create(klist->get_nks(), GlobalV::NBANDS); + elecstate->ekb.create(klist->get_nks(), PARAM.input.nbands); for (int ik = 0; ik < klist->get_nks(); ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.input.nbands; ib++) { if (ik < 3) { diff --git a/source/module_elecstate/test/elecstate_magnetism_test.cpp b/source/module_elecstate/test/elecstate_magnetism_test.cpp index 893ef36c5a7..b9266c7244b 100644 --- a/source/module_elecstate/test/elecstate_magnetism_test.cpp +++ b/source/module_elecstate/test/elecstate_magnetism_test.cpp @@ -75,7 +75,7 @@ TEST_F(MagnetismTest, ComputeMagnetizationS2) { PARAM.input.nspin = 2; PARAM.sys.two_fermi = false; - GlobalV::nelec = 10.0; + PARAM.input.nelec = 10.0; Charge* chr = new Charge; chr->nrxx = 100; diff --git a/source/module_elecstate/test/elecstate_print_test.cpp b/source/module_elecstate/test/elecstate_print_test.cpp index 748f44c2e94..5d24019660c 100644 --- a/source/module_elecstate/test/elecstate_print_test.cpp +++ b/source/module_elecstate/test/elecstate_print_test.cpp @@ -183,7 +183,7 @@ TEST_F(ElecStatePrintTest, PrintEigenvalueS4) TEST_F(ElecStatePrintTest, PrintBand) { PARAM.input.nspin = 1; - GlobalV::NBANDS = 2; + PARAM.input.nbands = 2; GlobalV::MY_RANK = 0; GlobalV::ofs_running.open("test.dat", std::ios::out); // print eigenvalue diff --git a/source/module_elecstate/test/elecstate_pw_test.cpp b/source/module_elecstate/test/elecstate_pw_test.cpp index 738af2b0441..b491da01a02 100644 --- a/source/module_elecstate/test/elecstate_pw_test.cpp +++ b/source/module_elecstate/test/elecstate_pw_test.cpp @@ -164,23 +164,23 @@ void Charge::check_rho() void Set_GlobalV_Default() { - PARAM.sys.device_flag = "cpu"; + PARAM.input.device = "cpu"; PARAM.input.precision = "double"; PARAM.sys.domag = false; PARAM.sys.domag_z = false; // Base class dependent PARAM.input.nspin = 1; - GlobalV::nelec = 10.0; - GlobalV::nupdown = 0.0; + PARAM.input.nelec = 10.0; + PARAM.input.nupdown = 0.0; PARAM.sys.two_fermi = false; - GlobalV::NBANDS = 6; - GlobalV::NLOCAL = 6; + PARAM.input.nbands = 6; + PARAM.sys.nlocal = 6; PARAM.input.esolver_type = "ksdft"; PARAM.input.lspinorb = false; PARAM.input.basis_type = "pw"; GlobalV::KPAR = 1; GlobalV::NPROC_IN_POOL = 1; - GlobalV::use_uspp = false; + PARAM.sys.use_uspp = false; } /************************************************ diff --git a/source/module_elecstate/test/potential_new_test.cpp b/source/module_elecstate/test/potential_new_test.cpp index b30a2b21cf6..e03619d867d 100644 --- a/source/module_elecstate/test/potential_new_test.cpp +++ b/source/module_elecstate/test/potential_new_test.cpp @@ -55,7 +55,7 @@ PotBase* Potential::get_pot_type(const std::string& pot_type) void Set_GlobalV_Default() { PARAM.input.nspin = 1; - PARAM.sys.device_flag = "cpu"; + PARAM.input.device = "cpu"; PARAM.input.precision = "double"; } } // namespace elecstate @@ -193,7 +193,7 @@ TEST_F(PotentialNewTest, ConstructorGPUDouble) { // this is just a trivial call to the GPU code rhopw->nrxx = 100; - PARAM.sys.device_flag = "gpu"; + PARAM.input.device = "gpu"; pot = new elecstate::Potential(rhopw, rhopw, ucell, vloc, structure_factors, etxc, vtxc); EXPECT_TRUE(pot->fixed_mode); EXPECT_TRUE(pot->dynamic_mode); @@ -206,7 +206,7 @@ TEST_F(PotentialNewTest, ConstructorGPUSingle) { // this is just a trivial call to the GPU code rhopw->nrxx = 100; - PARAM.sys.device_flag = "gpu"; + PARAM.input.device = "gpu"; PARAM.input.precision = "single"; pot = new elecstate::Potential(rhopw, rhopw, ucell, vloc, structure_factors, etxc, vtxc); EXPECT_TRUE(pot->fixed_mode); diff --git a/source/module_esolver/CMakeLists.txt b/source/module_esolver/CMakeLists.txt index 8ddf0949c3e..54f6d602d49 100644 --- a/source/module_esolver/CMakeLists.txt +++ b/source/module_esolver/CMakeLists.txt @@ -10,7 +10,6 @@ list(APPEND objects esolver_of.cpp esolver_of_interface.cpp esolver_of_tool.cpp - print_funcs.cpp pw_fun.cpp pw_init_after_vc.cpp pw_init_globalc.cpp diff --git a/source/module_esolver/cal_edm_tddft.cpp b/source/module_esolver/cal_edm_tddft.cpp index fab8a716e5a..a9cdd2c0515 100644 --- a/source/module_esolver/cal_edm_tddft.cpp +++ b/source/module_esolver/cal_edm_tddft.cpp @@ -2,7 +2,6 @@ #include "module_io/cal_r_overlap_R.h" #include "module_io/dipole_io.h" -#include "module_io/rho_io.h" #include "module_io/td_current_io.h" #include "module_io/write_HS.h" #include "module_io/write_HS_R.h" @@ -42,7 +41,7 @@ namespace ModuleESolver void ESolver_KS_LCAO_TDDFT::cal_edm_tddft() { // mohan add 2024-03-27 - const int nlocal = GlobalV::NLOCAL; + const int nlocal = PARAM.globalv.nlocal; assert(nlocal >= 0); dynamic_cast>*>(this->pelec) diff --git a/source/module_esolver/esolver.cpp b/source/module_esolver/esolver.cpp index 28473d1d99c..74ef101579a 100644 --- a/source/module_esolver/esolver.cpp +++ b/source/module_esolver/esolver.cpp @@ -23,11 +23,6 @@ extern "C" namespace ModuleESolver { -void ESolver::printname() -{ - std::cout << classname << std::endl; -} - std::string determine_type() { std::string esolver_type = "none"; @@ -100,7 +95,7 @@ std::string determine_type() GlobalV::ofs_running << " The esolver type has been set to : " << esolver_type << std::endl; - auto device_info = PARAM.globalv.device_flag; + auto device_info = PARAM.inp.device; for (char &c : device_info) { @@ -112,11 +107,11 @@ std::string determine_type() if (GlobalV::MY_RANK == 0) { std::cout << " RUNNING WITH DEVICE : " << device_info << " / " - << base_device::information::get_device_info(PARAM.globalv.device_flag) << std::endl; + << base_device::information::get_device_info(PARAM.inp.device) << std::endl; } GlobalV::ofs_running << "\n RUNNING WITH DEVICE : " << device_info << " / " - << base_device::information::get_device_info(PARAM.globalv.device_flag) << std::endl; + << base_device::information::get_device_info(PARAM.inp.device) << std::endl; return esolver_type; } @@ -132,7 +127,7 @@ ESolver* init_esolver(const Input_para& inp, UnitCell& ucell) if (esolver_type == "ksdft_pw") { #if ((defined __CUDA) || (defined __ROCM)) - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { @@ -153,6 +148,17 @@ ESolver* init_esolver(const Input_para& inp, UnitCell& ucell) return new ESolver_KS_PW, base_device::DEVICE_CPU>(); } } + else if (esolver_type == "sdft_pw") + { + // if (PARAM.inp.precision == "single") + // { + // return new ESolver_SDFT_PW, base_device::DEVICE_CPU>(); + // } + // else + // { + return new ESolver_SDFT_PW, base_device::DEVICE_CPU>(); + // } + } #ifdef __LCAO else if (esolver_type == "ksdft_lip") { @@ -187,13 +193,8 @@ ESolver* init_esolver(const Input_para& inp, UnitCell& ucell) else if (esolver_type == "lr_lcao") { // use constructor rather than Init function to initialize reference (instead of pointers) to ucell - if (PARAM.globalv.gamma_only_local){ - return new LR::ESolver_LR(inp, ucell); - } else if (PARAM.inp.nspin < 2) { - return new LR::ESolver_LR, double>(inp, ucell); - } else { - throw std::runtime_error("LR-TDDFT is not implemented for spin polarized case"); -} + if (PARAM.globalv.gamma_only_local) { return new LR::ESolver_LR(inp, ucell); } + else { return new LR::ESolver_LR, double>(inp, ucell); } } else if (esolver_type == "ksdft_lr_lcao") { @@ -235,10 +236,6 @@ ESolver* init_esolver(const Input_para& inp, UnitCell& ucell) return p_esolver_lr; } #endif - else if (esolver_type == "sdft_pw") - { - return new ESolver_SDFT_PW(); - } else if(esolver_type == "ofdft") { return new ESolver_OF(); diff --git a/source/module_esolver/esolver.h b/source/module_esolver/esolver.h index 1092be261e3..b4be298ed62 100644 --- a/source/module_esolver/esolver.h +++ b/source/module_esolver/esolver.h @@ -41,28 +41,8 @@ class ESolver //! calcualte stress of given cell virtual void cal_stress(ModuleBase::matrix& stress) = 0; + bool conv_esolver = true; // whether esolver is converged - // Print current classname. - void printname(); - - // temporarily - // get iterstep used in current scf - virtual int get_niter() - { - return 0; - } - - // get maxniter used in current scf - virtual int get_maxniter() - { - return 0; - } - - // get conv_elec used in current scf - virtual bool get_conv_elec() - { - return false; - } std::string classname; }; diff --git a/source/module_esolver/esolver_fp.cpp b/source/module_esolver/esolver_fp.cpp index a12d050040a..453b14cd632 100644 --- a/source/module_esolver/esolver_fp.cpp +++ b/source/module_esolver/esolver_fp.cpp @@ -1,13 +1,18 @@ #include "esolver_fp.h" #include "module_base/global_variable.h" +#include "module_elecstate/module_charge/symmetry_rho.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_io/cif_io.h" #include "module_io/cube_io.h" +#include "module_io/json_output/init_info.h" +#include "module_io/json_output/output_info.h" #include "module_io/output_log.h" +#include "module_io/print_info.h" +#include "module_io/rhog_io.h" #include "module_io/write_elecstat_pot.h" +#include "module_io/write_elf.h" #include "module_parameter/parameter.h" -#include "module_io/rhog_io.h" -#include "module_io/cif_io.h" namespace ModuleESolver { @@ -15,11 +20,16 @@ namespace ModuleESolver ESolver_FP::ESolver_FP() { // pw_rho = new ModuleBase::PW_Basis(); - pw_rho = new ModulePW::PW_Basis_Big(PARAM.globalv.device_flag, PARAM.inp.precision); - + // LCAO basis doesn't support GPU acceleration on FFT currently + std::string fft_device = PARAM.inp.device; + if(PARAM.inp.basis_type == "lcao") + { + fft_device = "cpu"; + } + pw_rho = new ModulePW::PW_Basis_Big(fft_device, PARAM.inp.precision); if ( PARAM.globalv.double_grid) { - pw_rhod = new ModulePW::PW_Basis_Big(PARAM.globalv.device_flag, PARAM.inp.precision); + pw_rhod = new ModulePW::PW_Basis_Big(fft_device, PARAM.inp.precision); } else { @@ -109,7 +119,7 @@ void ESolver_FP::before_all_runners(const Input_para& inp, UnitCell& cell) "data_?"); //! 4) print some information - this->print_rhofft(inp, GlobalV::ofs_running); + ModuleIO::print_rhofft(this->pw_rhod, this->pw_rho, this->pw_big, GlobalV::ofs_running); //! 5) initialize the charge extrapolation method if necessary this->CE.Init_CE(PARAM.inp.nspin, GlobalC::ucell.nat, this->pw_rhod->nrxx, inp.chg_extrap); @@ -121,10 +131,10 @@ void ESolver_FP::before_all_runners(const Input_para& inp, UnitCell& cell) void ESolver_FP::after_scf(const int istep) { // 0) output convergence information - ModuleIO::output_convergence_after_scf(this->conv_elec, this->pelec->f_en.etot); + ModuleIO::output_convergence_after_scf(this->conv_esolver, this->pelec->f_en.etot); // 1) write fermi energy - ModuleIO::output_efermi(this->conv_elec, this->pelec->eferm.ef); + ModuleIO::output_efermi(this->conv_esolver, this->pelec->eferm.ef); // 2) update delta rho for charge extrapolation CE.update_delta_rho(GlobalC::ucell, &(this->chr), &(this->sf)); @@ -148,21 +158,12 @@ void ESolver_FP::after_scf(const int istep) this->pw_rhod->real2recip(this->pelec->charge->rho_save[is], this->pelec->charge->rhog_save[is]); } std::string fn =PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, data, is, PARAM.inp.nspin, istep, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell), PARAM.inp.out_chg[1], @@ -170,21 +171,12 @@ void ESolver_FP::after_scf(const int istep) if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { fn =PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_TAU.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->kin_r_save[is], is, PARAM.inp.nspin, istep, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell)); } @@ -216,21 +208,12 @@ void ESolver_FP::after_scf(const int istep) { std::string fn =PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_POT.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->pot->get_effective_v(is), is, PARAM.inp.nspin, istep, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, 0.0, // efermi &(GlobalC::ucell), 3, // precision @@ -252,7 +235,41 @@ void ESolver_FP::after_scf(const int istep) &(GlobalC::ucell), this->pelec->pot->get_fixed_v()); } + + // 5) write ELF + if (PARAM.inp.out_elf[0] > 0) + { + this->pelec->charge->cal_elf = true; + Symmetry_rho srho; + for (int is = 0; is < PARAM.inp.nspin; is++) + { + srho.begin(is, *(this->pelec->charge), this->pw_rhod, GlobalC::ucell.symm); + } + + std::string out_dir =PARAM.globalv.global_out_dir; + ModuleIO::write_elf( +#ifdef __MPI + this->pw_big->bz, + this->pw_big->nbz, +#endif + out_dir, + istep, + PARAM.inp.nspin, + this->pelec->charge->rho, + this->pelec->charge->kin_r, + this->pw_rhod, + &(GlobalC::ucell), + PARAM.inp.out_elf[1]); + } } + + // #ifdef __RAPIDJSON + // // add Json of efermi energy converge + // Json::add_output_efermi_converge(this->pelec->eferm.ef * ModuleBase::Ry_to_eV, this->conv_esolver); + // // add nkstot,nkstot_ibz to output json + // int Jnkstot = this->pelec->klist->get_nkstot(); + // Json::add_nkstot(Jnkstot); + // #endif //__RAPIDJSON } void ESolver_FP::init_after_vc(const Input_para& inp, UnitCell& cell) @@ -324,135 +341,4 @@ void ESolver_FP::init_after_vc(const Input_para& inp, UnitCell& cell) return; } -void ESolver_FP::print_rhofft(const Input_para& inp, std::ofstream& ofs) -{ - std::cout << " UNIFORM GRID DIM : " << pw_rho->nx << " * " << pw_rho->ny << " * " << pw_rho->nz << std::endl; - std::cout << " UNIFORM GRID DIM(BIG) : " << pw_big->nbx << " * " << pw_big->nby << " * " << pw_big->nbz - << std::endl; - if ( PARAM.globalv.double_grid) - { - std::cout << " UNIFORM GRID DIM(DENSE) : " << pw_rhod->nx << " * " << pw_rhod->ny << " * " << pw_rhod->nz - << std::endl; - } - - ofs << "\n\n\n\n"; - ofs << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" - ">>>>" - << std::endl; - ofs << " | " - " |" - << std::endl; - ofs << " | Setup plane waves of charge/potential: " - " |" - << std::endl; - ofs << " | Use the energy cutoff and the lattice vectors to generate the " - " |" - << std::endl; - ofs << " | dimensions of FFT grid. The number of FFT grid on each " - "processor |" - << std::endl; - ofs << " | is 'nrxx'. The number of plane wave basis in reciprocal space " - "is |" - << std::endl; - ofs << " | different for charege/potential and wave functions. We also set " - " |" - << std::endl; - ofs << " | the 'sticks' for the parallel of FFT. The number of plane waves " - " |" - << std::endl; - ofs << " | is 'npw' in each processor. " - " |" - << std::endl; - ofs << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" - "<<<<" - << std::endl; - ofs << "\n\n\n\n"; - ofs << "\n SETUP THE PLANE WAVE BASIS" << std::endl; - - double ecut = 4 * PARAM.inp.ecutwfc; - if (inp.nx * inp.ny * inp.nz > 0) - { - ecut = this->pw_rho->gridecut_lat * this->pw_rho->tpiba2; - ofs << "use input fft dimensions for wave functions." << std::endl; - ofs << "calculate energy cutoff from nx, ny, nz:" << std::endl; - } - - ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for charge/potential (unit:Ry)", ecut); - - ModuleBase::GlobalFunc::OUT(ofs, - "fft grid for charge/potential", - this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz); - ModuleBase::GlobalFunc::OUT(ofs, "fft grid division", pw_big->bx, pw_big->by, pw_big->bz); - ModuleBase::GlobalFunc::OUT(ofs, "big fft grid for charge/potential", pw_big->nbx, pw_big->nby, pw_big->nbz); - ModuleBase::GlobalFunc::OUT(ofs, "nbxx", pw_big->nbxx); - ModuleBase::GlobalFunc::OUT(ofs, "nrxx", this->pw_rho->nrxx); - - ofs << "\n SETUP PLANE WAVES FOR CHARGE/POTENTIAL" << std::endl; - ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", this->pw_rho->npwtot); - ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", this->pw_rho->nstot); - - ofs << "\n PARALLEL PW FOR CHARGE/POTENTIAL" << std::endl; - ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; - - for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) - { - ofs << " " << std::setw(8) << i + 1 << std::setw(15) << this->pw_rho->nst_per[i] << std::setw(15) - << this->pw_rho->npw_per[i] << std::endl; - } - ofs << " --------------- sum -------------------" << std::endl; - ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << this->pw_rho->nstot << std::setw(15) - << this->pw_rho->npwtot << std::endl; - - ModuleBase::GlobalFunc::OUT(ofs, "number of |g|", this->pw_rho->ngg); - ModuleBase::GlobalFunc::OUT(ofs, "max |g|", this->pw_rho->gg_uniq[this->pw_rho->ngg - 1]); - ModuleBase::GlobalFunc::OUT(ofs, "min |g|", this->pw_rho->gg_uniq[0]); - - if ( PARAM.globalv.double_grid) - { - ofs << std::endl; - ofs << std::endl; - ofs << std::endl; - double ecut = PARAM.inp.ecutrho; - if (inp.ndx * inp.ndy * inp.ndz > 0) - { - ecut = this->pw_rhod->gridecut_lat * this->pw_rhod->tpiba2; - ofs << "use input fft dimensions for the dense part of charge " - "density." - << std::endl; - ofs << "calculate energy cutoff from ndx, ndy, ndz:" << std::endl; - } - ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for dense charge/potential (unit:Ry)", ecut); - - ModuleBase::GlobalFunc::OUT(ofs, - "fft grid for dense charge/potential", - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz); - - ModuleBase::GlobalFunc::OUT(ofs, "nrxx", this->pw_rhod->nrxx); - - ofs << "\n SETUP PLANE WAVES FOR dense CHARGE/POTENTIAL" << std::endl; - ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", this->pw_rhod->npwtot); - ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", this->pw_rhod->nstot); - - ofs << "\n PARALLEL PW FOR dense CHARGE/POTENTIAL" << std::endl; - ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; - - for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) - { - ofs << " " << std::setw(8) << i + 1 << std::setw(15) << this->pw_rhod->nst_per[i] << std::setw(15) - << this->pw_rhod->npw_per[i] << std::endl; - } - ofs << " --------------- sum -------------------" << std::endl; - ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << this->pw_rhod->nstot << std::setw(15) - << this->pw_rhod->npwtot << std::endl; - - ModuleBase::GlobalFunc::OUT(ofs, "number of |g|", this->pw_rhod->ngg); - ModuleBase::GlobalFunc::OUT(ofs, "max |g|", this->pw_rhod->gg_uniq[this->pw_rhod->ngg - 1]); - ModuleBase::GlobalFunc::OUT(ofs, "min |g|", this->pw_rhod->gg_uniq[0]); - } -} - } // namespace ModuleESolver diff --git a/source/module_esolver/esolver_fp.h b/source/module_esolver/esolver_fp.h index 4d5fcf5c410..02aa386dd85 100644 --- a/source/module_esolver/esolver_fp.h +++ b/source/module_esolver/esolver_fp.h @@ -61,19 +61,12 @@ namespace ModuleESolver //! K points in Brillouin zone K_Vectors kv; - bool conv_elec; // If electron density is converged in scf. - protected: //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. virtual void after_scf(const int istep); //! Charge extrapolation Charge_Extra CE; - - private: - - //! Print charge density using FFT - void print_rhofft(const Input_para& inp, std::ofstream &ofs); }; } diff --git a/source/module_esolver/esolver_ks.cpp b/source/module_esolver/esolver_ks.cpp index 0bc5c6ad0d7..da4c4c2c3cf 100644 --- a/source/module_esolver/esolver_ks.cpp +++ b/source/module_esolver/esolver_ks.cpp @@ -1,18 +1,20 @@ #include "esolver_ks.h" #include +#include #ifdef __MPI #include #else #include #endif #include "module_base/timer.h" +#include "module_cell/cal_atoms_info.h" #include "module_io/json_output/init_info.h" +#include "module_io/json_output/output_info.h" +#include "module_io/output_log.h" #include "module_io/print_info.h" #include "module_io/write_istate_info.h" #include "module_parameter/parameter.h" - -#include //--------------Temporary---------------- #include "module_base/global_variable.h" #include "module_hamilt_lcao/module_dftu/dftu.h" @@ -22,9 +24,6 @@ #include "module_base/parallel_common.h" #include "module_cell/module_paw/paw_cell.h" #endif -#include "module_io/json_output/output_info.h" - -#include "print_funcs.h" // mohan add 2024-07-27 namespace ModuleESolver { @@ -55,7 +54,13 @@ ESolver_KS::ESolver_KS() // pw_rho = new ModuleBase::PW_Basis(); // temporary, it will be removed - pw_wfc = new ModulePW::PW_Basis_K_Big(PARAM.globalv.device_flag, PARAM.inp.precision); + std::string fft_device = PARAM.inp.device; + // LCAO basis doesn't support GPU acceleration on FFT currently + if(PARAM.inp.basis_type == "lcao") + { + fft_device = "cpu"; + } + pw_wfc = new ModulePW::PW_Basis_K_Big(fft_device, PARAM.inp.precision); ModulePW::PW_Basis_K_Big* tmp = static_cast(pw_wfc); // should not use INPUT here, mohan 2024-05-12 @@ -145,7 +150,7 @@ void ESolver_KS::before_all_runners(const Input_para& inp, UnitCell& if (GlobalV::MY_RANK == 0) { - std::ifstream ifa(PARAM.inp.stru_file.c_str(), std::ios::in); + std::ifstream ifa(PARAM.globalv.global_in_stru.c_str(), std::ios::in); if (!ifa) { ModuleBase::WARNING_QUIT("set_libpaw_files", "can not open stru file"); @@ -187,13 +192,12 @@ void ESolver_KS::before_all_runners(const Input_para& inp, UnitCell& } delete[] atom_coord; delete[] atom_type; + CalAtomsInfo ca; + ca.cal_atoms_info(ucell.atoms, ucell.ntype, PARAM); } #endif /// End PAW - //! 3) calculate the electron number - ucell.cal_nelec(GlobalV::nelec); - //! 4) it has been established that // xc_func is same for all elements, therefore // only the first one if used @@ -221,7 +225,7 @@ void ESolver_KS::before_all_runners(const Input_para& inp, UnitCell& ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); //! 7) print information - Print_Info::setup_parameters(ucell, this->kv); + ModuleIO::setup_parameters(ucell, this->kv); //! 8) new plane wave basis, fft grids, etc. #ifdef __MPI @@ -258,7 +262,7 @@ void ESolver_KS::before_all_runners(const Input_para& inp, UnitCell& this->pw_wfc->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); - Print_functions::print_wfcfft(inp, *this->pw_wfc, GlobalV::ofs_running); + ModuleIO::print_wfcfft(inp, *this->pw_wfc, GlobalV::ofs_running); //! 10) initialize the real-space uniform grid for FFT and parallel //! distribution of plane waves @@ -419,7 +423,7 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT SCF"); bool firstscf = true; - this->conv_elec = false; + this->conv_esolver = false; this->niter = this->maxniter; // 4) SCF iterations @@ -429,7 +433,7 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) for (int iter = 1; iter <= this->maxniter; ++iter) { // 5) write head - this->write_head(GlobalV::ofs_running, istep, iter); + ModuleIO::write_head(GlobalV::ofs_running, istep, iter, this->basisname); #ifdef __MPI auto iterstart = MPI_Wtime(); @@ -449,7 +453,7 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) drho, PARAM.inp.pw_diag_thr, diag_ethr, - GlobalV::nelec); + PARAM.inp.nelec); } else if (PARAM.inp.esolver_type == "sdft") { @@ -462,7 +466,7 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) drho, PARAM.inp.pw_diag_thr, diag_ethr, - GlobalV::NBANDS, + PARAM.inp.nbands, esolver_KS_ne); } @@ -487,7 +491,7 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) // double drho = this->estate.caldr2(); // EState should be used after it is constructed. - drho = p_chgmix->get_drho(pelec->charge, GlobalV::nelec); + drho = p_chgmix->get_drho(pelec->charge, PARAM.inp.nelec); double hsolver_error = 0.0; if (firstscf) { @@ -495,10 +499,10 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) hsolver_error = hsolver::cal_hsolve_error(PARAM.inp.basis_type, PARAM.inp.esolver_type, diag_ethr, - GlobalV::nelec); - + PARAM.inp.nelec); + // The error of HSolver is larger than drho, - // so a more precise HSolver should be excuconv_elected. + // so a more precise HSolver should be executed. if (hsolver_error > drho) { diag_ethr = hsolver::reset_diag_ethr(GlobalV::ofs_running, @@ -508,16 +512,16 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) hsolver_error, drho, diag_ethr, - GlobalV::nelec); + PARAM.inp.nelec); this->hamilt2density(istep, iter, diag_ethr); - drho = p_chgmix->get_drho(pelec->charge, GlobalV::nelec); + drho = p_chgmix->get_drho(pelec->charge, PARAM.inp.nelec); hsolver_error = hsolver::cal_hsolve_error(PARAM.inp.basis_type, PARAM.inp.esolver_type, diag_ethr, - GlobalV::nelec); + PARAM.inp.nelec); } } // mixing will restart at this->p_chgmix->mixing_restart steps @@ -527,6 +531,11 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) this->p_chgmix->mixing_restart_step = iter + 1; } + if (PARAM.inp.scf_os_stop) // if oscillation is detected, SCF will stop + { + this->oscillate_esolver = this->p_chgmix->if_scf_oscillate(iter, drho, PARAM.inp.scf_os_ndim, PARAM.inp.scf_os_thr); + } + // drho will be 0 at this->p_chgmix->mixing_restart step, which is // not ground state bool not_restart_step = !(iter == this->p_chgmix->mixing_restart_step && PARAM.inp.mixing_restart > 0.0); @@ -540,11 +549,29 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) } #endif - this->conv_elec = (drho < this->scf_thr && not_restart_step && is_U_converged); + this->conv_esolver = (drho < this->scf_thr && not_restart_step && is_U_converged); + + // add energy threshold for SCF convergence + if (this->scf_ene_thr > 0.0) + { + // calculate energy of output charge density + this->update_pot(istep, iter); + this->pelec->cal_energies(2); // 2 means Kohn-Sham functional + // now, etot_old is the energy of input density, while etot is the energy of output density + this->pelec->f_en.etot_delta = this->pelec->f_en.etot - this->pelec->f_en.etot_old; + // output etot_delta + GlobalV::ofs_running << " DeltaE_womix = " << this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV << " eV" << std::endl; + if (iter > 1 && this->conv_esolver == 1) // only check when density is converged + { + // update the convergence flag + this->conv_esolver + = (std::abs(this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV) < this->scf_ene_thr); + } + } // If drho < hsolver_error in the first iter or drho < scf_thr, we // do not change rho. - if (drho < hsolver_error || this->conv_elec) + if (drho < hsolver_error || this->conv_esolver) { if (drho < hsolver_error) { @@ -577,17 +604,17 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) } #ifdef __MPI MPI_Bcast(&drho, 1, MPI_DOUBLE, 0, PARAPW_WORLD); - MPI_Bcast(&this->conv_elec, 1, MPI_DOUBLE, 0, PARAPW_WORLD); + MPI_Bcast(&this->conv_esolver, 1, MPI_DOUBLE, 0, PARAPW_WORLD); MPI_Bcast(pelec->charge->rho[0], this->pw_rhod->nrxx, MPI_DOUBLE, 0, PARAPW_WORLD); #endif // 9) update potential // Hamilt should be used after it is constructed. - // this->phamilt->update(conv_elec); + // this->phamilt->update(conv_esolver); this->update_pot(istep, iter); // 10) finish scf iterations - this->iter_finish(iter); + this->iter_finish(istep, iter); #ifdef __MPI double duration = (double)(MPI_Wtime() - iterstart); #else @@ -601,9 +628,9 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) double dkin = 0.0; // for meta-GGA if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { - dkin = p_chgmix->get_dkin(pelec->charge, GlobalV::nelec); + dkin = p_chgmix->get_dkin(pelec->charge, PARAM.inp.nelec); } - this->print_iter(iter, drho, dkin, duration, diag_ethr); + this->pelec->print_etot(this->conv_esolver, iter, drho, dkin, duration, PARAM.inp.printe, diag_ethr); // 12) Json, need to be moved to somewhere else #ifdef __RAPIDJSON @@ -617,9 +644,13 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) #endif //__RAPIDJSON // 13) check convergence - if (this->conv_elec) + if (this->conv_esolver || this->oscillate_esolver) { this->niter = iter; + if (this->oscillate_esolver) + { + std::cout << " !! Density oscillation is found, STOP HERE !!" << std::endl; + } break; } @@ -630,29 +661,18 @@ void ESolver_KS::runner(const int istep, UnitCell& ucell) } } // end scf iterations std::cout << " >> Leave SCF iteration.\n * * * * * *" << std::endl; -#ifdef __RAPIDJSON - // 14) add Json of efermi energy converge - Json::add_output_efermi_converge(this->pelec->eferm.ef * ModuleBase::Ry_to_eV, this->conv_elec); -#endif //__RAPIDJSON // 15) after scf ModuleBase::timer::tick(this->classname, "after_scf"); this->after_scf(istep); ModuleBase::timer::tick(this->classname, "after_scf"); - // 16) Json again -#ifdef __RAPIDJSON - // add nkstot,nkstot_ibz to output json - int Jnkstot = this->pelec->klist->get_nkstot(); - Json::add_nkstot(Jnkstot); -#endif //__RAPIDJSON - ModuleBase::timer::tick(this->classname, "runner"); return; }; template -void ESolver_KS::iter_finish(int& iter) +void ESolver_KS::iter_finish(const int istep, int& iter) { // 1 means Harris-Foulkes functional // 2 means Kohn-Sham functional @@ -664,13 +684,6 @@ void ESolver_KS::iter_finish(int& iter) } this->pelec->f_en.etot_delta = this->pelec->f_en.etot - this->pelec->f_en.etot_old; this->pelec->f_en.etot_old = this->pelec->f_en.etot; - - // add a energy threshold for SCF convergence - if (this->conv_elec == 0) // only check when density is not converged - { - this->conv_elec - = (iter != 1 && std::abs(this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV) < this->scf_ene_thr); - } } //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. @@ -685,88 +698,13 @@ void ESolver_KS::after_scf(const int istep) { this->pelec->print_eigenvalue(GlobalV::ofs_running); } -} - -//------------------------------------------------------------------------------ -//! the 8th function of ESolver_KS: print_head -//! mohan add 2024-05-12 -//------------------------------------------------------------------------------ -template -void ESolver_KS::print_head() -{ - std::cout << " " << std::setw(7) << "ITER"; - - if (PARAM.inp.nspin == 2) - { - std::cout << std::setw(10) << "TMAG"; - std::cout << std::setw(10) << "AMAG"; - } - - std::cout << std::setw(15) << "ETOT(eV)"; - std::cout << std::setw(15) << "EDIFF(eV)"; - std::cout << std::setw(11) << "DRHO"; - - if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) - { - std::cout << std::setw(11) << "DKIN"; - } - - std::cout << std::setw(11) << "TIME(s)" << std::endl; -} - -//------------------------------------------------------------------------------ -//! the 8th function of ESolver_KS: print_iter -//! mohan add 2024-05-12 -//------------------------------------------------------------------------------ -template -void ESolver_KS::print_iter(const int iter, - const double drho, - const double dkin, - const double duration, - const double ethr) -{ - this->pelec->print_etot(this->conv_elec, iter, drho, dkin, duration, PARAM.inp.printe, ethr); -} - -//------------------------------------------------------------------------------ -//! the 9th function of ESolver_KS: write_head -//! mohan add 2024-05-12 -//------------------------------------------------------------------------------ -template -void ESolver_KS::write_head(std::ofstream& ofs_running, const int istep, const int iter) -{ - ofs_running << "\n " << this->basisname << " ALGORITHM --------------- ION=" << std::setw(4) << istep + 1 - << " ELEC=" << std::setw(4) << iter << "--------------------------------\n"; -} - -//------------------------------------------------------------------------------ -//! the 10th function of ESolver_KS: getnieter -//! mohan add 2024-05-12 -//------------------------------------------------------------------------------ -template -int ESolver_KS::get_niter() -{ - return this->niter; -} - -//------------------------------------------------------------------------------ -//! the 11th function of ESolver_KS: get_maxniter -//! tqzhao add 2024-05-15 -//------------------------------------------------------------------------------ -template -int ESolver_KS::get_maxniter() -{ - return this->maxniter; -} - -//------------------------------------------------------------------------------ -//! the 12th function of ESolver_KS: get_conv_elec -//! tqzhao add 2024-05-15 -//------------------------------------------------------------------------------ -template -bool ESolver_KS::get_conv_elec() -{ - return this->conv_elec; + // #ifdef __RAPIDJSON + // // add Json of efermi energy converge + // Json::add_output_efermi_converge(this->pelec->eferm.ef * ModuleBase::Ry_to_eV, this->conv_esolver); + // // add nkstot,nkstot_ibz to output json + // int Jnkstot = this->pelec->klist->get_nkstot(); + // Json::add_nkstot(Jnkstot); + // #endif //__RAPIDJSON } //------------------------------------------------------------------------------ diff --git a/source/module_esolver/esolver_ks.h b/source/module_esolver/esolver_ks.h index 583be4910db..bcdb9abc941 100644 --- a/source/module_esolver/esolver_ks.h +++ b/source/module_esolver/esolver_ks.h @@ -50,24 +50,15 @@ class ESolver_KS : public ESolver_FP // calculate electron states from a specific Hamiltonian virtual void hamilt2estates(const double ethr){}; - // get current step of Ionic simulation - virtual int get_niter() override; - - // get maxniter used in current scf - virtual int get_maxniter() override; - - // get conv_elec used in current scf - virtual bool get_conv_elec() override; - - protected: - //! Something to do before SCF iterations. + protected: + //! Something to do before SCF iterations. virtual void before_scf(const int istep) {}; //! Something to do before hamilt2density function in each iter loop. virtual void iter_init(const int istep, const int iter) {}; //! Something to do after hamilt2density function in each iter loop. - virtual void iter_finish(int& iter); + virtual void iter_finish(const int istep, int& iter); //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. virtual void after_scf(const int istep) override; @@ -75,31 +66,7 @@ class ESolver_KS : public ESolver_FP //! It should be replaced by a function in Hamilt Class virtual void update_pot(const int istep, const int iter) {}; - protected: - - // Print the headline on the screen: - // ITER ETOT(eV) EDIFF(eV) DRHO TIME(s) - void print_head(); - - // Print inforamtion in each iter - // G1 -3.435545e+03 0.000000e+00 3.607e-01 2.862e-01 - // for metaGGA - // ITER ETOT(eV) EDIFF(eV) DRHO DKIN TIME(s) - // G1 -3.435545e+03 0.000000e+00 3.607e-01 3.522e-01 2.862e-01 - void print_iter( - const int iter, - const double drho, - const double dkin, - const double duration, - const double ethr); - - // Write the headline in the running_log file - // "PW/LCAO" ALGORITHM --------------- ION= 1 ELEC= 1-------------------------------- - void write_head( - std::ofstream& ofs_running, - const int istep, - const int iter); - + protected: //! Hamiltonian hamilt::Hamilt* p_hamilt = nullptr; @@ -112,13 +79,10 @@ class ESolver_KS : public ESolver_FP // wavefunction coefficients psi::Psi* psi = nullptr; - protected: - - std::string basisname; //PW or LCAO - - void print_wfcfft(const Input_para& inp, std::ofstream& ofs); - - double esolver_KS_ne = 0.0; + protected: + std::string basisname; // PW or LCAO + double esolver_KS_ne = 0.0; + bool oscillate_esolver = false; // whether esolver is oscillated }; } // end of namespace #endif diff --git a/source/module_esolver/esolver_ks_lcao.cpp b/source/module_esolver/esolver_ks_lcao.cpp index 735ef0dda10..580d5a91ca7 100644 --- a/source/module_esolver/esolver_ks_lcao.cpp +++ b/source/module_esolver/esolver_ks_lcao.cpp @@ -19,8 +19,6 @@ #include "module_parameter/parameter.h" //--------------temporary---------------------------- -#include - #include "module_base/global_function.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" #include "module_elecstate/module_charge/symmetry_rho.h" @@ -30,9 +28,11 @@ #include "module_hamilt_lcao/module_dftu/dftu.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_io/print_info.h" + +#include #ifdef __EXX -#include "module_ri/RPA_LRI.h" #include "module_io/restart_exx_csr.h" +#include "module_ri/RPA_LRI.h" #endif #ifdef __DEEPKS @@ -69,18 +69,18 @@ ESolver_KS_LCAO::ESolver_KS_LCAO() this->basisname = "LCAO"; #ifdef __EXX // 1. currently this initialization must be put in constructor rather than `before_all_runners()` - // because the latter is not reused by ESolver_LCAO_TDDFT, + // because the latter is not reused by ESolver_LCAO_TDDFT, // which cause the failure of the subsequent procedure reused by ESolver_LCAO_TDDFT // 2. always construct but only initialize when if(cal_exx) is true // because some members like two_level_step are used outside if(cal_exx) if (GlobalC::exx_info.info_ri.real_number) { - this->exx_lri_double = std::make_shared>(GlobalC::exx_info.info_ri); + this->exx_lri_double = std::make_shared>(GlobalC::exx_info.info_ri, GlobalC::exx_info.info_ewald); this->exd = std::make_shared>(exx_lri_double); } else { - this->exx_lri_complex = std::make_shared>>(GlobalC::exx_info.info_ri); + this->exx_lri_complex = std::make_shared>>(GlobalC::exx_info.info_ri, GlobalC::exx_info.info_ewald); this->exc = std::make_shared>>(exx_lri_complex); } #endif @@ -133,11 +133,10 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell } // 1.3) Setup k-points according to symmetry. - this->kv - .set(ucell.symm, PARAM.inp.kpoint_file, PARAM.inp.nspin, ucell.G, ucell.latvec, GlobalV::ofs_running); + this->kv.set(ucell.symm, PARAM.inp.kpoint_file, PARAM.inp.nspin, ucell.G, ucell.latvec, GlobalV::ofs_running); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); - Print_Info::setup_parameters(ucell, this->kv); + ModuleIO::setup_parameters(ucell, this->kv); } else { @@ -151,26 +150,25 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell if (this->pelec == nullptr) { // TK stands for double and complex? - this->pelec = new elecstate::ElecStateLCAO( - &(this->chr), // use which parameter? - &(this->kv), - this->kv.get_nks(), - &(this->GG), // mohan add 2024-04-01 - &(this->GK), // mohan add 2024-04-01 - this->pw_rho, - this->pw_big); + this->pelec = new elecstate::ElecStateLCAO(&(this->chr), // use which parameter? + &(this->kv), + this->kv.get_nks(), + &(this->GG), // mohan add 2024-04-01 + &(this->GK), // mohan add 2024-04-01 + this->pw_rho, + this->pw_big); } // 3) init LCAO basis // reading the localized orbitals/projectors // construct the interpolation tables. - LCAO_domain::init_basis_lcao(this->pv, - inp.onsite_radius, - inp.lcao_ecut, - inp.lcao_dk, - inp.lcao_dr, - inp.lcao_rmax, - ucell, + LCAO_domain::init_basis_lcao(this->pv, + inp.onsite_radius, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + ucell, two_center_bundle_, orb_); //------------------init Basis_lcao---------------------- @@ -178,8 +176,7 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell // 5) initialize density matrix // DensityMatrix is allocated here, DMK is also initialized here // DMR is not initialized here, it will be constructed in each before_scf - dynamic_cast*>(this->pelec) - ->init_DM(&this->kv, &(this->pv), PARAM.inp.nspin); + dynamic_cast*>(this->pelec)->init_DM(&this->kv, &(this->pv), PARAM.inp.nspin); // this function should be removed outside of the function if (PARAM.inp.calculation == "get_S") @@ -196,22 +193,30 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell #ifdef __EXX // 7) initialize exx // PLEASE simplify the Exx_Global interface - if (PARAM.inp.calculation == "scf" || PARAM.inp.calculation == "relax" - || PARAM.inp.calculation == "cell-relax" + if (PARAM.inp.calculation == "scf" || PARAM.inp.calculation == "relax" || PARAM.inp.calculation == "cell-relax" || PARAM.inp.calculation == "md") { if (GlobalC::exx_info.info_global.cal_exx) { XC_Functional::set_xc_first_loop(ucell); // initialize 2-center radial tables for EXX-LRI - if (GlobalC::exx_info.info_ri.real_number) { this->exx_lri_double->init(MPI_COMM_WORLD, this->kv, orb_); } - else { this->exx_lri_complex->init(MPI_COMM_WORLD, this->kv, orb_); } + if (GlobalC::exx_info.info_ri.real_number) + { + this->exx_lri_double->init(MPI_COMM_WORLD, this->kv, orb_); + this->exd->exx_before_all_runners(this->kv, GlobalC::ucell, this->pv); + } + else + { + this->exx_lri_complex->init(MPI_COMM_WORLD, this->kv, orb_); + this->exc->exx_before_all_runners(this->kv, GlobalC::ucell, this->pv); + } } } #endif // 8) initialize DFT+U - if (PARAM.inp.dft_plus_u) { + if (PARAM.inp.dft_plus_u) + { GlobalC::dftu.init(ucell, &this->pv, this->kv.get_nks(), orb_); } @@ -248,7 +253,7 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell // 14) set occupations if (PARAM.inp.ocp) { - this->pelec->fixed_weights(PARAM.inp.ocp_kb, GlobalV::NBANDS, GlobalV::nelec); + this->pelec->fixed_weights(PARAM.inp.ocp_kb, PARAM.inp.nbands, PARAM.inp.nelec); } // 15) if kpar is not divisible by nks, print a warning @@ -256,19 +261,19 @@ void ESolver_KS_LCAO::before_all_runners(const Input_para& inp, UnitCell { if (this->kv.get_nks() % GlobalV::KPAR_LCAO != 0) { - ModuleBase::WARNING("ESolver_KS_LCAO::before_all_runners", - "nks is not divisible by kpar."); + ModuleBase::WARNING("ESolver_KS_LCAO::before_all_runners", "nks is not divisible by kpar."); std::cout << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - "%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; - std::cout << " Warning: nks (" << this->kv.get_nks() << ") is not divisible by kpar (" - << GlobalV::KPAR_LCAO << ")." << std::endl; + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%%%%%%%%%%%%%%%" + << std::endl; + std::cout << " Warning: nks (" << this->kv.get_nks() << ") is not divisible by kpar (" << GlobalV::KPAR_LCAO + << ")." << std::endl; std::cout << " This may lead to poor load balance. It is strongly suggested to" << std::endl; std::cout << " set nks to be divisible by kpar, but if this is really what" << std::endl; std::cout << " you want, please ignore this warning." << std::endl; std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - "%%%%%%%%%%%%\n"; + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%\n"; } } @@ -416,7 +421,7 @@ void ESolver_KS_LCAO::after_all_runners() GlobalV::ofs_running << "\n Output bands in file: " << ss2.str() << std::endl; ModuleIO::nscf_band(is, ss2.str(), - GlobalV::NBANDS, + PARAM.inp.nbands, 0.0, PARAM.inp.out_band[1], this->pelec->ekb, @@ -443,32 +448,33 @@ void ESolver_KS_LCAO::after_all_runners() GlobalC::Pkpoints, GlobalC::ucell, this->pelec->eferm, - GlobalV::NBANDS, + PARAM.inp.nbands, this->p_hamilt); } if (PARAM.inp.out_mat_xc) { ModuleIO::write_Vxc(PARAM.inp.nspin, - GlobalV::NLOCAL, - GlobalV::DRANK, - &this->pv, - *this->psi, - GlobalC::ucell, - this->sf, - *this->pw_rho, - *this->pw_rhod, - GlobalC::ppcell.vloc, - *this->pelec->charge, - this->GG, - this->GK, - this->kv, - orb_.cutoffs(), - this->pelec->wg, - GlobalC::GridD + PARAM.globalv.nlocal, + GlobalV::DRANK, + &this->pv, + *this->psi, + GlobalC::ucell, + this->sf, + *this->pw_rho, + *this->pw_rhod, + GlobalC::ppcell.vloc, + *this->pelec->charge, + this->GG, + this->GK, + this->kv, + orb_.cutoffs(), + this->pelec->wg, + GlobalC::GridD #ifdef __EXX - , this->exx_lri_double ? &this->exx_lri_double->Hexxs : nullptr - , this->exx_lri_complex ? &this->exx_lri_complex->Hexxs : nullptr + , + this->exx_lri_double ? &this->exx_lri_double->Hexxs : nullptr, + this->exx_lri_complex ? &this->exx_lri_complex->Hexxs : nullptr #endif ); } @@ -476,26 +482,27 @@ void ESolver_KS_LCAO::after_all_runners() if (PARAM.inp.out_eband_terms) { ModuleIO::write_eband_terms(PARAM.inp.nspin, - GlobalV::NLOCAL, - GlobalV::DRANK, - &this->pv, - *this->psi, - GlobalC::ucell, - this->sf, - *this->pw_rho, - *this->pw_rhod, - GlobalC::ppcell.vloc, - *this->pelec->charge, - this->GG, - this->GK, - this->kv, - this->pelec->wg, - GlobalC::GridD, - orb_.cutoffs(), - this->two_center_bundle_ + PARAM.globalv.nlocal, + GlobalV::DRANK, + &this->pv, + *this->psi, + GlobalC::ucell, + this->sf, + *this->pw_rho, + *this->pw_rhod, + GlobalC::ppcell.vloc, + *this->pelec->charge, + this->GG, + this->GK, + this->kv, + this->pelec->wg, + GlobalC::GridD, + orb_.cutoffs(), + this->two_center_bundle_ #ifdef __EXX - , this->exx_lri_double ? &this->exx_lri_double->Hexxs : nullptr - , this->exx_lri_complex ? &this->exx_lri_complex->Hexxs : nullptr + , + this->exx_lri_double ? &this->exx_lri_double->Hexxs : nullptr, + this->exx_lri_complex ? &this->exx_lri_complex->Hexxs : nullptr #endif ); } @@ -503,7 +510,6 @@ void ESolver_KS_LCAO::after_all_runners() ModuleBase::timer::tick("ESolver_KS_LCAO", "after_all_runners"); } - //------------------------------------------------------------------------------ //! the 10th function of ESolver_KS_LCAO: iter_init //! mohan add 2024-05-11 @@ -619,11 +625,17 @@ void ESolver_KS_LCAO::iter_init(const int istep, const int iter) // calculate exact-exchange if (GlobalC::exx_info.info_ri.real_number) { - this->exd->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), this->kv, iter); + this->exd->exx_eachiterinit(istep, + *dynamic_cast*>(this->pelec)->get_DM(), + this->kv, + iter); } else { - this->exc->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), this->kv, iter); + this->exc->exx_eachiterinit(istep, + *dynamic_cast*>(this->pelec)->get_DM(), + this->kv, + iter); } #endif @@ -706,8 +718,7 @@ void ESolver_KS_LCAO::hamilt2density(int istep, int iter, double ethr) this->pelec->f_en.demet = 0.0; hsolver::HSolverLCAO hsolver_lcao_obj(&(this->pv), PARAM.inp.ks_solver); - hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, PARAM.inp.ks_solver, false); - + hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, false); if (PARAM.inp.out_bandgap) { @@ -810,7 +821,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) ModuleBase::TITLE("ESolver_KS_LCAO", "update_pot"); // 1) print Hamiltonian and Overlap matrix - if (this->conv_elec || iter == PARAM.inp.scf_nmax) + if (this->conv_esolver || iter == PARAM.inp.scf_nmax) { if (!PARAM.globalv.gamma_only_local && (PARAM.inp.out_mat_hs[0] || PARAM.inp.deepks_v_delta)) { @@ -818,7 +829,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) } for (int ik = 0; ik < this->kv.get_nks(); ++ik) { - if (PARAM.inp.out_mat_hs[0]|| PARAM.inp.deepks_v_delta) + if (PARAM.inp.out_mat_hs[0] || PARAM.inp.deepks_v_delta) { this->p_hamilt->updateHk(ik); } @@ -836,7 +847,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) { ModuleIO::save_mat(istep, h_mat.p, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, bit, PARAM.inp.out_mat_hs[1], 1, @@ -847,7 +858,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) GlobalV::DRANK); ModuleIO::save_mat(istep, s_mat.p, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, bit, PARAM.inp.out_mat_hs[1], 1, @@ -858,7 +869,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) GlobalV::DRANK); } #ifdef __DEEPKS - if(PARAM.inp.deepks_out_labels && PARAM.inp.deepks_v_delta) + if (PARAM.inp.deepks_out_labels && PARAM.inp.deepks_v_delta) { DeePKS_domain::save_h_mat(h_mat.p, this->pv.nloc); } @@ -868,7 +879,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) } // 2) print wavefunctions - if (elecstate::ElecStateLCAO::out_wfc_lcao && (this->conv_elec || iter == PARAM.inp.scf_nmax) + if (elecstate::ElecStateLCAO::out_wfc_lcao && (this->conv_esolver || iter == PARAM.inp.scf_nmax) && (istep % PARAM.inp.out_interval == 0)) { ModuleIO::write_wfc_nao(elecstate::ElecStateLCAO::out_wfc_lcao, @@ -880,8 +891,7 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) istep); } - - if (!this->conv_elec) + if (!this->conv_esolver) { if (PARAM.inp.nspin == 4) { @@ -906,12 +916,12 @@ void ESolver_KS_LCAO::update_pot(const int istep, const int iter) //! 5) cal_MW? (why put it here?) //------------------------------------------------------------------------------ template -void ESolver_KS_LCAO::iter_finish(int& iter) +void ESolver_KS_LCAO::iter_finish(const int istep, int& iter) { ModuleBase::TITLE("ESolver_KS_LCAO", "iter_finish"); // call iter_finish() of ESolver_KS - ESolver_KS::iter_finish(iter); + ESolver_KS::iter_finish(istep, iter); // 1) mix density matrix if mixing_restart + mixing_dmr + not first // mixing_restart at every iter @@ -933,72 +943,11 @@ void ESolver_KS_LCAO::iter_finish(int& iter) #ifdef __EXX // 3) save exx matrix - int two_level_step = GlobalC::exx_info.info_ri.real_number ? this->exd->two_level_step : this->exc->two_level_step; - - if (GlobalC::restart.info_save.save_H && two_level_step > 0 - && (!GlobalC::exx_info.info_global.separate_loop || iter == 1)) // to avoid saving the same value repeatedly + if (GlobalC::exx_info.info_global.cal_exx) { - ////////// for Add_Hexx_Type::k - /* - hamilt::HS_Matrix_K Hexxk_save(&this->pv, 1); - for (int ik = 0; ik < this->kv.get_nks(); ++ik) { - Hexxk_save.set_zero_hk(); - - hamilt::OperatorEXX> opexx_save(&Hexxk_save, - nullptr, - this->kv); - - opexx_save.contributeHk(ik); - - GlobalC::restart.save_disk("Hexx", - ik, - this->pv.get_local_size(), - Hexxk_save.get_hk()); - }*/ - ////////// for Add_Hexx_Type:R - const std::string& restart_HR_path = GlobalC::restart.folder + "HexxR" + std::to_string(GlobalV::MY_RANK); - if (GlobalC::exx_info.info_ri.real_number) - { - ModuleIO::write_Hexxs_csr(restart_HR_path, GlobalC::ucell, this->exd->get_Hexxs()); - } - else - { - ModuleIO::write_Hexxs_csr(restart_HR_path, GlobalC::ucell, this->exc->get_Hexxs()); - } - if (GlobalV::MY_RANK == 0) - { - GlobalC::restart.save_disk("Eexx", 0, 1, &this->pelec->f_en.exx); - } - } - - if (GlobalC::exx_info.info_global.cal_exx && this->conv_elec) - { - // Kerker mixing does not work for the density matrix. - // In the separate loop case, it can still work in the subsequent inner loops where Hexx(DM) is fixed. - // In the non-separate loop case where Hexx(DM) is updated in every iteration of the 2nd loop, it should be closed. - if (!GlobalC::exx_info.info_global.separate_loop) { this->p_chgmix->close_kerker_gg0(); } - if (GlobalC::exx_info.info_ri.real_number) - { - this->conv_elec = this->exd->exx_after_converge( - *this->p_hamilt, - *dynamic_cast*>(this->pelec)->get_DM(), - this->kv, - PARAM.inp.nspin, - iter, - this->pelec->f_en.etot, - this->scf_ene_thr); - } - else - { - this->conv_elec = this->exc->exx_after_converge( - *this->p_hamilt, - *dynamic_cast*>(this->pelec)->get_DM(), - this->kv, - PARAM.inp.nspin, - iter, - this->pelec->f_en.etot, - this->scf_ene_thr); - } + GlobalC::exx_info.info_ri.real_number ? + this->exd->exx_iter_finish(this->kv, GlobalC::ucell, *this->p_hamilt, *this->pelec, *this->p_chgmix, this->scf_ene_thr, iter, istep, this->conv_esolver) : + this->exc->exx_iter_finish(this->kv, GlobalC::ucell, *this->p_hamilt, *this->pelec, *this->p_chgmix, this->scf_ene_thr, iter, istep, this->conv_esolver); } #endif @@ -1017,21 +966,12 @@ void ESolver_KS_LCAO::iter_finish(int& iter) data = this->pelec->charge->rho_save[is]; } std::string fn = PARAM.globalv.global_out_dir + "/tmp_SPIN" + std::to_string(is + 1) + "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, data, is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell), 3, @@ -1039,21 +979,12 @@ void ESolver_KS_LCAO::iter_finish(int& iter) if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { fn = PARAM.globalv.global_out_dir + "/tmp_SPIN" + std::to_string(is + 1) + "_TAU.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->kin_r_save[is], is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell)); } @@ -1070,7 +1001,7 @@ void ESolver_KS_LCAO::iter_finish(int& iter) } // 6) use the converged occupation matrix for next MD/Relax SCF calculation - if (PARAM.inp.dft_plus_u && this->conv_elec) + if (PARAM.inp.dft_plus_u && this->conv_esolver) { GlobalC::dftu.initialed_locale = true; } @@ -1096,11 +1027,16 @@ template void ESolver_KS_LCAO::after_scf(const int istep) { ModuleBase::TITLE("ESolver_KS_LCAO", "after_scf"); - - // 1) call after_scf() of ESolver_KS + // 1) calculate the kinetic energy density tau, sunliang 2024-09-18 + if (PARAM.inp.out_elf[0] > 0) + { + this->pelec->cal_tau(*(this->psi)); + } + + // 2) call after_scf() of ESolver_KS ESolver_KS::after_scf(istep); - // 2) write density matrix for sparse matrix + // 3) write density matrix for sparse matrix ModuleIO::write_dmr(dynamic_cast*>(this->pelec)->get_DM()->get_DMR_vector(), this->pv, PARAM.inp.out_dm1, @@ -1108,7 +1044,7 @@ void ESolver_KS_LCAO::after_scf(const int istep) PARAM.inp.out_app_flag, istep); - // 3) write density matrix + // 4) write density matrix if (PARAM.inp.out_dm) { std::vector efermis(PARAM.inp.nspin == 2 ? 2 : 1); @@ -1125,13 +1061,17 @@ void ESolver_KS_LCAO::after_scf(const int istep) } #ifdef __EXX - // 4) write Hexx matrix for NSCF (see `out_chg` in docs/advanced/input_files/input-main.md) - if (GlobalC::exx_info.info_global.cal_exx && PARAM.inp.out_chg[0] && istep % PARAM.inp.out_interval == 0) // Peize Lin add if 2022.11.14 + // 5) write Hexx matrix for NSCF (see `out_chg` in docs/advanced/input_files/input-main.md) + if (GlobalC::exx_info.info_global.cal_exx && PARAM.inp.out_chg[0] + && istep % PARAM.inp.out_interval == 0) // Peize Lin add if 2022.11.14 { const std::string file_name_exx = PARAM.globalv.global_out_dir + "HexxR" + std::to_string(GlobalV::MY_RANK); - if (GlobalC::exx_info.info_ri.real_number) { + if (GlobalC::exx_info.info_ri.real_number) + { ModuleIO::write_Hexxs_csr(file_name_exx, GlobalC::ucell, this->exd->get_Hexxs()); - } else { + } + else + { ModuleIO::write_Hexxs_csr(file_name_exx, GlobalC::ucell, this->exc->get_Hexxs()); } } @@ -1145,7 +1085,7 @@ void ESolver_KS_LCAO::after_scf(const int istep) LDI.out_deepks_labels(this->pelec->f_en.etot, this->pelec->klist->get_nks(), GlobalC::ucell.nat, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, this->pelec->ekb, this->pelec->klist->kvec_d, GlobalC::ucell, @@ -1163,9 +1103,9 @@ void ESolver_KS_LCAO::after_scf(const int istep) // 11) write rpa information if (PARAM.inp.rpa) { - // ModuleRPA::DFT_RPA_interface - // rpa_interface(GlobalC::exx_info.info_global); - RPA_LRI rpa_lri_double(GlobalC::exx_info.info_ri); + // ModuleRPA::DFT_RPA_interface rpa_interface(GlobalC::exx_info.info_global); + // rpa_interface.rpa_exx_lcao().info.files_abfs = GlobalV::rpa_orbitals; + RPA_LRI rpa_lri_double(GlobalC::exx_info.info_ri, GlobalC::exx_info.info_ewald); rpa_lri_double.cal_postSCF_exx(*dynamic_cast*>(this->pelec)->get_DM(), MPI_COMM_WORLD, this->kv, @@ -1222,9 +1162,9 @@ void ESolver_KS_LCAO::after_scf(const int istep) // 15) write spin constrian MW? // spin constrain calculations, added by Tianqi Zhao. - if (PARAM.inp.sc_mag_switch) { - SpinConstrain& sc - = SpinConstrain::getScInstance(); + if (PARAM.inp.sc_mag_switch) + { + SpinConstrain& sc = SpinConstrain::getScInstance(); sc.cal_MW(istep, true); sc.print_Mag_Force(); } @@ -1254,14 +1194,14 @@ void ESolver_KS_LCAO::after_scf(const int istep) { hamilt::HS_Matrix_K hsk(&pv, true); hamilt::HContainer hR(&pv); - hamilt::Operator* ekinetic = - new hamilt::EkineticNew>(&hsk, - this->kv.kvec_d, - &hR, - &GlobalC::ucell, - orb_.cutoffs(), - &GlobalC::GridD, - two_center_bundle_.kinetic_orb.get()); + hamilt::Operator* ekinetic + = new hamilt::EkineticNew>(&hsk, + this->kv.kvec_d, + &hR, + &GlobalC::ucell, + orb_.cutoffs(), + &GlobalC::GridD, + two_center_bundle_.kinetic_orb.get()); const int nspin_k = (PARAM.inp.nspin == 2 ? 2 : 1); for (int ik = 0; ik < this->kv.get_nks() / nspin_k; ++ik) @@ -1269,7 +1209,7 @@ void ESolver_KS_LCAO::after_scf(const int istep) ekinetic->init(ik); ModuleIO::save_mat(0, hsk.get_hk(), - GlobalV::NLOCAL, + PARAM.globalv.nlocal, false, PARAM.inp.out_mat_tk[1], 1, diff --git a/source/module_esolver/esolver_ks_lcao.h b/source/module_esolver/esolver_ks_lcao.h index 4d0cc105147..5ebdd795485 100644 --- a/source/module_esolver/esolver_ks_lcao.h +++ b/source/module_esolver/esolver_ks_lcao.h @@ -56,7 +56,7 @@ class ESolver_KS_LCAO : public ESolver_KS { virtual void update_pot(const int istep, const int iter) override; - virtual void iter_finish(int& iter) override; + virtual void iter_finish(const int istep, int& iter) override; virtual void after_scf(const int istep) override; diff --git a/source/module_esolver/esolver_ks_lcao_tddft.cpp b/source/module_esolver/esolver_ks_lcao_tddft.cpp index 1a9dda6c475..e364535fc46 100644 --- a/source/module_esolver/esolver_ks_lcao_tddft.cpp +++ b/source/module_esolver/esolver_ks_lcao_tddft.cpp @@ -2,7 +2,6 @@ #include "module_io/cal_r_overlap_R.h" #include "module_io/dipole_io.h" -#include "module_io/rho_io.h" #include "module_io/td_current_io.h" #include "module_io/write_HS.h" #include "module_io/write_HS_R.h" @@ -11,8 +10,8 @@ //--------------temporary---------------------------- #include "module_base/blas_connector.h" #include "module_base/global_function.h" -#include "module_base/scalapack_connector.h" #include "module_base/lapack_connector.h" +#include "module_base/scalapack_connector.h" #include "module_elecstate/module_charge/symmetry_rho.h" #include "module_elecstate/occupy.h" #include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" // need divide_HS_in_frag @@ -73,34 +72,50 @@ void ESolver_KS_LCAO_TDDFT::before_all_runners(const Input_para& inp, UnitCell& GlobalC::ppcell.init_vloc(GlobalC::ppcell.vloc, pw_rho); // 3) initialize the electronic states for TDDFT - if (this->pelec == nullptr) { - this->pelec = new elecstate::ElecStateLCAO_TDDFT( - &this->chr, - &kv, - kv.get_nks(), - &this->GK, // mohan add 2024-04-01 - this->pw_rho, - pw_big); + if (this->pelec == nullptr) + { + this->pelec = new elecstate::ElecStateLCAO_TDDFT(&this->chr, + &kv, + kv.get_nks(), + &this->GK, // mohan add 2024-04-01 + this->pw_rho, + pw_big); } // 4) read the local orbitals and construct the interpolation tables. // initialize the pv - LCAO_domain::init_basis_lcao(this->pv, - inp.onsite_radius, - inp.lcao_ecut, - inp.lcao_dk, - inp.lcao_dr, - inp.lcao_rmax, - ucell, + LCAO_domain::init_basis_lcao(this->pv, + inp.onsite_radius, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + ucell, two_center_bundle_, orb_); // 5) allocate H and S matrices according to computational resources LCAO_domain::divide_HS_in_frag(PARAM.globalv.gamma_only_local, this->pv, kv.get_nks(), orb_); - // 6) initialize Density Matrix - dynamic_cast>*>(this->pelec)->init_DM(&kv, &this->pv, PARAM.inp.nspin); + dynamic_cast>*>(this->pelec) + ->init_DM(&kv, &this->pv, PARAM.inp.nspin); + +#ifdef __EXX + if (GlobalC::exx_info.info_global.cal_exx) + { + XC_Functional::set_xc_first_loop(ucell); + // initialize 2-center radial tables for EXX-LRI + if (GlobalC::exx_info.info_ri.real_number) + { + this->exx_lri_double->init(MPI_COMM_WORLD, this->kv, orb_); + } + else + { + this->exx_lri_complex->init(MPI_COMM_WORLD, this->kv, orb_); + } + } +#endif // 8) initialize the charge density this->pelec->charge->allocate(PARAM.inp.nspin); @@ -172,8 +187,8 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons if (istep >= 1) { module_tddft::Evolve_elec::solve_psi(istep, - GlobalV::NBANDS, - GlobalV::NLOCAL, + PARAM.inp.nbands, + PARAM.globalv.nlocal, this->p_hamilt, this->pv, this->psi, @@ -191,8 +206,8 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons else if (istep >= 2) { module_tddft::Evolve_elec::solve_psi(istep, - GlobalV::NBANDS, - GlobalV::NLOCAL, + PARAM.inp.nbands, + PARAM.globalv.nlocal, this->p_hamilt, this->pv, this->psi, @@ -213,7 +228,7 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons if (this->psi != nullptr) { hsolver::HSolverLCAO> hsolver_lcao_obj(&this->pv, PARAM.inp.ks_solver); - hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec_td, PARAM.inp.ks_solver, false); + hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec_td, false); } } // else @@ -233,7 +248,7 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons GlobalV::ofs_running << std::setiosflags(std::ios::showpoint); for (int ik = 0; ik < kv.get_nks(); ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { std::setprecision(6); GlobalV::ofs_running << ik + 1 << " " << ib + 1 << " " << this->pelec_td->wg(ik, ib) @@ -251,6 +266,13 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons this->pelec_td->print_band(ik, PARAM.inp.printe, iter); } +#ifdef __EXX + if (GlobalC::exx_info.info_ri.real_number) + this->exd->exx_hamilt2density(*this->pelec, this->pv, iter); + else + this->exc->exx_hamilt2density(*this->pelec, this->pv, iter); +#endif + // using new charge density. this->pelec->cal_energies(1); @@ -277,7 +299,7 @@ void ESolver_KS_LCAO_TDDFT::hamilt2density(const int istep, const int iter, cons void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) { // print Hamiltonian and Overlap matrix - if (this->conv_elec) + if (this->conv_esolver) { if (!PARAM.globalv.gamma_only_local) { @@ -299,35 +321,35 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) if (PARAM.inp.out_mat_hs[0]) { ModuleIO::save_mat(istep, - h_mat.p, - GlobalV::NLOCAL, - bit, - PARAM.inp.out_mat_hs[1], - 1, - PARAM.inp.out_app_flag, - "H", - "data-" + std::to_string(ik), - this->pv, - GlobalV::DRANK); + h_mat.p, + PARAM.globalv.nlocal, + bit, + PARAM.inp.out_mat_hs[1], + 1, + PARAM.inp.out_app_flag, + "H", + "data-" + std::to_string(ik), + this->pv, + GlobalV::DRANK); ModuleIO::save_mat(istep, - s_mat.p, - GlobalV::NLOCAL, - bit, - PARAM.inp.out_mat_hs[1], - 1, - PARAM.inp.out_app_flag, - "S", - "data-" + std::to_string(ik), - this->pv, - GlobalV::DRANK); + s_mat.p, + PARAM.globalv.nlocal, + bit, + PARAM.inp.out_mat_hs[1], + 1, + PARAM.inp.out_app_flag, + "S", + "data-" + std::to_string(ik), + this->pv, + GlobalV::DRANK); } } } } - if (elecstate::ElecStateLCAO>::out_wfc_lcao && (this->conv_elec || iter == PARAM.inp.scf_nmax) - && (istep % PARAM.inp.out_interval == 0)) + if (elecstate::ElecStateLCAO>::out_wfc_lcao + && (this->conv_esolver || iter == PARAM.inp.scf_nmax) && (istep % PARAM.inp.out_interval == 0)) { ModuleIO::write_wfc_nao(elecstate::ElecStateLCAO>::out_wfc_lcao, this->psi[0], @@ -339,7 +361,7 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) } // Calculate new potential according to new Charge Density - if (!this->conv_elec) + if (!this->conv_esolver) { if (PARAM.inp.nspin == 4) { @@ -356,11 +378,11 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) const int nloc = this->pv.nloc; const int ncol_nbands = this->pv.ncol_bands; const int nrow = this->pv.nrow; - const int nbands = GlobalV::NBANDS; - const int nlocal = GlobalV::NLOCAL; + const int nbands = PARAM.inp.nbands; + const int nlocal = PARAM.globalv.nlocal; // store wfc and Hk laststep - if (istep >= (wf.init_wfc == "file" ? 0 : 1) && this->conv_elec) + if (istep >= (wf.init_wfc == "file" ? 0 : 1) && this->conv_esolver) { if (this->psi_laststep == nullptr) { @@ -414,15 +436,15 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) } } - // calculate energy density matrix for tddft - if (istep >= (wf.init_wfc == "file" ? 0 : 2) && module_tddft::Evolve_elec::td_edm == 0) - { - this->cal_edm_tddft(); - } - } + // calculate energy density matrix for tddft + if (istep >= (wf.init_wfc == "file" ? 0 : 2) && module_tddft::Evolve_elec::td_edm == 0) + { + this->cal_edm_tddft(); + } + } // print "eigen value" for tddft - if (this->conv_elec) + if (this->conv_esolver) { GlobalV::ofs_running << "---------------------------------------------------------------" "---------------------------------" @@ -434,7 +456,7 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) for (int ik = 0; ik < kv.get_nks(); ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { GlobalV::ofs_running << ik + 1 << " " << ib + 1 << " " << this->pelec_td->ekb(ik, ib) * ModuleBase::Ry_to_eV << std::endl; @@ -449,6 +471,8 @@ void ESolver_KS_LCAO_TDDFT::update_pot(const int istep, const int iter) void ESolver_KS_LCAO_TDDFT::after_scf(const int istep) { + ESolver_KS_LCAO, double>::after_scf(istep); + for (int is = 0; is < PARAM.inp.nspin; is++) { if (module_tddft::Evolve_elec::out_dipole == 1) @@ -460,8 +484,8 @@ void ESolver_KS_LCAO_TDDFT::after_scf(const int istep) } if (TD_Velocity::out_current == true) { - elecstate::DensityMatrix, double>* tmp_DM = - dynamic_cast>*>(this->pelec)->get_DM(); + elecstate::DensityMatrix, double>* tmp_DM + = dynamic_cast>*>(this->pelec)->get_DM(); ModuleIO::write_current(istep, this->psi, @@ -472,7 +496,6 @@ void ESolver_KS_LCAO_TDDFT::after_scf(const int istep) orb_, this->RA); } - ESolver_KS_LCAO, double>::after_scf(istep); } } // namespace ModuleESolver diff --git a/source/module_esolver/esolver_ks_lcaopw.cpp b/source/module_esolver/esolver_ks_lcaopw.cpp index c91e8414a51..0d868dfc34b 100644 --- a/source/module_esolver/esolver_ks_lcaopw.cpp +++ b/source/module_esolver/esolver_ks_lcaopw.cpp @@ -32,7 +32,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" @@ -192,12 +191,12 @@ namespace ModuleESolver } template - void ESolver_KS_LIP::iter_finish(int& iter) + void ESolver_KS_LIP::iter_finish(const int istep, int& iter) { - ESolver_KS_PW::iter_finish(iter); + ESolver_KS_PW::iter_finish(istep, iter); #ifdef __EXX - if (GlobalC::exx_info.info_global.cal_exx && this->conv_elec) + if (GlobalC::exx_info.info_global.cal_exx && this->conv_esolver) { // no separate_loop case if (!GlobalC::exx_info.info_global.separate_loop) @@ -215,7 +214,7 @@ namespace ModuleESolver iter = 0; std::cout << " Entering 2nd SCF, where EXX is updated" << std::endl; this->two_level_step++; - this->conv_elec = false; + this->conv_esolver = false; } } // has separate_loop case @@ -223,7 +222,7 @@ namespace ModuleESolver else if (this->two_level_step == GlobalC::exx_info.info_global.hybrid_step || (iter == 1 && this->two_level_step != 0)) { - this->conv_elec = true; + this->conv_esolver = true; } else { @@ -247,7 +246,7 @@ namespace ModuleESolver << (double)(t_end.tv_sec - t_start.tv_sec) + (double)(t_end.tv_usec - t_start.tv_usec) / 1000000.0 << std::defaultfloat << " (s)" << std::endl; - this->conv_elec = false; + this->conv_esolver = false; } } #endif @@ -261,7 +260,7 @@ namespace ModuleESolver #ifdef __LCAO if (PARAM.inp.out_mat_xc) { - ModuleIO::write_Vxc(PARAM.inp.nspin, GlobalV::NLOCAL, + ModuleIO::write_Vxc(PARAM.inp.nspin, PARAM.globalv.nlocal, GlobalV::DRANK, *this->kspw_psi, GlobalC::ucell, this->sf, *this->pw_wfc, *this->pw_rho, *this->pw_rhod, GlobalC::ppcell.vloc, *this->pelec->charge, this->kv, this->pelec->wg diff --git a/source/module_esolver/esolver_ks_lcaopw.h b/source/module_esolver/esolver_ks_lcaopw.h index e5202aff463..c133791dcbe 100644 --- a/source/module_esolver/esolver_ks_lcaopw.h +++ b/source/module_esolver/esolver_ks_lcaopw.h @@ -28,7 +28,7 @@ namespace ModuleESolver protected: virtual void iter_init(const int istep, const int iter) override; - virtual void iter_finish(int& iter) override; + virtual void iter_finish(const int istep, int& iter) override; virtual void allocate_hamilt() override; virtual void deallocate_hamilt() override; diff --git a/source/module_esolver/esolver_ks_pw.cpp b/source/module_esolver/esolver_ks_pw.cpp index 22ec454c2ab..17ec60b6bb9 100644 --- a/source/module_esolver/esolver_ks_pw.cpp +++ b/source/module_esolver/esolver_ks_pw.cpp @@ -49,6 +49,10 @@ #include #include +#ifdef __DSP +#include "module_base/kernels/dsp/dsp_connector.h" +#endif + namespace ModuleESolver { @@ -67,6 +71,10 @@ ESolver_KS_PW::ESolver_KS_PW() container::kernels::createGpuSolverHandle(); } #endif +#ifdef __DSP + std::cout << " ** Initializing DSP Hardware..." << std::endl; + dspInitHandle(GlobalV::MY_RANK); +#endif } template @@ -92,7 +100,10 @@ ESolver_KS_PW::~ESolver_KS_PW() #endif delete reinterpret_cast*>(this->kspw_psi); } - +#ifdef __DSP + std::cout << " ** Closing DSP Hardware..." << std::endl; + dspDestoryHandle(GlobalV::MY_RANK); +#endif if (PARAM.inp.precision == "single") { delete reinterpret_cast, Device>*>(this->__kspw_psi); @@ -161,7 +172,7 @@ void ESolver_KS_PW::before_all_runners(const Input_para& inp, UnitCel //! 9) setup occupations if (PARAM.inp.ocp) { - this->pelec->fixed_weights(PARAM.inp.ocp_kb, GlobalV::NBANDS, GlobalV::nelec); + this->pelec->fixed_weights(PARAM.inp.ocp_kb, PARAM.inp.nbands, PARAM.inp.nelec); } } @@ -199,7 +210,7 @@ void ESolver_KS_PW::before_scf(const int istep) //---------------------------------------------------------- // about vdw, jiyy add vdwd3 and linpz add vdwd2 //---------------------------------------------------------- - auto vdw_solver = vdw::make_vdw(GlobalC::ucell, PARAM.inp); + auto vdw_solver = vdw::make_vdw(GlobalC::ucell, PARAM.inp, &(GlobalV::ofs_running)); if (vdw_solver != nullptr) { this->pelec->f_en.evdw = vdw_solver->get_energy(); @@ -213,7 +224,7 @@ void ESolver_KS_PW::before_scf(const int istep) //! cal_ux should be called before init_scf because //! the direction of ux is used in noncoline_rho - if (PARAM.inp.nspin == 4 && PARAM.globalv.domag) + if (PARAM.inp.nspin == 4) { GlobalC::ucell.cal_ux(); } @@ -228,21 +239,12 @@ void ESolver_KS_PW::before_scf(const int istep) { std::stringstream ss; ss << PARAM.globalv.global_out_dir << "SPIN" << is + 1 << "_CHG_INI.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->rho[is], is, PARAM.inp.nspin, istep, ss.str(), - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.ef, &(GlobalC::ucell)); } @@ -255,21 +257,12 @@ void ESolver_KS_PW::before_scf(const int istep) { std::stringstream ss; ss << PARAM.globalv.global_out_dir << "SPIN" << is + 1 << "_POT_INI.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->pot->get_effective_v(is), is, PARAM.inp.nspin, istep, ss.str(), - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, 0.0, // efermi &(GlobalC::ucell), 11, // precsion @@ -352,15 +345,6 @@ void ESolver_KS_PW::hamilt2density(const int istep, const int iter, c hsolver::DiagoIterAssist::SCF_ITER = iter; hsolver::DiagoIterAssist::PW_DIAG_THR = ethr; hsolver::DiagoIterAssist::PW_DIAG_NMAX = PARAM.inp.pw_diag_nmax; - - std::vector is_occupied(this->kspw_psi->get_nk() * this->kspw_psi->get_nbands(), true); - - elecstate::set_is_occupied(is_occupied, - this->pelec, - hsolver::DiagoIterAssist::SCF_ITER, - this->kspw_psi->get_nk(), - this->kspw_psi->get_nbands(), - PARAM.inp.diago_full_acc); hsolver::HSolverPW hsolver_pw_obj(this->pw_wfc, &this->wf, @@ -369,7 +353,7 @@ void ESolver_KS_PW::hamilt2density(const int istep, const int iter, c PARAM.inp.basis_type, PARAM.inp.ks_solver, PARAM.inp.use_paw, - GlobalV::use_uspp, + PARAM.globalv.use_uspp, PARAM.inp.nspin, hsolver::DiagoIterAssist::SCF_ITER, @@ -383,7 +367,6 @@ void ESolver_KS_PW::hamilt2density(const int istep, const int iter, c this->kspw_psi[0], this->pelec, this->pelec->ekb.c, - is_occupied, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL, false); @@ -432,7 +415,7 @@ void ESolver_KS_PW::hamilt2density(const int istep, const int iter, c template void ESolver_KS_PW::update_pot(const int istep, const int iter) { - if (!this->conv_elec) + if (!this->conv_esolver) { if (PARAM.inp.nspin == 4) { @@ -440,6 +423,9 @@ void ESolver_KS_PW::update_pot(const int istep, const int iter) } this->pelec->pot->update_from_charge(this->pelec->charge, &GlobalC::ucell); this->pelec->f_en.descf = this->pelec->cal_delta_escf(); +#ifdef __MPI + MPI_Bcast(&(this->pelec->f_en.descf), 1, MPI_DOUBLE, 0, PARAPW_WORLD); +#endif } else { @@ -448,16 +434,16 @@ void ESolver_KS_PW::update_pot(const int istep, const int iter) } template -void ESolver_KS_PW::iter_finish(int& iter) +void ESolver_KS_PW::iter_finish(const int istep, int& iter) { // call iter_finish() of ESolver_KS - ESolver_KS::iter_finish(iter); + ESolver_KS::iter_finish(istep, iter); // liuyu 2023-10-24 // D in uspp need vloc, thus needs update when veff updated // calculate the effective coefficient matrix for non-local pseudopotential // projectors - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { ModuleBase::matrix veff = this->pelec->pot->get_effective_v(); GlobalC::ppcell.cal_effective_D(veff, this->pw_rhod, GlobalC::ucell); @@ -479,21 +465,12 @@ void ESolver_KS_PW::iter_finish(int& iter) data = this->pelec->charge->rho_save[is]; } std::string fn = PARAM.globalv.global_out_dir + "/tmp_SPIN" + std::to_string(is + 1) + "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, data, is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell), 3, @@ -501,21 +478,12 @@ void ESolver_KS_PW::iter_finish(int& iter) if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) { fn = PARAM.globalv.global_out_dir + "/tmp_SPIN" + std::to_string(is + 1) + "_TAU.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->kin_r_save[is], is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell)); } @@ -538,10 +506,16 @@ void ESolver_KS_PW::iter_finish(int& iter) template void ESolver_KS_PW::after_scf(const int istep) { - // 1) call after_scf() of ESolver_KS + // 1) calculate the kinetic energy density tau, sunliang 2024-09-18 + if (PARAM.inp.out_elf[0] > 0) + { + this->pelec->cal_tau(*(this->psi)); + } + + // 2) call after_scf() of ESolver_KS ESolver_KS::after_scf(istep); - // 2) output wavefunctions + // 3) output wavefunctions if (this->wf.out_wfc_pw == 1 || this->wf.out_wfc_pw == 2) { std::stringstream ssw; @@ -732,7 +706,7 @@ void ESolver_KS_PW::after_all_runners() GlobalV::ofs_running << "\n Output bands in file: " << ss2.str() << std::endl; ModuleIO::nscf_band(is, ss2.str(), - GlobalV::NBANDS, + PARAM.inp.nbands, 0.0, PARAM.inp.out_band[1], this->pelec->ekb, diff --git a/source/module_esolver/esolver_ks_pw.h b/source/module_esolver/esolver_ks_pw.h index f2e65a4ef32..dc586a67a5a 100644 --- a/source/module_esolver/esolver_ks_pw.h +++ b/source/module_esolver/esolver_ks_pw.h @@ -46,7 +46,7 @@ class ESolver_KS_PW : public ESolver_KS virtual void update_pot(const int istep, const int iter) override; - virtual void iter_finish(int& iter) override; + virtual void iter_finish(const int istep, int& iter) override; virtual void after_scf(const int istep) override; diff --git a/source/module_esolver/esolver_of.cpp b/source/module_esolver/esolver_of.cpp index edd50a69627..a3bb656efd7 100644 --- a/source/module_esolver/esolver_of.cpp +++ b/source/module_esolver/esolver_of.cpp @@ -70,7 +70,6 @@ void ESolver_OF::before_all_runners(const Input_para& inp, UnitCell& ucell) this->max_iter_ = inp.scf_nmax; this->dV_ = ucell.omega / this->pw_rho->nxyz; - ucell.cal_nelec(GlobalV::nelec); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SETUP UNITCELL"); XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); @@ -93,7 +92,7 @@ void ESolver_OF::before_all_runners(const Input_para& inp, UnitCell& ucell) // print information // mohan add 2021-01-30 - Print_Info::setup_parameters(ucell, kv); + ModuleIO::setup_parameters(ucell, kv); // initialize the real-space uniform grid for FFT and parallel // distribution of plane waves @@ -135,7 +134,7 @@ void ESolver_OF::before_all_runners(const Input_para& inp, UnitCell& ucell) this->nelec_ = new double[PARAM.inp.nspin]; if (PARAM.inp.nspin == 1) { - this->nelec_[0] = GlobalV::nelec; + this->nelec_[0] = PARAM.inp.nelec; } else if (PARAM.inp.nspin == 2) { @@ -456,7 +455,7 @@ void ESolver_OF::update_rho() */ bool ESolver_OF::check_exit() { - this->conv_elec = false; + this->conv_esolver = false; bool potConv = false; bool potHold = false; // if normdLdphi nearly remains unchanged bool energyConv = false; @@ -477,12 +476,12 @@ bool ESolver_OF::check_exit() energyConv = true; } - this->conv_elec = (this->of_conv_ == "energy" && energyConv) || (this->of_conv_ == "potential" && potConv) - || (this->of_conv_ == "both" && potConv && energyConv); + this->conv_esolver = (this->of_conv_ == "energy" && energyConv) || (this->of_conv_ == "potential" && potConv) + || (this->of_conv_ == "both" && potConv && energyConv); this->print_info(); - if (this->conv_elec || this->iter_ >= this->max_iter_) + if (this->conv_esolver || this->iter_ >= this->max_iter_) { return true; } @@ -510,7 +509,13 @@ bool ESolver_OF::check_exit() */ void ESolver_OF::after_opt(const int istep, UnitCell& ucell) { - // 1) call after_scf() of ESolver_FP + // 1) calculate the kinetic energy density + if (PARAM.inp.out_elf[0] > 0) + { + this->kinetic_energy_density(this->pelec->charge->rho, this->pphi_, this->pelec->charge->kin_r); + } + + // 2) call after_scf() of ESolver_FP ESolver_FP::after_scf(istep); } diff --git a/source/module_esolver/esolver_of.h b/source/module_esolver/esolver_of.h index 46f2aa21ab1..b9e57bb1ae8 100644 --- a/source/module_esolver/esolver_of.h +++ b/source/module_esolver/esolver_of.h @@ -33,11 +33,6 @@ class ESolver_OF : public ESolver_FP virtual void cal_stress(ModuleBase::matrix& stress) override; - virtual int get_niter() override - { - return this->iter_; - } - private: // ======================= variables ========================== // ---------- the kinetic energy density functionals ---------- @@ -125,6 +120,7 @@ class ESolver_OF : public ESolver_FP void init_kedf(const Input_para& inp); void kinetic_potential(double** prho, double** pphi, ModuleBase::matrix& rpot); double kinetic_energy(); + void kinetic_energy_density(double** prho, double** pphi, double** rtau); void kinetic_stress(ModuleBase::matrix& kinetic_stress); // ---------------------- interfaces to optimization methods -------- diff --git a/source/module_esolver/esolver_of_interface.cpp b/source/module_esolver/esolver_of_interface.cpp index d5d76d9236d..118168a2a33 100644 --- a/source/module_esolver/esolver_of_interface.cpp +++ b/source/module_esolver/esolver_of_interface.cpp @@ -137,6 +137,40 @@ double ESolver_OF::kinetic_energy() return kinetic_energy; } +/** + * @brief [Interface to kedf] + * Calculated the kinetic energy density, ONLY SPIN=1 SUPPORTED + * + * @param [in] prho charge density + * @param [in] pphi phi^2 = rho + * @param [out] rtau kinetic energy density + */ +void ESolver_OF::kinetic_energy_density(double** prho, double** pphi, double** rtau) +{ + for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) + { + rtau[0][ir] = 0.0; + } + + if (this->of_kinetic_ == "tf" || this->of_kinetic_ == "tf+" || this->of_kinetic_ == "wt") + { + this->tf_->tau_tf(prho, rtau[0]); + } + if (this->of_kinetic_ == "vw" || this->of_kinetic_ == "tf+" || this->of_kinetic_ == "wt" + || this->of_kinetic_ == "lkt") + { + this->vw_->tau_vw(prho, this->pw_rho, rtau[0]); + } + if (this->of_kinetic_ == "wt") + { + this->wt_->tau_wt(prho, this->pw_rho, rtau[0]); + } + if (this->of_kinetic_ == "lkt") + { + this->lkt_->tau_lkt(prho, this->pw_rho, rtau[0]); + } +} + /** * @brief [Interface to kedf] * Calculate the stress of kedf diff --git a/source/module_esolver/esolver_of_tool.cpp b/source/module_esolver/esolver_of_tool.cpp index 5d307bff1fb..6e81ad33a64 100644 --- a/source/module_esolver/esolver_of_tool.cpp +++ b/source/module_esolver/esolver_of_tool.cpp @@ -431,7 +431,7 @@ void ESolver_OF::print_info() std::vector energies_Ry; std::vector energies_eV; if (PARAM.inp.printe > 0 - && ((this->iter_ + 1) % PARAM.inp.printe == 0 || this->conv_elec || this->iter_ == PARAM.inp.scf_nmax)) + && ((this->iter_ + 1) % PARAM.inp.printe == 0 || this->conv_esolver || this->iter_ == PARAM.inp.scf_nmax)) { titles.push_back("E_Total"); energies_Ry.push_back(this->pelec->f_en.etot); diff --git a/source/module_esolver/esolver_sdft_pw.cpp b/source/module_esolver/esolver_sdft_pw.cpp index 19ce25f03b5..2e21355208b 100644 --- a/source/module_esolver/esolver_sdft_pw.cpp +++ b/source/module_esolver/esolver_sdft_pw.cpp @@ -1,6 +1,5 @@ #include "esolver_sdft_pw.h" -#include "module_parameter/parameter.h" #include "module_base/memory.h" #include "module_base/timer.h" #include "module_elecstate/elecstate_pw_sdft.h" @@ -11,6 +10,7 @@ #include "module_io/cube_io.h" #include "module_io/output_log.h" #include "module_io/write_istate_info.h" +#include "module_parameter/parameter.h" #include #include @@ -29,35 +29,38 @@ namespace ModuleESolver { -ESolver_SDFT_PW::ESolver_SDFT_PW() +template +ESolver_SDFT_PW::ESolver_SDFT_PW() : stoche(PARAM.inp.nche_sto, PARAM.inp.method_sto, PARAM.inp.emax_sto, PARAM.inp.emin_sto) { - classname = "ESolver_SDFT_PW"; - basisname = "PW"; + this->classname = "ESolver_SDFT_PW"; + this->basisname = "PW"; } -ESolver_SDFT_PW::~ESolver_SDFT_PW() +template +ESolver_SDFT_PW::~ESolver_SDFT_PW() { } -void ESolver_SDFT_PW::before_all_runners(const Input_para& inp, UnitCell& ucell) +template +void ESolver_SDFT_PW::before_all_runners(const Input_para& inp, UnitCell& ucell) { // 1) initialize parameters from int Input class this->nche_sto = inp.nche_sto; this->method_sto = inp.method_sto; // 2) run "before_all_runners" in ESolver_KS - ESolver_KS::before_all_runners(inp, ucell); + ESolver_KS::before_all_runners(inp, ucell); // 3) initialize the pointer for electronic states of SDFT - this->pelec = new elecstate::ElecStatePW_SDFT(pw_wfc, - &(chr), - (K_Vectors*)(&(kv)), - &ucell, - &(GlobalC::ppcell), - this->pw_rhod, - this->pw_rho, - pw_big); + this->pelec = new elecstate::ElecStatePW_SDFT(this->pw_wfc, + &(this->chr), + &(this->kv), + &ucell, + &(GlobalC::ppcell), + this->pw_rhod, + this->pw_rho, + this->pw_big); // 4) inititlize the charge density. this->pelec->charge->allocate(PARAM.inp.nspin); @@ -66,92 +69,105 @@ void ESolver_SDFT_PW::before_all_runners(const Input_para& inp, UnitCell& ucell) // 5) initialize the potential. if (this->pelec->pot == nullptr) { - this->pelec->pot = new elecstate::Potential(pw_rhod, - pw_rho, + this->pelec->pot = new elecstate::Potential(this->pw_rhod, + this->pw_rho, &ucell, &(GlobalC::ppcell.vloc), - &(sf), + &(this->sf), &(this->pelec->f_en.etxc), &(this->pelec->f_en.vtxc)); - GlobalTemp::veff = &(this->pelec->pot->get_effective_v()); } // 6) prepare some parameters for electronic wave functions initilization - this->p_wf_init = new psi::WFInit>(PARAM.inp.init_wfc, - PARAM.inp.ks_solver, - PARAM.inp.basis_type, - PARAM.inp.psi_initializer, - &this->wf, - this->pw_wfc); + this->p_wf_init = new psi::WFInit(PARAM.inp.init_wfc, + PARAM.inp.ks_solver, + PARAM.inp.basis_type, + PARAM.inp.psi_initializer, + &this->wf, + this->pw_wfc); // 7) set occupatio, redundant? if (PARAM.inp.ocp) { - this->pelec->fixed_weights(PARAM.inp.ocp_kb, GlobalV::NBANDS, GlobalV::nelec); + this->pelec->fixed_weights(PARAM.inp.ocp_kb, PARAM.inp.nbands, PARAM.inp.nelec); } // 8) initialize the global classes this->Init_GlobalC(inp, ucell, GlobalC::ppcell); // temporary // 9) initialize the stochastic wave functions - stowf.init(&kv, pw_wfc->npwk_max); + this->stowf.init(&this->kv, this->pw_wfc->npwk_max); if (inp.nbands_sto != 0) { if (inp.initsto_ecut < inp.ecutwfc) { - Init_Sto_Orbitals(this->stowf, inp.seed_sto); + this->stowf.init_sto_orbitals(inp.seed_sto); } else { - Init_Sto_Orbitals_Ecut(this->stowf, inp.seed_sto, kv, *pw_wfc, inp.initsto_ecut); + this->stowf.init_sto_orbitals_Ecut(inp.seed_sto, this->kv, *this->pw_wfc, inp.initsto_ecut); } } else { - Init_Com_Orbitals(this->stowf); + this->stowf.init_com_orbitals(); } if (this->method_sto == 2) { - stowf.allocate_chiallorder(this->nche_sto); + this->stowf.allocate_chiallorder(this->nche_sto); } + this->stowf.sync_chi0(); + // 10) allocate spaces for \sqrt(f(H))|chi> and |\tilde{chi}> size_t size = stowf.chi0->size(); + this->stowf.shchi + = new psi::Psi(this->kv.get_nks(), this->stowf.nchip_max, this->wf.npwx, this->kv.ngk.data()); + ModuleBase::Memory::record("SDFT::shchi", size * sizeof(T)); - this->stowf.shchi = new psi::Psi>(kv.get_nks(), stowf.nchip_max, wf.npwx, kv.ngk.data()); - - ModuleBase::Memory::record("SDFT::shchi", size * sizeof(std::complex)); - - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { this->stowf.chiortho - = new psi::Psi>(kv.get_nks(), stowf.nchip_max, wf.npwx, kv.ngk.data()); - ModuleBase::Memory::record("SDFT::chiortho", size * sizeof(std::complex)); + = new psi::Psi(this->kv.get_nks(), this->stowf.nchip_max, this->wf.npwx, this->kv.ngk.data()); + ModuleBase::Memory::record("SDFT::chiortho", size * sizeof(T)); } return; } -void ESolver_SDFT_PW::before_scf(const int istep) +template +void ESolver_SDFT_PW::before_scf(const int istep) { - ESolver_KS_PW::before_scf(istep); + ESolver_KS_PW::before_scf(istep); + delete reinterpret_cast*>(this->p_hamilt); + this->p_hamilt = new hamilt::HamiltSdftPW(this->pelec->pot, + this->pw_wfc, + &this->kv, + PARAM.globalv.npol, + &this->stoche.emin_sto, + &this->stoche.emax_sto); + this->p_hamilt_sto = static_cast*>(this->p_hamilt); + if (istep > 0 && PARAM.inp.nbands_sto != 0 && PARAM.inp.initsto_freq > 0 && istep % PARAM.inp.initsto_freq == 0) { - Update_Sto_Orbitals(this->stowf, PARAM.inp.seed_sto); + this->stowf.update_sto_orbitals(PARAM.inp.seed_sto); } } -void ESolver_SDFT_PW::iter_finish(int& iter) +template +void ESolver_SDFT_PW::iter_finish(const int istep, int& iter) { // call iter_finish() of ESolver_KS - ESolver_KS>::iter_finish(iter); + ESolver_KS::iter_finish(istep, iter); } -void ESolver_SDFT_PW::after_scf(const int istep) +template +void ESolver_SDFT_PW::after_scf(const int istep) { // 1) call after_scf() of ESolver_KS_PW - ESolver_KS_PW>::after_scf(istep); + ESolver_KS_PW::after_scf(istep); } -void ESolver_SDFT_PW::hamilt2density(int istep, int iter, double ethr) +template +void ESolver_SDFT_PW::hamilt2density(int istep, int iter, double ethr) { // reset energy this->pelec->f_en.eband = 0.0; @@ -160,44 +176,37 @@ void ESolver_SDFT_PW::hamilt2density(int istep, int iter, double ethr) // be careful that istep start from 0 and iter start from 1 if (istep == 0 && iter == 1) { - hsolver::DiagoIterAssist>::need_subspace = false; + hsolver::DiagoIterAssist::need_subspace = false; } else { - hsolver::DiagoIterAssist>::need_subspace = true; + hsolver::DiagoIterAssist::need_subspace = true; } - hsolver::DiagoIterAssist>::PW_DIAG_THR = ethr; + hsolver::DiagoIterAssist::PW_DIAG_THR = ethr; - hsolver::DiagoIterAssist>::PW_DIAG_NMAX = PARAM.inp.pw_diag_nmax; + hsolver::DiagoIterAssist::PW_DIAG_NMAX = PARAM.inp.pw_diag_nmax; // hsolver only exists in this function - hsolver::HSolverPW_SDFT hsolver_pw_sdft_obj( - &this->kv, - this->pw_wfc, - &this->wf, - this->stowf, - this->stoche, - PARAM.inp.calculation, - PARAM.inp.basis_type, - PARAM.inp.ks_solver, - PARAM.inp.use_paw, - GlobalV::use_uspp, - PARAM.inp.nspin, - hsolver::DiagoIterAssist>::SCF_ITER, - hsolver::DiagoIterAssist>::PW_DIAG_NMAX, - hsolver::DiagoIterAssist>::PW_DIAG_THR, - hsolver::DiagoIterAssist>::need_subspace, - this->init_psi); - - hsolver_pw_sdft_obj.solve(this->p_hamilt, - this->psi[0], - this->pelec, - pw_wfc, - this->stowf, - istep, - iter, - false); + hsolver::HSolverPW_SDFT hsolver_pw_sdft_obj(&this->kv, + this->pw_wfc, + &this->wf, + this->stowf, + this->stoche, + this->p_hamilt_sto, + PARAM.inp.calculation, + PARAM.inp.basis_type, + PARAM.inp.ks_solver, + PARAM.inp.use_paw, + PARAM.globalv.use_uspp, + PARAM.inp.nspin, + hsolver::DiagoIterAssist::SCF_ITER, + hsolver::DiagoIterAssist::PW_DIAG_NMAX, + hsolver::DiagoIterAssist::PW_DIAG_THR, + hsolver::DiagoIterAssist::need_subspace, + this->init_psi); + + hsolver_pw_sdft_obj.solve(this->p_hamilt, this->psi[0], this->pelec, this->pw_wfc, this->stowf, istep, iter, false); this->init_psi = true; // set_diagethr need it @@ -208,7 +217,7 @@ void ESolver_SDFT_PW::hamilt2density(int istep, int iter, double ethr) Symmetry_rho srho; for (int is = 0; is < PARAM.inp.nspin; is++) { - srho.begin(is, *(this->pelec->charge), pw_rho, GlobalC::ucell.symm); + srho.begin(is, *(this->pelec->charge), this->pw_rho, GlobalC::ucell.symm); } this->pelec->f_en.deband = this->pelec->cal_delta_eband(); } @@ -221,45 +230,70 @@ void ESolver_SDFT_PW::hamilt2density(int istep, int iter, double ethr) } #endif } +#ifdef __MPI + MPI_Bcast(&(this->pelec->f_en.deband), 1, MPI_DOUBLE, 0, PARAPW_WORLD); +#endif } -double ESolver_SDFT_PW::cal_energy() +template +double ESolver_SDFT_PW::cal_energy() { return this->pelec->f_en.etot; } -void ESolver_SDFT_PW::cal_force(ModuleBase::matrix& force) +template +void ESolver_SDFT_PW::cal_force(ModuleBase::matrix& force) { Sto_Forces ff(GlobalC::ucell.nat); - ff.cal_stoforce(force, *this->pelec, pw_rho, &GlobalC::ucell.symm, &sf, &kv, pw_wfc, this->psi, this->stowf); + ff.cal_stoforce(force, + *this->pelec, + this->pw_rho, + &GlobalC::ucell.symm, + &this->sf, + &this->kv, + this->pw_wfc, + this->psi, + this->stowf); } -void ESolver_SDFT_PW::cal_stress(ModuleBase::matrix& stress) +template +void ESolver_SDFT_PW::cal_stress(ModuleBase::matrix& stress) { Sto_Stress_PW ss; ss.cal_stress(stress, *this->pelec, - pw_rho, + this->pw_rho, &GlobalC::ucell.symm, - &sf, - &kv, - pw_wfc, + &this->sf, + &this->kv, + this->pw_wfc, this->psi, this->stowf, - pelec->charge, + this->pelec->charge, &GlobalC::ppcell, GlobalC::ucell); } -void ESolver_SDFT_PW::after_all_runners() +template +void ESolver_SDFT_PW::after_all_runners() +{ + GlobalV::ofs_running << "\n\n --------------------------------------------" << std::endl; + GlobalV::ofs_running << std::setprecision(16); + GlobalV::ofs_running << " !FINAL_ETOT_IS " << this->pelec->f_en.etot * ModuleBase::Ry_to_eV << " eV" << std::endl; + GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; + ModuleIO::write_istate_info(this->pelec->ekb, this->pelec->wg, this->kv, &(GlobalC::Pkpoints)); +} + +template <> +void ESolver_SDFT_PW, base_device::DEVICE_CPU>::after_all_runners() { GlobalV::ofs_running << "\n\n --------------------------------------------" << std::endl; GlobalV::ofs_running << std::setprecision(16); GlobalV::ofs_running << " !FINAL_ETOT_IS " << this->pelec->f_en.etot * ModuleBase::Ry_to_eV << " eV" << std::endl; GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; - ModuleIO::write_istate_info(this->pelec->ekb, this->pelec->wg, kv, &(GlobalC::Pkpoints)); + ModuleIO::write_istate_info(this->pelec->ekb, this->pelec->wg, this->kv, &(GlobalC::Pkpoints)); if (this->method_sto == 2) { @@ -267,13 +301,7 @@ void ESolver_SDFT_PW::after_all_runners() } if (PARAM.inp.out_dos) { - Sto_DOS sto_dos(this->pw_wfc, - &this->kv, - this->pelec, - this->psi, - this->p_hamilt, - this->stoche, - &stowf); + Sto_DOS sto_dos(this->pw_wfc, &this->kv, this->pelec, this->psi, this->p_hamilt, this->stoche, &stowf); sto_dos.decide_param(PARAM.inp.dos_nche, PARAM.inp.emin_sto, PARAM.inp.emax_sto, @@ -308,7 +336,8 @@ void ESolver_SDFT_PW::after_all_runners() } } -void ESolver_SDFT_PW::others(const int istep) +template +void ESolver_SDFT_PW::others(const int istep) { ModuleBase::TITLE("ESolver_SDFT_PW", "others"); @@ -318,13 +347,14 @@ void ESolver_SDFT_PW::others(const int istep) } else { - ModuleBase::WARNING_QUIT("ESolver_SDFT_PW::others", "CALCULATION type not supported"); + ModuleBase::WARNING_QUIT("ESolver_SDFT_PW::others", "CALCULATION type not supported"); } return; } -void ESolver_SDFT_PW::nscf() +template +void ESolver_SDFT_PW::nscf() { ModuleBase::TITLE("ESolver_SDFT_PW", "nscf"); ModuleBase::timer::tick("ESolver_SDFT_PW", "nscf"); @@ -333,7 +363,7 @@ void ESolver_SDFT_PW::nscf() const int iter = 1; - const double diag_thr = std::max(std::min(1e-5, 0.1 * PARAM.inp.scf_thr / std::max(1.0, GlobalV::nelec)), 1e-12); + const double diag_thr = std::max(std::min(1e-5, 0.1 * PARAM.inp.scf_thr / std::max(1.0, PARAM.inp.nelec)), 1e-12); std::cout << " DIGA_THR : " << diag_thr << std::endl; @@ -346,4 +376,7 @@ void ESolver_SDFT_PW::nscf() ModuleBase::timer::tick("ESolver_SDFT_PW", "nscf"); return; } + +// template class ESolver_SDFT_PW, base_device::DEVICE_CPU>; +template class ESolver_SDFT_PW, base_device::DEVICE_CPU>; } // namespace ModuleESolver diff --git a/source/module_esolver/esolver_sdft_pw.h b/source/module_esolver/esolver_sdft_pw.h index 2d2d0231c87..71e5670c440 100644 --- a/source/module_esolver/esolver_sdft_pw.h +++ b/source/module_esolver/esolver_sdft_pw.h @@ -2,15 +2,16 @@ #define ESOLVER_SDFT_PW_H #include "esolver_ks_pw.h" -#include "module_hamilt_pw/hamilt_stodft/sto_hchi.h" +#include "module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h" +#include "module_hamilt_pw/hamilt_stodft/sto_che.h" #include "module_hamilt_pw/hamilt_stodft/sto_iter.h" #include "module_hamilt_pw/hamilt_stodft/sto_wf.h" -#include "module_hamilt_pw/hamilt_stodft/sto_che.h" namespace ModuleESolver { -class ESolver_SDFT_PW : public ESolver_KS_PW> +template +class ESolver_SDFT_PW : public ESolver_KS_PW { public: ESolver_SDFT_PW(); @@ -25,8 +26,9 @@ class ESolver_SDFT_PW : public ESolver_KS_PW> void cal_stress(ModuleBase::matrix& stress) override; public: - Stochastic_WF stowf; + Stochastic_WF stowf; StoChe stoche; + hamilt::HamiltSdftPW* p_hamilt_sto = nullptr; protected: virtual void before_scf(const int istep) override; @@ -37,7 +39,7 @@ class ESolver_SDFT_PW : public ESolver_KS_PW> virtual void others(const int istep) override; - virtual void iter_finish(int& iter) override; + virtual void iter_finish(const int istep, int& iter) override; virtual void after_scf(const int istep) override; @@ -49,13 +51,4 @@ class ESolver_SDFT_PW : public ESolver_KS_PW> }; } // namespace ModuleESolver - -// temporary setting: removed GlobalC but not breaking design philosophy -namespace GlobalTemp -{ - -extern const ModuleBase::matrix* veff; - -} - #endif diff --git a/source/module_esolver/io_npz.cpp b/source/module_esolver/io_npz.cpp index 2747f9d2865..ea354438ec0 100644 --- a/source/module_esolver/io_npz.cpp +++ b/source/module_esolver/io_npz.cpp @@ -1,5 +1,6 @@ //Deals with io of dm(r)/h(r) in npz format +#include "module_parameter/parameter.h" #include "module_esolver/esolver_ks_lcao.h" #include "module_base/parallel_reduce.h" @@ -72,7 +73,7 @@ void ESolver_KS_LCAO::read_mat_npz(std::string& zipname, hamilt::HContai const int it = GlobalC::ucell.iat2it[iat]; const int ia = GlobalC::ucell.iat2ia[iat]; - //get atomic number (copied from write_cube.cpp) + //get atomic number (copied from write_vdata_palgrid.cpp) std::string element = ""; element = GlobalC::ucell.atoms[it].label; std::string::iterator temp = element.begin(); @@ -367,7 +368,7 @@ void ESolver_KS_LCAO::output_mat_npz(std::string& zipname, const hamilt: const int it = GlobalC::ucell.iat2it[iat]; const int ia = GlobalC::ucell.iat2ia[iat]; - //get atomic number (copied from write_cube.cpp) + //get atomic number (copied from write_vdata_palgrid.cpp) std::string element = ""; element = GlobalC::ucell.atoms[it].label; std::string::iterator temp = element.begin(); @@ -426,8 +427,8 @@ void ESolver_KS_LCAO::output_mat_npz(std::string& zipname, const hamilt: #ifdef __MPI hamilt::HContainer* HR_serial; Parallel_Orbitals serialV; - serialV.set_serial(GlobalV::NLOCAL, GlobalV::NLOCAL); - serialV.set_atomic_trace(GlobalC::ucell.get_iat2iwt(), GlobalC::ucell.nat, GlobalV::NLOCAL); + serialV.set_serial(PARAM.globalv.nlocal, PARAM.globalv.nlocal); + serialV.set_atomic_trace(GlobalC::ucell.get_iat2iwt(), GlobalC::ucell.nat, PARAM.globalv.nlocal); if(GlobalV::MY_RANK == 0) { HR_serial = new hamilt::HContainer(&serialV); diff --git a/source/module_esolver/lcao_before_scf.cpp b/source/module_esolver/lcao_before_scf.cpp index 64bc023bfd8..2062f5afda5 100644 --- a/source/module_esolver/lcao_before_scf.cpp +++ b/source/module_esolver/lcao_before_scf.cpp @@ -77,7 +77,7 @@ void ESolver_KS_LCAO::beforesolver(const int istep) #ifdef __MPI ncol = this->pv.ncol_bands; #else - ncol = GlobalV::NBANDS; + ncol = PARAM.inp.nbands; #endif } this->psi = new psi::Psi(nsk, ncol, this->pv.nrow, nullptr); @@ -115,6 +115,7 @@ void ESolver_KS_LCAO::beforesolver(const int istep) orb_, DM #ifdef __EXX + , istep , GlobalC::exx_info.info_ri.real_number ? &this->exd->two_level_step : &this->exc->two_level_step , GlobalC::exx_info.info_ri.real_number ? &exx_lri_double->Hexxs : nullptr , GlobalC::exx_info.info_ri.real_number ? nullptr : &exx_lri_complex->Hexxs @@ -165,7 +166,7 @@ void ESolver_KS_LCAO::beforesolver(const int istep) // cal_ux should be called before init_scf because // the direction of ux is used in noncoline_rho //========================================================= - if (PARAM.inp.nspin == 4 && PARAM.globalv.domag) + if (PARAM.inp.nspin == 4) { GlobalC::ucell.cal_ux(); } @@ -198,7 +199,7 @@ void ESolver_KS_LCAO::before_scf(const int istep) //---------------------------------------------------------- // about vdw, jiyy add vdwd3 and linpz add vdwd2 //---------------------------------------------------------- - auto vdw_solver = vdw::make_vdw(GlobalC::ucell, PARAM.inp); + auto vdw_solver = vdw::make_vdw(GlobalC::ucell, PARAM.inp, &(GlobalV::ofs_running)); if (vdw_solver != nullptr) { this->pelec->f_en.evdw = vdw_solver->get_energy(); @@ -210,11 +211,11 @@ void ESolver_KS_LCAO::before_scf(const int istep) #ifdef __EXX // set xc type before the first cal of xc in pelec->init_scf if (GlobalC::exx_info.info_ri.real_number) { - this->exd->exx_beforescf(this->kv, *this->p_chgmix, GlobalC::ucell, this->pv, orb_); + this->exd->exx_beforescf(istep, this->kv, *this->p_chgmix, GlobalC::ucell, orb_); } else { - this->exc->exx_beforescf(this->kv, *this->p_chgmix, GlobalC::ucell, this->pv, orb_); + this->exc->exx_beforescf(istep, this->kv, *this->p_chgmix, GlobalC::ucell, orb_); } #endif // __EXX @@ -227,21 +228,12 @@ void ESolver_KS_LCAO::before_scf(const int istep) { std::stringstream ss; ss << PARAM.globalv.global_out_dir << "SPIN" << is + 1 << "_CHG_INI.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, // bz first, then nbz - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->rho[is], is, PARAM.inp.nspin, istep, ss.str(), - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.ef, &(GlobalC::ucell)); } @@ -254,21 +246,12 @@ void ESolver_KS_LCAO::before_scf(const int istep) { std::stringstream ss; ss << PARAM.globalv.global_out_dir << "SPIN" << is + 1 << "_POT_INI.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->pot->get_effective_v(is), is, PARAM.inp.nspin, istep, ss.str(), - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, 0.0, // efermi &(GlobalC::ucell), 11, // precsion @@ -309,21 +292,12 @@ void ESolver_KS_LCAO::before_scf(const int istep) for (int is = 0; is < nspin0; is++) { std::string fn = PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->charge->rho[is], is, PARAM.inp.nspin, istep, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, this->pelec->eferm.get_efval(is), &(GlobalC::ucell), 3, diff --git a/source/module_esolver/lcao_gets.cpp b/source/module_esolver/lcao_gets.cpp index cb1c1ab696a..19af5289668 100644 --- a/source/module_esolver/lcao_gets.cpp +++ b/source/module_esolver/lcao_gets.cpp @@ -22,7 +22,6 @@ #include "module_hamilt_lcao/hamilt_lcaodft/operator_lcao/operator_lcao.h" #include "module_hamilt_lcao/module_deltaspin/spin_constrain.h" #include "module_io/read_wfc_nao.h" -#include "module_io/rho_io.h" #include "module_io/write_elecstat_pot.h" #include "module_io/write_wfc_nao.h" #ifdef __EXX diff --git a/source/module_esolver/lcao_nscf.cpp b/source/module_esolver/lcao_nscf.cpp index 7904c0d6ea5..4bb4624e6a0 100644 --- a/source/module_esolver/lcao_nscf.cpp +++ b/source/module_esolver/lcao_nscf.cpp @@ -29,7 +29,6 @@ #include "module_hamilt_lcao/hamilt_lcaodft/operator_lcao/operator_lcao.h" #include "module_hamilt_lcao/module_deltaspin/spin_constrain.h" #include "module_io/read_wfc_nao.h" -#include "module_io/rho_io.h" #include "module_io/write_elecstat_pot.h" #include "module_io/write_wfc_nao.h" #ifdef __EXX @@ -53,7 +52,7 @@ void ESolver_KS_LCAO::nscf() { // istep becomes istep-1, this should be fixed in future int istep = 0; hsolver::HSolverLCAO hsolver_lcao_obj(&(this->pv), PARAM.inp.ks_solver); - hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, PARAM.inp.ks_solver, true); + hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, true); time_t time_finish = std::time(nullptr); ModuleBase::GlobalFunc::OUT_TIME("cal_bands", time_start, time_finish); @@ -62,7 +61,7 @@ void ESolver_KS_LCAO::nscf() { GlobalV::ofs_running << " band eigenvalue in this processor (eV) :" << std::endl; const int nspin = PARAM.inp.nspin; - const int nbands = GlobalV::NBANDS; + const int nbands = PARAM.inp.nbands; for (int ik = 0; ik < this->kv.get_nks(); ++ik) { @@ -197,21 +196,12 @@ void ESolver_KS_LCAO::nscf() { { std::string fn = PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_POT.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->pot->get_effective_v(is), is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, 0.0, // efermi &(GlobalC::ucell), 3, // precision diff --git a/source/module_esolver/lcao_others.cpp b/source/module_esolver/lcao_others.cpp index 667eac6c208..5b07c91f161 100644 --- a/source/module_esolver/lcao_others.cpp +++ b/source/module_esolver/lcao_others.cpp @@ -27,7 +27,6 @@ #include "module_hamilt_lcao/hamilt_lcaodft/operator_lcao/operator_lcao.h" #include "module_hamilt_lcao/module_deltaspin/spin_constrain.h" #include "module_io/read_wfc_nao.h" -#include "module_io/rho_io.h" #include "module_io/write_elecstat_pot.h" #include "module_io/write_wfc_nao.h" #ifdef __EXX @@ -110,13 +109,12 @@ void ESolver_KS_LCAO::others(const int istep) this->pw_big->nbz, PARAM.globalv.gamma_only_local, PARAM.inp.nbands_istate, - PARAM.inp.bands_to_print, - GlobalV::NBANDS, - GlobalV::nelec, + PARAM.inp.out_pchg, + PARAM.inp.nbands, + PARAM.inp.nelec, PARAM.inp.nspin, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, PARAM.globalv.global_out_dir, - GlobalV::MY_RANK, GlobalV::ofs_warning, &GlobalC::ucell, &GlobalC::GridD, @@ -140,13 +138,12 @@ void ESolver_KS_LCAO::others(const int istep) this->pw_big->nbz, PARAM.globalv.gamma_only_local, PARAM.inp.nbands_istate, - PARAM.inp.bands_to_print, - GlobalV::NBANDS, - GlobalV::nelec, + PARAM.inp.out_pchg, + PARAM.inp.nbands, + PARAM.inp.nelec, PARAM.inp.nspin, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, PARAM.globalv.global_out_dir, - GlobalV::MY_RANK, GlobalV::ofs_warning, &GlobalC::ucell, &GlobalC::GridD, @@ -172,12 +169,13 @@ void ESolver_KS_LCAO::others(const int istep) PARAM.inp.out_wfc_pw, this->wf.out_wfc_r, this->kv, - GlobalV::nelec, + PARAM.inp.nelec, PARAM.inp.nbands_istate, - PARAM.inp.bands_to_print, - GlobalV::NBANDS, + PARAM.inp.out_wfc_norm, + PARAM.inp.out_wfc_re_im, + PARAM.inp.nbands, PARAM.inp.nspin, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, PARAM.globalv.global_out_dir); } else @@ -191,12 +189,13 @@ void ESolver_KS_LCAO::others(const int istep) PARAM.inp.out_wfc_pw, this->wf.out_wfc_r, this->kv, - GlobalV::nelec, + PARAM.inp.nelec, PARAM.inp.nbands_istate, - PARAM.inp.bands_to_print, - GlobalV::NBANDS, + PARAM.inp.out_wfc_norm, + PARAM.inp.out_wfc_re_im, + PARAM.inp.nbands, PARAM.inp.nspin, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, PARAM.globalv.global_out_dir); } std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "getting wave function"); diff --git a/source/module_esolver/print_funcs.cpp b/source/module_esolver/print_funcs.cpp deleted file mode 100644 index c5a7c8c2726..00000000000 --- a/source/module_esolver/print_funcs.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "esolver_ks.h" -#include - -#include "module_io/print_info.h" -#include "module_parameter/parameter.h" -#include "module_base/global_variable.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" - -namespace Print_functions -{ - -void print_wfcfft( - const Input_para& inp, - ModulePW::PW_Basis_K& pw_wfc, - std::ofstream& ofs) -{ - ofs << "\n\n\n\n"; - ofs << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" - ">>>>" - << std::endl; - ofs << " | " - " |" - << std::endl; - ofs << " | Setup plane waves of wave functions: " - " |" - << std::endl; - ofs << " | Use the energy cutoff and the lattice vectors to generate the " - " |" - << std::endl; - ofs << " | dimensions of FFT grid. The number of FFT grid on each " - "processor |" - << std::endl; - ofs << " | is 'nrxx'. The number of plane wave basis in reciprocal space " - "is |" - << std::endl; - ofs << " | different for charege/potential and wave functions. We also set " - " |" - << std::endl; - ofs << " | the 'sticks' for the parallel of FFT. The number of plane wave " - "of |" - << std::endl; - ofs << " | each k-point is 'npwk[ik]' in each processor " - " |" - << std::endl; - ofs << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" - "<<<<" - << std::endl; - ofs << "\n\n\n\n"; - ofs << "\n SETUP PLANE WAVES FOR WAVE FUNCTIONS" << std::endl; - - double ecut = inp.ecutwfc; - if (std::abs(ecut - pw_wfc.gk_ecut * pw_wfc.tpiba2) > 1e-6) - { - ecut = pw_wfc.gk_ecut * pw_wfc.tpiba2; - ofs << "Energy cutoff for wavefunc is incompatible with nx, ny, nz and " - "it will be reduced!" - << std::endl; - } - ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for wavefunc (unit:Ry)", ecut); - ModuleBase::GlobalFunc::OUT(ofs, - "fft grid for wave functions", - pw_wfc.nx, - pw_wfc.ny, - pw_wfc.nz); - ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", pw_wfc.npwtot); - ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", pw_wfc.nstot); - - ofs << "\n PARALLEL PW FOR WAVE FUNCTIONS" << std::endl; - ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; - - for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) - { - ofs << " " << std::setw(8) << i + 1 << std::setw(15) << pw_wfc.nst_per[i] << std::setw(15) - << pw_wfc.npw_per[i] << std::endl; - } - - ofs << " --------------- sum -------------------" << std::endl; - ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << pw_wfc.nstot << std::setw(15) - << pw_wfc.npwtot << std::endl; - ModuleBase::GlobalFunc::DONE(ofs, "INIT PLANEWAVE"); -} - -} diff --git a/source/module_esolver/print_funcs.h b/source/module_esolver/print_funcs.h deleted file mode 100644 index 5a13df560a2..00000000000 --- a/source/module_esolver/print_funcs.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef PRINT_FUNCTIONS_H -#define PRINT_FUNCTIONS_H - -#include "module_parameter/input_parameter.h" -#include "module_basis/module_pw/pw_basis_k.h" - -namespace Print_functions -{ - void print_wfcfft( - const Input_para& inp, - ModulePW::PW_Basis_K& pw_wfc, - std::ofstream& ofs); -} - -#endif diff --git a/source/module_esolver/pw_fun.cpp b/source/module_esolver/pw_fun.cpp index dd227245982..81ca1d00be0 100644 --- a/source/module_esolver/pw_fun.cpp +++ b/source/module_esolver/pw_fun.cpp @@ -34,7 +34,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" @@ -71,15 +70,6 @@ void ESolver_KS_PW::hamilt2estates(const double ethr) hsolver::DiagoIterAssist::need_subspace = false; hsolver::DiagoIterAssist::PW_DIAG_THR = ethr; - std::vector is_occupied(this->kspw_psi->get_nk() * this->kspw_psi->get_nbands(), true); - - elecstate::set_is_occupied(is_occupied, - this->pelec, - hsolver::DiagoIterAssist::SCF_ITER, - this->kspw_psi->get_nk(), - this->kspw_psi->get_nbands(), - PARAM.inp.diago_full_acc); - hsolver::HSolverPW hsolver_pw_obj(this->pw_wfc, &this->wf, @@ -87,7 +77,7 @@ void ESolver_KS_PW::hamilt2estates(const double ethr) PARAM.inp.basis_type, PARAM.inp.ks_solver, PARAM.inp.use_paw, - GlobalV::use_uspp, + PARAM.globalv.use_uspp, PARAM.inp.nspin, hsolver::DiagoIterAssist::SCF_ITER, @@ -101,7 +91,6 @@ void ESolver_KS_PW::hamilt2estates(const double ethr) this->kspw_psi[0], this->pelec, this->pelec->ekb.c, - is_occupied, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL, true); diff --git a/source/module_esolver/pw_init_after_vc.cpp b/source/module_esolver/pw_init_after_vc.cpp index 27632fae36e..7d67d6f55f6 100644 --- a/source/module_esolver/pw_init_after_vc.cpp +++ b/source/module_esolver/pw_init_after_vc.cpp @@ -34,7 +34,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" diff --git a/source/module_esolver/pw_init_globalc.cpp b/source/module_esolver/pw_init_globalc.cpp index 9fd7b7110e7..ef1dbf31cc8 100644 --- a/source/module_esolver/pw_init_globalc.cpp +++ b/source/module_esolver/pw_init_globalc.cpp @@ -34,7 +34,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" @@ -90,7 +89,7 @@ void ESolver_KS_PW::Init_GlobalC(const Input_para& inp, &(this->sf)); this->kspw_psi - = PARAM.globalv.device_flag == "gpu" || PARAM.inp.precision == "single" + = PARAM.inp.device == "gpu" || PARAM.inp.precision == "single" ? new psi::Psi(this->psi[0]) : reinterpret_cast*>(this->psi); diff --git a/source/module_esolver/pw_nscf.cpp b/source/module_esolver/pw_nscf.cpp index acc5534be94..09217ff02fb 100644 --- a/source/module_esolver/pw_nscf.cpp +++ b/source/module_esolver/pw_nscf.cpp @@ -34,7 +34,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" @@ -64,7 +63,7 @@ void ESolver_KS_PW::nscf() { if (diag_ethr - 1e-2 > -1e-5) { diag_ethr = std::max(1e-13, - 0.1 * std::min(1e-2, PARAM.inp.scf_thr / GlobalV::nelec)); + 0.1 * std::min(1e-2, PARAM.inp.scf_thr / PARAM.inp.nelec)); } GlobalV::ofs_running << " PW_DIAG_THR = " << diag_ethr << std::endl; @@ -79,7 +78,7 @@ void ESolver_KS_PW::nscf() { //! 4) print out band energies and weights std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "writing band energies"); const int nspin = PARAM.inp.nspin; - const int nbands = GlobalV::NBANDS; + const int nbands = PARAM.inp.nbands; for (int ik = 0; ik < this->kv.get_nks(); ik++) { if (nspin == 2) { if (ik == 0) { @@ -166,21 +165,12 @@ void ESolver_KS_PW::nscf() { { std::string fn = PARAM.globalv.global_out_dir + "/SPIN" + std::to_string(is + 1) + "_POT.cube"; - ModuleIO::write_cube( -#ifdef __MPI - this->pw_big->bz, - this->pw_big->nbz, - this->pw_rhod->nplane, - this->pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, this->pelec->pot->get_effective_v(is), is, PARAM.inp.nspin, 0, fn, - this->pw_rhod->nx, - this->pw_rhod->ny, - this->pw_rhod->nz, 0.0, // efermi &(GlobalC::ucell), 3, // precision diff --git a/source/module_esolver/pw_others.cpp b/source/module_esolver/pw_others.cpp index 14423a8c7a7..23439501c18 100644 --- a/source/module_esolver/pw_others.cpp +++ b/source/module_esolver/pw_others.cpp @@ -34,7 +34,6 @@ #include "module_io/berryphase.h" #include "module_io/numerical_basis.h" #include "module_io/numerical_descriptor.h" -#include "module_io/rho_io.h" #include "module_io/to_wannier90_pw.h" #include "module_io/winput.h" #include "module_io/write_elecstat_pot.h" diff --git a/source/module_esolver/set_matrix_grid.cpp b/source/module_esolver/set_matrix_grid.cpp index 508ecc452d0..7766804e679 100644 --- a/source/module_esolver/set_matrix_grid.cpp +++ b/source/module_esolver/set_matrix_grid.cpp @@ -12,7 +12,6 @@ #include "module_hamilt_lcao/hamilt_lcaodft/operator_lcao/operator_lcao.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_io/read_wfc_nao.h" -#include "module_io/rho_io.h" #include "module_io/write_elecstat_pot.h" #include "module_io/write_wfc_nao.h" #include "module_parameter/parameter.h" diff --git a/source/module_hamilt_general/module_surchem/test/CMakeLists.txt b/source/module_hamilt_general/module_surchem/test/CMakeLists.txt index 52fe1cc14a8..0b1c30ebd24 100644 --- a/source/module_hamilt_general/module_surchem/test/CMakeLists.txt +++ b/source/module_hamilt_general/module_surchem/test/CMakeLists.txt @@ -33,7 +33,11 @@ AddTest( SOURCES cal_vcav_test.cpp ../cal_vcav.cpp ../surchem.cpp ../../../module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp ../../module_xc/xc_functional_gradcorr.cpp ../../module_xc/xc_functional.cpp ../../module_xc/xc_functional_wrapper_xc.cpp ../../module_xc/xc_functional_wrapper_gcxc.cpp - ../../module_xc/xc_functional_wrapper_tauxc.cpp + ../../module_xc/xc_functional_libxc.cpp + ../../module_xc/xc_functional_libxc_vxc.cpp + ../../module_xc/xc_functional_libxc_wrapper_xc.cpp + ../../module_xc/xc_functional_libxc_wrapper_gcxc.cpp + ../../module_xc/xc_functional_libxc_wrapper_tauxc.cpp ../../module_xc/xc_funct_corr_gga.cpp ../../module_xc/xc_funct_corr_lda.cpp ../../module_xc/xc_funct_exch_gga.cpp ../../module_xc/xc_funct_exch_lda.cpp ../../module_xc/xc_funct_hcth.cpp ) @@ -44,7 +48,11 @@ AddTest( SOURCES cal_vel_test.cpp ../cal_vel.cpp ../surchem.cpp ../cal_epsilon.cpp ../minimize_cg.cpp ../../../module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp ../../module_xc/xc_functional_gradcorr.cpp ../../module_xc/xc_functional.cpp ../../module_xc/xc_functional_wrapper_xc.cpp ../../module_xc/xc_functional_wrapper_gcxc.cpp - ../../module_xc/xc_functional_wrapper_tauxc.cpp + ../../module_xc/xc_functional_libxc.cpp + ../../module_xc/xc_functional_libxc_vxc.cpp + ../../module_xc/xc_functional_libxc_wrapper_xc.cpp + ../../module_xc/xc_functional_libxc_wrapper_gcxc.cpp + ../../module_xc/xc_functional_libxc_wrapper_tauxc.cpp ../../module_xc/xc_funct_corr_gga.cpp ../../module_xc/xc_funct_corr_lda.cpp ../../module_xc/xc_funct_exch_gga.cpp ../../module_xc/xc_funct_exch_lda.cpp ../../module_xc/xc_funct_hcth.cpp ) \ No newline at end of file diff --git a/source/module_hamilt_general/module_vdw/dftd3_xc_name.h b/source/module_hamilt_general/module_vdw/dftd3_xc_name.h new file mode 100644 index 00000000000..f2f1280bc8d --- /dev/null +++ b/source/module_hamilt_general/module_vdw/dftd3_xc_name.h @@ -0,0 +1,610 @@ +#ifndef DFTD3_XC_NAME_H +#define DFTD3_XC_NAME_H +/** + * Intro + * ----- + * This file stores the mapping from LibXC xcname to the "conventional" + * + * XCNotSupportedError + * ------------------- + * GGA_X_REVSSB_D + * GGA_X_SSB_D + * + * in J. Chem. Phys. 131, 094103 2009, a simplified version of PBC (the + * correlation part of PBE XC) is used as the correlation part, but libXC + * does not directly support one named as + * GGA_C_SPBEC. + * + * Certainly, those XC with dispersion correction in form of non-local + * correlation are not supported. Such as: + * + * vdw-DF family nonlocal dispersion correction included are not supported: + * GGA_X_OPTB86B_VDW + * GGA_X_OPTB88_VDW + * GGA_X_OPTPBE_VDW + * GGA_X_PBEK1_VDW + * + * VV09, VV10 and rVV10 nonlocal correlation included are not supported: + * GGA_XC_VV10 + * HYB_GGA_XC_LC_VV10 + * HYB_MGGA_XC_WB97M_V + * HYB_GGA_XC_WB97X_V + * MGGA_X_VCML + * MGGA_C_REVSCAN_VV10 + * MGGA_C_SCAN_VV10 + * MGGA_C_SCANL_VV10 + * MGGA_XC_B97M_V + * MGGA_XC_VCML_RVV10 + * + * There is also one quite special, the wB97X-D3BJ functional uses the + * wB97X-V functionals excluding the VV10 part, then use its own DFT-D3(BJ) + * parameters. This seems not recorded in simple-dftd3, so it is not supported + * temporarily: + * HYB_GGA_XC_WB97X_D3BJ + * HYB_GGA_XC_WB97X_V + */ +#include +#include +#include +#include "module_base/formatter.h" +#include +#include +#include "module_base/tool_quit.h" + +namespace DFTD3 { + const std::map xcname_libxc_xc_ = { + {"XC_LDA_XC_TETER93", "teter93"}, + {"XC_LDA_XC_ZLP", "zlp"}, + {"XC_MGGA_XC_OTPSS_D", "otpss_d"}, // DFT-D2 + {"XC_GGA_XC_OPBE_D", "opbe_d"}, // DFT-D2 + {"XC_GGA_XC_OPWLYP_D", "opwlyp_d"}, // DFT-D2 + {"XC_GGA_XC_OBLYP_D", "oblyp_d"}, // DFT-D2 + {"XC_GGA_XC_HCTH_407P", "hcth_407p"}, + {"XC_GGA_XC_HCTH_P76", "hcth_p76"}, + {"XC_GGA_XC_HCTH_P14", "hcth_p14"}, + {"XC_GGA_XC_B97_GGA1", "b97_gga1"}, + {"XC_GGA_XC_KT2", "kt2"}, + {"XC_GGA_XC_TH1", "th1"}, + {"XC_GGA_XC_TH2", "th2"}, + {"XC_GGA_XC_TH3", "th3"}, + {"XC_GGA_XC_TH4", "th4"}, + {"XC_GGA_XC_HCTH_93", "hcth_93"}, + {"XC_GGA_XC_HCTH_120", "hcth_120"}, + {"XC_GGA_XC_HCTH_147", "hcth_147"}, + {"XC_GGA_XC_HCTH_407", "hcth_407"}, + {"XC_GGA_XC_EDF1", "edf1"}, + {"XC_GGA_XC_XLYP", "xlyp"}, + {"XC_GGA_XC_KT1", "kt1"}, + {"XC_GGA_XC_B97_D", "b97_d"}, // DFT-D2? + {"XC_GGA_XC_PBE1W", "pbe1w"}, + {"XC_GGA_XC_MPWLYP1W", "mpwlyp1w"}, + {"XC_GGA_XC_PBELYP1W", "pbelyp1w"}, + {"XC_HYB_LDA_XC_LDA0", "lda0"}, + {"XC_HYB_LDA_XC_CAM_LDA0", "cam_lda0"}, + {"XC_GGA_XC_NCAP", "ncap"}, + {"XC_GGA_XC_MOHLYP", "mohlyp"}, + {"XC_GGA_XC_MOHLYP2", "mohlyp2"}, + {"XC_GGA_XC_TH_FL", "th_fl"}, + {"XC_GGA_XC_TH_FC", "th_fc"}, + {"XC_GGA_XC_TH_FCFO", "th_fcfo"}, + {"XC_GGA_XC_TH_FCO", "th_fco"}, + {"XC_MGGA_XC_CC06", "cc06"}, + {"XC_MGGA_XC_TPSSLYP1W", "tpsslyp1w"}, + {"XC_MGGA_XC_B97M_V", "b97m_v"}, + {"XC_GGA_XC_VV10", "vv10"}, + {"XC_LDA_XC_KSDT", "ksdt"}, + {"XC_HYB_GGA_XC_B97_1P", "b97_1p"}, + {"XC_HYB_GGA_XC_PBE_MOL0", "pbe_mol0"}, + {"XC_HYB_GGA_XC_PBE_SOL0", "pbe_sol0"}, + {"XC_HYB_GGA_XC_PBEB0", "pbeb0"}, + {"XC_HYB_GGA_XC_PBE_MOLB0", "pbe_molb0"}, + {"XC_GGA_XC_BEEFVDW", "beefvdw"}, + {"XC_MGGA_XC_HLE17", "hle17"}, + {"XC_HYB_GGA_XC_PBE50", "pbe50"}, + {"XC_HYB_GGA_XC_HFLYP", "hflyp"}, + {"XC_HYB_GGA_XC_B3P86_NWCHEM", "b3p86_nwchem"}, + {"XC_LDA_XC_CORRKSDT", "corrksdt"}, + {"XC_HYB_GGA_XC_RELPBE0", "relpbe0"}, + {"XC_GGA_XC_B97_3C", "b97_3c"}, + {"XC_HYB_MGGA_XC_BR3P86", "br3p86"}, + {"XC_HYB_GGA_XC_CASE21", "case21"}, + {"XC_HYB_GGA_XC_PBE_2X", "pbe_2x"}, + {"XC_HYB_GGA_XC_PBE38", "pbe38"}, + {"XC_HYB_GGA_XC_B3LYP3", "b3lyp3"}, + {"XC_HYB_GGA_XC_CAM_O3LYP", "cam_o3lyp"}, + {"XC_HYB_MGGA_XC_TPSS0", "tpss0"}, + {"XC_HYB_MGGA_XC_B94_HYB", "b94_hyb"}, + {"XC_HYB_GGA_XC_WB97X_D3", "wb97x_d3"}, // DFT-D3(0) + {"XC_HYB_GGA_XC_LC_BLYP", "lc_blyp"}, + {"XC_HYB_GGA_XC_B3PW91", "b3pw91"}, + {"XC_HYB_GGA_XC_B3LYP", "b3lyp"}, + {"XC_HYB_GGA_XC_B3P86", "b3p86"}, + {"XC_HYB_GGA_XC_O3LYP", "o3lyp"}, + {"XC_HYB_GGA_XC_MPW1K", "mpw1k"}, + {"XC_HYB_GGA_XC_PBEH", "pbeh"}, + {"XC_HYB_GGA_XC_B97", "b97"}, + {"XC_HYB_GGA_XC_B97_1", "b97_1"}, + {"XC_HYB_GGA_XC_APF", "apf"}, + {"XC_HYB_GGA_XC_B97_2", "b97_2"}, + {"XC_HYB_GGA_XC_X3LYP", "x3lyp"}, + {"XC_HYB_GGA_XC_B1WC", "b1wc"}, + {"XC_HYB_GGA_XC_B97_K", "b97_k"}, + {"XC_HYB_GGA_XC_B97_3", "b97_3"}, + {"XC_HYB_GGA_XC_MPW3PW", "mpw3pw"}, + {"XC_HYB_GGA_XC_B1LYP", "b1lyp"}, + {"XC_HYB_GGA_XC_B1PW91", "b1pw91"}, + {"XC_HYB_GGA_XC_MPW1PW", "mpw1pw"}, + {"XC_HYB_GGA_XC_MPW3LYP", "mpw3lyp"}, + {"XC_HYB_GGA_XC_SB98_1A", "sb98_1a"}, + {"XC_HYB_GGA_XC_SB98_1B", "sb98_1b"}, + {"XC_HYB_GGA_XC_SB98_1C", "sb98_1c"}, + {"XC_HYB_GGA_XC_SB98_2A", "sb98_2a"}, + {"XC_HYB_GGA_XC_SB98_2B", "sb98_2b"}, + {"XC_HYB_GGA_XC_SB98_2C", "sb98_2c"}, + {"XC_HYB_GGA_XC_HSE03", "hse03"}, + {"XC_HYB_GGA_XC_HSE06", "hse06"}, + {"XC_HYB_GGA_XC_HJS_PBE", "hjs_pbe"}, + {"XC_HYB_GGA_XC_HJS_PBE_SOL", "hjs_pbe_sol"}, + {"XC_HYB_GGA_XC_HJS_B88", "hjs_b88"}, + {"XC_HYB_GGA_XC_HJS_B97X", "hjs_b97x"}, + {"XC_HYB_GGA_XC_CAM_B3LYP", "cam_b3lyp"}, + {"XC_HYB_GGA_XC_TUNED_CAM_B3LYP", "tuned_cam_b3lyp"}, + {"XC_HYB_GGA_XC_BHANDH", "bhandh"}, + {"XC_HYB_GGA_XC_BHANDHLYP", "bhandhlyp"}, + {"XC_HYB_GGA_XC_MB3LYP_RC04", "mb3lyp_rc04"}, + {"XC_HYB_MGGA_XC_B88B95", "b88b95"}, + {"XC_HYB_MGGA_XC_B86B95", "b86b95"}, + {"XC_HYB_MGGA_XC_PW86B95", "pw86b95"}, + {"XC_HYB_MGGA_XC_BB1K", "bb1k"}, + {"XC_HYB_MGGA_XC_MPW1B95", "mpw1b95"}, + {"XC_HYB_MGGA_XC_MPWB1K", "mpwb1k"}, + {"XC_HYB_MGGA_XC_X1B95", "x1b95"}, + {"XC_HYB_MGGA_XC_XB1K", "xb1k"}, + {"XC_HYB_MGGA_XC_PW6B95", "pw6b95"}, + {"XC_HYB_MGGA_XC_PWB6K", "pwb6k"}, + {"XC_HYB_GGA_XC_MPWLYP1M", "mpwlyp1m"}, + {"XC_HYB_GGA_XC_REVB3LYP", "revb3lyp"}, + {"XC_HYB_GGA_XC_CAMY_BLYP", "camy_blyp"}, + {"XC_HYB_GGA_XC_PBE0_13", "pbe0_13"}, + {"XC_HYB_MGGA_XC_TPSSH", "tpssh"}, + {"XC_HYB_MGGA_XC_REVTPSSH", "revtpssh"}, + {"XC_HYB_GGA_XC_B3LYPS", "b3lyps"}, + {"XC_HYB_GGA_XC_QTP17", "qtp17"}, + {"XC_HYB_GGA_XC_B3LYP_MCM1", "b3lyp_mcm1"}, + {"XC_HYB_GGA_XC_B3LYP_MCM2", "b3lyp_mcm2"}, + {"XC_HYB_GGA_XC_WB97", "wb97"}, + {"XC_HYB_GGA_XC_WB97X", "wb97x"}, + {"XC_HYB_GGA_XC_LRC_WPBEH", "lrc_wpbeh"}, + {"XC_HYB_GGA_XC_WB97X_V", "wb97x_v"}, + {"XC_HYB_GGA_XC_LCY_PBE", "lcy_pbe"}, + {"XC_HYB_GGA_XC_LCY_BLYP", "lcy_blyp"}, + {"XC_HYB_GGA_XC_LC_VV10", "lc_vv10"}, + {"XC_HYB_GGA_XC_CAMY_B3LYP", "camy_b3lyp"}, + {"XC_HYB_GGA_XC_WB97X_D", "wb97x_d"}, // DFT-D2 + {"XC_HYB_GGA_XC_HPBEINT", "hpbeint"}, + {"XC_HYB_GGA_XC_LRC_WPBE", "lrc_wpbe"}, + {"XC_HYB_GGA_XC_B3LYP5", "b3lyp5"}, + {"XC_HYB_GGA_XC_EDF2", "edf2"}, + {"XC_HYB_GGA_XC_CAP0", "cap0"}, + {"XC_HYB_GGA_XC_LC_WPBE", "lc_wpbe"}, + {"XC_HYB_GGA_XC_HSE12", "hse12"}, + {"XC_HYB_GGA_XC_HSE12S", "hse12s"}, + {"XC_HYB_GGA_XC_HSE_SOL", "hse_sol"}, + {"XC_HYB_GGA_XC_CAM_QTP_01", "cam_qtp_01"}, + {"XC_HYB_GGA_XC_MPW1LYP", "mpw1lyp"}, + {"XC_HYB_GGA_XC_MPW1PBE", "mpw1pbe"}, + {"XC_HYB_GGA_XC_KMLYP", "kmlyp"}, + {"XC_HYB_GGA_XC_LC_WPBE_WHS", "lc_wpbe_whs"}, + {"XC_HYB_GGA_XC_LC_WPBEH_WHS", "lc_wpbeh_whs"}, + {"XC_HYB_GGA_XC_LC_WPBE08_WHS", "lc_wpbe08_whs"}, + {"XC_HYB_GGA_XC_LC_WPBESOL_WHS", "lc_wpbesol_whs"}, + {"XC_HYB_GGA_XC_CAM_QTP_00", "cam_qtp_00"}, + {"XC_HYB_GGA_XC_CAM_QTP_02", "cam_qtp_02"}, + {"XC_HYB_GGA_XC_LC_QTP", "lc_qtp"}, + {"XC_HYB_GGA_XC_BLYP35", "blyp35"}, + {"XC_HYB_MGGA_XC_WB97M_V", "wb97m_v"}, + {"XC_LDA_XC_1D_EHWLRG_1", "1d_ehwlrg_1"}, + {"XC_LDA_XC_1D_EHWLRG_2", "1d_ehwlrg_2"}, + {"XC_LDA_XC_1D_EHWLRG_3", "1d_ehwlrg_3"}, + {"XC_GGA_XC_HLE16", "hle16"}, + {"XC_LDA_XC_LP_A", "lp_a"}, + {"XC_LDA_XC_LP_B", "lp_b"}, + {"XC_HYB_MGGA_XC_B0KCIS", "b0kcis"}, + {"XC_MGGA_XC_LP90", "lp90"}, + {"XC_HYB_MGGA_XC_MPW1KCIS", "mpw1kcis"}, + {"XC_HYB_MGGA_XC_MPWKCIS1K", "mpwkcis1k"}, + {"XC_HYB_MGGA_XC_PBE1KCIS", "pbe1kcis"}, + {"XC_HYB_MGGA_XC_TPSS1KCIS", "tpss1kcis"}, + {"XC_HYB_GGA_XC_B5050LYP", "b5050lyp"}, + {"XC_LDA_XC_GDSMFB", "gdsmfb"}, + {"XC_GGA_XC_KT3", "kt3"}, + {"XC_HYB_LDA_XC_BN05", "bn05"}, + {"XC_HYB_GGA_XC_LB07", "lb07"}, + {"XC_HYB_MGGA_XC_B98", "b98"}, + {"XC_LDA_XC_TIH", "tih"}, + {"XC_HYB_GGA_XC_APBE0", "apbe0"}, + {"XC_HYB_GGA_XC_HAPBE", "hapbe"}, + {"XC_HYB_GGA_XC_RCAM_B3LYP", "rcam_b3lyp"}, + {"XC_HYB_GGA_XC_WC04", "wc04"}, + {"XC_HYB_GGA_XC_WP04", "wp04"}, + {"XC_HYB_GGA_XC_CAMH_B3LYP", "camh_b3lyp"}, + {"XC_HYB_GGA_XC_WHPBE0", "whpbe0"}, + {"XC_HYB_GGA_XC_LC_BLYP_EA", "lc_blyp_ea"}, + {"XC_HYB_GGA_XC_LC_BOP", "lc_bop"}, + {"XC_HYB_GGA_XC_LC_PBEOP", "lc_pbeop"}, + {"XC_HYB_GGA_XC_LC_BLYPR", "lc_blypr"}, + {"XC_HYB_GGA_XC_MCAM_B3LYP", "mcam_b3lyp"}, + {"XC_MGGA_XC_VCML_RVV10", "vcml_rvv10"}, + {"XC_HYB_MGGA_XC_GAS22", "gas22"}, + {"XC_HYB_MGGA_XC_R2SCANH", "r2scanh"}, + {"XC_HYB_MGGA_XC_R2SCAN0", "r2scan0"}, + {"XC_HYB_MGGA_XC_R2SCAN50", "r2scan50"}, + {"XC_HYB_GGA_XC_CAM_PBEH", "cam_pbeh"}, + {"XC_HYB_GGA_XC_CAMY_PBEH", "camy_pbeh"}, + {"XC_HYB_MGGA_XC_EDMGGAH", "edmggah"}, + {"XC_HYB_MGGA_XC_LC_TMLYP", "lc_tmlyp"}, + }; + const std::map xcname_libxc_xplusc_ = { + {"XC_GGA_X_GAM+XC_GGA_C_GAM", "gam"}, + {"XC_GGA_X_HCTH_A+XC_GGA_C_HCTH_A", "hcth_a"}, + {"XC_HYB_MGGA_X_DLDF+XC_MGGA_C_DLDF", "dldf"}, + {"XC_GGA_X_Q2D+XC_GGA_C_Q2D", "q2d"}, + {"XC_GGA_X_PBE_MOL+XC_GGA_C_PBE_MOL", "pbe_mol"}, + {"XC_GGA_X_PBEINT+XC_GGA_C_PBEINT", "pbeint"}, + {"XC_HYB_GGA_X_N12_SX+XC_GGA_C_N12_SX", "n12_sx"}, + {"XC_GGA_X_N12+XC_GGA_C_N12", "n12"}, + {"XC_GGA_X_PBE+XC_GGA_C_PBE", "pbe"}, + {"XC_GGA_X_B88+XC_MGGA_C_B88", "b88"}, + {"XC_GGA_X_PW91+XC_GGA_C_PW91", "pw91"}, + {"XC_GGA_X_PBE_SOL+XC_GGA_C_PBE_SOL", "pbe_sol"}, + {"XC_GGA_X_AM05+XC_GGA_C_AM05", "am05"}, + {"XC_GGA_X_XPBE+XC_GGA_C_XPBE", "xpbe"}, + {"XC_GGA_X_RGE2+XC_GGA_C_RGE2", "rge2"}, + {"XC_GGA_X_SOGGA11+XC_GGA_C_SOGGA11", "sogga11"}, + {"XC_GGA_X_APBE+XC_GGA_C_APBE", "apbe"}, + {"XC_MGGA_X_TPSS+XC_MGGA_C_TPSS", "tpss"}, + {"XC_MGGA_X_M06_L+XC_MGGA_C_M06_L", "m06_l"}, + {"XC_HYB_MGGA_X_TAU_HCTH+XC_GGA_C_TAU_HCTH", "tau_hcth"}, + {"XC_MGGA_X_REVTPSS+XC_MGGA_C_REVTPSS", "revtpss"}, + {"XC_MGGA_X_PKZB+XC_MGGA_C_PKZB", "pkzb"}, + {"XC_MGGA_X_M11_L+XC_MGGA_C_M11_L", "m11_l"}, + {"XC_MGGA_X_MN12_L+XC_MGGA_C_MN12_L", "mn12_l"}, + {"XC_HYB_MGGA_X_MN12_SX+XC_MGGA_C_MN12_SX", "mn12_sx"}, + {"XC_MGGA_X_MN15_L+XC_MGGA_C_MN15_L", "mn15_l"}, + {"XC_MGGA_X_SCAN+XC_MGGA_C_SCAN", "scan"}, + {"XC_GGA_X_PBEFE+XC_GGA_C_PBEFE", "pbefe"}, + {"XC_HYB_MGGA_X_MN15+XC_MGGA_C_MN15", "mn15"}, + {"XC_HYB_MGGA_X_BMK+XC_GGA_C_BMK", "bmk"}, + {"XC_MGGA_X_REVM06_L+XC_MGGA_C_REVM06_L", "revm06_l"}, + {"XC_HYB_MGGA_X_M08_HX+XC_MGGA_C_M08_HX", "m08_hx"}, + {"XC_HYB_MGGA_X_M08_SO+XC_MGGA_C_M08_SO", "m08_so"}, + {"XC_HYB_MGGA_X_M11+XC_MGGA_C_M11", "m11"}, + {"XC_GGA_X_CHACHIYO+XC_GGA_C_CHACHIYO", "chachiyo"}, + {"XC_HYB_MGGA_X_REVM11+XC_MGGA_C_REVM11", "revm11"}, + {"XC_HYB_MGGA_X_REVM06+XC_MGGA_C_REVM06", "revm06"}, + {"XC_HYB_MGGA_X_M06_SX+XC_MGGA_C_M06_SX", "m06_sx"}, + {"XC_GGA_X_PBE_GAUSSIAN+XC_GGA_C_PBE_GAUSSIAN", "pbe_gaussian"}, + {"XC_HYB_GGA_X_SOGGA11_X+XC_GGA_C_SOGGA11_X", "sogga11_x"}, + {"XC_HYB_MGGA_X_M05+XC_MGGA_C_M05", "m05"}, + {"XC_HYB_MGGA_X_M05_2X+XC_MGGA_C_M05_2X", "m05_2x"}, + {"XC_HYB_MGGA_X_M06_HF+XC_MGGA_C_M06_HF", "m06_hf"}, + {"XC_HYB_MGGA_X_M06+XC_MGGA_C_M06", "m06"}, + {"XC_HYB_MGGA_X_M06_2X+XC_MGGA_C_M06_2X", "m06_2x"}, + {"XC_MGGA_X_RSCAN+XC_MGGA_C_RSCAN", "rscan"}, + {"XC_MGGA_X_R2SCAN+XC_MGGA_C_R2SCAN", "r2scan"}, + {"XC_GGA_X_SG4+XC_GGA_C_SG4", "sg4"}, + {"XC_MGGA_X_TM+XC_MGGA_C_TM", "tm"}, + {"XC_MGGA_X_REVSCAN+XC_MGGA_C_REVSCAN", "revscan"}, + {"XC_MGGA_X_REGTPSS+XC_GGA_C_REGTPSS", "regtpss"}, + {"XC_MGGA_X_R2SCAN01+XC_MGGA_C_R2SCAN01", "r2scan01"}, + {"XC_MGGA_X_RPPSCAN+XC_MGGA_C_RPPSCAN", "rppscan"}, + {"XC_MGGA_X_REVTM+XC_MGGA_C_REVTM", "revtm"}, + {"XC_MGGA_X_SCANL+XC_MGGA_C_SCANL", "scanl"}, + {"XC_MGGA_X_MGGAC+XC_GGA_C_MGGAC", "mggac"}, + {"XC_MGGA_X_R2SCANL+XC_MGGA_C_R2SCANL", "r2scanl"}, + {"XC_GGA_X_B88+XC_GGA_C_LYP", "blyp"}, + {"XC_GGA_X_B88+XC_GGA_C_P86", "bp86"}, + {"XC_GGA_X_PW91+XC_GGA_C_PW91", "pw91"}, + {"XC_GGA_X_PBE+XC_GGA_C_PBE", "pbe"}, + {"XC_GGA_X_PBE_SOL+XC_GGA_C_PBE_SOL", "pbesol"}, + {"XC_MGGA_X_PKZB+XC_MGGA_C_PKZB", "pkzb"}, + {"XC_MGGA_X_TPSS+XC_MGGA_C_TPSS", "tpss"}, + {"XC_MGGA_X_REVTPSS+XC_MGGA_C_REVTPSS", "revtpss"}, + {"XC_MGGA_X_SCAN+XC_MGGA_C_SCAN", "scan"}, + {"XC_GGA_X_SOGGA+XC_GGA_C_PBE", "sogga"}, + {"XC_MGGA_X_BLOC+XC_MGGA_C_TPSSLOC", "bloc"}, + {"XC_GGA_X_OPTX+XC_GGA_C_LYP", "olyp"}, + {"XC_GGA_X_RPBE+XC_GGA_C_PBE", "rpbe"}, + {"XC_GGA_X_B88+XC_GGA_C_PBE", "bpbe"}, + {"XC_GGA_X_MPW91+XC_GGA_C_PW91", "mpw91"}, + {"XC_MGGA_X_MS0+XC_GGA_C_REGTPSS", "ms0"}, + {"XC_MGGA_X_MS1+XC_GGA_C_REGTPSS", "ms1"}, + {"XC_MGGA_X_MS2+XC_GGA_C_REGTPSS", "ms2"}, + {"XC_HYB_MGGA_X_MS2H+XC_GGA_C_REGTPSS", "ms2h"}, + {"XC_MGGA_X_MVS+XC_GGA_C_REGTPSS", "mvs"}, + {"XC_HYB_MGGA_X_MVSH+XC_GGA_C_REGTPSS", "mvsh"}, + {"XC_GGA_X_SOGGA11+XC_GGA_C_SOGGA11", "sogga11"}, + {"XC_HYB_GGA_X_SOGGA11_X+XC_GGA_C_SOGGA11_X", "sogga11-x"}, + {"XC_HYB_MGGA_X_DLDF+XC_MGGA_C_DLDF", "dldf"}, + {"XC_GGA_X_GAM+XC_GGA_C_GAM", "gam"}, + {"XC_MGGA_X_M06_L+XC_MGGA_C_M06_L", "m06-l"}, + {"XC_MGGA_X_M11_L+XC_MGGA_C_M11_L", "m11-l"}, + {"XC_MGGA_X_MN12_L+XC_MGGA_C_MN12_L", "mn12-l"}, + {"XC_MGGA_X_MN15_L+XC_MGGA_C_MN15_L", "mn15-l"}, + {"XC_GGA_X_N12+XC_GGA_C_N12", "n12"}, + {"XC_HYB_GGA_X_N12_SX+XC_GGA_C_N12_SX", "n12-sx"}, + {"XC_HYB_MGGA_X_MN12_SX+XC_MGGA_C_MN12_SX", "mn12-sx"}, + {"XC_HYB_MGGA_X_MN15+XC_MGGA_C_MN15", "mn15"}, + {"XC_MGGA_X_MBEEF+XC_GGA_C_PBE_SOL", "mbeef"}, + {"XC_HYB_MGGA_X_SCAN0+XC_MGGA_C_SCAN", "scan0"}, + {"XC_GGA_X_PBE+XC_GGA_C_OP_PBE", "pbeop"}, + {"XC_GGA_X_B88+XC_GGA_C_OP_B88", "bop"} + }; + + void _xcname_libxc_xplusc(const std::string& xcpattern, std::string& xname) + { + std::vector xc_words = FmtCore::split(xcpattern, "+"); + std::for_each(xc_words.begin(), xc_words.end(), [](std::string& s) { + s = (FmtCore::startswith(s, "XC_")? s: "XC_" + s); }); // add XC_ if not present + assert(xc_words.size() == 2); + + std::vector words = FmtCore::split(xc_words[0], "_"); + const std::string key = (words[2] == "X")? + xc_words[0] + "+" + xc_words[1]: xc_words[1] + "+" + xc_words[0]; + + if (xcname_libxc_xplusc_.find(key) != xcname_libxc_xplusc_.end()) { + xname = xcname_libxc_xplusc_.at(key); + } else { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::xcname_libxc_xplusc", + "XC's LibXC-notation on `" + xcpattern + "` not recognized"); + } + } + + void _xcname_libxc_xc(const std::string& xcpattern, std::string& xname) + { + // add XC_ if not present + const std::string key = FmtCore::startswith(xcpattern, "XC_")? xcpattern: "XC_" + xcpattern; + + if (xcname_libxc_xc_.find(key) != xcname_libxc_xc_.end()) { + xname = xcname_libxc_xc_.at(key); + } else { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::xcname_libxc_xc", + "XC's LibXC-notation on `" + xcpattern + "` not recognized"); + } + } + + void _xcname_libxc(const std::string& xcpattern, std::string& xname) + { + if (xcpattern.find("+") != std::string::npos) { + _xcname_libxc_xplusc(xcpattern, xname); + } else { + _xcname_libxc_xc(xcpattern, xname); + } + } + + std::string _xcname(const std::string& xcpattern) + { + std::string xcname = xcpattern; + const std::regex pattern("(LDA|GGA|MGGA|HYB|HYB_LDA|HYB_GGA|HYB_MGGA)_(X|C|XC|K)_(.*)"); + // as long as there is piece in xcpattern that can match, we can search for the corresponding name + if (std::regex_search(xcpattern, pattern)) { + _xcname_libxc(xcpattern, xcname); + } + return xcname; + } +} + +/** +import os +import re +def read_xc_func_h(fn): + with open(fn) as f: + lines = f.readlines() + out = {} + for line in lines: + words = line.strip().split() + xc, xcid = words[1], int(words[2]) + xc_annos = ' '.join(words[4:-1]) + out[xc] = {'id': xcid, 'annos': xc_annos} + return out + +def sort_xc(xc_data): + '''Sort the xc functionals into x, c, xc, k functionals. + + Parameters + ---------- + xc_data : dict + from function read_xc_func_h + + Returns + ------- + dict, dict, dict, dict + The dictionaries of x, c, xc, k functionals, whose keys are the + like LDA, GGA, MGGA, HYB, HYB_LDA, HYB_GGA, HYB_MGGA, values are + the dictionaries of the functionals, whose keys are the conventional + xc name, values include approx, annos, id, full. + ''' + x, c, xc, k = {}, {}, {}, {} + dictmap = {'X': x, 'C': c, 'XC': xc, 'K': k} + xcpat = r'XC_(LDA|GGA|MGGA|HYB|HYB_LDA|HYB_GGA|HYB_MGGA)_(X|C|XC|K)_(.*)' + for xc_name, data in xc_data.items(): + m = re.match(xcpat, xc_name) + if m is None: + print('Warning: cannot match', xc_name) + continue + approx, type_, name = m.groups() + dictmap[type_][name] = {'approx': approx, 'annos': data['annos'], + 'id': data['id'], 'full': xc_name} + return x, c, xc, k + +def pair_xc(x, c): + ''' + Pair the x and c functionals. + + Parameters + ---------- + x : dict + The dictionary of x functionals, whose keys are the conventional + xc name, values include approx, annos, id, full. + + c : dict + the same as x + + Returns + ------- + dict, dict + The dictionary of paired and unpaired x and c functionals, whose keys are the + conventional xc name, values are the dictionary of x and c functionals. + ''' + paired, unpaired = {}, {} + for xc_name, data in x.items(): + if xc_name in c: + paired[xc_name] = {'x': data, 'c': c[xc_name]} + else: + unpaired[xc_name] = data + return paired, unpaired + +def xc_to_stdmap(xc, conventional_lower=True): + '''print the xc in the way of c++ std::map. + + Parameters + ---------- + xc : dict + The dictionary of xc functionals, whose keys are the conventional + xc name, values include approx, annos, id, full. + conventional_lower : bool + Whether to convert the conventional name to lower case. + + Returns + ------- + str + The string of c++ code, std::map mapping + the full name of xc to its conventional name. + ''' + out = 'const std::map xcname_libxc_xc_ = {\n' + for name, data in xc.items(): + name = name.lower() if conventional_lower else name + out += ' {"%s", "%s"},\n' % (data['full'], name) + out += '};\n' + return out + +def paired_xc_to_stdmap(pairs, conventional_lower=True): + '''print the xc in the way of c++ std::map. + + Parameters + ---------- + pairs : dict + The dictionary of xc functionals, whose keys are the conventional + xc name, values include approx, annos, id, full. + conventional_lower : bool + Whether to convert the conventional name to lower case. + + Returns + ------- + str + The string of c++ code, std::map mapping + the full name of xc to its conventional name. + ''' + out = 'const std::map xcname_libxc_xplusc_ = {\n' + for name, data in pairs.items(): + name = name.lower() if conventional_lower else name + plus = f'{data["x"]["full"]}+{data["c"]["full"]}' + out += ' {"%s", "%s"},\n' % (plus, name) + # sulp = f'{data["c"]["full"]}+{data["x"]["full"]}' + # out += ' {"%s", "%s"},\n' % (sulp, name) + out += '};\n' + return out + +def special_x_and_c(x, c): + '''Special pairings of x and c functionals. The following data sheet is + from Pyscf: + https://github.com/pyscf/pyscf/blob/master/pyscf/dft/xcfun.py + Thanks for pointing out the bug by @QuantumMiska and the help from wsr (@hebrewsnabla) + + + Parameters + ---------- + x : dict + The dictionary of x functionals, whose keys are the conventional + xc name, values include approx, annos, id, full. + + c : dict + the same as x + + Returns + ------- + dict + The dictionary of special pairings of x and c functionals. + ''' + DATA = { + 'BLYP' : 'B88,LYP', + 'BP86' : 'B88,P86', + 'PW91' : 'PW91,PW91', + 'PBE' : 'PBE,PBE', + 'REVPBE' : 'REVPBE,PBE', + 'PBESOL' : 'PBE_SOL,PBE_SOL', + 'PKZB' : 'PKZB,PKZB', + 'TPSS' : 'TPSS,TPSS', + 'REVTPSS' : 'REVTPSS,REVTPSS', + 'SCAN' : 'SCAN,SCAN', + 'SOGGA' : 'SOGGA,PBE', + 'BLOC' : 'BLOC,TPSSLOC', + 'OLYP' : 'OPTX,LYP', + 'RPBE' : 'RPBE,PBE', + 'BPBE' : 'B88,PBE', + 'MPW91' : 'MPW91,PW91', + 'HFLYP' : 'HF,LYP', + 'HFPW92' : 'HF,PWMOD', + 'SPW92' : 'SLATER,PWMOD', + 'SVWN' : 'SLATER,VWN', + 'MS0' : 'MS0,REGTPSS', + 'MS1' : 'MS1,REGTPSS', + 'MS2' : 'MS2,REGTPSS', + 'MS2H' : 'MS2H,REGTPSS', + 'MVS' : 'MVS,REGTPSS', + 'MVSH' : 'MVSH,REGTPSS', + 'SOGGA11' : 'SOGGA11,SOGGA11', + 'SOGGA11-X': 'SOGGA11_X,SOGGA11_X', + 'KT1' : 'KT1X,VWN', + 'DLDF' : 'DLDF,DLDF', + 'GAM' : 'GAM,GAM', + 'M06-L' : 'M06_L,M06_L', + 'M11-L' : 'M11_L,M11_L', + 'MN12-L' : 'MN12_L,MN12_L', + 'MN15-L' : 'MN15_L,MN15_L', + 'N12' : 'N12,N12', + 'N12-SX' : 'N12_SX,N12_SX', + 'MN12-SX' : 'MN12_SX,MN12_SX', + 'MN15' : 'MN15,MN15', + 'MBEEF' : 'MBEEF,PBE_SOL', + 'SCAN0' : 'SCAN0,SCAN', + 'PBEOP' : 'PBE,OP_PBE', + 'BOP' : 'B88,OP_B88', + } + paired = {} + for name, data in DATA.items(): + xname, cname = data.split(',') + if xname in x and cname in c: + paired[name] = {'x': x[xname], 'c': c[cname]} + else: + print(f'Warning: {name} not found in x or c: {xname}, {cname}') + return paired + +def print_xc(xc): + print(f'{"Name":20s} {"Full":30s} {"Appr":10s} {"Annos"}') + for name, data in xc.items(): + print(f'{name:20s} {data["full"]:30s} {data["approx"]:10s} {data["annos"]}') + +if __name__ == '__main__': + libxc = '/root/soft/libxc/libxc-6.2.2' + f = 'src/xc_funcs.h' + xc_data = read_xc_func_h(os.path.join(libxc, f)) + x, c, xc, k = sort_xc(xc_data) + pairs, others = pair_xc(x, c) + special = special_x_and_c(x, c) + # print(xc_to_stdmap(xc)) + # print(paired_xc_to_stdmap(pairs)) + # print_xc(others) + print(paired_xc_to_stdmap(special)) + */ +#endif // DFTD3_XCNAME_H_ diff --git a/source/module_hamilt_general/module_vdw/dftd3_xc_param.h b/source/module_hamilt_general/module_vdw/dftd3_xc_param.h new file mode 100644 index 00000000000..0090c6f308e --- /dev/null +++ b/source/module_hamilt_general/module_vdw/dftd3_xc_param.h @@ -0,0 +1,595 @@ +#ifndef DFTD3_XC_PARAM_H_ +#define DFTD3_XC_PARAM_H_ +/** + * Intro + * ----- + * This file stores XC dependent DFT-D3 parameters for Grimme-D3 + * dispersion correction. + * + * Supported forms: + * + * DFT-D3(0): zero-damping + * DFT-D3(BJ): Becke-Johnson damping + * DFT-D3M(0): zero-damping with modified damping function + * DFT-D3M(BJ): Becke-Johnson damping with modified damping function + * + * A detailed introduction of undamped, and BJ damping, the modified + * damping can be found in DFT-D3 software manual, see: + * https://www.chemie.uni-bonn.de/grimme/de/software/dft-d3/man.pdf + * + * Other excellent learning materials (where you can find expression + * of both DFT-D2 and DFT-D3): + * DFT-D2: https://www.vasp.at/wiki/index.php/DFT-D2 + * DFT-D3: https://www.vasp.at/wiki/index.php/DFT-D3 + * + * Usage + * ----- + * call function DFTD3::search(xc, method, param) to get the DFT-D3 parameters + * for the given XC functional. The obtained param should be a std::vector, + * in which the first 9 elements are the DFT-D3 parameters: + * 's6', 'sr6', 'a1', 's8', 'sr8', 'a2', 's9', 'alp', 'bet' + * + * ParamNotFoundError + * ------------------ + * If the requested D3 parameters of XC are not found, then the ABACUS will + * WARNING_QUIT with the message "DFT-D3 parameters for XC not found". + * + * Other dispersion correction + * --------------------------- + * there are other kinds of dispersion correction, such as the xc VV09, VV10, + * and rVV10, and the vdw-DF family nonlocal dispersion correction. They will + * be mixed directly with the correlation and exchange part, which act + * differently from the DFT-D2 and D3 methods. + * + * Special: Omega-B97 family + * ------------------------- + * (thanks for help and discussion with @hhebrewsnabla and @moolawooda) + * wB97 XC family is special, their DFT-D3 supports are quite complicated. + * + * wB97 long-range exx with B97 + * wB97X wB97 with additional short-range exx + * wB97X-D wB97X_D from libXC with DFTD2, not in DFTD3 framework + * wB97X-D3 wB97X_D3 from libXC with DFTD3(0) + * wB97X-D3(BJ) wB97X_V from libXC with DFTD3(BJ) + * wB97X-V with VV10, not in DFTD3 framework + * wB97M-V with VV10, not in DFTD3 framework + * + * Recommended: http://bbs.keinsci.com/thread-19076-1-1.html + * Related information from Pyscf Github repo: + * https://github.com/pyscf/pyscf/issues/2069 + * + */ +#include +#include +#include +#include +#include +#include +#include "dftd3_xc_name.h" +// 's6', 'rs6', 'a1', 's8', 'rs8', 'a2', 's9', 'alp', 'bet' +namespace DFTD3 { + // DFT-D3(BJ) + std::map> bj = { + {"bp", {1.0, 0.3946, 0.3946, 3.2822, 4.8516, 4.8516, 1.0, 14.0, 0.0}}, + {"blyp", {1.0, 0.4298, 0.4298, 2.6996, 4.2359, 4.2359, 1.0, 14.0, 0.0}}, + {"revpbe", {1.0, 0.5238, 0.5238, 2.355, 3.5016, 3.5016, 1.0, 14.0, 0.0}}, + {"rpbe", {1.0, 0.182, 0.182, 0.8318, 4.0094, 4.0094, 1.0, 14.0, 0.0}}, + {"b97_d", {1.0, 0.5545, 0.5545, 2.2609, 3.2297, 3.2297, 1.0, 14.0, 0.0}}, + {"b973c", {1.0, 0.37, 0.37, 1.5, 4.1, 4.1, 1.0, 14.0, 0.0}}, + {"pbe", {1.0, 0.4289, 0.4289, 0.7875, 4.4407, 4.4407, 1.0, 14.0, 0.0}}, + {"rpw86pbe", {1.0, 0.4613, 0.4613, 1.3845, 4.5062, 4.5062, 1.0, 14.0, 0.0}}, + {"b3lyp", {1.0, 0.3981, 0.3981, 1.9889, 4.4211, 4.4211, 1.0, 14.0, 0.0}}, + {"tpss", {1.0, 0.4535, 0.4535, 1.9435, 4.4752, 4.4752, 1.0, 14.0, 0.0}}, + {"hf", {1.0, 0.3385, 0.3385, 0.9171, 2.883, 2.883, 1.0, 14.0, 0.0}}, + {"tpss0", {1.0, 0.3768, 0.3768, 1.2576, 4.5865, 4.5865, 1.0, 14.0, 0.0}}, + {"pbe0", {1.0, 0.4145, 0.4145, 1.2177, 4.8593, 4.8593, 1.0, 14.0, 0.0}}, + {"hse06", {1.0, 0.383, 0.383, 2.31, 5.685, 5.685, 1.0, 14.0, 0.0}}, + {"hse", {1.0, 0.383, 0.383, 2.31, 5.685, 5.685, 1.0, 14.0, 0.0}}, // ABACUS implements HSE06 as HSE + {"revpbe38", {1.0, 0.4309, 0.4309, 1.476, 3.9446, 3.9446, 1.0, 14.0, 0.0}}, + {"pw6b95", {1.0, 0.2076, 0.2076, 0.7257, 6.375, 6.375, 1.0, 14.0, 0.0}}, + {"b2plyp", {0.64, 0.3065, 0.3065, 0.9147, 5.057, 5.057, 1.0, 14.0, 0.0}}, + {"dsdblyp", {0.5, 0.0, 0.0, 0.213, 6.0519, 6.0519, 1.0, 14.0, 0.0}}, + {"dsdblypfc", {0.5, 0.0009, 0.0009, 0.2112, 5.9807, 5.9807, 1.0, 14.0, 0.0}}, + {"dodscan66", {0.3152, 0.0, 0.0, 0.0, 5.75, 5.75, 1.0, 14.0, 0.0}}, + {"revdsdblyp", {0.5451, 0.0, 0.0, 0.0, 5.2, 5.2, 1.0, 14.0, 0.0}}, + {"revdsdpbep86", {0.4377, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"revdsdpbeb95", {0.3686, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"revdsdpbe", {0.5746, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"revdodblyp", {0.6145, 0.0, 0.0, 0.0, 5.2, 5.2, 1.0, 14.0, 0.0}}, + {"revdodpbep86", {0.477, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"revdodpbeb95", {0.4107, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"revdodpbe", {0.6067, 0.0, 0.0, 0.0, 5.5, 5.5, 1.0, 14.0, 0.0}}, + {"bop", {1.0, 0.487, 0.487, 3.295, 3.5043, 3.5043, 1.0, 14.0, 0.0}}, + {"mpwlyp", {1.0, 0.4831, 0.4831, 2.0077, 4.5323, 4.5323, 1.0, 14.0, 0.0}}, + {"olyp", {1.0, 0.5299, 0.5299, 2.6205, 2.8065, 2.8065, 1.0, 14.0, 0.0}}, + {"pbesol", {1.0, 0.4466, 0.4466, 2.9491, 6.1742, 6.1742, 1.0, 14.0, 0.0}}, + {"bpbe", {1.0, 0.4567, 0.4567, 4.0728, 4.3908, 4.3908, 1.0, 14.0, 0.0}}, + {"opbe", {1.0, 0.5512, 0.5512, 3.3816, 2.9444, 2.9444, 1.0, 14.0, 0.0}}, + {"ssb", {1.0, -0.0952, -0.0952, -0.1744, 5.217, 5.217, 1.0, 14.0, 0.0}}, + {"revssb", {1.0, 0.472, 0.472, 0.4389, 4.0986, 4.0986, 1.0, 14.0, 0.0}}, + {"otpss", {1.0, 0.4634, 0.4634, 2.7495, 4.3153, 4.3153, 1.0, 14.0, 0.0}}, + {"b3pw91", {1.0, 0.4312, 0.4312, 2.8524, 4.4693, 4.4693, 1.0, 14.0, 0.0}}, + {"bhlyp", {1.0, 0.2793, 0.2793, 1.0354, 4.9615, 4.9615, 1.0, 14.0, 0.0}}, + {"revpbe0", {1.0, 0.4679, 0.4679, 1.7588, 3.7619, 3.7619, 1.0, 14.0, 0.0}}, + {"tpssh", {1.0, 0.4529, 0.4529, 2.2382, 4.655, 4.655, 1.0, 14.0, 0.0}}, + {"mpw1b95", {1.0, 0.1955, 0.1955, 1.0508, 6.4177, 6.4177, 1.0, 14.0, 0.0}}, + {"pwb6k", {1.0, 0.1805, 0.1805, 0.9383, 7.7627, 7.7627, 1.0, 14.0, 0.0}}, + {"b1b95", {1.0, 0.2092, 0.2092, 1.4507, 5.5545, 5.5545, 1.0, 14.0, 0.0}}, + {"bmk", {1.0, 0.194, 0.194, 2.086, 5.9197, 5.9197, 1.0, 14.0, 0.0}}, + {"camb3lyp", {1.0, 0.3708, 0.3708, 2.0674, 5.4743, 5.4743, 1.0, 14.0, 0.0}}, + {"lcwpbe", {1.0, 0.3919, 0.3919, 1.8541, 5.0897, 5.0897, 1.0, 14.0, 0.0}}, + {"b2gpplyp", {0.56, 0.0, 0.0, 0.2597, 6.3332, 6.3332, 1.0, 14.0, 0.0}}, + {"ptpss", {0.75, 0.0, 0.0, 0.2804, 6.5745, 6.5745, 1.0, 14.0, 0.0}}, + {"pwpb95", {0.82, 0.0, 0.0, 0.2904, 7.3141, 7.3141, 1.0, 14.0, 0.0}}, + {"hf_mixed", {1.0, 0.5607, 0.5607, 3.9027, 4.5622, 4.5622, 1.0, 14.0, 0.0}}, + {"hf_sv", {1.0, 0.4249, 0.4249, 2.1849, 4.2783, 4.2783, 1.0, 14.0, 0.0}}, + {"hf_minis", {1.0, 0.1702, 0.1702, 0.9841, 3.8506, 3.8506, 1.0, 14.0, 0.0}}, + {"b3lyp_631gd", {1.0, 0.5014, 0.5014, 4.0672, 4.8409, 4.8409, 1.0, 14.0, 0.0}}, + {"hcth120", {1.0, 0.3563, 0.3563, 1.0821, 4.3359, 4.3359, 1.0, 14.0, 0.0}}, + {"dftb3", {1.0, 0.5719, 0.5719, 0.5883, 3.6017, 3.6017, 1.0, 14.0, 0.0}}, + {"pw1pw", {1.0, 0.3807, 0.3807, 2.3363, 5.8844, 5.8844, 1.0, 14.0, 0.0}}, + {"pwgga", {1.0, 0.2211, 0.2211, 2.691, 6.7278, 6.7278, 1.0, 14.0, 0.0}}, + {"hsesol", {1.0, 0.465, 0.465, 2.9215, 6.2003, 6.2003, 1.0, 14.0, 0.0}}, + {"hf3c", {1.0, 0.4171, 0.4171, 0.8777, 2.9149, 2.9149, 1.0, 14.0, 0.0}}, + {"hf3cv", {1.0, 0.3063, 0.3063, 0.5022, 3.9856, 3.9856, 1.0, 14.0, 0.0}}, + {"pbeh3c", {1.0, 0.486, 0.486, 0.0, 4.5, 4.5, 1.0, 14.0, 0.0}}, + {"scan", {1.0, 0.538, 0.538, 0.0, 5.42, 5.42, 1.0, 14.0, 0.0}}, + {"rscan", {1.0, 0.47023427, 0.47023427, 1.08859014, 5.73408312, 5.73408312, 1.0, 14.0, 0.0}}, + {"r2scan", {1.0, 0.49484001, 0.49484001, 0.78981345, 5.73083694, 5.73083694, 1.0, 14.0, 0.0}}, + {"r2scanh", {1.0, 0.4709, 0.4709, 1.1236, 5.9157, 5.9157, 1.0, 14.0, 0.0}}, + {"r2scan0", {1.0, 0.4534, 0.4534, 1.1846, 5.8972, 5.8972, 1.0, 14.0, 0.0}}, + {"r2scan50", {1.0, 0.4311, 0.4311, 1.3294, 5.924, 5.924, 1.0, 14.0, 0.0}}, + {"wb97x_v", {1.0, 0.0, 0.0, 0.2641, 5.4959, 5.4959, 1.0, 14.0, 0.0}}, + // NOTE: the key `wb97x_v` directly corresonding to HYB_GGA_XC_WB97X_V, which can be further + // employed to construct either wB97X-V with VV10, or wB97X-D3BJ with D3BJ. Here it is the D3BJ + // parameter of wB97X-D3BJ, instead of those of wB97X-V. + {"wb97m", {1.0, 0.566, 0.566, 0.3908, 3.128, 3.128, 1.0, 14.0, 0.0}}, + {"b97m", {1.0, -0.078, -0.078, 0.1384, 5.5946, 5.5946, 1.0, 14.0, 0.0}}, + {"pbehpbe", {1.0, 0.0, 0.0, 1.1152, 6.7184, 6.7184, 1.0, 14.0, 0.0}}, + {"xlyp", {1.0, 0.0809, 0.0809, 1.5669, 5.3166, 5.3166, 1.0, 14.0, 0.0}}, + {"mpwpw", {1.0, 0.3168, 0.3168, 1.7974, 4.7732, 4.7732, 1.0, 14.0, 0.0}}, + {"hcth407", {1.0, 0.0, 0.0, 0.649, 4.8162, 4.8162, 1.0, 14.0, 0.0}}, + {"revtpss", {1.0, 0.4326, 0.4326, 1.4023, 4.4723, 4.4723, 1.0, 14.0, 0.0}}, + {"tauhcth", {1.0, 0.0, 0.0, 1.2626, 5.6162, 5.6162, 1.0, 14.0, 0.0}}, + {"b3p", {1.0, 0.4601, 0.4601, 3.3211, 4.9858, 4.9858, 1.0, 14.0, 0.0}}, + {"b1p", {1.0, 0.4724, 0.4724, 3.5681, 4.9858, 4.9858, 1.0, 14.0, 0.0}}, + {"b1lyp", {1.0, 0.1986, 0.1986, 2.1167, 5.3875, 5.3875, 1.0, 14.0, 0.0}}, + {"mpwb1k", {1.0, 0.1474, 0.1474, 0.9499, 6.6223, 6.6223, 1.0, 14.0, 0.0}}, + {"mpw1pw", {1.0, 0.3342, 0.3342, 1.8744, 4.9819, 4.9819, 1.0, 14.0, 0.0}}, + {"mpw1kcis", {1.0, 0.0576, 0.0576, 1.0893, 5.5314, 5.5314, 1.0, 14.0, 0.0}}, + {"pbeh1pbe", {1.0, 0.0, 0.0, 1.4877, 7.0385, 7.0385, 1.0, 14.0, 0.0}}, + {"pbe1kcis", {1.0, 0.0, 0.0, 0.7688, 6.2794, 6.2794, 1.0, 14.0, 0.0}}, + {"x3lyp", {1.0, 0.2022, 0.2022, 1.5744, 5.4184, 5.4184, 1.0, 14.0, 0.0}}, + {"o3lyp", {1.0, 0.0963, 0.0963, 1.8171, 5.994, 5.994, 1.0, 14.0, 0.0}}, + {"b97_1", {1.0, 0.0, 0.0, 0.4814, 6.2279, 6.2279, 1.0, 14.0, 0.0}}, + {"b97_2", {1.0, 0.0, 0.0, 0.9448, 5.994, 5.994, 1.0, 14.0, 0.0}}, + {"b98", {1.0, 0.0, 0.0, 0.7086, 6.0672, 6.0672, 1.0, 14.0, 0.0}}, + {"hiss", {1.0, 0.0, 0.0, 1.6112, 7.3539, 7.3539, 1.0, 14.0, 0.0}}, + {"hse03", {1.0, 0.0, 0.0, 1.1243, 6.8889, 6.8889, 1.0, 14.0, 0.0}}, + {"revtpssh", {1.0, 0.266, 0.266, 1.4076, 5.3761, 5.3761, 1.0, 14.0, 0.0}}, + {"revtpss0", {1.0, 0.2218, 0.2218, 1.6151, 5.7985, 5.7985, 1.0, 14.0, 0.0}}, + {"tpss1kcis", {1.0, 0.0, 0.0, 1.0542, 6.0201, 6.0201, 1.0, 14.0, 0.0}}, + {"tauhcthhyb", {1.0, 0.0, 0.0, 0.9585, 10.1389, 10.1389, 1.0, 14.0, 0.0}}, + {"m11", {1.0, 0.0, 0.0, 2.8112, 10.1389, 10.1389, 1.0, 14.0, 0.0}}, + {"sogga11x", {1.0, 0.133, 0.133, 1.1426, 5.7381, 5.7381, 1.0, 14.0, 0.0}}, + {"n12sx", {1.0, 0.3283, 0.3283, 2.49, 5.7898, 5.7898, 1.0, 14.0, 0.0}}, + {"mn12sx", {1.0, 0.0983, 0.0983, 1.1674, 8.0259, 8.0259, 1.0, 14.0, 0.0}}, + {"mn12l", {1.0, 0.0, 0.0, 2.2674, 9.1494, 9.1494, 1.0, 14.0, 0.0}}, + {"mn15", {1.0, 2.0971, 2.0971, 0.7862, 7.5923, 7.5923, 1.0, 14.0, 0.0}}, + {"lc_whpbe", {1.0, 0.2746, 0.2746, 1.1908, 5.3157, 5.3157, 1.0, 14.0, 0.0}}, + {"mpw2plyp", {0.66, 0.4105, 0.4105, 0.6223, 5.0136, 5.0136, 1.0, 14.0, 0.0}}, + {"pw91", {1.0, 0.6319, 0.6319, 1.9598, 4.5718, 4.5718, 1.0, 14.0, 0.0}}, + {"drpa75", {0.3754, 0.0, 0.0, 0.0, 4.5048, 4.5048, 1.0, 14.0, 0.0}}, + {"scsdrpa75", {0.2528, 0.0, 0.0, 0.0, 4.505, 4.505, 1.0, 14.0, 0.0}}, + {"optscsdrpa75", {0.2546, 0.0, 0.0, 0.0, 4.505, 4.505, 1.0, 14.0, 0.0}}, + {"dsdpbedrpa75", {0.3223, 0.0, 0.0, 0.0, 4.505, 4.505, 1.0, 14.0, 0.0}}, + {"dsdpbep86drpa75", {0.3012, 0.0, 0.0, 0.0, 4.505, 4.505, 1.0, 14.0, 0.0}}, + {"dsdpbep86_2011", {0.418, 0.0, 0.0, 0.0, 5.65, 5.65, 1.0, 14.0, 0.0}}, + {"dsdsvwn5", {0.46, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dsdsp86", {0.3, 0.0, 0.0, 0.0, 5.8, 5.8, 1.0, 14.0, 0.0}}, + {"dsdslyp", {0.3, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dsdspbe", {0.4, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + {"dsdbvwn5", {0.61, 0.0, 0.0, 0.0, 5.2, 5.2, 1.0, 14.0, 0.0}}, + {"dsdblyp_2013", {0.57, 0.0, 0.0, 0.0, 5.4, 5.4, 1.0, 14.0, 0.0}}, + {"dsdbpbe", {1.22, 0.0, 0.0, 0.0, 6.6, 6.6, 1.0, 14.0, 0.0}}, + {"dsdbp86", {0.76, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + {"dsdbpw91", {1.14, 0.0, 0.0, 0.0, 6.5, 6.5, 1.0, 14.0, 0.0}}, + {"dsdbb95", {1.02, 0.0, 0.0, 0.0, 6.8, 6.8, 1.0, 14.0, 0.0}}, + {"dsdpbevwn5", {0.54, 0.0, 0.0, 0.0, 5.1, 5.1, 1.0, 14.0, 0.0}}, + {"dsdpbelyp", {0.43, 0.0, 0.0, 0.0, 5.2, 5.2, 1.0, 14.0, 0.0}}, + {"dsdpbe", {0.78, 0.0, 0.0, 0.0, 6.1, 6.1, 1.0, 14.0, 0.0}}, + {"dsdpbep86", {0.48, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dsdpbepw91", {0.73, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + {"dsdpbeb95", {0.61, 0.0, 0.0, 0.0, 6.2, 6.2, 1.0, 14.0, 0.0}}, + {"dsdpbehb95", {0.58, 0.0, 0.0, 0.0, 6.2, 6.2, 1.0, 14.0, 0.0}}, + {"dsdpbehp86", {0.46, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dsdmpwlyp", {0.48, 0.0, 0.0, 0.0, 5.3, 5.3, 1.0, 14.0, 0.0}}, + {"dsdmpwpw91", {0.9, 0.0, 0.0, 0.0, 6.2, 6.2, 1.0, 14.0, 0.0}}, + {"dsdmpwp86", {0.59, 0.0, 0.0, 0.0, 5.8, 5.8, 1.0, 14.0, 0.0}}, + {"dsdmpwpbe", {0.96, 0.0, 0.0, 0.0, 6.3, 6.3, 1.0, 14.0, 0.0}}, + {"dsdmpwb95", {0.82, 0.0, 0.0, 0.0, 6.6, 6.6, 1.0, 14.0, 0.0}}, + {"dsdhsepbe", {0.79, 0.0, 0.0, 0.0, 6.1, 6.1, 1.0, 14.0, 0.0}}, + {"dsdhsepw91", {0.74, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + {"dsdhsep86", {0.46, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dsdhselyp", {0.4, 0.0, 0.0, 0.0, 5.2, 5.2, 1.0, 14.0, 0.0}}, + {"dsdtpss", {0.72, 0.0, 0.0, 0.0, 6.5, 6.5, 1.0, 14.0, 0.0}}, + {"dsdtpssb95", {0.91, 0.0, 0.0, 0.0, 7.9, 7.9, 1.0, 14.0, 0.0}}, + {"dsdolyp", {0.93, 0.0, 0.0, 0.0, 5.8, 5.8, 1.0, 14.0, 0.0}}, + {"dsdxlyp", {0.51, 0.0, 0.0, 0.0, 5.3, 5.3, 1.0, 14.0, 0.0}}, + {"dsdxb95", {0.92, 0.0, 0.0, 0.0, 6.7, 6.7, 1.0, 14.0, 0.0}}, + {"dsdb98", {0.07, 0.0, 0.0, 0.0, 3.7, 3.7, 1.0, 14.0, 0.0}}, + {"dsdbmk", {0.17, 0.0, 0.0, 0.0, 3.9, 3.9, 1.0, 14.0, 0.0}}, + {"dsdthcth", {0.39, 0.0, 0.0, 0.0, 4.8, 4.8, 1.0, 14.0, 0.0}}, + {"dsdhcth407", {0.53, 0.0, 0.0, 0.0, 5.0, 5.0, 1.0, 14.0, 0.0}}, + {"dodsvwn5", {0.57, 0.0, 0.0, 0.0, 5.6, 5.6, 1.0, 14.0, 0.0}}, + {"dodblyp", {0.96, 0.0, 0.0, 0.0, 5.1, 5.1, 1.0, 14.0, 0.0}}, + {"dodpbe", {0.91, 0.0, 0.0, 0.0, 5.9, 5.9, 1.0, 14.0, 0.0}}, + {"dodpbep86", {0.72, 0.0, 0.0, 0.0, 5.4, 5.4, 1.0, 14.0, 0.0}}, + {"dodpbeb95", {0.71, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + {"dodhsep86", {0.69, 0.0, 0.0, 0.0, 5.4, 5.4, 1.0, 14.0, 0.0}}, + {"dodpbehb95", {0.67, 0.0, 0.0, 0.0, 6.0, 6.0, 1.0, 14.0, 0.0}}, + }; + // DFT-D3(0) + std::map> zero = { + {"slaterdirac", {1.0, 0.999, 0.999, -1.957, 0.697, 0.697, 1.0, 14.0, 0.0}}, + {"bp", {1.0, 1.139, 1.139, 1.683, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"blyp", {1.0, 1.094, 1.094, 1.682, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"revpbe", {1.0, 0.923, 0.923, 1.01, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"rpbe", {1.0, 0.872, 0.872, 0.514, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b97_d", {1.0, 0.892, 0.892, 0.909, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b973c", {1.0, 1.06, 1.06, 1.5, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pbe", {1.0, 1.217, 1.217, 0.722, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"rpw86pbe", {1.0, 1.224, 1.224, 0.901, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b3lyp", {1.0, 1.261, 1.261, 1.703, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tpss", {1.0, 1.166, 1.166, 1.105, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hf", {1.0, 1.158, 1.158, 1.746, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tpss0", {1.0, 1.252, 1.252, 1.242, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pbe0", {1.0, 1.287, 1.287, 0.928, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hse06", {1.0, 1.129, 1.129, 0.109, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hse", {1.0, 1.129, 1.129, 0.109, 1.0, 1.0, 1.0, 14.0, 0.0}}, // ABACUS implements HSE06 as HSE + {"revpbe38", {1.0, 1.021, 1.021, 0.862, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pw6b95", {1.0, 1.532, 1.532, 0.862, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b2plyp", {0.64, 1.427, 1.427, 1.022, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"dsdblyp", {0.5, 1.569, 1.569, 0.705, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpwlyp", {1.0, 1.239, 1.239, 1.098, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"olyp", {1.0, 0.806, 0.806, 1.764, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"bpbe", {1.0, 1.087, 1.087, 2.033, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"opbe", {1.0, 0.837, 0.837, 2.033, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"ssb", {1.0, 1.215, 1.215, 0.663, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"revssb", {1.0, 1.221, 1.221, 0.56, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"otpss", {1.0, 1.128, 1.128, 1.494, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b3pw91", {1.0, 1.176, 1.176, 1.775, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"bhlyp", {1.0, 1.37, 1.37, 1.442, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tpssh", {1.0, 1.223, 1.223, 1.219, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpw1b95", {1.0, 1.605, 1.605, 1.118, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pwb6k", {1.0, 1.66, 1.66, 0.55, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b1b95", {1.0, 1.613, 1.613, 1.868, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"bmk", {1.0, 1.931, 1.931, 2.168, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"camb3lyp", {1.0, 1.378, 1.378, 1.217, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"lcwpbe", {1.0, 1.355, 1.355, 1.279, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b2gpplyp", {0.56, 1.586, 1.586, 0.76, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"ptpss", {0.75, 1.541, 1.541, 0.879, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pwpb95", {0.82, 1.557, 1.557, 0.705, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pw1pw", {1.0, 1.4968, 1.4968, 1.1786, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"scan", {1.0, 1.324, 1.324, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"wb97x_d3", {1.0, 1.281, 1.281, 1.0, 1.094, 1.094, 1.0, 14.0, 0.0}}, + // NOTE: simple-dftd3 assign the D3(0) parameters of functional wB97X-D3 + // to a key `wb97x`, but the functional wB97X itself does not own these params. + // instead, there is a XC in libxc really names HYB_GGA_WB97X_D3 + {"pbehpbe", {1.0, 1.5703, 1.5703, 1.401, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"xlyp", {1.0, 0.9384, 0.9384, 0.7447, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpwpw", {1.0, 1.3725, 1.3725, 1.9467, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hcth407", {1.0, 4.0426, 4.0426, 2.7694, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"revtpss", {1.0, 1.3491, 1.3491, 1.3666, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tauhcth", {1.0, 0.932, 0.932, 0.5662, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b3p", {1.0, 1.1897, 1.1897, 1.1961, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b1p", {1.0, 1.1815, 1.1815, 1.1209, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b1lyp", {1.0, 1.3725, 1.3725, 1.9467, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpwb1k", {1.0, 1.671, 1.671, 1.061, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpw1lyp", {1.0, 2.0512, 2.0512, 1.9529, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpw1pw", {1.0, 1.2892, 1.2892, 1.4758, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpw1kcis", {1.0, 1.7231, 1.7231, 2.2917, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpwkcis1k", {1.0, 1.4853, 1.4853, 1.7553, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pbeh1pbe", {1.0, 1.3719, 1.3719, 1.043, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pbe1kcis", {1.0, 3.6355, 3.6355, 1.7934, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"x3lyp", {1.0, 1.0, 1.0, 0.299, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"o3lyp", {1.0, 1.406, 1.406, 1.8058, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b97_1", {1.0, 3.7924, 3.7924, 1.6418, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b97_2", {1.0, 1.7066, 1.7066, 1.6418, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"b98", {1.0, 2.6895, 2.6895, 1.9078, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hiss", {1.0, 1.3338, 1.3338, 0.7615, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"hse03", {1.0, 1.3944, 1.3944, 1.0156, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"revtpssh", {1.0, 1.3224, 1.3224, 1.2504, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"revtpss0", {1.0, 1.2881, 1.2881, 1.0649, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tpss1kcis", {1.0, 1.7729, 1.7729, 2.0902, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"tauhcthhyb", {1.0, 1.5001, 1.5001, 1.6302, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pkzb", {1.0, 0.6327, 0.6327, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"n12", {1.0, 1.3493, 1.3493, 2.3916, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mpw2plyp", {0.66, 1.5527, 1.5527, 0.7529, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m05", {1.0, 1.373, 1.373, 0.595, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m052x", {1.0, 1.417, 1.417, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m06l", {1.0, 1.581, 1.581, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m06", {1.0, 1.325, 1.325, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m062x", {1.0, 1.619, 1.619, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m08hx", {1.0, 1.6247, 1.6247, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"m11l", {1.0, 2.3933, 2.3933, 1.1129, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"mn15l", {1.0, 3.3388, 3.3388, 0.0, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"pwp", {1.0, 2.104, 2.104, 0.8747, 1.0, 1.0, 1.0, 14.0, 0.0}}, + }; + // DFT-D3M(BJ): not implemented for beta + std::map> bjm = { + {"bp", {1.0, 0.82185, 0.82185, 3.140281, 2.728151, 2.728151, 1.0, 14.0, 0.0}}, + {"blyp", {1.0, 0.448486, 0.448486, 1.875007, 3.610679, 3.610679, 1.0, 14.0, 0.0}}, + {"b97_d", {1.0, 0.240184, 0.240184, 1.206988, 3.864426, 3.864426, 1.0, 14.0, 0.0}}, + {"pbe", {1.0, 0.012092, 0.012092, 0.35894, 5.938951, 5.938951, 1.0, 14.0, 0.0}}, + {"b3lyp", {1.0, 0.278672, 0.278672, 1.466677, 4.606311, 4.606311, 1.0, 14.0, 0.0}}, + {"pbe0", {1.0, 0.007912, 0.007912, 0.528823, 6.162326, 6.162326, 1.0, 14.0, 0.0}}, + {"b2plyp", {0.64, 0.486434, 0.486434, 0.67282, 3.656466, 3.656466, 1.0, 14.0, 0.0}}, + {"lcwpbe", {1.0, 0.563761, 0.563761, 0.906564, 3.59368, 3.59368, 1.0, 14.0, 0.0}}, + }; + // DFT-D3M(0): not implemented for beta + std::map> zerom = { + {"bp", {1.0, 1.23346, 1.23346, 1.945174, 1.0, 1.0, 1.0, 14.0, 0.0}}, + {"blyp", {1.0, 1.279637, 1.279637, 1.841686, 1.0, 1.0, 1.0, 14.0, 0.01437}}, + {"b97_d", {1.0, 1.151808, 1.151808, 1.020078, 1.0, 1.0, 1.0, 14.0, 0.035964}}, + {"pbe", {1.0, 2.340218, 2.340218, 0.0, 1.0, 1.0, 1.0, 14.0, 0.129434}}, + {"b3lyp", {1.0, 1.338153, 1.338153, 1.532981, 1.0, 1.0, 1.0, 14.0, 0.013988}}, + {"pbe0", {1.0, 2.077949, 2.077949, 8.1e-05, 1.0, 1.0, 1.0, 14.0, 0.116755}}, + {"b2plyp", {0.64, 1.313134, 1.313134, 0.717543, 1.0, 1.0, 1.0, 14.0, 0.016035}}, + {"lcwpbe", {1.0, 1.366361, 1.366361, 1.280619, 1.0, 1.0, 1.0, 14.0, 0.00316}}, + }; + // DFT-D3(OptimizedPower) + std::map> op = { + {"blyp", {1.0, 0.425, 0.425, 1.31867, 3.5, 3.5, 1.0, 14.0, 2.0}}, + {"revpbe", {1.0, 0.6, 0.6, 1.44765, 2.5, 2.5, 1.0, 14.0, 0.0}}, + {"b97_d", {1.0, 0.6, 0.6, 1.46861, 2.5, 2.5, 1.0, 14.0, 0.0}}, + {"pbe", {0.91826, 0.2, 0.2, 0.0, 4.75, 4.75, 1.0, 14.0, 6.0}}, + {"b3lyp", {1.0, 0.3, 0.3, 0.78311, 4.25, 4.25, 1.0, 14.0, 4.0}}, + {"tpss", {1.0, 0.575, 0.575, 0.51581, 3.0, 3.0, 1.0, 14.0, 8.0}}, + {"pbe0", {0.8829, 0.15, 0.15, 0.0, 4.75, 4.75, 1.0, 14.0, 6.0}}, + {"revpbe0", {1.0, 0.725, 0.725, 1.25684, 2.25, 2.25, 1.0, 14.0, 0.0}}, + {"tpssh", {1.0, 0.575, 0.575, 0.43185, 3.0, 3.0, 1.0, 14.0, 8.0}}, + {"revtpss", {1.0, 0.7, 0.7, 0.27632, 2.5, 2.5, 1.0, 14.0, 8.0}}, + {"b97_1", {0.97388, 0.15, 0.15, 0.0, 4.25, 4.25, 1.0, 14.0, 6.0}}, + {"revtpssh", {1.0, 0.575, 0.575, 0.12467, 3.0, 3.0, 1.0, 14.0, 10.0}}, + {"ms2", {1.0, 0.7, 0.7, 0.90743, 4.0, 4.0, 1.0, 14.0, 2.0}}, + {"ms2h", {1.0, 0.65, 0.65, 1.69464, 4.75, 4.75, 1.0, 14.0, 0.0}}, + }; + // a declaration + std::string _lowercase(const std::string& s); + /** + * @brief Get the dftd3 params object. + * dftd3 method fall back: xc-bjm -> xc-bj -> pbe-bj + * xc-zerom -> xc-zero -> pbe-zero + * + * @param xc the functional name + * @param d3method the d3 method, can be "bj", "zero-damping", "bj-modified", "zero-damping-modified", "op" + * @param param the dftd3 parameters, ALL_KEYS = {'s6', 'rs6', 'a1', 's8', 'rs8', 'a2', 's9', 'alp', 'bet'} + */ + void _search(const std::string& xc, + const std::string& method, + std::vector& param) + { + const std::string xc_lowercase = _lowercase(xc); + const std::vector allowed_ = { "bj", "zero", "bjm", "zerom", "op" }; + assert(std::find(allowed_.begin(), allowed_.end(), method) != allowed_.end()); + if (method == "op") + { + if (op.find(xc_lowercase) != op.end()) + { + param = op[xc_lowercase]; + } + else + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "XC (`" + xc + "`)'s DFT-D3(OP) parameters not found"); + } + } + else if (method == "bjm") + { + if (bjm.find(xc_lowercase) != bjm.end()) + { + param = bjm[xc_lowercase]; + } + else + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "XC (`" + xc + "`)'s DFT-D3M(BJ) parameters not found"); + } + } + else if (method == "bj") + { + if (bj.find(xc_lowercase) != bj.end()) + { + param = bj[xc_lowercase]; + } + else + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "XC (`" + xc + "`)'s DFT-D3(BJ) parameters not found"); + } + } + else if (method == "zerom") + { + if (zerom.find(xc_lowercase) != zerom.end()) + { + param = zerom[xc_lowercase]; + } + else + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "XC (`" + xc + "`)'s DFT-D3M(0) parameters not found"); + } + } + else if (method == "zero") + { + if (zero.find(xc_lowercase) != zero.end()) + { + param = zero[xc_lowercase]; + } + else + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "XC (`" + xc + "`)'s DFT-D3(0) parameters not found"); + } + } + else // should not reach here + { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::DFTD3::_search", + "Unknown DFT-D3 method: " + method); + } + } + + std::string _lowercase(const std::string& s) + { + std::string result = s; + std::transform(s.begin(), s.end(), result.begin(), ::tolower); + return result; + } + + std::string _uppercase(const std::string& s) + { + std::string result = s; + std::transform(s.begin(), s.end(), result.begin(), ::toupper); + return result; + } + + /** + * @brief Get DFT-D3 parameters. If if there are parameters defined, + * then it will overwrite the search result. If all parameters are + * defined already by user, then search will not performed. + * + * @param xc XC functional name + * @param d3method can be "d3_0" or "d3_bj" + * @param s6_in user defined s6, default is "default" + * @param s8_in user defined s8, default is "default" + * @param a1_in user defined a1, default is "default" + * @param a2_in user defined a2, default is "default" + * @param s6 [out] s6 parameter + * @param s8 [out] s8 parameter + * @param a1 [out] a1 parameter + * @param a2 [out] a2 parameter + */ + void dftd3_params(const std::string& xc_in, + const std::string& d3method, + const std::string& s6_in, + const std::string& s8_in, + const std::string& a1_in, + const std::string& a2_in, + double& s6, + double& s8, + double& a1, + double& a2, + std::ofstream* plog = nullptr) + { + const std::map param_map = { + {"d3_bj", "bj"}, {"d3_0", "zero"}, {"d3_bjm", "bjm"}, {"d3_0m", "zerom"}, + {"op", "op"}}; + + const std::vector flag = {s6_in, s8_in, a1_in, a2_in}; + const bool autoset = std::any_of(flag.begin(), flag.end(), [](const std::string& s) { return s == "default"; }); + if (!autoset) // all parameters are defined + { + s6 = std::stod(s6_in); + s8 = std::stod(s8_in); + a1 = std::stod(a1_in); + a2 = std::stod(a2_in); + } + else + { + std::vector param; + const std::string xc = DFTD3::_xcname(xc_in); + _search(xc, param_map.at(d3method), param); + s6 = (s6_in == "default") ? param[0] : std::stod(s6_in); + s8 = (s8_in == "default") ? param[3] : std::stod(s8_in); + a1 = (a1_in == "default") ? param[2] : std::stod(a1_in); + a2 = (a2_in == "default") ? param[5] : std::stod(a2_in); + if (plog != nullptr) // logging the autoset + { + param = {s6, s8, a1, a2}; + FmtTable vdwd3tab({"Parameters", "Original", "Autoset"}, 4, {"%10s", "%10s", "%10.4f"}); + const std::vector items = {"s6", "s8", "a1", "a2"}; + vdwd3tab << items << flag << param; + (*plog) << "\nDFT-D3 Dispersion correction parameters autoset\n" << vdwd3tab.str() + << "XC functional: " << xc_in << std::endl; + } + + } + } +} + +/* +''' +dftd3 parameters from +https://github.com/dftd3/simple-dftd3/blob/main/assets/parameters.toml + +this script is to convert the toml file to c++ map +''' + +import toml + +def load(fn): + with open(fn, 'r') as f: + data = toml.load(f) + return data + +def xc_indexing(data): + out = {'bj': {}, 'zero': {}, 'bjm': {}, 'zerom': {}, 'op': {}} + for xc, param in data['parameter'].items(): + for vdw_method, value in param['d3'].items(): + out[vdw_method][xc] = {k: v for k, v in value.items() if k != 'doi'} + return out + +def complete(vdw_method, value): + ''' + for each functional, the zero damping version must be provided + for each vdw method, all parameters including + s6, rs6/a1, s8, rs8/a2, s9, alp, bet must be provided, otherwise + use the default value + ''' + DEFAULT = { + 'bj': {'s6': 1.0, 's9': 1.0, 'alp': 14.0}, + 'zero': {'s6': 1.0, 's9': 1.0, 'rs8': 1.0, 'alp': 14.0}, + 'bjm': {'s6': 1.0, 's9': 1.0, 'alp': 14.0}, + 'zerom': {'s6': 1.0, 's9': 1.0, 'rs8': 1.0, 'alp': 14.0}, + 'op': {'s9': 1.0, 'alp': 14.0} + } + ALL_KEYS = {'s6', 'rs6', 'a1', 's8', 'rs8', 'a2', 's9', 'alp', 'bet'} + EQUIVALENT = {'rs6': 'a1', 'a1': 'rs6', 'rs8': 'a2', 'a2': 'rs8'} + out = value.copy() + for k in ALL_KEYS: + equilk = EQUIVALENT.get(k, k) + val = [out.get(k), out.get(equilk), + DEFAULT[vdw_method].get(k), DEFAULT[vdw_method].get(equilk)] + val = [v for v in val if v is not None] + val = [0.0] if not val else val + out[k] = val[0] + out[equilk] = out[k] + # equivalent? + # according to + # abacus-develop/source/module_hamilt_general/module_vdw/vdwd3_parameters.cpp + # https://abacus.deepmodeling.com/en/latest/advanced/input_files/input-main.html + + return out + +def make_stdmap(data): + for vdw_method, param in data.items(): + print(f'std::map> {vdw_method} = {{') + for xc, value in param.items(): + print(f' {{\"{xc}\", {{', end='') + print(', '.join([f'{v}' for v in value.values()]), end='') + print('}},') + print('};') + +if __name__ == '__main__': + fn = 'dftd3.toml' + data = load(fn) + data = xc_indexing(data) + for vdw_method, param in data.items(): + for xc, value in param.items(): + raw = complete(vdw_method, value) + data[vdw_method][xc] = {k: raw[k] + for k in ['s6', 'rs6', 'a1', 's8', 'rs8', 'a2', 's9', 'alp', 'bet']} + make_stdmap(data) +*/ +#endif // DFTD3_XC_PARAM_H diff --git a/source/module_hamilt_general/module_vdw/test/CMakeLists.txt b/source/module_hamilt_general/module_vdw/test/CMakeLists.txt index 70848009562..8833b3cf089 100644 --- a/source/module_hamilt_general/module_vdw/test/CMakeLists.txt +++ b/source/module_hamilt_general/module_vdw/test/CMakeLists.txt @@ -9,4 +9,10 @@ AddTest( TARGET vdwTest LIBS parameter ${math_libs} base device vdw SOURCES vdw_test.cpp +) + +AddTest( + TARGET dftd3_xc + LIBS parameter ${math_libs} base device + SOURCES dftd3_xc_test.cpp ) \ No newline at end of file diff --git a/source/module_hamilt_general/module_vdw/test/dftd3_xc_test.cpp b/source/module_hamilt_general/module_vdw/test/dftd3_xc_test.cpp new file mode 100644 index 00000000000..3ed3a421469 --- /dev/null +++ b/source/module_hamilt_general/module_vdw/test/dftd3_xc_test.cpp @@ -0,0 +1,104 @@ +#include +#include "module_hamilt_general/module_vdw/dftd3_xc_name.h" +#include "module_hamilt_general/module_vdw/dftd3_xc_param.h" + +TEST(DFTD3XCTest, SearchXcnameLibXCXplusC) +{ + std::string xname; + DFTD3::_xcname_libxc_xplusc("XC_GGA_X_PBE+XC_GGA_C_OP_PBE", xname); + EXPECT_EQ(xname, "pbeop"); + // then test the case with out prefix XC_ + DFTD3::_xcname_libxc_xplusc("GGA_X_PBE+GGA_C_OP_PBE", xname); + EXPECT_EQ(xname, "pbeop"); +} + +TEST(DFTD3XCTest, SearchXcnameLibXCXC) +{ + std::string xname; + DFTD3::_xcname_libxc_xc("XC_LDA_XC_TETER93", xname); + EXPECT_EQ(xname, "teter93"); + // then test the case with out prefix XC_ + DFTD3::_xcname_libxc_xc("LDA_XC_TETER93", xname); + EXPECT_EQ(xname, "teter93"); +} + +TEST(DFTD3XCTest, SearchXcnameLibXC) +{ + std::string xname; + DFTD3::_xcname_libxc("XC_GGA_X_PBE+XC_GGA_C_OP_PBE", xname); + EXPECT_EQ(xname, "pbeop"); + // then test the case with out prefix XC_ + DFTD3::_xcname_libxc("GGA_X_PBE+GGA_C_OP_PBE", xname); + EXPECT_EQ(xname, "pbeop"); +} + +TEST(DFTD3XCTest, SearchXcname) +{ + std::string xcpattern = "XC_GGA_X_PBE+XC_GGA_C_OP_PBE"; + std::string xname = DFTD3::_xcname(xcpattern); + EXPECT_EQ(xname, "pbeop"); + + xcpattern = "XC_LDA_XC_TETER93"; + xname = DFTD3::_xcname(xcpattern); + EXPECT_EQ(xname, "teter93"); + + xcpattern = "default"; + xname = DFTD3::_xcname(xcpattern); + EXPECT_EQ(xname, "default"); + + xcpattern = "pbe"; + xname = DFTD3::_xcname(xcpattern); + EXPECT_EQ(xname, "pbe"); +} + +TEST(DFTD3XCTest, SuccessfulSearch) +{ + std::string xc = "pbe"; + std::string d3method = "d3_0"; + std::string s6_in = "default"; + std::string s8_in = "default"; + std::string a1_in = "default"; + std::string a2_in = "default"; + double s6, s8, a1, a2; + DFTD3::dftd3_params(xc, d3method, s6_in, s8_in, a1_in, a2_in, s6, s8, a1, a2); + EXPECT_DOUBLE_EQ(s6, 1.0); + EXPECT_DOUBLE_EQ(s8, 0.722); + EXPECT_DOUBLE_EQ(a1, 1.217); + EXPECT_DOUBLE_EQ(a2, 1.0); + + // a more complicated case: MGGA_X_SCAN+MGGA_C_SCAN + xc = "XC_MGGA_X_SCAN+XC_MGGA_C_SCAN"; + DFTD3::dftd3_params(xc, d3method, s6_in, s8_in, a1_in, a2_in, s6, s8, a1, a2); + EXPECT_DOUBLE_EQ(s6, 1.0); + EXPECT_DOUBLE_EQ(s8, 0.0); + EXPECT_DOUBLE_EQ(a1, 1.324); + EXPECT_DOUBLE_EQ(a2, 1.0); + + // user defines all parameters + s6_in = "1.1"; + s8_in = "0.1"; + a1_in = "1.325"; + a2_in = "1.1"; + DFTD3::dftd3_params(xc, d3method, s6_in, s8_in, a1_in, a2_in, s6, s8, a1, a2); + EXPECT_DOUBLE_EQ(s6, 1.1); + EXPECT_DOUBLE_EQ(s8, 0.1); + EXPECT_DOUBLE_EQ(a1, 1.325); + EXPECT_DOUBLE_EQ(a2, 1.1); + + // user defines one parameter + s6_in = "1.1"; + s8_in = "default"; + a1_in = "default"; + a2_in = "default"; + DFTD3::dftd3_params(xc, d3method, s6_in, s8_in, a1_in, a2_in, s6, s8, a1, a2); + EXPECT_DOUBLE_EQ(s6, 1.1); + EXPECT_DOUBLE_EQ(s8, 0.0); + EXPECT_DOUBLE_EQ(a1, 1.324); + EXPECT_DOUBLE_EQ(a2, 1.0); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/source/module_hamilt_general/module_vdw/vdw.cpp b/source/module_hamilt_general/module_vdw/vdw.cpp index 4644ab70355..b070d527aef 100644 --- a/source/module_hamilt_general/module_vdw/vdw.cpp +++ b/source/module_hamilt_general/module_vdw/vdw.cpp @@ -6,30 +6,35 @@ namespace vdw { -std::unique_ptr make_vdw(const UnitCell &ucell, const Input_para &input) +std::unique_ptr make_vdw(const UnitCell &ucell, + const Input_para &input, + std::ofstream* plog) { - if (ucell.nat < 2 && input.vdw_method != "none") - { - ModuleBase::WARNING("VDW", "Only one atom in this system, and will not do the calculation of VDW"); - return nullptr; - } - else if (input.vdw_method == "d2") + // if (ucell.nat < 2 && input.vdw_method != "none") + // { + // ModuleBase::WARNING("VDW", "Only one atom in this system, and will not do the calculation of VDW"); + // return nullptr; + // } + if (input.vdw_method == "d2") { std::unique_ptr vdw_ptr = make_unique(ucell); - vdw_ptr->parameter().initial_parameters(input); + vdw_ptr->parameter().initial_parameters(input, plog); vdw_ptr->parameter().initset(ucell); return vdw_ptr; } else if (input.vdw_method == "d3_0" || input.vdw_method == "d3_bj") { std::unique_ptr vdw_ptr = make_unique(ucell); - vdw_ptr->parameter().initial_parameters(input); + vdw_ptr->parameter().initial_parameters(input, plog); return vdw_ptr; } - else + else if (input.vdw_method != "none") { + ModuleBase::WARNING_QUIT("ModuleHamiltGeneral::ModuleVDW::make_vdw", + "Unrecognized Van der Waals correction method: " + input.vdw_method); return nullptr; } + return nullptr; // "none" method } } // namespace vdw \ No newline at end of file diff --git a/source/module_hamilt_general/module_vdw/vdw.h b/source/module_hamilt_general/module_vdw/vdw.h index 94b54239cba..257b80cd981 100644 --- a/source/module_hamilt_general/module_vdw/vdw.h +++ b/source/module_hamilt_general/module_vdw/vdw.h @@ -48,7 +48,17 @@ class Vdw virtual void cal_stress() = 0; }; -std::unique_ptr make_vdw(const UnitCell &ucell, const Input_para &input); +/** + * @brief make vdw correction object + * + * @param ucell UnitCell instance + * @param input Parameter instance + * @param plog optional, for logging the parameter setting process + * @return std::unique_ptr + */ +std::unique_ptr make_vdw(const UnitCell &ucell, + const Input_para &input, + std::ofstream* plog = nullptr); } // namespace vdw diff --git a/source/module_hamilt_general/module_vdw/vdwd2_parameters.cpp b/source/module_hamilt_general/module_vdw/vdwd2_parameters.cpp index de8bda7bcc6..a562244be3b 100644 --- a/source/module_hamilt_general/module_vdw/vdwd2_parameters.cpp +++ b/source/module_hamilt_general/module_vdw/vdwd2_parameters.cpp @@ -9,7 +9,7 @@ namespace vdw { -void Vdwd2Parameters::initial_parameters(const Input_para &input) +void Vdwd2Parameters::initial_parameters(const Input_para &input, std::ofstream* plog) { scaling_ = std::stod(input.vdw_s6); damping_ = input.vdw_d; diff --git a/source/module_hamilt_general/module_vdw/vdwd2_parameters.h b/source/module_hamilt_general/module_vdw/vdwd2_parameters.h index ef981b2c0a1..06d4a527933 100644 --- a/source/module_hamilt_general/module_vdw/vdwd2_parameters.h +++ b/source/module_hamilt_general/module_vdw/vdwd2_parameters.h @@ -31,7 +31,15 @@ class Vdwd2Parameters : public VdwParameters void R0_input(const std::string &file, const std::string &unit); void initset(const UnitCell &ucell); // init sets of vdwd2 once this correction is called - void initial_parameters(const Input_para &input); // initial parameters of Vdwd2 with INPUT file + + /** + * @brief initial parameters of Vdwd2 with INPUT file + * + * @param input Parameter instance + * @param plog optional, for logging the parameter setting process (not implemented) + */ + void initial_parameters(const Input_para &input, + std::ofstream* plog = nullptr); inline const std::map C6() const { return C6_; } inline const std::map R0() const { return R0_; } diff --git a/source/module_hamilt_general/module_vdw/vdwd3.cpp b/source/module_hamilt_general/module_vdw/vdwd3.cpp index be68c13651d..b5b0798c63c 100644 --- a/source/module_hamilt_general/module_vdw/vdwd3.cpp +++ b/source/module_hamilt_general/module_vdw/vdwd3.cpp @@ -24,29 +24,33 @@ void Vdwd3::init() std::vector at_kind = atom_kind(); iz_.reserve(ucell_.nat); xyz_.reserve(ucell_.nat); - for (size_t it = 0; it != ucell_.ntype; it++) + for (size_t it = 0; it != ucell_.ntype; it++) { for (size_t ia = 0; ia != ucell_.atoms[it].na; ia++) { iz_.emplace_back(at_kind[it]); xyz_.emplace_back(ucell_.atoms[it].tau[ia] * ucell_.lat0); } +} std::vector tau_max(3); if (para_.model() == "radius") { rep_vdw_.resize(3); set_criteria(para_.rthr2(), lat_, tau_max); - for (size_t i = 0; i < 3; i++) + for (size_t i = 0; i < 3; i++) { rep_vdw_[i] = std::ceil(tau_max[i]); +} } - else if (para_.model() == "period") + else if (para_.model() == "period") { rep_vdw_ = {para_.period().x, para_.period().y, para_.period().z}; +} rep_cn_.resize(3); set_criteria(para_.cn_thr2(), lat_, tau_max); - for (size_t i = 0; i < 3; i++) + for (size_t i = 0; i < 3; i++) { rep_cn_[i] = ceil(tau_max[i]); } +} void Vdwd3::set_criteria(double rthr, const std::vector> &lat, std::vector &tau_max) { @@ -66,13 +70,15 @@ void Vdwd3::set_criteria(double rthr, const std::vector Vdwd3::atom_kind() { std::vector atom_kind(ucell_.ntype); - for (size_t i = 0; i != ucell_.ntype; i++) - for (int j = 0; j != ModuleBase::element_name.size(); j++) + for (size_t i = 0; i != ucell_.ntype; i++) { + for (int j = 0; j != ModuleBase::element_name.size(); j++) { if (ucell_.atoms[i].ncpp.psd == ModuleBase::element_name[j]) { atom_kind[i] = j; break; } +} +} return atom_kind; } @@ -91,24 +97,25 @@ void Vdwd3::cal_energy() if (para_.version() == "d3_0") // DFT-D3(zero-damping) { double tmp; - for (int iat = 0; iat != ucell_.nat - 1; iat++) + for (int iat = 0; iat != ucell_.nat - 1; iat++) { for (int jat = iat + 1; jat != ucell_.nat; jat++) { get_c6(iz_[iat], iz_[jat], cn[iat], cn[jat], c6); - if (para_.abc()) + if (para_.abc()) // three-body term { ij = lin(iat, jat); cc6ab[ij] = std::sqrt(c6); } - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; - r2 = (xyz_[iat] - xyz_[jat] + tau).norm2(); - if (r2 > para_.rthr2()) + r2 = (xyz_[iat] - xyz_[jat] + tau).norm2(); // |r+T|^2 + if (r2 > para_.rthr2()) { // neglect the distance larger than rthr2 continue; +} rr = para_.r0ab()[iz_[iat]][iz_[jat]] / std::sqrt(r2); // zero-damping function tmp = para_.rs6() * rr; @@ -123,7 +130,10 @@ void Vdwd3::cal_energy() r8 = r6 * r2; e8 += c8 * damp8 / r8; } // end tau +} +} } // end jat +} for (int iat = 0; iat != ucell_.nat; iat++) { @@ -134,17 +144,19 @@ void Vdwd3::cal_energy() ij = lin(iat, jat); cc6ab[ij] = std::sqrt(c6); } - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { - if (taux == 0 && tauy == 0 && tauz == 0) + if (taux == 0 && tauy == 0 && tauz == 0) { continue; +} tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = tau.norm2(); - if (r2 > para_.rthr2()) + if (r2 > para_.rthr2()) { continue; +} rr = para_.r0ab()[iz_[iat]][iz_[jat]] / std::sqrt(r2); // zero-damping function @@ -160,6 +172,8 @@ void Vdwd3::cal_energy() r8 = r6 * r2; e8 += c8 * damp8 / r8 * 0.5; } // end tau +} +} } // end iat } // end d3_0 else if (para_.version() == "d3_bj") // DFT-D3(BJ-damping) @@ -175,15 +189,16 @@ void Vdwd3::cal_energy() ij = lin(iat, jat); cc6ab[ij] = std::sqrt(c6); } - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = (xyz_[iat] - xyz_[jat] + tau).norm2(); - if (r2 > para_.rthr2()) + if (r2 > para_.rthr2()) { continue; +} rr = para_.r0ab()[iz_[iat]][iz_[jat]] / std::sqrt(r2); // BJ-damping function @@ -198,6 +213,8 @@ void Vdwd3::cal_energy() r8 = r6 * r2; e8 += c8 / (r8 + damp8); } // end tau +} +} } // end jat int jat = iat; get_c6(iz_[iat], iz_[jat], cn[iat], cn[jat], c6); @@ -209,17 +226,19 @@ void Vdwd3::cal_energy() ij = lin(iat, jat); cc6ab[ij] = std::sqrt(c6); } - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { - if (taux == 0 && tauy == 0 && tauz == 0) + if (taux == 0 && tauy == 0 && tauz == 0) { continue; +} tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = tau.norm2(); - if (r2 > para_.rthr2()) + if (r2 > para_.rthr2()) { continue; +} rr = para_.r0ab()[iz_[iat]][iz_[jat]] / std::sqrt(r2); r6 = std::pow(r2, 3); @@ -229,6 +248,8 @@ void Vdwd3::cal_energy() r8 = r6 * r2; e8 += c8 / (r8 + damp8) * 0.5; } // end tau +} +} } // end iat } // end d3_bj @@ -256,8 +277,9 @@ void Vdwd3::cal_force() pbc_gdisp(g, smearing_sigma); - for (size_t iat = 0; iat != ucell_.nat; iat++) + for (size_t iat = 0; iat != ucell_.nat; iat++) { force_[iat] = -2.0 * g[iat]; +} ModuleBase::timer::tick("Vdwd3", "cal_force"); } @@ -286,7 +308,7 @@ void Vdwd3::get_c6(int iat, int jat, double nci, double ncj, double &c6) { double c6mem = -1e99, rsum = 0.0, csum = 0.0, r_save = 1e99; double cn1, cn2, r; - for (size_t i = 0; i != para_.mxc()[iat]; i++) + for (size_t i = 0; i != para_.mxc()[iat]; i++) { for (size_t j = 0; j != para_.mxc()[jat]; j++) { c6 = para_.c6ab()[0][j][i][jat][iat]; @@ -305,6 +327,7 @@ void Vdwd3::get_c6(int iat, int jat, double nci, double ncj, double &c6) csum += tmp1 * c6; } } +} c6 = (rsum > 1e-99) ? csum / rsum : c6mem; } @@ -315,21 +338,26 @@ void Vdwd3::pbc_ncoord(std::vector &cn) double xn = 0.0; ModuleBase::Vector3 tau; double r2, rr; - for (size_t iat = 0; iat != ucell_.nat; iat++) - for (int taux = -rep_cn_[0]; taux <= rep_cn_[0]; taux++) - for (int tauy = -rep_cn_[1]; tauy <= rep_cn_[1]; tauy++) + for (size_t iat = 0; iat != ucell_.nat; iat++) { + for (int taux = -rep_cn_[0]; taux <= rep_cn_[0]; taux++) { + for (int tauy = -rep_cn_[1]; tauy <= rep_cn_[1]; tauy++) { for (int tauz = -rep_cn_[2]; tauz <= rep_cn_[2]; tauz++) { - if (iat == i && taux == 0 && tauy == 0 && tauz == 0) + if (iat == i && taux == 0 && tauy == 0 && tauz == 0) { continue; +} tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = (xyz_[iat] - xyz_[i] + tau).norm2(); - if (r2 > para_.cn_thr2()) + if (r2 > para_.cn_thr2()) { continue; +} rr = (para_.rcov()[iz_[i]] + para_.rcov()[iz_[iat]]) / std::sqrt(r2); xn += 1.0 / (1.0 + exp(-para_.k1() * (rr - 1.0))); } +} +} +} cn[i] = xn; } } @@ -346,7 +374,7 @@ void Vdwd3::pbc_three_body(const std::vector &iz, double r0ij, r0ik, r0jk, c9, rij2, rik2, rjk2, rr0ij, rr0ik, rr0jk, geomean, fdamp, tmp1, tmp2, tmp3, tmp4, ang; ModuleBase::Vector3 ijvec, ikvec, jkvec, jtau, ktau; std::vector repmin(3), repmax(3); - for (int iat = 2; iat != ucell_.nat; iat++) + for (int iat = 2; iat != ucell_.nat; iat++) { for (int jat = 1; jat != iat; jat++) { ijvec = xyz_[jat] - xyz_[iat]; @@ -378,25 +406,28 @@ void Vdwd3::pbc_three_body(const std::vector &iz, jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = (ijvec + jtau).norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / r0ij; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / r0ik; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / r0jk; geomean = std::pow(rr0ij * rr0ik * rr0jk, 1.0 / 3.0); @@ -410,11 +441,14 @@ void Vdwd3::pbc_three_body(const std::vector &iz, eabc += ang * c9 * fdamp; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux } // end kat } // end jat +} // end iat for (int iat = 1; iat != ucell_.nat; iat++) @@ -445,29 +479,33 @@ void Vdwd3::pbc_three_body(const std::vector &iz, { repmin[2] = std::max(-rep_cn_[2], jtauz - rep_cn_[2]); repmax[2] = std::min(rep_cn_[2], jtauz + rep_cn_[2]); - if (jtaux == 0 && jtauy == 0 && jtauz == 0) + if (jtaux == 0 && jtauy == 0 && jtauz == 0) { continue; +} jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = (ijvec + jtau).norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / r0ij; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / r0ik; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / r0jk; geomean = std::pow(rr0ij * rr0ik * rr0jk, 1.0 / 3.0); @@ -481,13 +519,15 @@ void Vdwd3::pbc_three_body(const std::vector &iz, eabc += ang * c9 * fdamp / 2.0; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux } // end kat } // end iat - for (int iat = 1; iat != ucell_.nat; iat++) + for (int iat = 1; iat != ucell_.nat; iat++) { for (int jat = 0; jat != iat; jat++) { int kat = jat; @@ -518,26 +558,30 @@ void Vdwd3::pbc_three_body(const std::vector &iz, jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = (ijvec + jtau).norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / r0ij; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { - if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) + if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) { continue; +} ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / r0ik; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / r0jk; geomean = std::pow(rr0ij * rr0ik * rr0jk, 1.0 / 3.0); @@ -551,10 +595,13 @@ void Vdwd3::pbc_three_body(const std::vector &iz, eabc += ang * c9 * fdamp / 2.0; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux } // end jat +} // end iat for (int iat = 0; iat != ucell_.nat; iat++) @@ -587,31 +634,37 @@ void Vdwd3::pbc_three_body(const std::vector &iz, repmax[2] = std::min(rep_cn_[2], jtauz + rep_cn_[2]); jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; - if (jtaux == 0 && jtauy == 0 && jtauz == 0) + if (jtaux == 0 && jtauy == 0 && jtauz == 0) { continue; +} rij2 = jtau.norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / r0ij; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { - if (ktaux == 0 && ktauy == 0 && ktauz == 0) + if (ktaux == 0 && ktauy == 0 && ktauz == 0) { continue; - if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) +} + if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) { continue; +} ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = ktau.norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / r0ik; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / r0jk; geomean = std::pow(rr0ij * rr0ik * rr0jk, 1.0 / 3.0); @@ -625,6 +678,8 @@ void Vdwd3::pbc_three_body(const std::vector &iz, eabc += ang * c9 * fdamp / 6.0; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux @@ -637,7 +692,7 @@ void Vdwd3::get_dc6_dcnij(int mxci, int mxcj, double cni, double cnj, int izi, i double r_save = 9999.0, c6mem = -1e99, zaehler = 0.0, nenner = 0.0; double dzaehler_i = 0.0, dnenner_i = 0.0, dzaehler_j = 0.0, dnenner_j = 0.0; double c6ref = 0.0, cn_refi = 0.0, cn_refj = 0.0, r = 0.0, expterm = 0.0, term = 0.0; - for (size_t a = 0; a != mxci; a++) + for (size_t a = 0; a != mxci; a++) { for (size_t b = 0; b != mxcj; b++) { c6ref = para_.c6ab()[0][b][a][izj][izi]; @@ -664,6 +719,7 @@ void Vdwd3::get_dc6_dcnij(int mxci, int mxcj, double cni, double cnj, int izi, i dnenner_j += term; } } +} if (nenner > 1e-99) { @@ -710,8 +766,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m r42 = para_.r2r4()[iz_[iat]] * para_.r2r4()[iz_[iat]]; rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[iat]]; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] @@ -748,6 +804,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc6_rest_sum[linii] += dc6_rest; } } // end tau +} +} for (int jat = 0; jat != iat; jat++) { get_dc6_dcnij(para_.mxc()[iz_[iat]], para_.mxc()[iz_[jat]], cn[iat], cn[jat], @@ -760,15 +818,16 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[jat]]; dc6ij[jat][iat] = dc6iji; dc6ij[iat][jat] = dc6ijj; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = (xyz_[jat] - xyz_[iat] + tau).norm2(); - if (r2 > para_.rthr2()) + if (r2 > para_.rthr2()) { continue; +} r = std::sqrt(r2); r6 = std::pow(r2, 3); @@ -794,6 +853,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc6i[jat] += dc6_rest * dc6ijj; dc6_rest_sum[linij] += dc6_rest; } // end tau +} +} } // end jat } // end iat } // end d3_0 @@ -812,8 +873,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m r0 = para_.rs6() * std::sqrt(3.0 * r42) + para_.rs18(); rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[iat]]; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] @@ -843,6 +904,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc6_rest_sum[linii] += dc6_rest; } } // end tau +} +} for (int jat = 0; jat != iat; jat++) { get_dc6_dcnij(para_.mxc()[iz_[iat]], para_.mxc()[iz_[jat]], cn[iat], cn[jat], @@ -855,15 +918,16 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[jat]]; dc6ij[jat][iat] = dc6iji; dc6ij[iat][jat] = dc6ijj; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = (xyz_[jat] - xyz_[iat] + tau).norm2(); - if (r2 > para_.rthr2()) + if (r2 > para_.rthr2()) { continue; +} r = std::sqrt(r2); r4 = r2 * r2; @@ -884,6 +948,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc6i[jat] += dc6_rest * dc6ijj; dc6_rest_sum[linij] += dc6_rest; } // end tau +} +} } // end jat } // end iat } // end d3_bj @@ -929,24 +995,27 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = (ijvec + jtau).norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / para_.r0ab()[iz_[jat]][iz_[iat]]; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / para_.r0ab()[iz_[kat]][iz_[iat]]; rr0jk = std::sqrt(rjk2) / para_.r0ab()[iz_[kat]][iz_[jat]]; @@ -1004,6 +1073,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc9 = (dc6ij[iat][kat] / c6ik + dc6ij[jat][kat] / c6jk) * c9 * 0.5; dc6i[kat] += dc6_rest * dc9; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux @@ -1040,29 +1111,33 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m { repmin[2] = std::max(-rep_cn_[2], jtauz - rep_cn_[2]); repmax[2] = std::min(rep_cn_[2], jtauz + rep_cn_[2]); - if (jtaux == 0 && jtauy == 0 && jtauz == 0) + if (jtaux == 0 && jtauy == 0 && jtauz == 0) { continue; +} jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = jtau.norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / para_.r0ab()[iz_[jat]][iz_[iat]]; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / para_.r0ab()[iz_[kat]][iz_[iat]]; rr0jk = std::sqrt(rjk2) / para_.r0ab()[iz_[kat]][iz_[jat]]; @@ -1120,13 +1195,15 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc9 = (dc6ij[iat][kat] / c6ik + dc6ij[jat][kat] / c6jk) * c9 * 0.5; dc6i[kat] += dc6_rest * dc9; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux } // end kat } // end iat - for (int iat = 1; iat != ucell_.nat; iat++) + for (int iat = 1; iat != ucell_.nat; iat++) { for (int jat = 0; jat != iat; jat++) { int kat = jat; @@ -1157,27 +1234,31 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = (ijvec + jtau).norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / para_.r0ab()[iz_[jat]][iz_[iat]]; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { - if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) + if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) { continue; +} ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = (ikvec + ktau).norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / para_.r0ab()[iz_[kat]][iz_[iat]]; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / para_.r0ab()[iz_[kat]][iz_[jat]]; geomean2 = rij2 * rjk2 * rik2; @@ -1234,10 +1315,13 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc9 = (dc6ij[iat][kat] / c6ik + dc6ij[jat][kat] / c6jk) * c9 * 0.5; dc6i[kat] += dc6_rest * dc9; } // end ktau +} +} } // end jtauz } // end jtauy } // end jtaux } // end jat +} // end iat for (int iat = 0; iat != ucell_.nat; iat++) @@ -1267,33 +1351,39 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m { repmin[2] = std::max(-rep_cn_[2], jtauz - rep_cn_[2]); repmax[2] = std::min(rep_cn_[2], jtauz + rep_cn_[2]); - if (jtaux == 0 && jtauy == 0 && jtauz == 0) + if (jtaux == 0 && jtauy == 0 && jtauz == 0) { continue; +} jtau = static_cast(jtaux) * lat_[0] + static_cast(jtauy) * lat_[1] + static_cast(jtauz) * lat_[2]; rij2 = jtau.norm2(); - if (rij2 > para_.cn_thr2()) + if (rij2 > para_.cn_thr2()) { continue; +} rr0ij = std::sqrt(rij2) / para_.r0ab()[iz_[jat]][iz_[iat]]; - for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) - for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) + for (int ktaux = repmin[0]; ktaux <= repmax[0]; ktaux++) { + for (int ktauy = repmin[1]; ktauy <= repmax[1]; ktauy++) { for (int ktauz = repmin[2]; ktauz <= repmax[2]; ktauz++) { - if (ktaux == 0 && ktauy == 0 && ktauz == 0) + if (ktaux == 0 && ktauy == 0 && ktauz == 0) { continue; - if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) +} + if (jtaux == ktaux && jtauy == ktauy && jtauz == ktauz) { continue; +} ktau = static_cast(ktaux) * lat_[0] + static_cast(ktauy) * lat_[1] + static_cast(ktauz) * lat_[2]; rik2 = ktau.norm2(); - if (rik2 > para_.cn_thr2()) + if (rik2 > para_.cn_thr2()) { continue; +} rr0ik = std::sqrt(rik2) / para_.r0ab()[iz_[kat]][iz_[iat]]; rjk2 = (jkvec + ktau - jtau).norm2(); - if (rjk2 > para_.cn_thr2()) + if (rjk2 > para_.cn_thr2()) { continue; +} rr0jk = std::sqrt(rjk2) / para_.r0ab()[iz_[kat]][iz_[jat]]; geomean2 = rij2 * rjk2 * rik2; @@ -1350,6 +1440,8 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m dc9 = (dc6ij[iat][kat] / c6ik + dc6ij[jat][kat] / c6jk) * c9 * 0.5; dc6i[kat] += dc6_rest * dc9; } // end ktau +} +} } // end jtauz } // end jtauy } // jtaux @@ -1359,29 +1451,31 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m // dE/dr_ij * dr_ij/dxyz_i double expterm, dcnn, x1; ModuleBase::Vector3 rij, vec3; - for (int iat = 1; iat != ucell_.nat; iat++) + for (int iat = 1; iat != ucell_.nat; iat++) { for (int jat = 0; jat != iat; jat++) { linij = lin(iat, jat); rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[jat]]; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; rij = xyz_[jat] - xyz_[iat] + tau; r2 = rij.norm2(); - if (r2 > para_.rthr2() || r2 < 0.5) + if (r2 > para_.rthr2() || r2 < 0.5) { continue; +} r = std::sqrt(r2); if (r2 < para_.cn_thr2()) { expterm = exp(-para_.k1() * (rcovij / r - 1.0)); dcnn = -para_.k1() * rcovij * expterm / (r2 * (expterm + 1.0) * (expterm + 1.0)); } - else + else { dcnn = 0.0; +} x1 = drij[linij][taux + rep_vdw_[0]][tauy + rep_vdw_[1]][tauz + rep_vdw_[2]] + dcnn * (dc6i[iat] + dc6i[jat]); vec3 = x1 * rij / r; @@ -1390,23 +1484,28 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m std::vector vec = {vec3.x, vec3.y, vec3.z}; std::vector rij_vec = {rij.x, rij.y, rij.z}; - for (size_t i = 0; i != 3; i++) + for (size_t i = 0; i != 3; i++) { for (size_t j = 0; j != 3; j++) { smearing_sigma(i, j) += vec[j] * rij_vec[i]; } +} } // end tau +} +} } // end iat, jat +} for (int iat = 0; iat != ucell_.nat; iat++) { linii = lin(iat, iat); rcovij = para_.rcov()[iz_[iat]] + para_.rcov()[iz_[iat]]; - for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) - for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) + for (int taux = -rep_vdw_[0]; taux <= rep_vdw_[0]; taux++) { + for (int tauy = -rep_vdw_[1]; tauy <= rep_vdw_[1]; tauy++) { for (int tauz = -rep_vdw_[2]; tauz <= rep_vdw_[2]; tauz++) { - if (taux == 0 && tauy == 0 && tauz == 0) + if (taux == 0 && tauy == 0 && tauz == 0) { continue; +} tau = static_cast(taux) * lat_[0] + static_cast(tauy) * lat_[1] + static_cast(tauz) * lat_[2]; r2 = tau.norm2(); @@ -1416,19 +1515,23 @@ void Vdwd3::pbc_gdisp(std::vector> &g, ModuleBase::m expterm = exp(-para_.k1() * (rcovij / r - 1.0)); dcnn = -para_.k1() * rcovij * expterm / (r2 * (expterm + 1.0) * (expterm + 1.0)); } - else + else { dcnn = 0.0; +} x1 = drij[linii][taux + rep_vdw_[0]][tauy + rep_vdw_[1]][tauz + rep_vdw_[2]] + dcnn * dc6i[iat]; vec3 = x1 * tau / r; std::vector vec = {vec3.x, vec3.y, vec3.z}; std::vector tau_vec = {tau.x, tau.y, tau.z}; - for (size_t i = 0; i != 3; i++) + for (size_t i = 0; i != 3; i++) { for (size_t j = 0; j != 3; j++) { smearing_sigma(i, j) += vec[j] * tau_vec[i]; } +} } // end tau +} +} } // end iat } diff --git a/source/module_hamilt_general/module_vdw/vdwd3_parameters.cpp b/source/module_hamilt_general/module_vdw/vdwd3_parameters.cpp index e0336c38284..4e1bed1ae00 100644 --- a/source/module_hamilt_general/module_vdw/vdwd3_parameters.cpp +++ b/source/module_hamilt_general/module_vdw/vdwd3_parameters.cpp @@ -5,14 +5,15 @@ //========================================================== #include "vdwd3_parameters.h" - #include "module_base/constants.h" - +#include +#include "dftd3_xc_param.h" namespace vdw { -void Vdwd3Parameters::initial_parameters(const Input_para &input) +void Vdwd3Parameters::initial_parameters(const Input_para &input, std::ofstream* plog) { + // initialize the dftd3 parameters mxc_.resize(max_elem_, 1); r0ab_.resize(max_elem_, std::vector(max_elem_, 0.0)); @@ -22,11 +23,11 @@ void Vdwd3Parameters::initial_parameters(const Input_para &input) std::vector>>( 5, std::vector>(max_elem_, std::vector(max_elem_, 0.0))))); - - s6_ = std::stod(input.vdw_s6); - s18_ = std::stod(input.vdw_s8); - rs6_ = std::stod(input.vdw_a1); - rs18_ = std::stod(input.vdw_a2); + + DFTD3::dftd3_params(input.dft_functional, input.vdw_method, + input.vdw_s6, input.vdw_s8, input.vdw_a1, input.vdw_a2, + s6_, s18_, rs6_, rs18_, /* rs6: a1, rs18: a2 */ + plog); abc_ = input.vdw_abc; version_ = input.vdw_method; model_ = input.vdw_cutoff_type; diff --git a/source/module_hamilt_general/module_vdw/vdwd3_parameters.h b/source/module_hamilt_general/module_vdw/vdwd3_parameters.h index c5f005a7b7c..95d1a031439 100644 --- a/source/module_hamilt_general/module_vdw/vdwd3_parameters.h +++ b/source/module_hamilt_general/module_vdw/vdwd3_parameters.h @@ -21,7 +21,14 @@ class Vdwd3Parameters : public VdwParameters ~Vdwd3Parameters() = default; - void initial_parameters(const Input_para &input); + /** + * @brief initialize the parameter by either input (from user setting) or autoset by dft XC + * + * @param input Parameter instance + * @param plog optional, for logging the parameter setting process + */ + void initial_parameters(const Input_para &input, + std::ofstream* plog = nullptr); // for logging the parameter autoset inline const std::string &version() const { return version_; } diff --git a/source/module_hamilt_general/module_xc/CMakeLists.txt b/source/module_hamilt_general/module_xc/CMakeLists.txt index 195f144eb43..4db1ef083d7 100644 --- a/source/module_hamilt_general/module_xc/CMakeLists.txt +++ b/source/module_hamilt_general/module_xc/CMakeLists.txt @@ -6,12 +6,17 @@ add_library( xc_functional_gradcorr.cpp xc_functional_wrapper_xc.cpp xc_functional_wrapper_gcxc.cpp - xc_functional_wrapper_tauxc.cpp xc_funct_exch_lda.cpp xc_funct_corr_lda.cpp xc_funct_exch_gga.cpp xc_funct_corr_gga.cpp xc_funct_hcth.cpp + xc_functional_libxc.cpp + xc_functional_libxc_tools.cpp + xc_functional_libxc_vxc.cpp + xc_functional_libxc_wrapper_xc.cpp + xc_functional_libxc_wrapper_gcxc.cpp + xc_functional_libxc_wrapper_tauxc.cpp ) if(ENABLE_COVERAGE) diff --git a/source/module_hamilt_general/module_xc/exx_info.h b/source/module_hamilt_general/module_xc/exx_info.h index d94f5e63753..013dc04db33 100644 --- a/source/module_hamilt_general/module_xc/exx_info.h +++ b/source/module_hamilt_general/module_xc/exx_info.h @@ -2,6 +2,7 @@ #define EXX_INFO_H #include "module_ri/conv_coulomb_pot_k.h" +#include "module_ri/singular_value.h" #include "xc_functional.h" struct Exx_Info @@ -9,9 +10,12 @@ struct Exx_Info struct Exx_Info_Global { bool cal_exx = false; + bool use_ewald = false; Conv_Coulomb_Pot_K::Ccp_Type ccp_type; double hybrid_alpha = 0.25; + double cam_alpha = 0.0; + double cam_beta = 0.0; double hse_omega = 0.11; double mixing_beta_for_loop1 = 1.0; @@ -28,15 +32,31 @@ struct Exx_Info double lambda = 0.3; Exx_Info_Lip(const Exx_Info::Exx_Info_Global& info_global) - :ccp_type(info_global.ccp_type), - hse_omega(info_global.hse_omega) {} + : ccp_type(info_global.ccp_type), hse_omega(info_global.hse_omega) + { + } }; Exx_Info_Lip info_lip; + struct Exx_Info_Ewald + { + Singular_Value::Fq_type fq_type; + const bool& use_ewald; + + double ewald_qdiv = 2; + + Exx_Info_Ewald(const Exx_Info::Exx_Info_Global& info_global) : use_ewald(info_global.use_ewald) + { + } + }; + Exx_Info_Ewald info_ewald; + struct Exx_Info_RI { const Conv_Coulomb_Pot_K::Ccp_Type& ccp_type; const double& hse_omega; + const double& cam_alpha; + const double& cam_beta; bool real_number = false; @@ -58,13 +78,14 @@ struct Exx_Info int abfs_Lmax = 0; // tmp Exx_Info_RI(const Exx_Info::Exx_Info_Global& info_global) - : ccp_type(info_global.ccp_type), hse_omega(info_global.hse_omega) + : ccp_type(info_global.ccp_type), hse_omega(info_global.hse_omega), cam_alpha(info_global.cam_alpha), + cam_beta(info_global.cam_beta) { } }; Exx_Info_RI info_ri; - Exx_Info() : info_lip(this->info_global), info_ri(this->info_global) + Exx_Info() : info_lip(this->info_global), info_ewald(this->info_global), info_ri(this->info_global) { } }; diff --git a/source/module_hamilt_general/module_xc/test/CMakeLists.txt b/source/module_hamilt_general/module_xc/test/CMakeLists.txt index 112be038f9c..7466f40a92d 100644 --- a/source/module_hamilt_general/module_xc/test/CMakeLists.txt +++ b/source/module_hamilt_general/module_xc/test/CMakeLists.txt @@ -4,12 +4,13 @@ AddTest( TARGET XCTest_PBE LIBS parameter MPI::MPI_CXX Libxc::xc # required by global.h; for details, `remove_definitions(-D__MPI)`. SOURCES test_xc.cpp ../xc_functional.cpp ../xc_functional_wrapper_xc.cpp ../xc_functional_wrapper_gcxc.cpp ../xc_funct_corr_gga.cpp ../xc_funct_corr_lda.cpp ../xc_funct_exch_gga.cpp ../xc_funct_exch_lda.cpp ../xc_funct_hcth.cpp + ../xc_functional_libxc_wrapper_gcxc.cpp ../xc_functional_libxc.cpp ) AddTest( TARGET XCTest_HSE LIBS parameter MPI::MPI_CXX Libxc::xc # required by global.h; for details, `remove_definitions(-D__MPI)`. - SOURCES test_xc1.cpp ../xc_functional.cpp + SOURCES test_xc1.cpp ../xc_functional.cpp ../xc_functional_libxc.cpp ) @@ -17,6 +18,7 @@ AddTest( TARGET XCTest_PZ_SPN LIBS parameter MPI::MPI_CXX Libxc::xc # required by global.h; for details, `remove_definitions(-D__MPI)`. SOURCES test_xc2.cpp ../xc_functional.cpp ../xc_functional_wrapper_xc.cpp ../xc_functional_wrapper_gcxc.cpp ../xc_funct_corr_gga.cpp ../xc_funct_corr_lda.cpp ../xc_funct_exch_gga.cpp ../xc_funct_exch_lda.cpp ../xc_funct_hcth.cpp + ../xc_functional_libxc_wrapper_gcxc.cpp ../xc_functional_libxc_wrapper_xc.cpp ../xc_functional_libxc.cpp ) @@ -25,20 +27,28 @@ AddTest( LIBS parameter MPI::MPI_CXX Libxc::xc ${math_libs} psi device container SOURCES test_xc3.cpp ../xc_functional_gradcorr.cpp ../xc_functional.cpp ../xc_functional_wrapper_xc.cpp ../xc_functional_wrapper_gcxc.cpp - ../xc_functional_wrapper_tauxc.cpp + ../xc_functional_libxc.cpp + ../xc_functional_libxc_wrapper_xc.cpp + ../xc_functional_libxc_wrapper_gcxc.cpp + ../xc_functional_libxc_wrapper_tauxc.cpp ../xc_funct_corr_gga.cpp ../xc_funct_corr_lda.cpp ../xc_funct_exch_gga.cpp ../xc_funct_exch_lda.cpp ../xc_funct_hcth.cpp ../../../module_base/matrix.cpp ../../../module_base/memory.cpp ../../../module_base/libm/branred.cpp ../../../module_base/libm/sincos.cpp + ../../../module_base/blas_connector.cpp ) AddTest( TARGET XCTest_SCAN LIBS parameter MPI::MPI_CXX Libxc::xc SOURCES test_xc4.cpp ../xc_functional.cpp ../xc_functional_wrapper_xc.cpp - ../xc_functional_wrapper_gcxc.cpp ../xc_functional_wrapper_tauxc.cpp + ../xc_functional_wrapper_gcxc.cpp + ../xc_functional_libxc.cpp + ../xc_functional_libxc_wrapper_xc.cpp + ../xc_functional_libxc_wrapper_gcxc.cpp + ../xc_functional_libxc_wrapper_tauxc.cpp ../xc_funct_corr_gga.cpp ../xc_funct_corr_lda.cpp ../xc_funct_exch_gga.cpp ../xc_funct_exch_lda.cpp ../xc_funct_hcth.cpp ) @@ -48,13 +58,19 @@ AddTest( LIBS parameter MPI::MPI_CXX Libxc::xc ${math_libs} psi device container SOURCES test_xc5.cpp ../xc_functional_gradcorr.cpp ../xc_functional.cpp ../xc_functional_wrapper_xc.cpp ../xc_functional_wrapper_gcxc.cpp - ../xc_functional_wrapper_tauxc.cpp + ../xc_functional_libxc.cpp + ../xc_functional_libxc_wrapper_xc.cpp + ../xc_functional_libxc_wrapper_gcxc.cpp + ../xc_functional_libxc_wrapper_tauxc.cpp ../xc_funct_corr_gga.cpp ../xc_funct_corr_lda.cpp ../xc_funct_exch_gga.cpp ../xc_funct_exch_lda.cpp ../xc_funct_hcth.cpp ../xc_functional_vxc.cpp + ../xc_functional_libxc_vxc.cpp + ../xc_functional_libxc_tools.cpp + ../../../module_base/blas_connector.cpp ../../../module_base/matrix.cpp ../../../module_base/memory.cpp ../../../module_base/timer.cpp ../../../module_base/libm/branred.cpp ../../../module_base/libm/sincos.cpp -) +) \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/test/test_xc.cpp b/source/module_hamilt_general/module_xc/test/test_xc.cpp index 654b20ca95d..c568cc4ee33 100644 --- a/source/module_hamilt_general/module_xc/test/test_xc.cpp +++ b/source/module_hamilt_general/module_xc/test/test_xc.cpp @@ -1,5 +1,6 @@ #include "gtest/gtest.h" #include "../xc_functional.h" +#include "../xc_functional_libxc.h" #include "../exx_info.h" #include "xctest.h" @@ -829,7 +830,7 @@ class XCTest_PBE0 : public XCTest void SetUp() { XC_Functional::set_xc_type("PBE0"); - XC_Functional::get_hybrid_alpha(0.5); + XC_Functional::set_hybrid_alpha(0.5, 0.0, 0.0); std::vector rho = {0.17E+01, 0.17E+01, 0.15E+01, 0.88E-01, 0.18E+04}; std::vector grho = {0.81E-11, 0.17E+01, 0.36E+02, 0.87E-01, 0.55E+00}; @@ -884,7 +885,7 @@ class XCTest_PBE_LibXC : public XCTest XC_Functional::xc(rho[i],e,v); e_lda.push_back(e); v_lda.push_back(v); - XC_Functional::gcxc_libxc(rho[i],grho[i],e,v1,v2); + XC_Functional_Libxc::gcxc_libxc(XC_Functional::get_func_id(), rho[i],grho[i],e,v1,v2); e_gga.push_back(e); v1_gga.push_back(v1); v2_gga.push_back(v2); diff --git a/source/module_hamilt_general/module_xc/test/test_xc1.cpp b/source/module_hamilt_general/module_xc/test/test_xc1.cpp index 3d0105aa739..805e341b90f 100644 --- a/source/module_hamilt_general/module_xc/test/test_xc1.cpp +++ b/source/module_hamilt_general/module_xc/test/test_xc1.cpp @@ -38,7 +38,7 @@ class XCTest_HSE : public XCTest void SetUp() { XC_Functional::set_xc_type("HSE"); - XC_Functional::get_hybrid_alpha(0.5); + XC_Functional::set_hybrid_alpha(0.5, 0.0, 0.0); } }; @@ -53,7 +53,7 @@ class XCTest_SCAN0 : public XCTest void SetUp() { XC_Functional::set_xc_type("SCAN0"); - XC_Functional::get_hybrid_alpha(0.5); + XC_Functional::set_hybrid_alpha(0.5, 0.0, 0.0); } }; diff --git a/source/module_hamilt_general/module_xc/test/test_xc2.cpp b/source/module_hamilt_general/module_xc/test/test_xc2.cpp index be91b74aa55..ad23626ac3a 100644 --- a/source/module_hamilt_general/module_xc/test/test_xc2.cpp +++ b/source/module_hamilt_general/module_xc/test/test_xc2.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "xctest.h" #include "../xc_functional.h" +#include "../xc_functional_libxc.h" #include "../exx_info.h" /************************************************ * unit test of functionals @@ -455,7 +456,7 @@ class XCTest_PBE_SPN_LibXC : public XCTest double e,v1,v2,v3,v4,v5; double r1 = rho[i] * (1+zeta[i]) / 2.0; double r2 = rho[i] * (1-zeta[i]) / 2.0; - XC_Functional::gcxc_spin_libxc(r1,r2,gdr[i],gdr[i],e,v1,v2,v3,v4,v5); + XC_Functional_Libxc::gcxc_spin_libxc(XC_Functional::get_func_id(), r1,r2,gdr[i],gdr[i],e,v1,v2,v3,v4,v5); e_gga.push_back(e); v1_gga.push_back(v1+v3); v2_gga.push_back(v2+v4); @@ -494,7 +495,7 @@ class XCTest_PZ_SPN_LibXC : public XCTest double e,v1,v2; double r1 = rho[i] * (1+zeta[i]) / 2.0; double r2 = rho[i] * (1-zeta[i]) / 2.0; - XC_Functional::xc_spin_libxc(r1,r2,e,v1,v2); + XC_Functional_Libxc::xc_spin_libxc(XC_Functional::get_func_id(), r1,r2,e,v1,v2); e_lda.push_back(e); v1_lda.push_back(v1); v2_lda.push_back(v2); diff --git a/source/module_hamilt_general/module_xc/test/test_xc4.cpp b/source/module_hamilt_general/module_xc/test/test_xc4.cpp index eb179cb0a26..41fd60f4254 100644 --- a/source/module_hamilt_general/module_xc/test/test_xc4.cpp +++ b/source/module_hamilt_general/module_xc/test/test_xc4.cpp @@ -1,4 +1,5 @@ #include "../xc_functional.h" +#include "../xc_functional_libxc.h" #include "gtest/gtest.h" #include "xctest.h" #include "../exx_info.h" @@ -43,7 +44,7 @@ class XCTest_SCAN : public XCTest for(int i=0;i<5;i++) { double e,v,v1,v2,v3; - XC_Functional::tau_xc(rho[i],grho[i],tau[i],e,v1,v2,v3); + XC_Functional_Libxc::tau_xc(XC_Functional::get_func_id(), rho[i],grho[i],tau[i],e,v1,v2,v3); e_.push_back(e); v1_.push_back(v1); v2_.push_back(v2); diff --git a/source/module_hamilt_general/module_xc/test/test_xc5.cpp b/source/module_hamilt_general/module_xc/test/test_xc5.cpp index 5bc516b72c2..2eed4b35089 100644 --- a/source/module_hamilt_general/module_xc/test/test_xc5.cpp +++ b/source/module_hamilt_general/module_xc/test/test_xc5.cpp @@ -1,4 +1,5 @@ #include "../xc_functional.h" +#include "../xc_functional_libxc.h" #include "gtest/gtest.h" #define private public #include "module_parameter/parameter.h" @@ -282,7 +283,7 @@ class XCTest_VXC_meta : public XCTest PARAM.input.nspin = 1; std::tuple etxc_vtxc_v - = XC_Functional::v_xc_meta(rhopw.nrxx,ucell.omega,ucell.tpiba,&chr); + = XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), rhopw.nrxx,ucell.omega,ucell.tpiba,&chr); et1 = std::get<0>(etxc_vtxc_v); vt1 = std::get<1>(etxc_vtxc_v); v1 = std::get<2>(etxc_vtxc_v); @@ -290,7 +291,7 @@ class XCTest_VXC_meta : public XCTest PARAM.input.nspin = 2; etxc_vtxc_v - = XC_Functional::v_xc_meta(rhopw.nrxx,ucell.omega,ucell.tpiba,&chr); + = XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), rhopw.nrxx,ucell.omega,ucell.tpiba,&chr); et2 = std::get<0>(etxc_vtxc_v); vt2 = std::get<1>(etxc_vtxc_v); v2 = std::get<2>(etxc_vtxc_v); diff --git a/source/module_hamilt_general/module_xc/xc_functional.cpp b/source/module_hamilt_general/module_xc/xc_functional.cpp index c3a671d7140..e63845e3ff2 100644 --- a/source/module_hamilt_general/module_xc/xc_functional.cpp +++ b/source/module_hamilt_general/module_xc/xc_functional.cpp @@ -6,6 +6,10 @@ #include "module_cell/module_paw/paw_cell.h" #endif +#ifdef USE_LIBXC +#include "xc_functional_libxc.h" +#endif + XC_Functional::XC_Functional(){} XC_Functional::~XC_Functional(){} @@ -14,10 +18,19 @@ std::vector XC_Functional::func_id(1); int XC_Functional::func_type = 0; bool XC_Functional::use_libxc = true; double XC_Functional::hybrid_alpha = 0.25; +double XC_Functional::cam_alpha = 0.0; +double XC_Functional::cam_beta = 0.0; -void XC_Functional::get_hybrid_alpha(const double alpha_in) +void XC_Functional::set_hybrid_alpha(const double alpha_in, const double cam_alpha_in, const double cam_beta_in) { hybrid_alpha = alpha_in; + cam_alpha = cam_alpha_in; + cam_beta = cam_beta_in; +} + +double XC_Functional::get_hybrid_alpha() +{ + return hybrid_alpha; } int XC_Functional::get_func_type() @@ -30,9 +43,10 @@ void XC_Functional::set_xc_first_loop(const UnitCell& ucell) the first scf iteration only calculate the functional without exact exchange. but in "nscf" calculation, there is no need of "two-level" method. */ - if (ucell.atoms[0].ncpp.xc_func == "HF" - || ucell.atoms[0].ncpp.xc_func == "PBE0" - || ucell.atoms[0].ncpp.xc_func == "HSE") { + if (ucell.atoms[0].ncpp.xc_func == "HF" || ucell.atoms[0].ncpp.xc_func == "HSE" + || ucell.atoms[0].ncpp.xc_func == "PBE0"|| ucell.atoms[0].ncpp.xc_func == "LC_PBE" + || ucell.atoms[0].ncpp.xc_func == "LC_WPBE" || ucell.atoms[0].ncpp.xc_func == "LRC_WPBEH" + || ucell.atoms[0].ncpp.xc_func == "CAM_PBEH") { XC_Functional::set_xc_type("pbe"); } else if (ucell.atoms[0].ncpp.xc_func == "SCAN0") { @@ -50,7 +64,7 @@ void XC_Functional::set_xc_type(const std::string xc_func_in) //such as for PBE we have: // func_id.push_back(XC_GGA_X_PBE); // func_id.push_back(XC_GGA_C_PBE); - + func_id.clear(); std::string xc_func = xc_func_in; std::transform(xc_func.begin(), xc_func.end(), xc_func.begin(), (::toupper)); @@ -120,7 +134,7 @@ void XC_Functional::set_xc_type(const std::string xc_func_in) func_id.push_back(XC_GGA_C_PBE); func_type = 2; use_libxc = false; - } + } else if ( xc_func == "BLYP") //B88+LYP { func_id.push_back(XC_GGA_X_B88); @@ -134,14 +148,14 @@ void XC_Functional::set_xc_type(const std::string xc_func_in) func_id.push_back(XC_GGA_C_P86); func_type = 2; use_libxc = false; - } + } else if ( xc_func == "PW91") //PW91_X+PW91_C { func_id.push_back(XC_GGA_X_PW91); func_id.push_back(XC_GGA_C_PW91); func_type = 2; use_libxc = false; - } + } else if ( xc_func == "HCTH") //HCTH_X+HCTH_C { func_id.push_back(XC_GGA_X_HCTH_A); @@ -194,12 +208,44 @@ void XC_Functional::set_xc_type(const std::string xc_func_in) func_type = 4; use_libxc = true; } + else if( xc_func == "LC_PBE") + { + func_id.push_back(XC_HYB_GGA_XC_LC_PBEOP); + func_type = 4; + use_libxc = true; + } + else if( xc_func == "LC_WPBE") + { + func_id.push_back(XC_HYB_GGA_XC_LC_WPBE); + func_type = 4; + use_libxc = true; + } + else if( xc_func == "LRC_WPBE") + { + func_id.push_back(XC_HYB_GGA_XC_LRC_WPBE); + func_type = 4; + use_libxc = true; + } + else if( xc_func == "LRC_WPBEH") + { + func_id.push_back(XC_HYB_GGA_XC_LRC_WPBEH); + func_type = 4; + use_libxc = true; + } + else if( xc_func == "CAM_PBEH") + { + func_id.push_back(XC_HYB_GGA_XC_CAM_PBEH); + func_type = 4; + use_libxc = true; + } #endif else { #ifdef USE_LIBXC //see if it matches libxc functionals - set_xc_type_libxc(xc_func); + const std::pair> type_id = XC_Functional_Libxc::set_xc_type_libxc(xc_func); + func_type = std::get<0>(type_id); + func_id = std::get<1>(type_id); use_libxc = true; #else ModuleBase::WARNING_QUIT("xc_functional.cpp","functional name not recognized!"); @@ -232,109 +278,13 @@ void XC_Functional::set_xc_type(const std::string xc_func_in) #endif #ifndef USE_LIBXC - if(xc_func == "SCAN" || xc_func == "HSE" || xc_func == "SCAN0") + if(xc_func == "SCAN" || xc_func == "HSE" || xc_func == "SCAN0" || + xc_func == "LC_PBE" || xc_func == "LC_WPBE" || xc_func == "LRC_WPBE" || + xc_func == "LRC_PBEH" || xc_func == "CAM_PBEH") { - ModuleBase::WARNING_QUIT("set_xc_type","to use SCAN, SCAN0, or HSE, LIBXC is required"); + ModuleBase::WARNING_QUIT("set_xc_type","to use SCAN, SCAN0, HSE, long-range corrected (LC_PBE, LC_WPBE...) or CAM_PBEH LIBXC is required"); } use_libxc = false; #endif } - -#ifdef USE_LIBXC -void XC_Functional::set_xc_type_libxc(std::string xc_func_in) -{ - - // determine the type (lda/gga/mgga) - func_type = 1; - if(xc_func_in.find("GGA") != std::string::npos) { func_type = 2; -} - if(xc_func_in.find("MGGA") != std::string::npos) { func_type = 3; -} - if(xc_func_in.find("HYB") != std::string::npos) { func_type =4; -} - if(xc_func_in.find("HYB") != std::string::npos && xc_func_in.find("MGGA") != std::string::npos) { func_type =5; -} - - // determine the id - int pos = 0; - std::string delimiter = "+"; - std::string token; - while ((pos = xc_func_in.find(delimiter)) != std::string::npos) - { - token = xc_func_in.substr(0, pos); - int id = xc_functional_get_number(token.c_str()); - std::cout << "func,id" << token << " " << id << std::endl; - if (id == -1) { ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc","functional name not recognized!"); -} - func_id.push_back(id); - xc_func_in.erase(0, pos + delimiter.length()); - } - int id = xc_functional_get_number(xc_func_in.c_str()); - std::cout << "func,id" << xc_func_in << " " << id << std::endl; - if (id == -1) { ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc","functional name not recognized!"); -} - func_id.push_back(id); - -} -#endif - -#ifdef USE_LIBXC -std::vector XC_Functional::init_func(const int xc_polarized) -{ - // 'funcs' is the return value - std::vector funcs; - - //------------------------------------------- - // define a function named 'add_func', which - // initialize a functional according to its ID - //------------------------------------------- - auto add_func = [&]( const int func_id ) - { - funcs.push_back({}); - // 'xc_func_init' is defined in Libxc - xc_func_init( &funcs.back(), func_id, xc_polarized ); - }; - - for(int id : func_id) - { - if(id == XC_LDA_XC_KSDT || id == XC_LDA_XC_CORRKSDT || id == XC_LDA_XC_GDSMFB) //finite temperature XC functionals - { - add_func(id); - double parameter_finitet[1] = {PARAM.inp.xc_temperature * 0.5}; // converts to Hartree for libxc - xc_func_set_ext_params(&funcs.back(), parameter_finitet); - } -#ifdef __EXX - else if( id == XC_HYB_GGA_XC_PBEH ) // PBE0 - { - add_func( XC_HYB_GGA_XC_PBEH ); - double parameter_hse[3] = { GlobalC::exx_info.info_global.hybrid_alpha, - GlobalC::exx_info.info_global.hse_omega, - GlobalC::exx_info.info_global.hse_omega }; - xc_func_set_ext_params(&funcs.back(), parameter_hse); - } - else if( id == XC_HYB_GGA_XC_HSE06 ) // HSE06 hybrid functional - { - add_func( XC_HYB_GGA_XC_HSE06 ); - double parameter_hse[3] = { GlobalC::exx_info.info_global.hybrid_alpha, - GlobalC::exx_info.info_global.hse_omega, - GlobalC::exx_info.info_global.hse_omega }; - xc_func_set_ext_params(&funcs.back(), parameter_hse); - } -#endif - else - { - add_func( id ); - } - } - return funcs; -} - -void XC_Functional::finish_func(std::vector &funcs) -{ - for(xc_func_type func : funcs) - { - xc_func_end(&func); - } -} -#endif diff --git a/source/module_hamilt_general/module_xc/xc_functional.h b/source/module_hamilt_general/module_xc/xc_functional.h index 1789831f515..72f65d7a7d4 100644 --- a/source/module_hamilt_general/module_xc/xc_functional.h +++ b/source/module_hamilt_general/module_xc/xc_functional.h @@ -49,20 +49,6 @@ class XC_Functional const Charge* const chr, const UnitCell *ucell); // charge density - // using libxc - static std::tuple v_xc_libxc( - const int &nrxx, // number of real-space grid - const double &omega, // volume of cell - const double tpiba, - const Charge* const chr); // charge density - - // for mGGA functional - static std::tuple v_xc_meta( - const int &nrxx, // number of real-space grid - const double &omega, // volume of cell - const double tpiba, - const Charge* const chr); - //------------------- // xc_functional.cpp //------------------- @@ -75,22 +61,15 @@ class XC_Functional // func_id, which is the LIBXC id of functional // func_type, which is as specified in get_func_type // use_libxc, whether to use LIBXC. The rule is to NOT use it for functionals that we already have. -// 3. set_xc_type_libxc : sets functional type, which allows combination of LIBXC keyword connected by "+" -// for example, "XC_LDA_X+XC_LDA_C_PZ" -// 4. init_func : which converts func_id into corresponding xc_func_type vector static int get_func_type(); static void set_xc_type(const std::string xc_func_in); // For hybrid functional - static void get_hybrid_alpha(const double alpha_in); + static void set_hybrid_alpha(const double alpha_in, const double cam_alpha_in, const double cam_beta_in); + static double get_hybrid_alpha(); /// Usually in exx caculation, the first SCF loop should be converged with PBE static void set_xc_first_loop(const UnitCell& ucell); -#ifdef USE_LIBXC - static void set_xc_type_libxc(const std::string xc_func_in); - static std::vector init_func(const int xc_polarized); - static void finish_func(std::vector &funcs); -#endif private: @@ -100,6 +79,11 @@ class XC_Functional //exx_hybrid_alpha for mixing exx in hybrid functional: static double hybrid_alpha; + static double cam_alpha; + static double cam_beta; + + public: + static std::vector get_func_id() { return func_id; } //------------------- // xc_functional_wrapper_xc.cpp @@ -133,8 +117,6 @@ class XC_Functional // LSDA static void xc_spin(const double &rho, const double &zeta, double &exc, double &vxcup, double &vxcdw); - static void xc_spin_libxc(const double &rhoup, const double &rhodw, - double &exc, double &vxcup, double &vxcdw); //------------------- // xc_functional_wrapper_gcxc.cpp @@ -145,8 +127,6 @@ class XC_Functional // 1. gcxc, which is the wrapper for gradient correction part // 2. gcx_spin, spin polarized, exchange only // 3. gcc_spin, spin polarized, correlation only -// 4. gcxc_libxc, the entire GGA functional, LIBXC, for nspin=1 case -// 5. gcxc_spin_libxc, the entire GGA functional, LIBXC, for nspin=2 case // The difference between our realization (gcxc/gcx_spin/gcc_spin) and // LIBXC, and the reason for not having gcxc_libxc is explained @@ -155,8 +135,6 @@ class XC_Functional // GGA static void gcxc(const double &rho, const double &grho, double &sxc, double &v1xc, double &v2xc); - static void gcxc_libxc(const double &rho, const double &grho, - double &sxc, double &v1xc, double &v2xc); // spin polarized GGA static void gcx_spin(double rhoup, double rhodw, double grhoup2, double grhodw2, @@ -165,33 +143,6 @@ class XC_Functional static void gcc_spin(double rho, double &zeta, double grho, double &sc, double &v1cup, double &v1cdw, double &v2c); - static void gcxc_spin_libxc(double rhoup, double rhodw, - ModuleBase::Vector3 gdr1, ModuleBase::Vector3 gdr2, - double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud); - -//------------------- -// xc_functional_wrapper_tauxc.cpp -//------------------- - -// This file contains wrapper for the mGGA functionals -// it includes 1 subroutine: -// 1. tau_xc -// 2. tau_xc_spin - -// NOTE : mGGA is realized through LIBXC - -#ifdef USE_LIBXC - // mGGA - static void tau_xc(const double &rho, const double &grho, const double &atau, double &sxc, - double &v1xc, double &v2xc, double &v3xc); - - static void tau_xc_spin(double rhoup, double rhodw, - ModuleBase::Vector3 gdr1, ModuleBase::Vector3 gdr2, - double tauup, double taudw, - double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud, - double &v3xcup, double &v3xcdw); -#endif - //------------------- // xc_functional_gradcorr.cpp //------------------- diff --git a/source/module_hamilt_general/module_xc/xc_functional_gradcorr.cpp b/source/module_hamilt_general/module_xc/xc_functional_gradcorr.cpp index 4ad50c5905a..42501465108 100644 --- a/source/module_hamilt_general/module_xc/xc_functional_gradcorr.cpp +++ b/source/module_hamilt_general/module_xc/xc_functional_gradcorr.cpp @@ -17,6 +17,10 @@ #include #include +#ifdef USE_LIBXC +#include "xc_functional_libxc.h" +#endif + // from gradcorr.f90 void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, const Charge* const chr, ModulePW::PW_Basis* rhopw, const UnitCell *ucell, @@ -24,18 +28,14 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, { ModuleBase::TITLE("XC_Functional","gradcorr"); - if(func_type == 0 || func_type == 1) { return; // none or LDA functional -} + if(func_type == 0 || func_type == 1) { return; } // none or LDA functional bool igcc_is_lyp = false; - if( func_id[1] == XC_GGA_C_LYP) { igcc_is_lyp = true; -} + if( func_id[1] == XC_GGA_C_LYP) { igcc_is_lyp = true; } int nspin0 = PARAM.inp.nspin; - if(PARAM.inp.nspin==4) { nspin0 =1; -} - if(PARAM.inp.nspin==4&&(PARAM.globalv.domag||PARAM.globalv.domag_z)) { nspin0 = 2; -} + if(PARAM.inp.nspin==4) { nspin0 =1; } + if(PARAM.inp.nspin==4&&(PARAM.globalv.domag||PARAM.globalv.domag_z)) { nspin0 = 2; } assert(nspin0>0); const double fac = 1.0/ nspin0; @@ -91,8 +91,7 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, } gdr1 = new ModuleBase::Vector3[rhopw->nrxx]; - if(!is_stress) { h1 = new ModuleBase::Vector3[rhopw->nrxx]; -} + if(!is_stress) { h1 = new ModuleBase::Vector3[rhopw->nrxx]; } XC_Functional::grad_rho( rhogsum1 , gdr1, rhopw, ucell->tpiba); @@ -118,8 +117,7 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, } gdr2 = new ModuleBase::Vector3[rhopw->nrxx]; - if(!is_stress) { h2 = new ModuleBase::Vector3[rhopw->nrxx]; -} + if(!is_stress) { h2 = new ModuleBase::Vector3[rhopw->nrxx]; } XC_Functional::grad_rho( rhogsum2 , gdr2, rhopw, ucell->tpiba); } @@ -186,7 +184,7 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, } gdr2 = new ModuleBase::Vector3[rhopw->nrxx]; - h2 = new ModuleBase::Vector3[rhopw->nrxx]; + if(!is_stress) h2 = new ModuleBase::Vector3[rhopw->nrxx]; XC_Functional::grad_rho( rhogsum1 , gdr1, rhopw, ucell->tpiba); XC_Functional::grad_rho( rhogsum2 , gdr2, rhopw, ucell->tpiba); @@ -253,11 +251,11 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, { double v3xc; double atau = chr->kin_r[0][ir]/2.0; - XC_Functional::tau_xc( arho, grho2a, atau, sxc, v1xc, v2xc, v3xc); + XC_Functional_Libxc::tau_xc( func_id, arho, grho2a, atau, sxc, v1xc, v2xc, v3xc); } else { - XC_Functional::gcxc_libxc( arho, grho2a, sxc, v1xc, v2xc); + XC_Functional_Libxc::gcxc_libxc( func_id, arho, grho2a, sxc, v1xc, v2xc); } #endif } // end use_libxc @@ -313,12 +311,16 @@ void XC_Functional::gradcorr(double &etxc, double &vtxc, ModuleBase::matrix &v, double v3xcup, v3xcdw; double atau1 = chr->kin_r[0][ir]/2.0; double atau2 = chr->kin_r[1][ir]/2.0; - XC_Functional::tau_xc_spin( rhotmp1[ir], rhotmp2[ir], gdr1[ir], gdr2[ir], + XC_Functional_Libxc::tau_xc_spin( + func_id, + rhotmp1[ir], rhotmp2[ir], gdr1[ir], gdr2[ir], atau1, atau2, sxc, v1xcup, v1xcdw, v2xcup, v2xcdw, v2xcud, v3xcup, v3xcdw); } else { - XC_Functional::gcxc_spin_libxc(rhotmp1[ir], rhotmp2[ir], gdr1[ir], gdr2[ir], + XC_Functional_Libxc::gcxc_spin_libxc( + func_id, + rhotmp1[ir], rhotmp2[ir], gdr1[ir], gdr2[ir], sxc, v1xcup, v1xcdw, v2xcup, v2xcdw, v2xcud); } if(is_stress) diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc.cpp new file mode 100644 index 00000000000..bf15abbb9e7 --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc.cpp @@ -0,0 +1,215 @@ +#ifdef USE_LIBXC + +#include "xc_functional_libxc.h" +#include "module_parameter/parameter.h" +#include "module_base/tool_quit.h" + +#ifdef __EXX +#include "module_hamilt_pw/hamilt_pwdft/global.h" // just for GlobalC::exx_info +#endif + +#include +#include +bool xc_with_laplacian(const std::string& xc_func_in) +{ + // see Pyscf: https://github.com/pyscf/pyscf/blob/master/pyscf/dft/libxc.py#L1062 + // ABACUS issue: https://github.com/deepmodeling/abacus-develop/issues/5372 + const std::vector not_supported = { + "MGGA_XC_CC06", "MGGA_C_CS", "MGGA_X_BR89", "MGGA_X_MK00"}; + for (const std::string& s : not_supported) + { + if (xc_func_in.find(s) != std::string::npos) + { + return true; + } + } + return false; +} + +std::string _uppercase(const std::string& str) +{ + std::string result = str; + std::transform(result.begin(), result.end(), result.begin(), ::toupper); + return result; +} + +bool not_supported_xc_with_nonlocal_vdw(const std::string& xc_func_in) +{ + const std::string xc_func = _uppercase(xc_func_in); + if(xc_func.find("VDW") != std::string::npos) { return true; } + /* known excluded: GGA_X_OPTB86B_VDW, GGA_X_OPTB88_VDW, GGA_X_OPTPBE_VDW, GGA_X_PBEK1_VDW */ + + if(xc_func.find("VV10") != std::string::npos) { return true; } + /* known excluded: GGA_XC_VV10, HYB_GGA_XC_LC_VV10, MGGA_C_REVSCAN_VV10, MGGA_C_SCAN_VV10, + MGGA_C_SCANL_VV10, MGGA_XC_VCML_RVV10 */ + + const std::vector not_supported = {"C09X", "VCML", "HYB_MGGA_XC_WB97M_V", "MGGA_XC_B97M_V"}; + for(const std::string& str : not_supported) + { + if(xc_func.find(str) != std::string::npos) { return true; } + } + /* known excluded: GGA_X_C09X, MGGA_X_VCML, HYB_MGGA_XC_WB97M_V, MGGA_XC_B97M_V */ + + /* There is also a functional not quite sure: HYB_GGA_XC_WB97X_V */ + if(xc_func.find("HYB_GGA_XC_WB97X_V") != std::string::npos) + { + std::cout << " WARNING: range-seperated XC omega-B97 family with nonlocal correction term is used.\n" + << " if you are not planning to use these functionals like wB97X-D3BJ that:\n" + << " XC_GGA_XC_WB97X_V with specified D3BJ DFT-D3 parameters, this is not what\n" + << " you want." << std::endl; + } + return false; +} + +std::pair> XC_Functional_Libxc::set_xc_type_libxc(std::string xc_func_in) +{ + // determine the type (lda/gga/mgga) + if (xc_with_laplacian(xc_func_in)) + { + ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc", + "XC Functional involving Laplacian of rho is not implemented."); + } + int func_type; //0:none, 1:lda, 2:gga, 3:mgga, 4:hybrid lda/gga, 5:hybrid mgga + if(not_supported_xc_with_nonlocal_vdw(xc_func_in)) + { ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc","functionals with non-local dispersion are not supported."); } + func_type = 1; + if(xc_func_in.find("GGA") != std::string::npos) { func_type = 2; } + if(xc_func_in.find("MGGA") != std::string::npos) { func_type = 3; } + if(xc_func_in.find("HYB") != std::string::npos) { func_type =4; } + if(xc_func_in.find("HYB") != std::string::npos && xc_func_in.find("MGGA") != std::string::npos) { func_type =5; } + + // determine the id + std::vector func_id; // libxc id of functional + int pos = 0; + std::string delimiter = "+"; + std::string token; + while ((pos = xc_func_in.find(delimiter)) != std::string::npos) + { + token = xc_func_in.substr(0, pos); + int id = xc_functional_get_number(token.c_str()); + std::cout << "func,id" << token << " " << id << std::endl; + if (id == -1) { ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc","functional name not recognized!"); } + func_id.push_back(id); + xc_func_in.erase(0, pos + delimiter.length()); + } + int id = xc_functional_get_number(xc_func_in.c_str()); + std::cout << "func,id" << xc_func_in << " " << id << std::endl; + if (id == -1) { ModuleBase::WARNING_QUIT("XC_Functional::set_xc_type_libxc","functional name not recognized!"); } + func_id.push_back(id); + + return std::make_pair(func_type, func_id); +} + +std::vector XC_Functional_Libxc::init_func(const std::vector &func_id, const int xc_polarized) +{ + // 'funcs' is the return value + std::vector funcs; + + //------------------------------------------- + // define a function named 'add_func', which + // initialize a functional according to its ID + //------------------------------------------- + auto add_func = [&]( const int func_id ) + { + funcs.push_back({}); + // 'xc_func_init' is defined in Libxc + xc_func_init( &funcs.back(), func_id, xc_polarized ); + }; + + for(int id : func_id) + { + if(id == XC_LDA_XC_KSDT || id == XC_LDA_XC_CORRKSDT || id == XC_LDA_XC_GDSMFB) //finite temperature XC functionals + { + add_func(id); + double parameter_finitet[1] = {PARAM.inp.xc_temperature * 0.5}; // converts to Hartree for libxc + xc_func_set_ext_params(&funcs.back(), parameter_finitet); + } +#ifdef __EXX + else if( id == XC_HYB_GGA_XC_PBEH ) // PBE0 + { + add_func( XC_HYB_GGA_XC_PBEH ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.hybrid_alpha, + GlobalC::exx_info.info_global.hse_omega, + GlobalC::exx_info.info_global.hse_omega }; + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + else if( id == XC_HYB_GGA_XC_HSE06 ) // HSE06 hybrid functional + { + add_func( XC_HYB_GGA_XC_HSE06 ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.hybrid_alpha, + GlobalC::exx_info.info_global.hse_omega, + GlobalC::exx_info.info_global.hse_omega }; + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + // Long-range corrected functionals: + else if( id == XC_HYB_GGA_XC_LC_PBEOP ) // LC version of PBE + { + // This is a range-separated hybrid functional with range-separation constant 0.330, + // and 0.0% short-range and 100.0% long-range exact exchange, + // using the error function kernel. + add_func( XC_HYB_GGA_XC_LC_PBEOP ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.hse_omega }; //Range separation constant: 0.33 + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + else if( id == XC_HYB_GGA_XC_LC_WPBE ) // Long-range corrected PBE (LC-wPBE) by Vydrov and Scuseria + { + // This is a range-separated hybrid functional with range-separation constant 0.400, + // and 0.0% short-range and 100.0% long-range exact exchange, + // using the error function kernel. + add_func( XC_HYB_GGA_XC_LC_WPBE ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.cam_alpha, //Fraction of Hartree-Fock exchange: 1.0 + GlobalC::exx_info.info_global.cam_beta, //Fraction of short-range exact exchange: -1.0 + GlobalC::exx_info.info_global.hse_omega }; //Range separation constant: 0.4 + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + else if( id == XC_HYB_GGA_XC_LRC_WPBE ) // Long-range corrected PBE (LRC-wPBE) by by Rohrdanz, Martins and Herbert + { + // This is a range-separated hybrid functional with range-separation constant 0.300, + // and 0.0% short-range and 100.0% long-range exact exchange, + // using the error function kernel. + add_func( XC_HYB_GGA_XC_LRC_WPBE ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.cam_alpha, //Fraction of Hartree-Fock exchange: 1.0 + GlobalC::exx_info.info_global.cam_beta, //Fraction of short-range exact exchange: -1.0 + GlobalC::exx_info.info_global.hse_omega }; //Range separation constant: 0.3 + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + else if( id == XC_HYB_GGA_XC_LRC_WPBEH ) // Long-range corrected short-range hybrid PBE (LRC-wPBEh) by Rohrdanz, Martins and Herbert + { + // This is a range-separated hybrid functional with range-separation constant 0.200, + // and 20.0% short-range and 100.0% long-range exact exchange, + // using the error function kernel. + add_func( XC_HYB_GGA_XC_LRC_WPBEH ); + double parameter_hse[3] = { GlobalC::exx_info.info_global.cam_alpha, //Fraction of Hartree-Fock exchange: 1.0 + GlobalC::exx_info.info_global.cam_beta, //Fraction of short-range exact exchange: -0.8 + GlobalC::exx_info.info_global.hse_omega }; //Range separation constant: 0.2 + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } + else if( id == XC_HYB_GGA_XC_CAM_PBEH ) // CAM hybrid screened exchange PBE version + { + // This is a range-separated hybrid functional with range-separation constant 0.700, + // and 100.0% short-range and 20.0% long-range exact exchange, + // using the error function kernel. + add_func( XC_HYB_GGA_XC_CAM_PBEH); + double parameter_hse[3] = { GlobalC::exx_info.info_global.cam_alpha, //Fraction of Hartree-Fock exchange: 0.2 + GlobalC::exx_info.info_global.cam_beta, //Fraction of short-range exact exchange: 0.8 + GlobalC::exx_info.info_global.hse_omega }; //Range separation constant: 0.7 + xc_func_set_ext_params(&funcs.back(), parameter_hse); + } +#endif + else + { + add_func( id ); + } + } + return funcs; +} + +void XC_Functional_Libxc::finish_func(std::vector &funcs) +{ + for(xc_func_type func : funcs) + { + xc_func_end(&func); + } +} + +#endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc.h b/source/module_hamilt_general/module_xc/xc_functional_libxc.h new file mode 100644 index 00000000000..26044c1b90c --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc.h @@ -0,0 +1,178 @@ +#ifndef XC_FUNCTIONAL_LIBXC_H +#define XC_FUNCTIONAL_LIBXC_H + +#ifdef USE_LIBXC + +#include "module_base/matrix.h" +#include "module_base/vector3.h" + +#include + +#include +#include + +class Charge; + +namespace XC_Functional_Libxc +{ +//------------------- +// xc_functional_libxc.cpp +//------------------- + + // sets functional type, which allows combination of LIBXC keyword connected by "+" + // for example, "XC_LDA_X+XC_LDA_C_PZ" + extern std::pair> set_xc_type_libxc(const std::string xc_func_in); + + // converts func_id into corresponding xc_func_type vector + extern std::vector init_func(const std::vector &func_id, const int xc_polarized); + + extern void finish_func(std::vector &funcs); + + +//------------------- +// xc_functional_libxc_vxc.cpp +//------------------- + + extern std::tuple v_xc_libxc( + const std::vector &func_id, + const int &nrxx, // number of real-space grid + const double &omega, // volume of cell + const double tpiba, + const Charge* const chr); // charge density + + // for mGGA functional + extern std::tuple v_xc_meta( + const std::vector &func_id, + const int &nrxx, // number of real-space grid + const double &omega, // volume of cell + const double tpiba, + const Charge* const chr); + + +//------------------- +// xc_functional_libxc_tools.cpp +//------------------- + + // converting rho (abacus=>libxc) + extern std::vector convert_rho( + const int nspin, + const std::size_t nrxx, + const Charge* const chr); + + // converting rho (abacus=>libxc) + extern std::tuple, std::vector> convert_rho_amag_nspin4( + const int nspin, + const std::size_t nrxx, + const Charge* const chr); + + // calculating grho + extern std::vector>> cal_gdr( + const int nspin, + const std::size_t nrxx, + const std::vector &rho, + const double tpiba, + const Charge* const chr); + + // converting grho (abacus=>libxc) + extern std::vector convert_sigma( + const std::vector>> &gdr); + + // sgn for threshold mask + extern std::vector cal_sgn( + const double rho_threshold, + const double grho_threshold, + const xc_func_type &func, + const int nspin, + const std::size_t nrxx, + const std::vector &rho, + const std::vector &sigma); + + // converting etxc from exc (libxc=>abacus) + extern double convert_etxc( + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector &rho, + std::vector exc); + + // converting vtxc and v from vrho and vsigma (libxc=>abacus) + extern std::pair convert_vtxc_v( + const xc_func_type &func, + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector &rho, + const std::vector>> &gdr, + const std::vector &vrho, + const std::vector &vsigma, + const double tpiba, + const Charge* const chr); + + // dh for gga v + extern std::vector> cal_dh( + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector>> &gdr, + const std::vector &vsigma, + const double tpiba, + const Charge* const chr); + + // convert v for NSPIN=4 + extern ModuleBase::matrix convert_v_nspin4( + const std::size_t nrxx, + const Charge* const chr, + const std::vector &amag, + const ModuleBase::matrix &v); + + +//------------------- +// xc_functional_libxc_wrapper_xc.cpp +//------------------- + + extern void xc_spin_libxc( + const std::vector &func_id, + const double &rhoup, const double &rhodw, + double &exc, double &vxcup, double &vxcdw); + + +//------------------- +// xc_functional_libxc_wrapper_gcxc.cpp +//------------------- + + // the entire GGA functional, for nspin=1 case + extern void gcxc_libxc( + const std::vector &func_id, + const double &rho, const double &grho, + double &sxc, double &v1xc, double &v2xc); + + // the entire GGA functional, for nspin=2 case + extern void gcxc_spin_libxc( + const std::vector &func_id, + const double rhoup, const double rhodw, + const ModuleBase::Vector3 gdr1, const ModuleBase::Vector3 gdr2, + double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud); + + +//------------------- +// xc_functional_libxc_wrapper_tauxc.cpp +//------------------- + + // wrapper for the mGGA functionals + extern void tau_xc( + const std::vector &func_id, + const double &rho, const double &grho, const double &atau, double &sxc, + double &v1xc, double &v2xc, double &v3xc); + + extern void tau_xc_spin( + const std::vector &func_id, + double rhoup, double rhodw, + ModuleBase::Vector3 gdr1, ModuleBase::Vector3 gdr2, + double tauup, double taudw, + double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud, + double &v3xcup, double &v3xcdw); +} // namespace XC_Functional_Libxc + +#endif // USE_LIBXC + +#endif // XC_FUNCTIONAL_LIBXC_H \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc_tools.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc_tools.cpp new file mode 100644 index 00000000000..6975d066b78 --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc_tools.cpp @@ -0,0 +1,290 @@ +#ifdef USE_LIBXC + +#include "xc_functional_libxc.h" +#include "xc_functional.h" +#include "module_elecstate/module_charge/charge.h" +#include "module_parameter/parameter.h" + +// converting rho (abacus=>libxc) +std::vector XC_Functional_Libxc::convert_rho( + const int nspin, + const std::size_t nrxx, + const Charge* const chr) +{ + std::vector rho(nrxx*nspin); + #ifdef _OPENMP + #pragma omp parallel for collapse(2) schedule(static, 1024) + #endif + for( int is=0; isrho[is][ir] + 1.0/nspin*chr->rho_core[ir]; + return rho; +} + +// converting rho (abacus=>libxc) +std::tuple, std::vector> +XC_Functional_Libxc::convert_rho_amag_nspin4( + const int nspin, + const std::size_t nrxx, + const Charge* const chr) +{ + assert(PARAM.inp.nspin==4); + std::vector rho(nrxx*nspin); + std::vector amag(nrxx); + #ifdef _OPENMP + #pragma omp parallel for + #endif + for( int ir=0; irrho[0][ir] + chr->rho_core[ir] ); + amag[ir] = std::sqrt( std::pow(chr->rho[1][ir],2) + + std::pow(chr->rho[2][ir],2) + + std::pow(chr->rho[3][ir],2) ); + const double amag_clip = (amag[ir]>> +XC_Functional_Libxc::cal_gdr( + const int nspin, + const std::size_t nrxx, + const std::vector &rho, + const double tpiba, + const Charge* const chr) +{ + std::vector>> gdr(nspin); + for( int is=0; is!=nspin; ++is ) + { + std::vector rhor(nrxx); + #ifdef _OPENMP + #pragma omp parallel for schedule(static, 1024) + #endif + for(std::size_t ir=0; ir> rhog(chr->rhopw->npw); + chr->rhopw->real2recip(rhor.data(), rhog.data()); + + //------------------------------------------- + // compute the gradient of charge density and + // store the gradient in gdr[is] + //------------------------------------------- + gdr[is].resize(nrxx); + XC_Functional::grad_rho(rhog.data(), gdr[is].data(), chr->rhopw, tpiba); + } // end for(is) + return gdr; +} + +// converting grho (abacus=>libxc) +std::vector XC_Functional_Libxc::convert_sigma( + const std::vector>> &gdr) +{ + const std::size_t nspin = gdr.size(); + assert(nspin>0); + const std::size_t nrxx = gdr[0].size(); + for(std::size_t is=1; is sigma( nrxx * ((1==nspin)?1:3) ); + if( 1==nspin ) + { + #ifdef _OPENMP + #pragma omp parallel for schedule(static, 1024) + #endif + for( std::size_t ir=0; ir XC_Functional_Libxc::cal_sgn( + const double rho_threshold, + const double grho_threshold, + const xc_func_type &func, + const int nspin, + const std::size_t nrxx, + const std::vector &rho, + const std::vector &sigma) +{ + std::vector sgn(nrxx*nspin, 1.0); + // in the case of GGA correlation for polarized case, + // a cutoff for grho is required to ensure that libxc gives reasonable results + if(nspin==2 && func.info->family != XC_FAMILY_LDA && func.info->kind==XC_CORRELATION) + { + #ifdef _OPENMP + #pragma omp parallel for schedule(static, 512) + #endif + for( int ir=0; irabacus) +double XC_Functional_Libxc::convert_etxc( + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector &rho, + std::vector exc) +{ + double etxc = 0.0; + #ifdef _OPENMP + #pragma omp parallel for collapse(2) reduction(+:etxc) schedule(static, 256) + #endif + for( int is=0; isabacus) +std::pair XC_Functional_Libxc::convert_vtxc_v( + const xc_func_type &func, + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector &rho, + const std::vector>> &gdr, + const std::vector &vrho, + const std::vector &vsigma, + const double tpiba, + const Charge* const chr) +{ + double vtxc = 0.0; + ModuleBase::matrix v(nspin, nrxx); + + #ifdef _OPENMP + #pragma omp parallel for collapse(2) reduction(+:vtxc) schedule(static, 256) + #endif + for( int is=0; isfamily == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA) + { + const std::vector> dh = XC_Functional_Libxc::cal_dh(nspin, nrxx, sgn, gdr, vsigma, tpiba, chr); + + double rvtxc = 0.0; + #ifdef _OPENMP + #pragma omp parallel for collapse(2) reduction(+:rvtxc) schedule(static, 256) + #endif + for( int is=0; isfamily == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA)) + + return std::make_pair(vtxc, std::move(v)); +} + + +// dh for gga v +std::vector> XC_Functional_Libxc::cal_dh( + const int nspin, + const std::size_t nrxx, + const std::vector &sgn, + const std::vector>> &gdr, + const std::vector &vsigma, + const double tpiba, + const Charge* const chr) +{ + std::vector>> h( + nspin, + std::vector>(nrxx) ); + if( 1==nspin ) + { + #ifdef _OPENMP + #pragma omp parallel for schedule(static, 1024) + #endif + for( std::size_t ir=0; ir> dh(nspin, std::vector(nrxx)); + for( int is=0; is!=nspin; ++is ) + XC_Functional::grad_dot( h[is].data(), dh[is].data(), chr->rhopw, tpiba); + + return dh; +} + + +// convert v for NSPIN=4 +ModuleBase::matrix XC_Functional_Libxc::convert_v_nspin4( + const std::size_t nrxx, + const Charge* const chr, + const std::vector &amag, + const ModuleBase::matrix &v) +{ + assert(PARAM.inp.nspin==4); + constexpr double vanishing_charge = 1.0e-10; + ModuleBase::matrix v_nspin4(PARAM.inp.nspin, nrxx); + for( int ir=0; ir vanishing_charge ) + { + const double vs = 0.5 * (v(0,ir)-v(1,ir)); + for(int ipol=1; ipolrho[ipol][ir] / amag[ir]; + } + } + } + return v_nspin4; +} + +#endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc_vxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc_vxc.cpp new file mode 100644 index 00000000000..8b270cd2332 --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc_vxc.cpp @@ -0,0 +1,395 @@ +#ifdef USE_LIBXC + +#include "xc_functional.h" +#include "xc_functional_libxc.h" +#include "module_elecstate/module_charge/charge.h" +#include "module_base/global_variable.h" +#include "module_parameter/parameter.h" +#include "module_base/parallel_reduce.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" + +#include + +#include + +std::tuple XC_Functional_Libxc::v_xc_libxc( // Peize Lin update for nspin==4 at 2023.01.14 + const std::vector &func_id, + const int &nrxx, // number of real-space grid + const double &omega, // volume of cell + const double tpiba, + const Charge* const chr) +{ + ModuleBase::TITLE("XC_Functional_Libxc","v_xc_libxc"); + ModuleBase::timer::tick("XC_Functional_Libxc","v_xc_libxc"); + + const int nspin = + (PARAM.inp.nspin == 1 || ( PARAM.inp.nspin ==4 && !PARAM.globalv.domag && !PARAM.globalv.domag_z)) + ? 1 : 2; + + //---------------------------------------------------------- + // xc_func_type is defined in Libxc package + // to understand the usage of xc_func_type, + // use can check on website, for example: + // https://www.tddft.org/programs/libxc/manual/libxc-5.1.x/ + //---------------------------------------------------------- + + std::vector funcs = XC_Functional_Libxc::init_func( func_id, (1==nspin) ? XC_UNPOLARIZED:XC_POLARIZED ); + + const bool is_gga = [&funcs]() + { + for( xc_func_type &func : funcs ) + { + switch( func.info->family ) + { + case XC_FAMILY_GGA: + case XC_FAMILY_HYB_GGA: + return true; + } + } + return false; + }(); + + // converting rho + std::vector rho; + std::vector amag; + if(1==nspin || 2==PARAM.inp.nspin) + { + rho = XC_Functional_Libxc::convert_rho(nspin, nrxx, chr); + } + else + { + std::tuple,std::vector> rho_amag = XC_Functional_Libxc::convert_rho_amag_nspin4(nspin, nrxx, chr); + rho = std::get<0>(std::move(rho_amag)); + amag = std::get<1>(std::move(rho_amag)); + } + + std::vector>> gdr; + std::vector sigma; + if(is_gga) + { + gdr = XC_Functional_Libxc::cal_gdr(nspin, nrxx, rho, tpiba, chr); + sigma = XC_Functional_Libxc::convert_sigma(gdr); + } + + double etxc = 0.0; + double vtxc = 0.0; + ModuleBase::matrix v(nspin,nrxx); + + for( xc_func_type &func : funcs ) + { + // jiyy add for threshold + constexpr double rho_threshold = 1E-6; + constexpr double grho_threshold = 1E-10; + + xc_func_set_dens_threshold(&func, rho_threshold); + + // sgn for threshold mask + const std::vector sgn = XC_Functional_Libxc::cal_sgn(rho_threshold, grho_threshold, func, nspin, nrxx, rho, sigma); + + std::vector exc ( nrxx ); + std::vector vrho ( nrxx * nspin ); + std::vector vsigma( nrxx * ((1==nspin)?1:3) ); + switch( func.info->family ) + { + case XC_FAMILY_LDA: + // call Libxc function: xc_lda_exc_vxc + xc_lda_exc_vxc( &func, nrxx, rho.data(), + exc.data(), vrho.data() ); + break; + case XC_FAMILY_GGA: + case XC_FAMILY_HYB_GGA: + // call Libxc function: xc_gga_exc_vxc + xc_gga_exc_vxc( &func, nrxx, rho.data(), sigma.data(), + exc.data(), vrho.data(), vsigma.data() ); + break; + default: + throw std::domain_error("func.info->family ="+std::to_string(func.info->family) + +" unfinished in "+std::string(__FILE__)+" line "+std::to_string(__LINE__)); + break; + } + + etxc += XC_Functional_Libxc::convert_etxc(nspin, nrxx, sgn, rho, exc); + const std::pair vtxc_v = XC_Functional_Libxc::convert_vtxc_v( + func, nspin, nrxx, + sgn, rho, gdr, + vrho, vsigma, + tpiba, chr); + vtxc += std::get<0>(vtxc_v); + v += std::get<1>(vtxc_v); + } // end for( xc_func_type &func : funcs ) + + if(4==PARAM.inp.nspin) + { + v = XC_Functional_Libxc::convert_v_nspin4(nrxx, chr, amag, v); + } + + //------------------------------------------------- + // for MPI, reduce the exchange-correlation energy + //------------------------------------------------- + #ifdef __MPI + Parallel_Reduce::reduce_pool(etxc); + Parallel_Reduce::reduce_pool(vtxc); + #endif + + etxc *= omega / chr->rhopw->nxyz; + vtxc *= omega / chr->rhopw->nxyz; + + XC_Functional_Libxc::finish_func(funcs); + + ModuleBase::timer::tick("XC_Functional_Libxc","v_xc_libxc"); + return std::make_tuple( etxc, vtxc, std::move(v) ); +} + + +//the interface to libxc xc_mgga_exc_vxc(xc_func,n,rho,grho,laplrho,tau,e,v1,v2,v3,v4) +//xc_func : LIBXC data type, contains information on xc functional +//n: size of array, nspin*nnr +//rho,grho,laplrho: electron density, its gradient and laplacian +//tau(kin_r): kinetic energy density +//e: energy density +//v1-v4: derivative of energy density w.r.t rho, gradient, laplacian and tau +//v1 and v2 are combined to give v; v4 goes into vofk + +//XC_POLARIZED, XC_UNPOLARIZED: internal flags used in LIBXC, denote the polarized(nspin=1) or unpolarized(nspin=2) calculations, definition can be found in xc.h from LIBXC + +// [etxc, vtxc, v, vofk] = XC_Functional::v_xc(...) +std::tuple XC_Functional_Libxc::v_xc_meta( + const std::vector &func_id, + const int &nrxx, // number of real-space grid + const double &omega, // volume of cell + const double tpiba, + const Charge* const chr) +{ + ModuleBase::TITLE("XC_Functional_Libxc","v_xc_meta"); + ModuleBase::timer::tick("XC_Functional_Libxc","v_xc_meta"); + + double e2 = 2.0; + + //output of the subroutine + double etxc = 0.0; + double vtxc = 0.0; + ModuleBase::matrix v(PARAM.inp.nspin,nrxx); + ModuleBase::matrix vofk(PARAM.inp.nspin,nrxx); + + //---------------------------------------------------------- + // xc_func_type is defined in Libxc package + // to understand the usage of xc_func_type, + // use can check on website, for example: + // https://www.tddft.org/programs/libxc/manual/libxc-5.1.x/ + //---------------------------------------------------------- + + const int nspin = PARAM.inp.nspin; + std::vector funcs = XC_Functional_Libxc::init_func( func_id, ( (1==nspin) ? XC_UNPOLARIZED:XC_POLARIZED ) ); + + const std::vector rho = XC_Functional_Libxc::convert_rho(nspin, nrxx, chr); + const std::vector>> gdr + = XC_Functional_Libxc::cal_gdr(nspin, nrxx, rho, tpiba, chr); + const std::vector sigma = XC_Functional_Libxc::convert_sigma(gdr); + + //converting kin_r + std::vector kin_r; + kin_r.resize(nrxx*nspin); +#ifdef _OPENMP +#pragma omp parallel for collapse(2) schedule(static, 1024) +#endif + for( int is=0; iskin_r[is][ir] / 2.0; + } + } + + std::vector exc ( nrxx ); + std::vector vrho ( nrxx * nspin ); + std::vector vsigma ( nrxx * ((1==nspin)?1:3) ); + std::vector vtau ( nrxx * nspin ); + std::vector vlapl ( nrxx * nspin ); + + constexpr double rho_th = 1e-8; + constexpr double grho_th = 1e-12; + constexpr double tau_th = 1e-8; + // sgn for threshold mask + std::vector sgn( nrxx * nspin); +#ifdef _OPENMP +#pragma omp parallel for schedule(static, 1024) +#endif + for(int i = 0; i < nrxx * nspin; ++i) + { + sgn[i] = 1.0; + } + + if(nspin == 1) + { +#ifdef _OPENMP +#pragma omp parallel for schedule(static, 1024) +#endif + for( int ir=0; irfamily == XC_FAMILY_MGGA); + xc_mgga_exc_vxc(&func, nrxx, rho.data(), sigma.data(), sigma.data(), + kin_r.data(), exc.data(), vrho.data(), vsigma.data(), vlapl.data(), vtau.data()); + + //process etxc + for( int is=0; is!=nspin; ++is ) + { +#ifdef _OPENMP +#pragma omp parallel for reduction(+:etxc) schedule(static, 256) +#endif + for( int ir=0; ir< nrxx; ++ir ) + { +#ifdef __EXX + if (func.info->number == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) + { + exc[ir] *= (1.0 - XC_Functional::get_hybrid_alpha()); + } +#endif + etxc += ModuleBase::e2 * exc[ir] * rho[ir*nspin+is] * sgn[ir*nspin+is]; + } + } + + //process vtxc +#ifdef _OPENMP +#pragma omp parallel for collapse(2) reduction(+:vtxc) schedule(static, 256) +#endif + for( int is=0; isnumber == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) + { + vrho[ir*nspin+is] *= (1.0 - XC_Functional::get_hybrid_alpha()); + } +#endif + const double v_tmp = ModuleBase::e2 * vrho[ir*nspin+is] * sgn[ir*nspin+is]; + v(is,ir) += v_tmp; + vtxc += v_tmp * chr->rho[is][ir]; + } + } + + //process vsigma + std::vector>> h( + nspin, + std::vector>(nrxx) ); + if( 1==nspin ) + { +#ifdef _OPENMP +#pragma omp parallel for schedule(static, 1024) +#endif + for( int ir=0; ir< nrxx; ++ir ) + { +#ifdef __EXX + if (func.info->number == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) + { + vsigma[ir] *= (1.0 - XC_Functional::get_hybrid_alpha()); + } +#endif + h[0][ir] = 2.0 * gdr[0][ir] * vsigma[ir] * 2.0 * sgn[ir]; + } + } + else + { +#ifdef _OPENMP +#pragma omp parallel for schedule(static, 64) +#endif + for( int ir=0; ir< nrxx; ++ir ) + { +#ifdef __EXX + if (func.info->number == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) + { + vsigma[ir*3] *= (1.0 - XC_Functional::get_hybrid_alpha()); + vsigma[ir*3+1] *= (1.0 - XC_Functional::get_hybrid_alpha()); + vsigma[ir*3+2] *= (1.0 - XC_Functional::get_hybrid_alpha()); + } +#endif + h[0][ir] = 2.0 * (gdr[0][ir] * vsigma[ir*3 ] * sgn[ir*2 ] * 2.0 + + gdr[1][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); + h[1][ir] = 2.0 * (gdr[1][ir] * vsigma[ir*3+2] * sgn[ir*2+1] * 2.0 + + gdr[0][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); + } + } + + // define two dimensional array dh [ nspin, nrxx ] + std::vector> dh(nspin, std::vector( nrxx)); + for( int is=0; is!=nspin; ++is ) + { + XC_Functional::grad_dot( h[is].data(), + dh[is].data(), chr->rhopw, + tpiba); + } + + double rvtxc = 0.0; +#ifdef _OPENMP +#pragma omp parallel for collapse(2) reduction(+:rvtxc) schedule(static, 256) +#endif + for( int is=0; isnumber == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) + { + vtau[ir*nspin+is] *= (1.0 - XC_Functional::get_hybrid_alpha()); + } +#endif + vofk(is,ir) += vtau[ir*nspin+is] * sgn[ir*nspin+is]; + } + } + } + + //------------------------------------------------- + // for MPI, reduce the exchange-correlation energy + //------------------------------------------------- +#ifdef __MPI + Parallel_Reduce::reduce_pool(etxc); + Parallel_Reduce::reduce_pool(vtxc); +#endif + + etxc *= omega / chr->rhopw->nxyz; + vtxc *= omega / chr->rhopw->nxyz; + + XC_Functional_Libxc::finish_func(funcs); + + ModuleBase::timer::tick("XC_Functional_Libxc","v_xc_meta"); + return std::make_tuple( etxc, vtxc, std::move(v), std::move(vofk) ); +} + +#endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_gcxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_gcxc.cpp new file mode 100644 index 00000000000..ce4aad00d8f --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_gcxc.cpp @@ -0,0 +1,79 @@ +#ifdef USE_LIBXC + +#include "xc_functional_libxc.h" + +#include +#include + +void XC_Functional_Libxc::gcxc_libxc( + const std::vector &func_id, + const double &rho, const double &grho, + double &sxc, double &v1xc, double &v2xc) +{ + sxc = v1xc = v2xc = 0.0; + + constexpr double small = 1.e-6; + constexpr double smallg = 1.e-10; + if (rho <= small || grho < smallg) + { + return; + } + + std::vector funcs = XC_Functional_Libxc::init_func(func_id, XC_UNPOLARIZED); + for(xc_func_type &func : funcs) + { + double s,v1,v2; + xc_gga_exc_vxc(&func, 1, &rho, &grho, &s, &v1, &v2); + sxc += s * rho; + v1xc += v1; + v2xc += v2 * 2.0; + } + XC_Functional_Libxc::finish_func(funcs); +} // end subroutine gcxc_libxc + + + +void XC_Functional_Libxc::gcxc_spin_libxc( + const std::vector &func_id, + const double rhoup, const double rhodw, + const ModuleBase::Vector3 gdr1, const ModuleBase::Vector3 gdr2, + double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud) +{ + sxc = v1xcup = v1xcdw = 0.0; + v2xcup = v2xcdw = v2xcud = 0.0; + const std::array rho = {rhoup, rhodw}; + const std::array grho = {gdr1.norm2(), gdr1*gdr2, gdr2.norm2()}; + + std::vector funcs = XC_Functional_Libxc::init_func(func_id, XC_POLARIZED); + for(xc_func_type &func : funcs) + { + if( func.info->family == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA) + { + constexpr double rho_threshold = 1E-6; + constexpr double grho_threshold = 1E-10; + std::array sgn = {1.0, 1.0}; + if(func.info->kind==XC_CORRELATION) + { + if ( rho[0] v1xc; + std::array v2xc; + // call Libxc function: xc_gga_exc_vxc + xc_gga_exc_vxc( &func, 1, rho.data(), grho.data(), &s, v1xc.data(), v2xc.data()); + sxc += s * (rho[0] * sgn[0] + rho[1] * sgn[1]); + v1xcup += v1xc[0] * sgn[0]; + v1xcdw += v1xc[1] * sgn[1]; + v2xcup += 2.0 * v2xc[0] * sgn[0]; + v2xcud += v2xc[1] * sgn[0] * sgn[1]; + v2xcdw += 2.0 * v2xc[2] * sgn[1]; + } + } + XC_Functional_Libxc::finish_func(funcs); +} + +#endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_wrapper_tauxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_tauxc.cpp similarity index 65% rename from source/module_hamilt_general/module_xc/xc_functional_wrapper_tauxc.cpp rename to source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_tauxc.cpp index 2cabd645341..b265af9bb15 100644 --- a/source/module_hamilt_general/module_xc/xc_functional_wrapper_tauxc.cpp +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_tauxc.cpp @@ -2,27 +2,31 @@ // it includes 1 subroutine: // 1. tau_xc -#include "xc_functional.h" +#ifdef USE_LIBXC + +#include "xc_functional_libxc.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include //tau_xc and tau_xc_spin: interface for calling xc_mgga_exc_vxc from LIBXC //XC_POLARIZED, XC_UNPOLARIZED: internal flags used in LIBXC, denote the polarized(nspin=1) or unpolarized(nspin=2) calculations, definition can be found in xc.h from LIBXC -#ifdef USE_LIBXC -void XC_Functional::tau_xc(const double &rho, const double &grho, const double &atau, double &sxc, +void XC_Functional_Libxc::tau_xc( + const std::vector &func_id, + const double &rho, const double &grho, const double &atau, double &sxc, double &v1xc, double &v2xc, double &v3xc) { double s, v1, v2, v3; double lapl_rho, vlapl_rho; lapl_rho = grho; - std::vector funcs = init_func(XC_UNPOLARIZED); - + std::vector funcs = XC_Functional_Libxc::init_func(func_id, XC_UNPOLARIZED); + sxc = 0.0; v1xc = 0.0; v2xc = 0.0; v3xc = 0.0; for(xc_func_type &func : funcs) { xc_mgga_exc_vxc(&func,1,&rho,&grho,&lapl_rho,&atau,&s,&v1,&v2,&vlapl_rho,&v3); #ifdef __EXX - if (func.info->number == XC_MGGA_X_SCAN && get_func_type() == 5) + if (func.info->number == XC_MGGA_X_SCAN && XC_Functional::get_func_type() == 5) { s *= (1.0 - GlobalC::exx_info.info_global.hybrid_alpha); v1 *= (1.0 - GlobalC::exx_info.info_global.hybrid_alpha); @@ -35,54 +39,37 @@ void XC_Functional::tau_xc(const double &rho, const double &grho, const double & v1xc += v1; v3xc += v3; } - finish_func(funcs); + XC_Functional_Libxc::finish_func(funcs); return; } -void XC_Functional::tau_xc_spin(double rhoup, double rhodw, +void XC_Functional_Libxc::tau_xc_spin( + const std::vector &func_id, + double rhoup, double rhodw, ModuleBase::Vector3 gdr1, ModuleBase::Vector3 gdr2, double tauup, double taudw, double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud, double &v3xcup, double &v3xcdw) { - - std::vector funcs = init_func(XC_POLARIZED); - - double *rho, *grho, *tau, *v1xc, *v2xc, *v3xc, *sgn, s; sxc = v1xcup = v1xcdw = 0.0; v2xcup = v2xcdw = v2xcud = 0.0; v3xcup = v3xcdw = 0.0; - rho = new double[2]; - grho= new double[3]; - tau = new double[2]; - v1xc= new double[2]; - v2xc= new double[3]; - v3xc= new double[2]; - sgn = new double[2]; - - rho[0] = rhoup; - rho[1] = rhodw; - grho[0] = gdr1.norm2(); - grho[1] = gdr1 * gdr2; - grho[2] = gdr2.norm2(); - tau[0] = tauup; - tau[1] = taudw; - double lapl[2] = {0.0,0.0}; - double vlapl[2]; + const std::array rho = {rhoup, rhodw}; + const std::array grho = {gdr1.norm2(), gdr1 * gdr2, gdr2.norm2()}; + const std::array tau = {tauup, taudw}; - const double rho_threshold = 1E-6; - const double grho_threshold = 1E-10; + std::vector funcs = XC_Functional_Libxc::init_func(func_id, XC_POLARIZED); for(xc_func_type &func : funcs) { if( func.info->family == XC_FAMILY_MGGA || func.info->family == XC_FAMILY_HYB_MGGA) { - sgn[0] = sgn[1] = 1.0; - // call Libxc function: xc_mgga_exc_vxc - xc_mgga_exc_vxc( &func, 1, rho, grho, lapl, tau, &s, v1xc, v2xc, vlapl, v3xc); + constexpr double rho_threshold = 1E-6; + constexpr double grho_threshold = 1E-10; + std::array sgn = {1.0, 1.0}; if(func.info->kind==XC_CORRELATION) { if ( rho[0] v1xc, v3xc, lapl, vlapl; + std::array v2xc; + // call Libxc function: xc_mgga_exc_vxc + xc_mgga_exc_vxc( &func, 1, rho.data(), grho.data(), lapl.data(), tau.data(), &s, v1xc.data(), v2xc.data(), vlapl.data(), v3xc.data()); + sxc += s * (rho[0] * sgn[0] + rho[1] * sgn[1]); v1xcup += v1xc[0] * sgn[0]; v1xcdw += v1xc[1] * sgn[1]; @@ -101,16 +95,7 @@ void XC_Functional::tau_xc_spin(double rhoup, double rhodw, } } - delete[] grho; - delete[] rho; - delete[] tau; - delete[] v1xc; - delete[] v2xc; - delete[] v3xc; - delete[] sgn; - finish_func(funcs); - - return; + XC_Functional_Libxc::finish_func(funcs); } #endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_xc.cpp b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_xc.cpp new file mode 100644 index 00000000000..aa2cf664ad3 --- /dev/null +++ b/source/module_hamilt_general/module_xc/xc_functional_libxc_wrapper_xc.cpp @@ -0,0 +1,32 @@ +#ifdef USE_LIBXC + +#include "xc_functional_libxc.h" + +void XC_Functional_Libxc::xc_spin_libxc( + const std::vector &func_id, + const double &rhoup, const double &rhodw, + double &exc, double &vxcup, double &vxcdw) +{ + const std::vector rho_ud = {rhoup, rhodw}; + exc = vxcup = vxcdw = 0.0; + + std::vector funcs = XC_Functional_Libxc::init_func(func_id, XC_POLARIZED); + + for(xc_func_type &func : funcs) + { + double e = 0.0; + std::vector vxc_ud(2); + if( func.info->family == XC_FAMILY_LDA) + { + // call Libxc function: xc_lda_exc_vxc + xc_lda_exc_vxc( &func, 1, rho_ud.data(), &e, vxc_ud.data()); + } + exc += e; + vxcup += vxc_ud[0]; + vxcdw += vxc_ud[1]; + } + + XC_Functional_Libxc::finish_func(funcs); +} + +#endif \ No newline at end of file diff --git a/source/module_hamilt_general/module_xc/xc_functional_vxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_vxc.cpp index 236a51e3b9b..7aeb677a786 100644 --- a/source/module_hamilt_general/module_xc/xc_functional_vxc.cpp +++ b/source/module_hamilt_general/module_xc/xc_functional_vxc.cpp @@ -8,6 +8,11 @@ #include "module_base/parallel_reduce.h" #include "module_base/timer.h" #include "module_parameter/parameter.h" + +#ifdef USE_LIBXC +#include "xc_functional_libxc.h" +#endif + // [etxc, vtxc, v] = XC_Functional::v_xc(...) std::tuple XC_Functional::v_xc( const int &nrxx, // number of real-space grid @@ -20,7 +25,7 @@ std::tuple XC_Functional::v_xc( if(use_libxc) { #ifdef USE_LIBXC - return v_xc_libxc(nrxx, ucell->omega, ucell->tpiba, chr); + return XC_Functional_Libxc::v_xc_libxc(XC_Functional::get_func_id(), nrxx, ucell->omega, ucell->tpiba, chr); #else ModuleBase::WARNING_QUIT("v_xc","compile with LIBXC"); #endif @@ -125,9 +130,13 @@ std::tuple XC_Functional::v_xc( if(use_libxc) { +#ifdef USE_LIBXC double rhoup = arhox * (1.0+zeta) / 2.0; double rhodw = arhox * (1.0-zeta) / 2.0; - XC_Functional::xc_spin_libxc(rhoup, rhodw, exc, vxc[0], vxc[1]); + XC_Functional_Libxc::xc_spin_libxc(XC_Functional::get_func_id(), rhoup, rhodw, exc, vxc[0], vxc[1]); +#else + ModuleBase::WARNING_QUIT("v_xc","compile with LIBXC"); +#endif } else { @@ -175,618 +184,3 @@ std::tuple XC_Functional::v_xc( ModuleBase::timer::tick("XC_Functional","v_xc"); return std::make_tuple(etxc, vtxc, std::move(v)); } - -#ifdef USE_LIBXC - -std::tuple XC_Functional::v_xc_libxc( // Peize Lin update for nspin==4 at 2023.01.14 - const int &nrxx, // number of real-space grid - const double &omega, // volume of cell - const double tpiba, - const Charge* const chr) -{ - ModuleBase::TITLE("XC_Functional","v_xc_libxc"); - ModuleBase::timer::tick("XC_Functional","v_xc_libxc"); - - const int nspin = - (PARAM.inp.nspin == 1 || ( PARAM.inp.nspin ==4 && !PARAM.globalv.domag && !PARAM.globalv.domag_z)) - ? 1 : 2; - - double etxc = 0.0; - double vtxc = 0.0; - ModuleBase::matrix v(nspin,nrxx); - - //---------------------------------------------------------- - // xc_func_type is defined in Libxc package - // to understand the usage of xc_func_type, - // use can check on website, for example: - // https://www.tddft.org/programs/libxc/manual/libxc-5.1.x/ - //---------------------------------------------------------- - - std::vector funcs = init_func( (1==nspin) ? XC_UNPOLARIZED:XC_POLARIZED ); - - const bool is_gga = [&funcs]() - { - for( xc_func_type &func : funcs ) - { - switch( func.info->family ) - { - case XC_FAMILY_GGA: - case XC_FAMILY_HYB_GGA: - return true; - } - } - return false; - }(); - - // converting rho - std::vector rho(nrxx*nspin); - std::vector amag; - if(1==nspin || 2==PARAM.inp.nspin) - { - #ifdef _OPENMP - #pragma omp parallel for collapse(2) schedule(static, 1024) - #endif - for( int is=0; isrho[is][ir] + 1.0/nspin*chr->rho_core[ir]; -} -} - } - else - { - amag.resize(nrxx); - #ifdef _OPENMP - #pragma omp parallel for - #endif - for( int ir=0; irrho[0][ir] + chr->rho_core[ir] ); - amag[ir] = std::sqrt( std::pow(chr->rho[1][ir],2) + std::pow(chr->rho[2][ir],2) + std::pow(chr->rho[3][ir],2) ); - const double amag_clip = (amag[ir]>> gdr; - std::vector sigma; - if(is_gga) - { - // calculating grho - gdr.resize( nspin ); - for( int is=0; is!=nspin; ++is ) - { - std::vector rhor(nrxx); - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 1024) - #endif - for(int ir=0; ir> rhog(chr->rhopw->npw); - chr->rhopw->real2recip(rhor.data(), rhog.data()); - - //------------------------------------------- - // compute the gradient of charge density and - // store the gradient in gdr[is] - //------------------------------------------- - gdr[is].resize(nrxx); - XC_Functional::grad_rho(rhog.data(), gdr[is].data(), chr->rhopw, tpiba); - } // end for(is) - - // converting grho - sigma.resize( nrxx * ((1==nspin)?1:3) ); - if( 1==nspin ) - { - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 1024) - #endif - for( int ir=0; ir sgn(nrxx*nspin, 1.0); - // in the case of GGA correlation for polarized case, - // a cutoff for grho is required to ensure that libxc gives reasonable results - if(nspin==2 && func.info->family != XC_FAMILY_LDA && func.info->kind==XC_CORRELATION) - { - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 512) - #endif - for( int ir=0; ir exc ( nrxx ); - std::vector vrho ( nrxx * nspin ); - std::vector vsigma( nrxx * ((1==nspin)?1:3) ); - switch( func.info->family ) - { - case XC_FAMILY_LDA: - // call Libxc function: xc_lda_exc_vxc - xc_lda_exc_vxc( &func, nrxx, rho.data(), - exc.data(), vrho.data() ); - break; - case XC_FAMILY_GGA: - case XC_FAMILY_HYB_GGA: - // call Libxc function: xc_gga_exc_vxc - xc_gga_exc_vxc( &func, nrxx, rho.data(), sigma.data(), - exc.data(), vrho.data(), vsigma.data() ); - break; - default: - throw std::domain_error("func.info->family ="+std::to_string(func.info->family) - +" unfinished in "+std::string(__FILE__)+" line "+std::to_string(__LINE__)); - break; - } - - #ifdef _OPENMP - #pragma omp parallel for collapse(2) reduction(+:etxc) schedule(static, 256) - #endif - for( int is=0; isfamily == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA) - { - std::vector>> h( nspin, - std::vector>(nrxx) ); - if( 1==nspin ) - { - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 1024) - #endif - for( int ir=0; ir< nrxx; ++ir ) { - h[0][ir] = 2.0 * gdr[0][ir] * vsigma[ir] * 2.0 * sgn[ir]; -} - } - else - { - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 1024) - #endif - for( int ir=0; ir< nrxx; ++ir ) - { - h[0][ir] = 2.0 * (gdr[0][ir] * vsigma[ir*3 ] * sgn[ir*2 ] * 2.0 - + gdr[1][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); - h[1][ir] = 2.0 * (gdr[1][ir] * vsigma[ir*3+2] * sgn[ir*2+1] * 2.0 - + gdr[0][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); - } - } - - // define two dimensional array dh [ nspin, nrxx ] - std::vector> dh(nspin, std::vector(nrxx)); - for( int is=0; is!=nspin; ++is ) { - XC_Functional::grad_dot( h[is].data(), dh[is].data(), chr->rhopw, tpiba); -} - - double rvtxc = 0.0; - #ifdef _OPENMP - #pragma omp parallel for collapse(2) reduction(+:rvtxc) schedule(static, 256) - #endif - for( int is=0; isfamily == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA)) - } // end for( xc_func_type &func : funcs ) - - //------------------------------------------------- - // for MPI, reduce the exchange-correlation energy - //------------------------------------------------- - #ifdef __MPI - Parallel_Reduce::reduce_pool(etxc); - Parallel_Reduce::reduce_pool(vtxc); - #endif - - etxc *= omega / chr->rhopw->nxyz; - vtxc *= omega / chr->rhopw->nxyz; - - finish_func(funcs); - - if(1==PARAM.inp.nspin || 2==PARAM.inp.nspin) - { - ModuleBase::timer::tick("XC_Functional","v_xc_libxc"); - return std::make_tuple( etxc, vtxc, std::move(v) ); - } - else if(4==PARAM.inp.nspin) - { - constexpr double vanishing_charge = 1.0e-10; - ModuleBase::matrix v_nspin4(PARAM.inp.nspin,nrxx); - for( int ir=0; ir vanishing_charge ) - { - const double vs = 0.5 * (v(0,ir)-v(1,ir)); - for(int ipol=1; ipol<4; ++ipol) { - v_nspin4(ipol,ir) = vs * chr->rho[ipol][ir] / amag[ir]; -} - } - } - } - - ModuleBase::timer::tick("XC_Functional","v_xc_libxc"); - return std::make_tuple( etxc, vtxc, std::move(v_nspin4) ); - } // end if(4==PARAM.inp.nspin) - else//NSPIN != 1,2,4 is not supported - { - throw std::domain_error("PARAM.inp.nspin ="+std::to_string(PARAM.inp.nspin) - +" unfinished in "+std::string(__FILE__)+" line "+std::to_string(__LINE__)); - } -} - -//the interface to libxc xc_mgga_exc_vxc(xc_func,n,rho,grho,laplrho,tau,e,v1,v2,v3,v4) -//xc_func : LIBXC data type, contains information on xc functional -//n: size of array, nspin*nnr -//rho,grho,laplrho: electron density, its gradient and laplacian -//tau(kin_r): kinetic energy density -//e: energy density -//v1-v4: derivative of energy density w.r.t rho, gradient, laplacian and tau -//v1 and v2 are combined to give v; v4 goes into vofk - -//XC_POLARIZED, XC_UNPOLARIZED: internal flags used in LIBXC, denote the polarized(nspin=1) or unpolarized(nspin=2) calculations, definition can be found in xc.h from LIBXC - -// [etxc, vtxc, v, vofk] = XC_Functional::v_xc(...) -std::tuple XC_Functional::v_xc_meta( - const int &nrxx, // number of real-space grid - const double &omega, // volume of cell - const double tpiba, - const Charge* const chr) -{ - ModuleBase::TITLE("XC_Functional","v_xc_meta"); - ModuleBase::timer::tick("XC_Functional","v_xc_meta"); - - double e2 = 2.0; - - //output of the subroutine - double etxc = 0.0; - double vtxc = 0.0; - ModuleBase::matrix v(PARAM.inp.nspin,nrxx); - ModuleBase::matrix vofk(PARAM.inp.nspin,nrxx); - - //---------------------------------------------------------- - // xc_func_type is defined in Libxc package - // to understand the usage of xc_func_type, - // use can check on website, for example: - // https://www.tddft.org/programs/libxc/manual/libxc-5.1.x/ - //---------------------------------------------------------- - - const int nspin = PARAM.inp.nspin; - std::vector funcs = init_func( ( (1==nspin) ? XC_UNPOLARIZED:XC_POLARIZED ) ); - - // converting rho - std::vector rho; - rho.resize(nrxx*nspin); -#ifdef _OPENMP -#pragma omp parallel for collapse(2) schedule(static, 1024) -#endif - for( int is=0; isrho[is][ir] + 1.0/nspin*chr->rho_core[ir]; - } - } - - std::vector>> gdr; - std::vector sigma; - - // calculating grho - gdr.resize( nspin ); - for( int is=0; is!=nspin; ++is ) - { - std::vector rhor(nrxx); -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 1024) -#endif - for(int ir=0; ir> rhog(chr->rhopw->npw); - chr->rhopw->real2recip(rhor.data(), rhog.data()); - - //------------------------------------------- - // compute the gradient of charge density and - // store the gradient in gdr[is] - //------------------------------------------- - gdr[is].resize(nrxx); - XC_Functional::grad_rho(rhog.data(), gdr[is].data(), chr->rhopw, tpiba); - } - - // converting grho - sigma.resize( nrxx * ((1==nspin)?1:3) ); - - if( 1==nspin ) - { -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 1024) -#endif - for( int ir=0; ir kin_r; - kin_r.resize(nrxx*nspin); -#ifdef _OPENMP -#pragma omp parallel for collapse(2) schedule(static, 1024) -#endif - for( int is=0; iskin_r[is][ir] / 2.0; - } - } - - std::vector exc ( nrxx ); - std::vector vrho ( nrxx * nspin ); - std::vector vsigma ( nrxx * ((1==nspin)?1:3) ); - std::vector vtau ( nrxx * nspin ); - std::vector vlapl ( nrxx * nspin ); - - const double rho_th = 1e-8; - const double grho_th = 1e-12; - const double tau_th = 1e-8; - // sgn for threshold mask - std::vector sgn( nrxx * nspin); -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 1024) -#endif - for(int i = 0; i < nrxx * nspin; ++i) - { - sgn[i] = 1.0; - } - - if(nspin == 1) - { -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 1024) -#endif - for( int ir=0; irfamily == XC_FAMILY_MGGA); - xc_mgga_exc_vxc(&func, nrxx, rho.data(), sigma.data(), sigma.data(), - kin_r.data(), exc.data(), vrho.data(), vsigma.data(), vlapl.data(), vtau.data()); - - //process etxc - for( int is=0; is!=nspin; ++is ) - { -#ifdef _OPENMP -#pragma omp parallel for reduction(+:etxc) schedule(static, 256) -#endif - for( int ir=0; ir< nrxx; ++ir ) - { -#ifdef __EXX - if (func.info->number == XC_MGGA_X_SCAN && get_func_type() == 5) - { - exc[ir] *= (1.0 - XC_Functional::hybrid_alpha); - } -#endif - etxc += ModuleBase::e2 * exc[ir] * rho[ir*nspin+is] * sgn[ir*nspin+is]; - } - } - - //process vtxc -#ifdef _OPENMP -#pragma omp parallel for collapse(2) reduction(+:vtxc) schedule(static, 256) -#endif - for( int is=0; isnumber == XC_MGGA_X_SCAN && get_func_type() == 5) - { - vrho[ir*nspin+is] *= (1.0 - XC_Functional::hybrid_alpha); - } -#endif - const double v_tmp = ModuleBase::e2 * vrho[ir*nspin+is] * sgn[ir*nspin+is]; - v(is,ir) += v_tmp; - vtxc += v_tmp * chr->rho[is][ir]; - } - } - - //process vsigma - std::vector>> h( nspin, std::vector>(nrxx) ); - if( 1==nspin ) - { -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 1024) -#endif - for( int ir=0; ir< nrxx; ++ir ) - { -#ifdef __EXX - if (func.info->number == XC_MGGA_X_SCAN && get_func_type() == 5) - { - vsigma[ir] *= (1.0 - XC_Functional::hybrid_alpha); - } -#endif - h[0][ir] = 2.0 * gdr[0][ir] * vsigma[ir] * 2.0 * sgn[ir]; - } - } - else - { -#ifdef _OPENMP -#pragma omp parallel for schedule(static, 64) -#endif - for( int ir=0; ir< nrxx; ++ir ) - { -#ifdef __EXX - if (func.info->number == XC_MGGA_X_SCAN && get_func_type() == 5) - { - vsigma[ir*3] *= (1.0 - XC_Functional::hybrid_alpha); - vsigma[ir*3+1] *= (1.0 - XC_Functional::hybrid_alpha); - vsigma[ir*3+2] *= (1.0 - XC_Functional::hybrid_alpha); - } -#endif - h[0][ir] = 2.0 * (gdr[0][ir] * vsigma[ir*3 ] * sgn[ir*2 ] * 2.0 - + gdr[1][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); - h[1][ir] = 2.0 * (gdr[1][ir] * vsigma[ir*3+2] * sgn[ir*2+1] * 2.0 - + gdr[0][ir] * vsigma[ir*3+1] * sgn[ir*2] * sgn[ir*2+1]); - } - } - - // define two dimensional array dh [ nspin, nrxx ] - std::vector> dh(nspin, std::vector( nrxx)); - for( int is=0; is!=nspin; ++is ) - { - XC_Functional::grad_dot( ModuleBase::GlobalFunc::VECTOR_TO_PTR(h[is]), - ModuleBase::GlobalFunc::VECTOR_TO_PTR(dh[is]), chr->rhopw, - tpiba); - } - - double rvtxc = 0.0; -#ifdef _OPENMP -#pragma omp parallel for collapse(2) reduction(+:rvtxc) schedule(static, 256) -#endif - for( int is=0; isnumber == XC_MGGA_X_SCAN && get_func_type() == 5) - { - vtau[ir*nspin+is] *= (1.0 - XC_Functional::hybrid_alpha); - } -#endif - vofk(is,ir) += vtau[ir*nspin+is] * sgn[ir*nspin+is]; - } - } - } - - //------------------------------------------------- - // for MPI, reduce the exchange-correlation energy - //------------------------------------------------- -#ifdef __MPI - Parallel_Reduce::reduce_pool(etxc); - Parallel_Reduce::reduce_pool(vtxc); -#endif - - etxc *= omega / chr->rhopw->nxyz; - vtxc *= omega / chr->rhopw->nxyz; - - finish_func(funcs); - - ModuleBase::timer::tick("XC_Functional","v_xc_meta"); - return std::make_tuple( etxc, vtxc, std::move(v), std::move(vofk) ); - -} - -#endif //ifdef USE_LIBXC diff --git a/source/module_hamilt_general/module_xc/xc_functional_wrapper_gcxc.cpp b/source/module_hamilt_general/module_xc/xc_functional_wrapper_gcxc.cpp index 09a58005572..4e485f1b543 100644 --- a/source/module_hamilt_general/module_xc/xc_functional_wrapper_gcxc.cpp +++ b/source/module_hamilt_general/module_xc/xc_functional_wrapper_gcxc.cpp @@ -11,6 +11,10 @@ #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_base/global_function.h" +#ifdef USE_LIBXC +#include "xc_functional_libxc.h" +#endif + void XC_Functional::gcxc(const double &rho, const double &grho, double &sxc, double &v1xc, double &v2xc) { @@ -293,96 +297,3 @@ void XC_Functional::gcc_spin(double rho, double &zeta, double grho, double &sc, //} return; } //end subroutine gcc_spin - -void XC_Functional::gcxc_libxc(const double &rho, const double &grho, double &sxc, - double &v1xc, double &v2xc) -{ -#ifdef USE_LIBXC - - const double small = 1.e-6; - const double smallg = 1.e-10; - double s,v1,v2; - sxc = v1xc = v2xc = 0.0; - - if (rho <= small || grho < smallg) - { - return; - } - - std::vector funcs = init_func(XC_UNPOLARIZED); - - - for(xc_func_type &func : funcs) - { - xc_gga_exc_vxc(&func, 1, &rho, &grho, &s, &v1, &v2); - - sxc += s * rho; - v2xc += v2 * 2.0; - v1xc += v1; - } - finish_func(funcs); - - return; -#else - ModuleBase::WARNING_QUIT("gcxc_libxc","compile with LIBXC to use this subroutine"); -#endif -} // end subroutine gcxc_libxc - -void XC_Functional::gcxc_spin_libxc(double rhoup, double rhodw, - ModuleBase::Vector3 gdr1, ModuleBase::Vector3 gdr2, - double &sxc, double &v1xcup, double &v1xcdw, double &v2xcup, double &v2xcdw, double &v2xcud) -{ -#ifdef USE_LIBXC - std::vector funcs = init_func(XC_POLARIZED); - double *rho, *grho, *v1xc, *v2xc, *sgn, s; - sxc = v1xcup = v1xcdw = 0.0; - v2xcup = v2xcdw = v2xcud = 0.0; - rho = new double[2]; - grho= new double[3]; - v1xc= new double[2]; - v2xc= new double[3]; - sgn = new double[2]; - - rho[0] = rhoup; - rho[1] = rhodw; - grho[0] = gdr1.norm2(); - grho[1] = gdr1 * gdr2; - grho[2] = gdr2.norm2(); - - const double rho_threshold = 1E-6; - const double grho_threshold = 1E-10; - - for(xc_func_type &func : funcs) - { - if( func.info->family == XC_FAMILY_GGA || func.info->family == XC_FAMILY_HYB_GGA) - { - sgn[0] = sgn[1] = 1.0; - // call Libxc function: xc_gga_exc_vxc - xc_gga_exc_vxc( &func, 1, rho, grho, &s, v1xc, v2xc); - if(func.info->kind==XC_CORRELATION) - { - if ( rho[0] funcs = init_func(XC_POLARIZED); - - for(xc_func_type &func : funcs) - { - if( func.info->family == XC_FAMILY_LDA) - { - // call Libxc function: xc_lda_exc_vxc - xc_lda_exc_vxc( &func, 1, rho_ud, &e, vxc_ud); - } - exc += e; - vxcup += vxc_ud[0]; - vxcdw += vxc_ud[1]; - } - - finish_func(funcs); - delete[] rho_ud; - delete[] vxc_ud; -#else - ModuleBase::WARNING_QUIT("xc_spin_libxc","compile with LIBXC to use this subroutine"); -#endif } \ No newline at end of file diff --git a/source/module_hamilt_general/operator.cpp b/source/module_hamilt_general/operator.cpp index 22007499b98..a7cf8a64372 100644 --- a/source/module_hamilt_general/operator.cpp +++ b/source/module_hamilt_general/operator.cpp @@ -60,7 +60,7 @@ typename Operator::hpsi_info Operator::hPsi(hpsi_info& inp this->hpsi = new psi::Psi(hpsi_pointer, *psi_input, 1, nbands / psi_input->npol); } - auto call_act = [&, this](const Operator* op) -> void { + auto call_act = [&, this](const Operator* op, const bool& is_first_node) -> void { // a "psi" with the bands of needed range psi::Psi psi_wrapper(const_cast(tmpsi_in), 1, nbands, psi_input->get_nbasis()); switch (op->get_act_type()) @@ -69,17 +69,17 @@ typename Operator::hpsi_info Operator::hPsi(hpsi_info& inp op->act(psi_wrapper, *this->hpsi, nbands); break; default: - op->act(nbands, psi_input->get_nbasis(), psi_input->npol, tmpsi_in, this->hpsi->get_pointer(), psi_input->get_ngk(op->ik)); + op->act(nbands, psi_input->get_nbasis(), psi_input->npol, tmpsi_in, this->hpsi->get_pointer(), psi_input->get_ngk(op->ik), is_first_node); break; } }; ModuleBase::timer::tick("Operator", "hPsi"); - call_act(this); + call_act(this, true); // first node Operator* node((Operator*)this->next_op); while (node != nullptr) { - call_act(node); + call_act(node, false); // other nodes node = (Operator*)(node->next_op); } ModuleBase::timer::tick("Operator", "hPsi"); @@ -162,7 +162,7 @@ T* Operator::get_hpsi(const hpsi_info& info) const size_t total_hpsi_size = nbands_range * this->hpsi->get_nbasis(); // ModuleBase::GlobalFunc::ZEROS(hpsi_pointer, total_hpsi_size); // denghui replaced at 20221104 - set_memory_op()(this->ctx, hpsi_pointer, 0, total_hpsi_size); + // set_memory_op()(this->ctx, hpsi_pointer, 0, total_hpsi_size); return hpsi_pointer; } diff --git a/source/module_hamilt_general/operator.h b/source/module_hamilt_general/operator.h index c8d8eb5373d..f040efc7104 100644 --- a/source/module_hamilt_general/operator.h +++ b/source/module_hamilt_general/operator.h @@ -57,12 +57,14 @@ class Operator ///do operation : |hpsi_choosed> = V|psi_choosed> ///V is the target operator act on choosed psi, the consequence should be added to choosed hpsi /// interface type 1: pointer-only (default) + /// @note PW: nbasis = max_npw * npol, nbands = nband * npol, npol = npol. Strange but PAY ATTENTION!!! virtual void act(const int nbands, const int nbasis, const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik = 0)const {}; + const int ngk_ik = 0, + const bool is_first_node = false)const {}; /// developer-friendly interfaces for act() function /// interface type 2: input and change the Psi-type HPsi diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/CMakeLists.txt b/source/module_hamilt_lcao/hamilt_lcaodft/CMakeLists.txt index 5349dd7e281..470558b296d 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/CMakeLists.txt +++ b/source/module_hamilt_lcao/hamilt_lcaodft/CMakeLists.txt @@ -16,15 +16,12 @@ if(ENABLE_LCAO) operator_lcao/td_pot_mixing.cpp operator_lcao/sc_lambda_lcao.cpp operator_lcao/dftu_lcao.cpp + pulay_force_stress_center2.cpp FORCE_STRESS.cpp FORCE_gamma.cpp FORCE_k.cpp - fvl_dphi_gamma.cpp - fvl_dphi_k.cpp - fedm_gamma.cpp - fedm_k.cpp - ftvnl_dphi_gamma.cpp - ftvnl_dphi_k.cpp + stress_tools.cpp + edm.cpp fvnl_dbeta_gamma.cpp fvnl_dbeta_k.cpp grid_init.cpp diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE.h b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE.h index 8644bf804b7..51d840089dd 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE.h +++ b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE.h @@ -94,7 +94,7 @@ class Force_LCAO const bool isstress, ForceStressArrays& fsr, const UnitCell& ucell, - const elecstate::DensityMatrix* dm, + const elecstate::DensityMatrix& dm, const psi::Psi* psi, const Parallel_Orbitals& pv, const elecstate::ElecState* pelec, @@ -136,12 +136,16 @@ class Force_LCAO typename TGint::type& gint, ModuleBase::matrix& fvl_dphi, ModuleBase::matrix& svl_dphi); + + elecstate::DensityMatrix cal_edm(const elecstate::ElecState* pelec, + const psi::Psi& psi, + const elecstate::DensityMatrix& dm, + const K_Vectors& kv, + const Parallel_Orbitals& pv, + const int& nspin, + const int& nbands, + const UnitCell& ucell, + Record_adj& ra) const; }; -// this namespace used to store global function for some stress operation -namespace StressTools -{ -// set upper matrix to whole matrix -void stress_fill(const double& lat0_, const double& omega_, ModuleBase::matrix& stress_matrix); -} // namespace StressTools #endif diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_STRESS.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_STRESS.cpp index a3258438cc3..2c33589d259 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_STRESS.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_STRESS.cpp @@ -270,38 +270,42 @@ void Force_Stress_LCAO::getForceStress(const bool isforce, } #ifdef __EXX - // Force and Stress contribution from exx - ModuleBase::matrix force_exx; - ModuleBase::matrix stress_exx; - if (GlobalC::exx_info.info_global.cal_exx) - { - if (isforce) - { - if (GlobalC::exx_info.info_ri.real_number) - { - exx_lri_double.cal_exx_force(); - force_exx = GlobalC::exx_info.info_global.hybrid_alpha * exx_lri_double.force_exx; - } - else - { - exx_lri_complex.cal_exx_force(); - force_exx = GlobalC::exx_info.info_global.hybrid_alpha * exx_lri_complex.force_exx; - } - } - if (isstress) - { - if (GlobalC::exx_info.info_ri.real_number) - { - exx_lri_double.cal_exx_stress(); - stress_exx = GlobalC::exx_info.info_global.hybrid_alpha * exx_lri_double.stress_exx; - } - else - { - exx_lri_complex.cal_exx_stress(); - stress_exx = GlobalC::exx_info.info_global.hybrid_alpha * exx_lri_complex.stress_exx; - } - } - } + //Force and Stress contribution from exx + ModuleBase::matrix force_exx; + ModuleBase::matrix stress_exx; + if( GlobalC::exx_info.info_global.cal_exx ) + { + const double coeff = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; + if(isforce) + { + if(GlobalC::exx_info.info_ri.real_number) + { + exx_lri_double.cal_exx_force(); + force_exx = coeff * exx_lri_double.force_exx; + } + else + { + exx_lri_complex.cal_exx_force(); + force_exx = coeff * exx_lri_complex.force_exx; + } + } + if(isstress) + { + if(GlobalC::exx_info.info_ri.real_number) + { + exx_lri_double.cal_exx_stress(); + stress_exx = coeff * exx_lri_double.stress_exx; + } + else + { + exx_lri_complex.cal_exx_stress(); + stress_exx = coeff * exx_lri_complex.stress_exx; + } + } + } #endif //-------------------------------- // begin calculate and output force diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_gamma.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_gamma.cpp index 8fd39e3f0e1..db631841cd2 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_gamma.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_gamma.cpp @@ -13,6 +13,7 @@ #include "module_elecstate/elecstate_lcao.h" #include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" #include "module_io/write_HS.h" +#include "module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress.h" template <> void Force_LCAO::allocate(const Parallel_Orbitals& pv, @@ -158,13 +159,13 @@ void Force_LCAO::finish_ftable(ForceStressArrays& fsr) //{ // std::cout << "\n PRINT " << name << std::endl; // std::cout << std::setprecision(6) << std::endl; -// for (int i = 0; i < GlobalV::NLOCAL; i++) +// for (int i = 0; i < PARAM.globalv.nlocal; i++) // { -// for (int j = 0; j < GlobalV::NLOCAL; j++) +// for (int j = 0; j < PARAM.globalv.nlocal; j++) // { -// if (std::abs(mm[i * GlobalV::NLOCAL + j]) > 1.0e-5) +// if (std::abs(mm[i * PARAM.globalv.nlocal + j]) > 1.0e-5) // { -// std::cout << std::setw(12) << mm[i * GlobalV::NLOCAL + j]; +// std::cout << std::setw(12) << mm[i * PARAM.globalv.nlocal + j]; // } // else // { @@ -215,10 +216,17 @@ void Force_LCAO::ftable(const bool isforce, // allocate DHloc_fixed_x, DHloc_fixed_y, DHloc_fixed_z this->allocate(pv, fsr, two_center_bundle, orb); + const double* dSx[3] = { fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z }; + const double* dSxy[6] = { fsr.DSloc_11, fsr.DSloc_12, fsr.DSloc_13, fsr.DSloc_22, fsr.DSloc_23, fsr.DSloc_33 }; // calculate the force related to 'energy density matrix'. - this->cal_fedm(isforce, isstress, fsr, ucell, dm, psi, pv, pelec, foverlap, soverlap); + PulayForceStress::cal_pulay_fs(foverlap, soverlap, + this->cal_edm(pelec, *psi, *dm, *kv, pv, PARAM.inp.nspin, PARAM.inp.nbands, ucell, *ra), + ucell, pv, dSx, dSxy, isforce, isstress); - this->cal_ftvnl_dphi(dm, pv, ucell, fsr, isforce, isstress, ftvnl_dphi, stvnl_dphi); + const double* dHx[3] = { fsr.DHloc_fixed_x, fsr.DHloc_fixed_y, fsr.DHloc_fixed_z }; + const double* dHxy[6] = { fsr.DHloc_fixed_11, fsr.DHloc_fixed_12, fsr.DHloc_fixed_13, fsr.DHloc_fixed_22, fsr.DHloc_fixed_23, fsr.DHloc_fixed_33 }; + //tvnl_dphi + PulayForceStress::cal_pulay_fs(ftvnl_dphi, stvnl_dphi, *dm, ucell, pv, dHx, dHxy, isforce, isstress); this->cal_fvnl_dbeta(dm, pv, @@ -231,9 +239,9 @@ void Force_LCAO::ftable(const bool isforce, fvnl_dbeta, svnl_dbeta); - this->cal_fvl_dphi(isforce, isstress, pelec->pot, gint, fvl_dphi, svl_dphi); + // vl_dphi + PulayForceStress::cal_pulay_fs(fvl_dphi, svl_dphi, *dm, ucell, pelec->pot, gint, isforce, isstress, false/*reset dm to gint*/); - // caoyu add for DeePKS #ifdef __DEEPKS if (PARAM.inp.deepks_scf) { @@ -271,7 +279,7 @@ void Force_LCAO::ftable(const bool isforce, if (PARAM.inp.deepks_out_unittest) { - LCAO_deepks_io::print_dm(dm_gamma[0], GlobalV::NLOCAL, this->ParaV->nrow); + LCAO_deepks_io::print_dm(dm_gamma[0], PARAM.globalv.nlocal, this->ParaV->nrow); GlobalC::ld.check_projected_dm(); @@ -314,23 +322,3 @@ void Force_LCAO::ftable(const bool isforce, ModuleBase::timer::tick("Force_LCAO", "ftable"); return; } - -namespace StressTools -{ -void stress_fill(const double& lat0_, const double& omega_, ModuleBase::matrix& stress_matrix) -{ - assert(omega_ > 0.0); - double weight = lat0_ / omega_; - for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - if (j > i) - { - stress_matrix(j, i) = stress_matrix(i, j); - } - stress_matrix(i, j) *= weight; - } - } -} -} // namespace StressTools diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_k.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_k.cpp index ff11c217c49..1c4b10f251e 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_k.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/FORCE_k.cpp @@ -12,6 +12,7 @@ #include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_io/write_HS.h" +#include "module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress.h" #include #include @@ -216,8 +217,8 @@ void Force_LCAO>::finish_ftable(ForceStressArrays& fsr) // RA.for_2d(pv, GlobalV::GAMMA_ONLY_LOCAL, GlobalC::ORB.cutoffs()); // // double* test; -// test = new double[GlobalV::NLOCAL * GlobalV::NLOCAL]; -// ModuleBase::GlobalFunc::ZEROS(test, GlobalV::NLOCAL * GlobalV::NLOCAL); +// test = new double[PARAM.globalv.nlocal * PARAM.globalv.nlocal]; +// ModuleBase::GlobalFunc::ZEROS(test, PARAM.globalv.nlocal * PARAM.globalv.nlocal); // // for (int T1 = 0; T1 < GlobalC::ucell.ntype; T1++) // { @@ -240,7 +241,7 @@ void Force_LCAO>::finish_ftable(ForceStressArrays& fsr) // { // const int iw2_all = start2 + kk; // assert(irr < pv.nnr); -// test[iw1_all * GlobalV::NLOCAL + iw2_all] += mmm[irr]; +// test[iw1_all * PARAM.globalv.nlocal + iw2_all] += mmm[irr]; // ++irr; // } // } @@ -251,13 +252,13 @@ void Force_LCAO>::finish_ftable(ForceStressArrays& fsr) // // std::cout << "\n " << name << std::endl; // std::cout << std::setprecision(4); -// for (int i = 0; i < GlobalV::NLOCAL; i++) +// for (int i = 0; i < PARAM.globalv.nlocal; i++) // { -// for (int j = 0; j < GlobalV::NLOCAL; j++) +// for (int j = 0; j < PARAM.globalv.nlocal; j++) // { -// if (std::abs(test[i * GlobalV::NLOCAL + j]) > 1.0e-5) +// if (std::abs(test[i * PARAM.globalv.nlocal + j]) > 1.0e-5) // { -// std::cout << std::setw(12) << test[i * GlobalV::NLOCAL + j]; +// std::cout << std::setw(12) << test[i * PARAM.globalv.nlocal + j]; // } // else // { @@ -312,14 +313,21 @@ void Force_LCAO>::ftable(const bool isforce, kv->get_nks(), kv->kvec_d); + const double* dSx[3] = { fsr.DSloc_Rx, fsr.DSloc_Ry, fsr.DSloc_Rz }; // calculate the energy density matrix // and the force related to overlap matrix and energy density matrix. - this->cal_fedm(isforce, isstress, fsr, ucell, dm, psi, pv, pelec, foverlap, soverlap, kv, ra); + PulayForceStress::cal_pulay_fs(foverlap, soverlap, + this->cal_edm(pelec, *psi, *dm, *kv, pv, PARAM.inp.nspin, PARAM.inp.nbands, ucell, *ra), + ucell, pv, dSx, fsr.DH_r, isforce, isstress, ra, -1.0, 1.0); - this->cal_ftvnl_dphi(dm, pv, ucell, fsr, isforce, isstress, ftvnl_dphi, stvnl_dphi, ra); + const double* dHx[3] = { fsr.DHloc_fixedR_x, fsr.DHloc_fixedR_y, fsr.DHloc_fixedR_z }; // T+Vnl + const double* dHxy[6] = { fsr.stvnl11, fsr.stvnl12, fsr.stvnl13, fsr.stvnl22, fsr.stvnl23, fsr.stvnl33 }; //T + // tvnl_dphi + PulayForceStress::cal_pulay_fs(ftvnl_dphi, stvnl_dphi, *dm, ucell, pv, dHx, dHxy, isforce, isstress, ra, 1.0, -1.0); // doing on the real space grid. - this->cal_fvl_dphi(isforce, isstress, pelec->pot, gint, fvl_dphi, svl_dphi); + // vl_dphi + PulayForceStress::cal_pulay_fs(fvl_dphi, svl_dphi, *dm, ucell, pelec->pot, gint, isforce, isstress, false/*reset dm to gint*/); this->cal_fvnl_dbeta(dm, pv, diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_hamilt.hpp b/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_hamilt.hpp index e3d52324ef1..5ac68798781 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_hamilt.hpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_hamilt.hpp @@ -36,7 +36,10 @@ void sparse_format::cal_HR_exx( ModuleBase::TITLE("sparse_format", "cal_HR_exx"); ModuleBase::timer::tick("sparse_format", "cal_HR_exx"); - const Tdata frac = GlobalC::exx_info.info_global.hybrid_alpha; + const Tdata frac = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; std::map> atoms_pos; for (int iat = 0; iat < GlobalC::ucell.nat; ++iat) { diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_init_basis.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_init_basis.cpp index 92384e4c5c7..e0dc45bd6d3 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_init_basis.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/LCAO_init_basis.cpp @@ -23,7 +23,7 @@ void init_basis_lcao(Parallel_Orbitals& pv, { ModuleBase::TITLE("ESolver_KS_LCAO", "init_basis_lcao"); - const int nlocal = GlobalV::NLOCAL; + const int nlocal = PARAM.globalv.nlocal; int nb2d = PARAM.inp.nb2d; // autoset NB2D first if (nb2d == 0) @@ -76,20 +76,20 @@ void init_basis_lcao(Parallel_Orbitals& pv, // is determined in 'divide_HS_2d' subroutine int try_nb = pv.init(nlocal, nlocal, nb2d, DIAG_WORLD); - try_nb += pv.set_nloc_wfc_Eij(GlobalV::NBANDS, GlobalV::ofs_running, GlobalV::ofs_warning); + try_nb += pv.set_nloc_wfc_Eij(PARAM.inp.nbands, GlobalV::ofs_running, GlobalV::ofs_warning); if (try_nb != 0) { pv.set(nlocal, nlocal, 1, pv.blacs_ctxt); - try_nb = pv.set_nloc_wfc_Eij(GlobalV::NBANDS, GlobalV::ofs_running, GlobalV::ofs_warning); + try_nb = pv.set_nloc_wfc_Eij(PARAM.inp.nbands, GlobalV::ofs_running, GlobalV::ofs_warning); } // init blacs context for genelpa - pv.set_desc_wfc_Eij(nlocal, GlobalV::NBANDS, pv.nrow); + pv.set_desc_wfc_Eij(nlocal, PARAM.inp.nbands, pv.nrow); #else pv.set_serial(nlocal, nlocal); pv.nrow_bands = nlocal; - pv.ncol_bands = GlobalV::NBANDS; + pv.ncol_bands = PARAM.inp.nbands; // Zhang Xiaoyang enable the serial version of LCAO and recovered this function usage. 2024-07-06 #endif diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/edm.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/edm.cpp new file mode 100644 index 00000000000..c8b9e01b94a --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/edm.cpp @@ -0,0 +1,104 @@ +#include "FORCE.h" +#include "module_elecstate/module_dm/cal_dm_psi.h" +#include "module_base/memory.h" +#include "module_parameter/parameter.h" +template<> +elecstate::DensityMatrix Force_LCAO::cal_edm(const elecstate::ElecState* pelec, + const psi::Psi& psi, + const elecstate::DensityMatrix& dm, + const K_Vectors& kv, + const Parallel_Orbitals& pv, + const int& nspin, + const int& nbands, + const UnitCell& ucell, + Record_adj& ra) const +{ + ModuleBase::matrix wg_ekb; + wg_ekb.create(nspin, nbands); + + for(int is=0; iswg(is,ib) * pelec->ekb(is, ib); + } + } + + // construct a DensityMatrix for Gamma-Only + elecstate::DensityMatrix edm(&pv, nspin); + +#ifdef __PEXSI + if (PARAM.inp.ks_solver == "pexsi") + { + auto pes = dynamic_cast*>(pelec); + for (int ik = 0; ik < nspin; ik++) + { + edm.set_DMK_pointer(ik, pes->get_DM()->pexsi_EDM[ik]); + } + + } + else +#endif + { + elecstate::cal_dm_psi(edm.get_paraV_pointer(), wg_ekb, psi, edm); + } + return edm; +} + +template<> +elecstate::DensityMatrix, double> Force_LCAO>::cal_edm(const elecstate::ElecState* pelec, + const psi::Psi>& psi, + const elecstate::DensityMatrix, double>& dm, + const K_Vectors& kv, + const Parallel_Orbitals& pv, + const int& nspin, + const int& nbands, + const UnitCell& ucell, + Record_adj& ra) const +{ + + // construct a DensityMatrix object + const int nspin_dm = nspin == 2 ? 2 : 1; + elecstate::DensityMatrix, double> edm(&pv, nspin_dm, kv.kvec_d, kv.get_nks() / nspin_dm); + + //-------------------------------------------- + // calculate the energy density matrix here. + //-------------------------------------------- + + ModuleBase::matrix wg_ekb; + wg_ekb.create(kv.get_nks(), nbands); + ModuleBase::Memory::record("Force::wg_ekb", sizeof(double) * kv.get_nks() * nbands); +#ifdef _OPENMP +#pragma omp parallel for collapse(2) schedule(static, 1024) +#endif + for (int ik = 0; ik < kv.get_nks(); ik++) + { + for (int ib = 0; ib < nbands; ib++) + { + wg_ekb(ik, ib) = pelec->wg(ik, ib) * pelec->ekb(ik, ib); + } + } + + // use the original formula (Hamiltonian matrix) to calculate energy density matrix + if (dm.EDMK.size()) + { +#ifdef _OPENMP +#pragma omp parallel for schedule(static) +#endif + for (int ik = 0; ik < kv.get_nks(); ++ik) + { + edm.set_DMK_pointer(ik, dm.EDMK[ik].c); + } + } + else + { + // cal_dm_psi + elecstate::cal_dm_psi(edm.get_paraV_pointer(), wg_ekb, psi, edm); + } + + // cal_dm_2d + edm.init_DMR(ra, &ucell); + edm.cal_DMR(); + // edm.sum_DMR_spin(); + return edm; +} \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/fedm_gamma.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/fedm_gamma.cpp deleted file mode 100644 index 728525a6566..00000000000 --- a/source/module_hamilt_lcao/hamilt_lcaodft/fedm_gamma.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "FORCE.h" -#include "module_elecstate/elecstate_lcao.h" -#include "module_parameter/parameter.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_base/parallel_reduce.h" -#include "module_base/timer.h" -#include "module_psi/psi.h" -#include "module_elecstate/cal_dm.h" -#include "module_elecstate/module_dm/cal_dm_psi.h" - -// force due to the overlap matrix. -// need energy density matrix here. -template<> -void Force_LCAO::cal_fedm( - const bool isforce, - const bool isstress, - ForceStressArrays &fsr, // mohan add 2024-06-16 - const UnitCell& ucell, - const elecstate::DensityMatrix* dm, - const psi::Psi* psi, - const Parallel_Orbitals& pv, - const elecstate::ElecState *pelec, - ModuleBase::matrix &foverlap, - ModuleBase::matrix& soverlap, - const K_Vectors* kv, - Record_adj* ra) -{ - ModuleBase::TITLE("Force_LCAO","cal_fedm"); - ModuleBase::timer::tick("Force_LCAO","cal_fedm"); - - const int nspin = PARAM.inp.nspin; - const int nbands = GlobalV::NBANDS; - const int nlocal = GlobalV::NLOCAL; - - ModuleBase::matrix wg_ekb; - wg_ekb.create(nspin, nbands); - - for(int is=0; iswg(is,ib) * pelec->ekb(is, ib); - } - } - - // construct a DensityMatrix for Gamma-Only - elecstate::DensityMatrix edm(&pv, nspin); - -#ifdef __PEXSI - if (PARAM.inp.ks_solver == "pexsi") - { - auto pes = dynamic_cast*>(pelec); - for (int ik = 0; ik < nspin; ik++) - { - edm.set_DMK_pointer(ik, pes->get_DM()->pexsi_EDM[ik]); - } - - } - else -#endif - { - elecstate::cal_dm_psi(edm.get_paraV_pointer(), wg_ekb, psi[0], edm); - } - - - for(int i=0; i=0 && nu>=0) - { - const int index = mu * pv.ncol + nu; - double sum = 0.0; - for(int is=0; is -#include - -#ifdef __DEEPKS -#include "module_hamilt_lcao/module_deepks/LCAO_deepks.h" -#endif - -#ifdef _OPENMP -#include -#endif - -#include "module_hamilt_lcao/hamilt_lcaodft/record_adj.h" - -template <> -void Force_LCAO>::cal_fedm(const bool isforce, - const bool isstress, - ForceStressArrays& fsr, - const UnitCell& ucell, - const elecstate::DensityMatrix, double>* dm, - const psi::Psi>* psi, - const Parallel_Orbitals& pv, - const elecstate::ElecState* pelec, - ModuleBase::matrix& foverlap, - ModuleBase::matrix& soverlap, - const K_Vectors* kv, - Record_adj* ra) -{ - ModuleBase::TITLE("Force_LCAO", "cal_fedm"); - ModuleBase::timer::tick("Force_LCAO", "cal_fedm"); - - const int nspin = PARAM.inp.nspin; - const int nbands = GlobalV::NBANDS; - - // construct a DensityMatrix object - elecstate::DensityMatrix, double> edm(kv, &pv, nspin); - - //-------------------------------------------- - // calculate the energy density matrix here. - //-------------------------------------------- - - ModuleBase::matrix wg_ekb; - wg_ekb.create(kv->get_nks(), nbands); - ModuleBase::Memory::record("Force::wg_ekb", sizeof(double) * kv->get_nks() * nbands); -#ifdef _OPENMP -#pragma omp parallel for collapse(2) schedule(static, 1024) -#endif - for (int ik = 0; ik < kv->get_nks(); ik++) - { - for (int ib = 0; ib < nbands; ib++) - { - wg_ekb(ik, ib) = pelec->wg(ik, ib) * pelec->ekb(ik, ib); - } - } - std::vector edm_k(kv->get_nks()); - - // use the original formula (Hamiltonian matrix) to calculate energy density matrix - if (dm->EDMK.size()) - { -#ifdef _OPENMP -#pragma omp parallel for schedule(static) -#endif - for (int ik = 0; ik < kv->get_nks(); ++ik) - { - edm.set_DMK_pointer(ik, dm->EDMK[ik].c); - } - } - else - { - // cal_dm_psi - elecstate::cal_dm_psi(edm.get_paraV_pointer(), wg_ekb, psi[0], edm); - } - - // cal_dm_2d - edm.init_DMR(*ra, &ucell); - edm.cal_DMR(); - edm.sum_DMR_spin(); - //-------------------------------------------- - // summation \sum_{i,j} E(i,j)*dS(i,j) - // BEGIN CALCULATION OF FORCE OF EACH ATOM - //-------------------------------------------- - int total_irr = 0; -#ifdef _OPENMP -#pragma omp parallel - { - int num_threads = omp_get_num_threads(); - ModuleBase::matrix local_soverlap(3, 3); - int local_total_irr = 0; -#else - ModuleBase::matrix& local_soverlap = soverlap; - int& local_total_irr = total_irr; -#endif - - ModuleBase::Vector3 tau1, dtau, tau2; - -#ifdef _OPENMP -#pragma omp for schedule(dynamic) -#endif - for (int iat = 0; iat < ucell.nat; iat++) - { - const int T1 = ucell.iat2it[iat]; - Atom* atom1 = &ucell.atoms[T1]; - const int I1 = ucell.iat2ia[iat]; - // get iat1 - int iat1 = ucell.itia2iat(T1, I1); - double* foverlap_iat; - if (isforce) - { - foverlap_iat = &foverlap(iat, 0); - } - -#ifdef _OPENMP - // using local stack to avoid false sharing in multi-threaded case - double foverlap_temp[3] = {0.0, 0.0, 0.0}; - if (num_threads > 1) - { - foverlap_iat = foverlap_temp; - } -#endif - int irr = pv.nlocstart[iat]; - const int start1 = ucell.itiaiw2iwt(T1, I1, 0); - for (int cb = 0; cb < ra->na_each[iat]; ++cb) - { - const int T2 = ra->info[iat][cb][3]; - const int I2 = ra->info[iat][cb][4]; - - const int start2 = ucell.itiaiw2iwt(T2, I2, 0); - - Atom* atom2 = &ucell.atoms[T2]; - - // get iat2 - int iat2 = ucell.itia2iat(T2, I2); - double Rx = ra->info[iat][cb][0]; - double Ry = ra->info[iat][cb][1]; - double Rz = ra->info[iat][cb][2]; - // get BaseMatrix - hamilt::BaseMatrix* tmp_matrix = edm.get_DMR_pointer(1)->find_matrix(iat1, iat2, Rx, Ry, Rz); - if (tmp_matrix == nullptr) - { - continue; - } - int row_ap = pv.atom_begin_row[iat1]; - int col_ap = pv.atom_begin_col[iat2]; - // get DMR - for (int mu = 0; mu < pv.get_row_size(iat1); ++mu) - { - for (int nu = 0; nu < pv.get_col_size(iat2); ++nu) - { - // here do not sum over spin due to edm.sum_DMR_spin(); - double edm2d1 = tmp_matrix->get_value(mu, nu); - double edm2d2 = 2.0 * edm2d1; - - if (isforce) - { - foverlap_iat[0] -= edm2d2 * fsr.DSloc_Rx[irr]; - foverlap_iat[1] -= edm2d2 * fsr.DSloc_Ry[irr]; - foverlap_iat[2] -= edm2d2 * fsr.DSloc_Rz[irr]; - } - if (isstress) - { - for (int ipol = 0; ipol < 3; ipol++) - { - local_soverlap(0, ipol) += edm2d1 * fsr.DSloc_Rx[irr] * fsr.DH_r[irr * 3 + ipol]; - if (ipol < 1) - { - continue; - } - local_soverlap(1, ipol) += edm2d1 * fsr.DSloc_Ry[irr] * fsr.DH_r[irr * 3 + ipol]; - if (ipol < 2) - { - continue; - } - local_soverlap(2, ipol) += edm2d1 * fsr.DSloc_Rz[irr] * fsr.DH_r[irr * 3 + ipol]; - } - } - //} - ++local_total_irr; - ++irr; - } // end kk - } // end jj - } // end cb -#ifdef _OPENMP - if (isforce && num_threads > 1) - { - foverlap(iat, 0) += foverlap_iat[0]; - foverlap(iat, 1) += foverlap_iat[1]; - foverlap(iat, 2) += foverlap_iat[2]; - } -#endif - } // end iat -#ifdef _OPENMP -#pragma omp critical(cal_foverlap_k_reduce) - { - total_irr += local_total_irr; - if (isstress) - { - for (int ipol = 0; ipol < 3; ipol++) - { - soverlap(0, ipol) += local_soverlap(0, ipol); - if (ipol < 1) - { - continue; - } - soverlap(1, ipol) += local_soverlap(1, ipol); - if (ipol < 2) - { - continue; - } - soverlap(2, ipol) += local_soverlap(2, ipol); - } - } - } - } -#endif - - if (isstress) - { - StressTools::stress_fill(ucell.lat0, ucell.omega, soverlap); - } - - if (total_irr != pv.nnr) - { - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "wrong irr", total_irr); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "wrong pv.nnr", pv.nnr); - ModuleBase::WARNING_QUIT("Force_LCAO::fedm_k", "irr!=pv.nnr"); - } - - ModuleBase::timer::tick("Force_LCAO", "cal_fedm"); - return; -} diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_gamma.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_gamma.cpp deleted file mode 100644 index ea5ca9ed833..00000000000 --- a/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_gamma.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "FORCE.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_parameter/parameter.h" -#include "module_cell/module_neighbor/sltk_grid_driver.h" -#include -#include "module_base/timer.h" - -template<> -void Force_LCAO::cal_ftvnl_dphi( - const elecstate::DensityMatrix* dm, - const Parallel_Orbitals& pv, - const UnitCell& ucell, - ForceStressArrays& fsr, - const bool isforce, - const bool isstress, - ModuleBase::matrix& ftvnl_dphi, - ModuleBase::matrix& stvnl_dphi, - Record_adj* ra) -{ - ModuleBase::TITLE("Force_LCAO","cal_ftvnl_dphi"); - ModuleBase::timer::tick("Force_LCAO","cal_ftvnl_dphi"); - - const int nlocal = GlobalV::NLOCAL; - const int nspin = PARAM.inp.nspin; - - for(int i=0; i= 0 && nu >= 0 ) - { - const int index = mu * pv.ncol + nu; - //contribution from deriv of AO's in T+VNL term - - double sum = 0.0; - for(int is=0; isget_DMK(is+1, 0, nu, mu); - } - sum *= 2.0; - - if(isforce) - { - ftvnl_dphi(iat,0) += sum * fsr.DHloc_fixed_x[index]; - ftvnl_dphi(iat,1) += sum * fsr.DHloc_fixed_y[index]; - ftvnl_dphi(iat,2) += sum * fsr.DHloc_fixed_z[index]; - } - if(isstress) - { - stvnl_dphi(0,0) += sum/2.0 * fsr.DHloc_fixed_11[index]; - stvnl_dphi(0,1) += sum/2.0 * fsr.DHloc_fixed_12[index]; - stvnl_dphi(0,2) += sum/2.0 * fsr.DHloc_fixed_13[index]; - stvnl_dphi(1,1) += sum/2.0 * fsr.DHloc_fixed_22[index]; - stvnl_dphi(1,2) += sum/2.0 * fsr.DHloc_fixed_23[index]; - stvnl_dphi(2,2) += sum/2.0 * fsr.DHloc_fixed_33[index]; - } - } - } - } - - if(isstress) - { - StressTools::stress_fill(ucell.lat0, ucell.omega, stvnl_dphi); - } - - ModuleBase::timer::tick("Force_LCAO","cal_ftvnl_dphi"); - return; -} diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_k.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_k.cpp deleted file mode 100644 index f8f5a463c38..00000000000 --- a/source/module_hamilt_lcao/hamilt_lcaodft/ftvnl_dphi_k.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "FORCE.h" - -#include "module_parameter/parameter.h" -#include -#include - -#include "module_base/memory.h" -#include "module_base/parallel_reduce.h" -#include "module_base/timer.h" -#include "module_base/tool_threading.h" -#include "module_cell/module_neighbor/sltk_grid_driver.h" -#include "module_elecstate/cal_dm.h" -#include "module_elecstate/module_dm/cal_dm_psi.h" -#include "module_elecstate/elecstate_lcao.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_io/write_HS.h" - -#ifdef __DEEPKS -#include "module_hamilt_lcao/module_deepks/LCAO_deepks.h" -#endif - -#ifdef _OPENMP -#include -#endif - - -template<> -void Force_LCAO>::cal_ftvnl_dphi( - const elecstate::DensityMatrix, double>* dm, - const Parallel_Orbitals& pv, - const UnitCell& ucell, - ForceStressArrays& fsr, - const bool isforce, - const bool isstress, - ModuleBase::matrix& ftvnl_dphi, - ModuleBase::matrix& stvnl_dphi, - Record_adj* ra) -{ - ModuleBase::TITLE("Force_LCAO", "cal_ftvnl_dphi"); - ModuleBase::timer::tick("Force_LCAO", "cal_ftvnl_dphi"); - - const int nspin_DMR = (PARAM.inp.nspin == 2) ? 2 : 1; - - int total_irr = 0; - // get the adjacent atom's information. - -#ifdef _OPENMP -#pragma omp parallel - { - int num_threads = omp_get_num_threads(); - ModuleBase::matrix local_stvnl_dphi(3, 3); - int local_total_irr = 0; -#pragma omp for schedule(dynamic) -#else - ModuleBase::matrix& local_stvnl_dphi = stvnl_dphi; - int& local_total_irr = total_irr; -#endif - for (int iat = 0; iat < ucell.nat; iat++) - { - const int T1 = ucell.iat2it[iat]; - Atom* atom1 = &ucell.atoms[T1]; - const int I1 = ucell.iat2ia[iat]; - // get iat1 - int iat1 = ucell.itia2iat(T1, I1); - // - int irr = pv.nlocstart[iat]; - const int start1 = ucell.itiaiw2iwt(T1, I1, 0); - double* ftvnl_dphi_iat; - if (isforce) - { - ftvnl_dphi_iat = &ftvnl_dphi(iat, 0); - } -#ifdef _OPENMP - // using local stack to avoid false sharing in multi-threaded case - double ftvnl_dphi_temp[3] = {0.0, 0.0, 0.0}; - if (num_threads > 1) - { - ftvnl_dphi_iat = ftvnl_dphi_temp; - } -#endif - for (int cb = 0; cb < ra->na_each[iat]; ++cb) - { - const int T2 = ra->info[iat][cb][3]; - const int I2 = ra->info[iat][cb][4]; - const int start2 = ucell.itiaiw2iwt(T2, I2, 0); - Atom* atom2 = &ucell.atoms[T2]; - // get iat2 - int iat2 = ucell.itia2iat(T2, I2); - double Rx = ra->info[iat][cb][0]; - double Ry = ra->info[iat][cb][1]; - double Rz = ra->info[iat][cb][2]; - // get BaseMatrix - if (pv.get_row_size(iat1) <= 0 || pv.get_col_size(iat2) <= 0) - { - continue; - } - std::vector*> tmp_matrix; - for (int is = 0; is < nspin_DMR; ++is) - { - tmp_matrix.push_back(dm->get_DMR_pointer(is+1)->find_matrix(iat1, iat2, Rx, Ry, Rz)); - } - - for (int mu = 0; mu < pv.get_row_size(iat1); ++mu) - { - for (int nu = 0; nu < pv.get_col_size(iat2); ++nu) - { - // get value from dm - double dm2d1 = 0.0; - for (int is = 0; is < nspin_DMR; ++is) - { - dm2d1 += tmp_matrix[is]->get_value(mu, nu); - } - double dm2d2 = 2.0 * dm2d1; - // - if (isforce) - { - ftvnl_dphi_iat[0] += dm2d2 * fsr.DHloc_fixedR_x[irr]; - ftvnl_dphi_iat[1] += dm2d2 * fsr.DHloc_fixedR_y[irr]; - ftvnl_dphi_iat[2] += dm2d2 * fsr.DHloc_fixedR_z[irr]; - } - if (isstress) - { - local_stvnl_dphi(0, 0) -= dm2d1 * fsr.stvnl11[irr]; - local_stvnl_dphi(0, 1) -= dm2d1 * fsr.stvnl12[irr]; - local_stvnl_dphi(0, 2) -= dm2d1 * fsr.stvnl13[irr]; - local_stvnl_dphi(1, 1) -= dm2d1 * fsr.stvnl22[irr]; - local_stvnl_dphi(1, 2) -= dm2d1 * fsr.stvnl23[irr]; - local_stvnl_dphi(2, 2) -= dm2d1 * fsr.stvnl33[irr]; - } - //} - ++local_total_irr; - ++irr; - } // end kk - } // end jj - } // end cb -#ifdef _OPENMP - if (isforce && num_threads > 1) - { - ftvnl_dphi(iat, 0) += ftvnl_dphi_iat[0]; - ftvnl_dphi(iat, 1) += ftvnl_dphi_iat[1]; - ftvnl_dphi(iat, 2) += ftvnl_dphi_iat[2]; - } -#endif - } // end iat -#ifdef _OPENMP -#pragma omp critical(cal_ftvnl_dphi_k_reduce) - { - total_irr += local_total_irr; - if (isstress) - { - stvnl_dphi(0, 0) += local_stvnl_dphi(0, 0); - stvnl_dphi(0, 1) += local_stvnl_dphi(0, 1); - stvnl_dphi(0, 2) += local_stvnl_dphi(0, 2); - stvnl_dphi(1, 1) += local_stvnl_dphi(1, 1); - stvnl_dphi(1, 2) += local_stvnl_dphi(1, 2); - stvnl_dphi(2, 2) += local_stvnl_dphi(2, 2); - } - } - } -#endif - assert(total_irr == pv.nnr); - - if (isstress) - { - StressTools::stress_fill(ucell.lat0, ucell.omega, stvnl_dphi); - } - - ModuleBase::timer::tick("Force_LCAO", "cal_ftvnl_dphi"); - return; -} diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/fvl_dphi_gamma.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/fvl_dphi_gamma.cpp deleted file mode 100644 index 5f0c97f63b0..00000000000 --- a/source/module_hamilt_lcao/hamilt_lcaodft/fvl_dphi_gamma.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "FORCE.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_parameter/parameter.h" -#include "module_base/timer.h" - -template<> -void Force_LCAO::cal_fvl_dphi( - const bool isforce, - const bool isstress, - const elecstate::Potential* pot_in, - TGint::type& gint, - ModuleBase::matrix& fvl_dphi, - ModuleBase::matrix& svl_dphi) -{ - ModuleBase::TITLE("Force_LCAO","cal_fvl_dphi"); - ModuleBase::timer::tick("Force_LCAO","cal_fvl_dphi"); - - const int nspin = PARAM.inp.nspin; - - fvl_dphi.zero_out(); - svl_dphi.zero_out(); - - for(int is=0; isget_effective_v(is); - const double* vofk_eff1 = nullptr; - - if(XC_Functional::get_func_type()==3 || XC_Functional::get_func_type()==5) - { - vofk_eff1 = pot_in->get_effective_vofk(is); - - Gint_inout inout( - is, - vr_eff1, - vofk_eff1, - isforce, - isstress, - &fvl_dphi, - &svl_dphi, - Gint_Tools::job_type::force_meta); - - gint.cal_gint(&inout); - } - else - { - Gint_inout inout( - is, - vr_eff1, - isforce, - isstress, - &fvl_dphi, - &svl_dphi, - Gint_Tools::job_type::force); - - gint.cal_gint(&inout); - } - } - - if(isstress) - { - for(int i=0;i<3;i++) - { - for(int j=0;j<3;j++) - { - if(i -#include - -#include "module_base/memory.h" -#include "module_base/parallel_reduce.h" -#include "module_base/timer.h" -#include "module_base/tool_threading.h" -#include "module_cell/module_neighbor/sltk_grid_driver.h" -#include "module_elecstate/cal_dm.h" -#include "module_elecstate/module_dm/cal_dm_psi.h" -#include "module_elecstate/elecstate_lcao.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_io/write_HS.h" - -#ifdef __DEEPKS -#include "module_hamilt_lcao/module_deepks/LCAO_deepks.h" -#endif - -#ifdef _OPENMP -#include -#endif - - -// calculate the force due to < phi | Vlocal | dphi > -template<> -void Force_LCAO>::cal_fvl_dphi( - const bool isforce, - const bool isstress, - const elecstate::Potential* pot_in, - TGint>::type& gint, - ModuleBase::matrix& fvl_dphi, - ModuleBase::matrix& svl_dphi) -{ - ModuleBase::TITLE("Force_LCAO", "cal_fvl_dphi"); - if (!isforce && !isstress) - { - return; - } - - ModuleBase::timer::tick("Force_LCAO", "cal_fvl_dphi"); - - const int nspin = PARAM.inp.nspin; - - for (int is = 0; is < nspin; ++is) - { - const double* vr_eff1 = pot_in->get_effective_v(is); - const double* vofk_eff1 = nullptr; - - if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) - { - vofk_eff1 = pot_in->get_effective_vofk(is); - } - - //-------------------------------- - // Grid integration here. - //-------------------------------- - // fvl_dphi can not be set to zero here if Vna is used - if (isstress || isforce) - { - // meta GGA functionals - if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) - { - Gint_inout inout(is, - vr_eff1, - vofk_eff1, - isforce, - isstress, - &fvl_dphi, - &svl_dphi, - Gint_Tools::job_type::force_meta); - - gint.cal_gint(&inout); - } - else - { - Gint_inout inout(is, - vr_eff1, - isforce, - isstress, - &fvl_dphi, - &svl_dphi, - Gint_Tools::job_type::force); - - gint.cal_gint(&inout); - } - } - } - - if (isstress) - { - StressTools::stress_fill(-1.0, GlobalC::ucell.omega, svl_dphi); - } - - ModuleBase::timer::tick("Force_LCAO", "cal_fvl_dphi"); - return; -} diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_gamma.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_gamma.cpp index f387f0f923d..aef53810add 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_gamma.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_gamma.cpp @@ -3,6 +3,7 @@ #include "module_parameter/parameter.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_hamilt_lcao/hamilt_lcaodft/stress_tools.h" #include diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_k.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_k.cpp index fe36856c658..b57ad57d73b 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_k.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/fvnl_dbeta_k.cpp @@ -10,6 +10,7 @@ #include "module_elecstate/module_dm/cal_dm_psi.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_io/write_HS.h" +#include "module_hamilt_lcao/hamilt_lcaodft/stress_tools.h" #include #include diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.cpp index 78ca687d24e..6706b7048a3 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.cpp @@ -75,6 +75,7 @@ HamiltLCAO::HamiltLCAO(Gint_Gamma* GG_in, const LCAO_Orbitals& orb, elecstate::DensityMatrix* DM_in #ifdef __EXX + , const int istep , int* exx_two_level_step , std::vector>>>* Hexxd , std::vector>>>>* Hexxc @@ -176,13 +177,14 @@ HamiltLCAO::HamiltLCAO(Gint_Gamma* GG_in, pot_in->pot_register(pot_register_in); // effective potential term Operator* veff = new Veff>(GG_in, - this->hsk, - this->kv->kvec_d, - pot_in, - this->hR, // no explicit call yet - &GlobalC::ucell, - orb.cutoffs(), - &GlobalC::GridD + this->hsk, + this->kv->kvec_d, + pot_in, + this->hR, // no explicit call yet + &GlobalC::ucell, + orb.cutoffs(), + &GlobalC::GridD, + PARAM.inp.nspin ); this->getOperator()->add(veff); } @@ -244,13 +246,14 @@ HamiltLCAO::HamiltLCAO(Gint_Gamma* GG_in, pot_in->pot_register(pot_register_in); // Veff term this->getOperator() = new Veff>(GK_in, - this->hsk, - kv->kvec_d, - pot_in, - this->hR, - &GlobalC::ucell, - orb.cutoffs(), - &GlobalC::GridD); + this->hsk, + kv->kvec_d, + pot_in, + this->hR, + &GlobalC::ucell, + orb.cutoffs(), + &GlobalC::GridD, + PARAM.inp.nspin); // reset spin index and real space Hamiltonian matrix int start_spin = -1; GK_in->reset_spin(start_spin); @@ -413,6 +416,7 @@ HamiltLCAO::HamiltLCAO(Gint_Gamma* GG_in, Hexxd, Hexxc, Add_Hexx_Type::R, + istep, exx_two_level_step, !GlobalC::restart.info_load.restart_exx && GlobalC::restart.info_load.load_H); diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.h b/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.h index 740fff3008f..0cd597b5b05 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.h +++ b/source/module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.h @@ -2,6 +2,7 @@ #define W_ABACUS_DEVELOP_ABACUS_DEVELOP_SOURCE_MODULE_HAMILT_LCAO_HAMILT_LCAODFT_HAMILT_LCAO_H #include "module_basis/module_nao/two_center_bundle.h" +#include "module_cell/klist.h" #include "module_elecstate/module_dm/density_matrix.h" #include "module_elecstate/potentials/potential_new.h" #include "module_hamilt_general/hamilt.h" @@ -36,6 +37,7 @@ class HamiltLCAO : public Hamilt const LCAO_Orbitals& orb, elecstate::DensityMatrix* DM_in #ifdef __EXX + , const int istep , int* exx_two_level_step = nullptr , std::vector>>>* Hexxd = nullptr , std::vector>>>>* Hexxc = nullptr @@ -104,6 +106,8 @@ class HamiltLCAO : public Hamilt /// current_spin for NSPIN=2, 0: hamiltonian for spin up, 1: hamiltonian for spin down int current_spin = 0; + const int istep = 0; + // sk and hk will be refactored to HamiltLCAO later // std::vector sk; // std::vector hk; diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.h b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.h index afe27a7733f..9e1653be1a3 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.h +++ b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.h @@ -32,6 +32,7 @@ class OperatorEXX> : public OperatorLCAO std::vector>>>* Hexxd_in = nullptr, std::vector>>>>* Hexxc_in = nullptr, Add_Hexx_Type add_hexx_type_in = Add_Hexx_Type::R, + const int istep_in = 0, int* two_level_step_in = nullptr, const bool restart_in = false); @@ -54,6 +55,8 @@ class OperatorEXX> : public OperatorLCAO /// @brief if restart, read and save Hexx, and directly use it during the first outer loop. bool restart = false; + const int istep = 0; // the ion step + void add_loaded_Hexx(const int ik); const K_Vectors& kv; diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.hpp b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.hpp index 06f4e5518a2..d72ada24c72 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.hpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/op_exx_lcao.hpp @@ -85,13 +85,15 @@ OperatorEXX>::OperatorEXX(HS_Matrix_K* hsk_in, std::vector>>>* Hexxd_in, std::vector>>>>* Hexxc_in, Add_Hexx_Type add_hexx_type_in, - int* two_level_step_in, + const int istep, + int* two_level_step_in, const bool restart_in) : OperatorLCAO(hsk_in, kv_in.kvec_d, hR_in), kv(kv_in), Hexxd(Hexxd_in), Hexxc(Hexxc_in), add_hexx_type(add_hexx_type_in), + istep(istep), two_level_step(two_level_step_in), restart(restart_in) { @@ -104,12 +106,12 @@ OperatorEXX>::OperatorEXX(HS_Matrix_K* hsk_in, const std::string file_name_exx = PARAM.globalv.global_readin_dir + "HexxR" + std::to_string(GlobalV::MY_RANK); if (GlobalC::exx_info.info_ri.real_number) { - ModuleIO::read_Hexxs_csr(file_name_exx, GlobalC::ucell, PARAM.inp.nspin, GlobalV::NLOCAL, *Hexxd); + ModuleIO::read_Hexxs_csr(file_name_exx, GlobalC::ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd); if (this->add_hexx_type == Add_Hexx_Type::R) { reallocate_hcontainer(*Hexxd, this->hR); } } else { - ModuleIO::read_Hexxs_csr(file_name_exx, GlobalC::ucell, PARAM.inp.nspin, GlobalV::NLOCAL, *Hexxc); + ModuleIO::read_Hexxs_csr(file_name_exx, GlobalC::ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc); if (this->add_hexx_type == Add_Hexx_Type::R) { reallocate_hcontainer(*Hexxc, this->hR); } } this->use_cell_nearest = false; @@ -180,10 +182,10 @@ OperatorEXX>::OperatorEXX(HS_Matrix_K* hsk_in, // read in Hexx(R) const std::string restart_HR_path = GlobalC::restart.folder + "HexxR" + std::to_string(GlobalV::MY_RANK); if (GlobalC::exx_info.info_ri.real_number) { - ModuleIO::read_Hexxs_csr(restart_HR_path, GlobalC::ucell, PARAM.inp.nspin, GlobalV::NLOCAL, *Hexxd); + ModuleIO::read_Hexxs_csr(restart_HR_path, GlobalC::ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd); } else { - ModuleIO::read_Hexxs_csr(restart_HR_path, GlobalC::ucell, PARAM.inp.nspin, GlobalV::NLOCAL, *Hexxc); + ModuleIO::read_Hexxs_csr(restart_HR_path, GlobalC::ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc); } } @@ -201,33 +203,40 @@ void OperatorEXX>::contributeHR() { ModuleBase::TITLE("OperatorEXX", "contributeHR"); // Peize Lin add 2016-12-03 - if (PARAM.inp.calculation != "nscf" && this->two_level_step != nullptr && *this->two_level_step == 0 && !this->restart) { return; //in the non-exx loop, do nothing -} + if (this->istep == 0 && PARAM.inp.calculation != "nscf" && this->two_level_step != nullptr && *this->two_level_step == 0 && !this->restart) { return; } //in the non-exx loop, do nothing + if (this->add_hexx_type == Add_Hexx_Type::k) { return; } + if (XC_Functional::get_func_type() == 4 || XC_Functional::get_func_type() == 5) { + const double coeff = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; // add H(R) normally - if (GlobalC::exx_info.info_ri.real_number) { + if (GlobalC::exx_info.info_ri.real_number) + { RI_2D_Comm::add_HexxR( this->current_spin, - GlobalC::exx_info.info_global.hybrid_alpha, + coeff, *this->Hexxd, *this->hR->get_paraV(), PARAM.globalv.npol, *this->hR, this->use_cell_nearest ? &this->cell_nearest : nullptr); - } else { + } + else + { RI_2D_Comm::add_HexxR( this->current_spin, - GlobalC::exx_info.info_global.hybrid_alpha, + coeff, *this->Hexxc, *this->hR->get_paraV(), PARAM.globalv.npol, *this->hR, this->use_cell_nearest ? &this->cell_nearest : nullptr); -} + } } - if (PARAM.inp.nspin == 2) { this->current_spin = 1 - this->current_spin; -} + if (PARAM.inp.nspin == 2) { this->current_spin = 1 - this->current_spin; } } template @@ -235,8 +244,10 @@ void OperatorEXX>::contributeHk(int ik) { ModuleBase::TITLE("OperatorEXX", "constributeHR"); // Peize Lin add 2016-12-03 - if (PARAM.inp.calculation != "nscf" && this->two_level_step != nullptr && *this->two_level_step == 0 && !this->restart) { return; //in the non-exx loop, do nothing -} + if (PARAM.inp.calculation != "nscf" && this->two_level_step != nullptr && *this->two_level_step == 0 && !this->restart) { return; } //in the non-exx loop, do nothing + + if (this->add_hexx_type == Add_Hexx_Type::R) { throw std::invalid_argument("Set Add_Hexx_Type::k sto call OperatorEXX::contributeHk()."); } + if (XC_Functional::get_func_type() == 4 || XC_Functional::get_func_type() == 5) { if (this->restart && this->two_level_step != nullptr) @@ -261,12 +272,15 @@ void OperatorEXX>::contributeHk(int ik) } } // cal H(k) from H(R) normally - + const double coeff = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; if (GlobalC::exx_info.info_ri.real_number) { RI_2D_Comm::add_Hexx( this->kv, ik, - GlobalC::exx_info.info_global.hybrid_alpha, + coeff, *this->Hexxd, *this->hR->get_paraV(), this->hsk->get_hk()); @@ -274,7 +288,7 @@ void OperatorEXX>::contributeHk(int ik) RI_2D_Comm::add_Hexx( this->kv, ik, - GlobalC::exx_info.info_global.hybrid_alpha, + coeff, *this->Hexxc, *this->hR->get_paraV(), this->hsk->get_hk()); diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/veff_lcao.h b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/veff_lcao.h index ee92f87777a..37ac1872241 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/veff_lcao.h +++ b/source/module_hamilt_lcao/hamilt_lcaodft/operator_lcao/veff_lcao.h @@ -36,39 +36,41 @@ class Veff> : public OperatorLCAO * @param GK_in: the pointer of Gint_k object, used for grid integration */ Veff>(Gint_k* GK_in, - HS_Matrix_K* hsk_in, - const std::vector>& kvec_d_in, - elecstate::Potential* pot_in, - hamilt::HContainer* hR_in, - const UnitCell* ucell_in, - const std::vector& orb_cutoff, - Grid_Driver* GridD_in) + HS_Matrix_K* hsk_in, + const std::vector>& kvec_d_in, + elecstate::Potential* pot_in, + hamilt::HContainer* hR_in, + const UnitCell* ucell_in, + const std::vector& orb_cutoff, + Grid_Driver* GridD_in, + const int& nspin) : GK(GK_in), orb_cutoff_(orb_cutoff), pot(pot_in), ucell(ucell_in), gd(GridD_in), OperatorLCAO(hsk_in, kvec_d_in, hR_in) { this->cal_type = calculation_type::lcao_gint; this->initialize_HR(ucell_in, GridD_in); - GK_in->initialize_pvpR(*ucell_in, GridD_in); + GK_in->initialize_pvpR(*ucell_in, GridD_in, nspin); } /** * @brief Construct a new Veff object for Gamma-only calculation * @param GG_in: the pointer of Gint_Gamma object, used for grid integration */ Veff>(Gint_Gamma* GG_in, - HS_Matrix_K* hsk_in, - const std::vector>& kvec_d_in, - elecstate::Potential* pot_in, - hamilt::HContainer* hR_in, - const UnitCell* ucell_in, - const std::vector& orb_cutoff, - Grid_Driver* GridD_in) + HS_Matrix_K* hsk_in, + const std::vector>& kvec_d_in, + elecstate::Potential* pot_in, + hamilt::HContainer* hR_in, + const UnitCell* ucell_in, + const std::vector& orb_cutoff, + Grid_Driver* GridD_in, + const int& nspin) : GG(GG_in), orb_cutoff_(orb_cutoff), pot(pot_in), OperatorLCAO(hsk_in, kvec_d_in, hR_in) { this->cal_type = calculation_type::lcao_gint; this->initialize_HR(ucell_in, GridD_in); - GG_in->initialize_pvpR(*ucell_in, GridD_in); + GG_in->initialize_pvpR(*ucell_in, GridD_in, nspin); } ~Veff>(){}; diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress.h b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress.h new file mode 100644 index 00000000000..e4a7c4fd0b0 --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress.h @@ -0,0 +1,69 @@ +#pragma once +#include "module_basis/module_nao/two_center_bundle.h" +#include "module_elecstate/module_dm/density_matrix.h" +#include "module_hamilt_lcao/module_gint/gint_gamma.h" +#include "module_hamilt_lcao/module_gint/gint_k.h" +#include "module_elecstate/potentials/potential_new.h" +#include "module_cell/unitcell.h" +#include "module_hamilt_lcao/hamilt_lcaodft/stress_tools.h" +#ifndef TGINT_H +#define TGINT_H +template +struct TGint; +template <> struct TGint { using type = Gint_Gamma; }; +template <> struct TGint> { using type = Gint_k; }; +#endif + +/// calculate the abstract formulas: +/// $Tr[D*dH/dx]$ (force) and $1/V Tr[D*(dH/dx_a*x_b)]$ (stress) +/// where D can be any (energy) density matrix +/// and H can be any operator +namespace PulayForceStress +{ + /// for 2-center-integration terms, provided force and stress derivatives + template + void cal_pulay_fs( + ModuleBase::matrix& f, ///< [out] force + ModuleBase::matrix& s, ///< [out] stress + const elecstate::DensityMatrix& dm, ///< [in] density matrix or energy density matrix + const UnitCell& ucell, ///< [in] unit cell + const Parallel_Orbitals& pv, ///< [in] parallel orbitals + const double* (&dHSx)[3], ///< [in] dHSx x, y, z, for force + const double* (&dHSxy)[6], ///< [in] dHSxy 11, 12, 13, 22, 23, 33, for stress + const bool& isforce, + const bool& isstress, + Record_adj* ra = nullptr, + const double& factor_force = 1.0, + const double& factor_stress = 1.0); + + /// for 2-center-integration terms, provided force derivatives and coordinate difference + template + void cal_pulay_fs( + ModuleBase::matrix& f, ///< [out] force + ModuleBase::matrix& s, ///< [out] stress + const elecstate::DensityMatrix& dm, ///< [in] density matrix or energy density matrix + const UnitCell& ucell, ///< [in] unit cell + const Parallel_Orbitals& pv, ///< [in] parallel orbitals + const double* (&dHSx)[3], ///< [in] dHSx x, y, z, for force and stress + const double* dtau, ///< [in] dr x, y, z, for stress + const bool& isforce, + const bool& isstress, + Record_adj* ra = nullptr, + const double& factor_force = 1.0, + const double& factor_stress = 1.0); + + /// for grid-integration terms + template + void cal_pulay_fs( + ModuleBase::matrix& f, ///< [out] force + ModuleBase::matrix& s, ///< [out] stress + const elecstate::DensityMatrix& dm, ///< [in] density matrix or energy density matrix + const UnitCell& ucell, ///< [in] unit cell + const elecstate::Potential* pot, ///< [in] potential on grid + typename TGint::type& gint, ///< [in] Gint object + const bool& isforce, + const bool& isstress, + const bool& set_dmr_gint = true); +} +#include "pulay_force_stress_center2_template.hpp" +#include "pulay_force_stress_gint.hpp" \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2.cpp new file mode 100644 index 00000000000..ea49096da5b --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2.cpp @@ -0,0 +1,103 @@ +#include "pulay_force_stress.h" +namespace PulayForceStress +{ + template<> // gamma-only, provided xy + void cal_pulay_fs( + ModuleBase::matrix& f, + ModuleBase::matrix& s, + const elecstate::DensityMatrix& dm, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const double* (&dHSx)[3], + const double* (&dHSxy)[6], + const bool& isforce, + const bool& isstress, + Record_adj* ra, + const double& factor_force, + const double& factor_stress) + { + ModuleBase::TITLE("Force_LCAO", "cal_pulay_fs_center2"); + ModuleBase::timer::tick("Force_LCAO", "cal_pulay_fs_center2"); + + const int nspin = PARAM.inp.nspin; + const int nlocal = PARAM.globalv.nlocal; + + for (int i = 0; i < nlocal; ++i) + { + const int iat = ucell.iwt2iat[i]; + for (int j = 0; j < nlocal; ++j) + { + const int mu = pv.global2local_row(j); + const int nu = pv.global2local_col(i); + + if (mu >= 0 && nu >= 0) + { + const int index = mu * pv.ncol + nu; + double sum = 0.0; + for (int is = 0; is < nspin; ++is) { sum += dm.get_DMK(is + 1, 0, nu, mu); } + if (isforce) + { + const double sumf = sum * factor_force; + for (int i = 0; i < 3; ++i) { f(iat, i) += sumf * 2.0 * dHSx[i][index]; } + } + if (isstress) + { + const double sums = sum * factor_stress; + int ij = 0; + for (int i = 0; i < 3;++i) { for (int j = i; j < 3; ++j) { s(i, j) += sums * dHSxy[ij++][index]; } } + } + } + } + } + + if (isstress) { StressTools::stress_fill(ucell.lat0, ucell.omega, s); } + + ModuleBase::timer::tick("Force_LCAO", "cal_pulay_fs_center2"); + } + + template<> //multi-k, provided xy + void cal_pulay_fs( + ModuleBase::matrix& f, + ModuleBase::matrix& s, + const elecstate::DensityMatrix, double>& dm, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const double* (&dHSx)[3], + const double* (&dHSxy)[6], + const bool& isforce, + const bool& isstress, + Record_adj* ra, + const double& factor_force, + const double& factor_stress) + { + auto stress_func = [](ModuleBase::matrix& local_s, const double& dm2d1_s, const double** dHSx, const double** dHSxy, const double* dtau, const int& irr) + { + int ij = 0; + for (int i = 0; i < 3; ++i) { for (int j = i; j < 3; ++j) { local_s(i, j) += dm2d1_s * dHSxy[ij++][irr]; } } + }; + cal_pulay_fs(f, s, dm, ucell, pv, dHSx, dHSxy, nullptr, isforce, isstress, ra, factor_force, factor_stress, stress_func); + } + + template<> // multi-k, provided x + void cal_pulay_fs( + ModuleBase::matrix& f, + ModuleBase::matrix& s, + const elecstate::DensityMatrix, double>& dm, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const double* (&dHSx)[3], + const double* dtau, + const bool& isforce, + const bool& isstress, + Record_adj* ra, + const double& factor_force, + const double& factor_stress) + { + auto stress_func = [](ModuleBase::matrix& local_s, const double& dm2d1_s, const double** dHSx, const double** dHSxy, const double* dtau, const int& irr) + { + for (int i = 0; i < 3; ++i) { for (int j = i; j < 3; ++j) { local_s(i, j) += dm2d1_s * dHSx[i][irr] * dtau[irr * 3 + j]; } } + }; + cal_pulay_fs(f, s, dm, ucell, pv, dHSx, nullptr, dtau, isforce, isstress, ra, factor_force, factor_stress, stress_func); + } + +} \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2_template.hpp b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2_template.hpp new file mode 100644 index 00000000000..e0eedffaadc --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_center2_template.hpp @@ -0,0 +1,128 @@ +#pragma once +#include "pulay_force_stress.h" +#include "module_base/timer.h" +#include "module_parameter/parameter.h" +namespace PulayForceStress +{ + // common kernel + template + inline void cal_pulay_fs( + ModuleBase::matrix& f, + ModuleBase::matrix& s, + const elecstate::DensityMatrix& dm, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const double** dHSx, + const double** dHSxy, + const double* dtau, + const bool& isforce, + const bool& isstress, + Record_adj* ra, + const double& factor_force, + const double& factor_stress, + Tfunc& stress_func) + { + ModuleBase::TITLE("Force_LCAO", "cal_pulay_fs_center2"); + ModuleBase::timer::tick("Force_LCAO", "cal_pulay_fs_center2"); + + const int nspin_DMR = (PARAM.inp.nspin == 2) ? 2 : 1; + int total_irr = 0; +#ifdef _OPENMP +#pragma omp parallel + { + int num_threads = omp_get_num_threads(); + ModuleBase::matrix local_s(3, 3); + int local_total_irr = 0; +#else + ModuleBase::matrix& local_s = s; + int& local_total_irr = total_irr; +#endif + +#ifdef _OPENMP +#pragma omp for schedule(dynamic) +#endif + for (int iat = 0; iat < ucell.nat; iat++) + { + const int T1 = ucell.iat2it[iat]; + Atom* atom1 = &ucell.atoms[T1]; + const int I1 = ucell.iat2ia[iat]; + // get iat1 + int iat1 = ucell.itia2iat(T1, I1); + double* f_iat; + if (isforce) { f_iat = &f(iat, 0); } +#ifdef _OPENMP + // using local stack to avoid false sharing in multi-threaded case + double f_tmp[3] = { 0.0, 0.0, 0.0 }; + if (num_threads > 1) { f_iat = f_tmp; } +#endif + int irr = pv.nlocstart[iat]; + const int start1 = ucell.itiaiw2iwt(T1, I1, 0); + for (int cb = 0; cb < ra->na_each[iat]; ++cb) + { + const int T2 = ra->info[iat][cb][3]; + const int I2 = ra->info[iat][cb][4]; + const int start2 = ucell.itiaiw2iwt(T2, I2, 0); + Atom* atom2 = &ucell.atoms[T2]; + // get iat2 + int iat2 = ucell.itia2iat(T2, I2); + double Rx = ra->info[iat][cb][0]; + double Ry = ra->info[iat][cb][1]; + double Rz = ra->info[iat][cb][2]; + // get BaseMatrix + if (pv.get_row_size(iat1) <= 0 || pv.get_col_size(iat2) <= 0) { continue; } + std::vector*> tmp_matrix; + for (int is = 0; is < nspin_DMR; ++is) + { + tmp_matrix.push_back(dm.get_DMR_pointer(is + 1)->find_matrix(iat1, iat2, Rx, Ry, Rz)); + } + for (int mu = 0; mu < pv.get_row_size(iat1); ++mu) + { + for (int nu = 0; nu < pv.get_col_size(iat2); ++nu) + { + // the DMR should not be summed over spin, do the summation here + double dm2d1 = 0.0; + for (int is = 0; is < nspin_DMR; ++is) { dm2d1 += tmp_matrix[is]->get_value(mu, nu); } + double dm2d2 = 2.0 * dm2d1; + if (isforce) + { + const double dm2d2_f = dm2d2 * factor_force; + for (int i = 0; i < 3; ++i) { f_iat[i] += dm2d2_f * dHSx[i][irr]; } + } + if (isstress) + { + const double dm2d1_s = dm2d1 * factor_stress; + stress_func(local_s, dm2d1_s, dHSx, dHSxy, dtau, irr); + } + ++local_total_irr; + ++irr; + } + } + } +#ifdef _OPENMP + if (isforce && num_threads > 1) { for (int i = 0; i < 3; ++i) { f(iat, i) += f_iat[i]; } } +#endif + } // end iat +#ifdef _OPENMP +#pragma omp critical(cal_foverlap_k_reduce) + { + total_irr += local_total_irr; + if (isstress) + { + for (int i = 0; i < 3; ++i) { for (int j = i; j < 3; ++j) { s(i, j) += local_s(i, j); } } + } + } + } +#endif + + if (total_irr != pv.nnr) + { + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "wrong irr", total_irr); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "wrong pv.nnr", pv.nnr); + ModuleBase::WARNING_QUIT("Force_LCAO::cal_pulay_fs_center2", "irr!=pv.nnr"); + } + + if (isstress) { StressTools::stress_fill(ucell.lat0, ucell.omega, s); } + + ModuleBase::timer::tick("Force_LCAO", "cal_pulay_fs_center2"); + } +} diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_gint.hpp b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_gint.hpp new file mode 100644 index 00000000000..feb567eca2b --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/pulay_force_stress_gint.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "pulay_force_stress.h" +#include "module_hamilt_lcao/hamilt_lcaodft/stress_tools.h" +#include "module_hamilt_general/module_xc/xc_functional.h" +#include "module_parameter/parameter.h" +namespace PulayForceStress +{ + template + void cal_pulay_fs( + ModuleBase::matrix& f, ///< [out] force + ModuleBase::matrix& s, ///< [out] stress + const elecstate::DensityMatrix& dm, ///< [in] density matrix + const UnitCell& ucell, ///< [in] unit cell + const elecstate::Potential* pot, ///< [in] potential on grid + typename TGint::type& gint, + const bool& isforce, + const bool& isstress, + const bool& set_dmr_gint) + { + if (set_dmr_gint) { gint.transfer_DM2DtoGrid(dm.get_DMR_vector()); } // 2d block to grid + const int nspin = PARAM.inp.nspin; + for (int is = 0; is < nspin; ++is) + { + const double* vr_eff1 = pot->get_effective_v(is); + const double* vofk_eff1 = nullptr; + if (XC_Functional::get_func_type() == 3 || XC_Functional::get_func_type() == 5) + { + vofk_eff1 = pot->get_effective_vofk(is); + Gint_inout inout(is, vr_eff1, vofk_eff1, isforce, isstress, &f, &s, Gint_Tools::job_type::force_meta); + gint.cal_gint(&inout); + } + else + { + Gint_inout inout(is, vr_eff1, isforce, isstress, &f, &s, Gint_Tools::job_type::force); + gint.cal_gint(&inout); + } + } + if (isstress) { StressTools::stress_fill(-1.0, ucell.omega, s); } + } +} \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/spar_u.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/spar_u.cpp index f8f886688a4..4515ea185c0 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/spar_u.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/spar_u.cpp @@ -76,12 +76,12 @@ void sparse_format::cal_HR_dftu( GlobalC::dftu.cal_eff_pot_mat_R_double(current_spin, SR_tmp, HR_tmp); - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { ir = pv.global2local_row(i); if (ir >= 0) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { ic = pv.global2local_col(j); if (ic >= 0) @@ -196,12 +196,12 @@ void sparse_format::cal_HR_dftu_soc( GlobalC::dftu.cal_eff_pot_mat_R_complex_double(current_spin, SR_soc_tmp, HR_soc_tmp); - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { ir = pv.global2local_row(i); if (ir >= 0) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { ic = pv.global2local_col(j); if (ic >= 0) diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.cpp new file mode 100644 index 00000000000..9a62eae1a5b --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.cpp @@ -0,0 +1,20 @@ +#include "stress_tools.h" +namespace StressTools +{ +void stress_fill(const double& lat0_, const double& omega_, ModuleBase::matrix& stress_matrix) +{ + assert(omega_ > 0.0); + double weight = lat0_ / omega_; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + if (j > i) + { + stress_matrix(j, i) = stress_matrix(i, j); + } + stress_matrix(i, j) *= weight; + } + } +} +} // namespace StressTools \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.h b/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.h new file mode 100644 index 00000000000..4ae6ed31ee1 --- /dev/null +++ b/source/module_hamilt_lcao/hamilt_lcaodft/stress_tools.h @@ -0,0 +1,8 @@ +#pragma once +#include "module_base/matrix.h" +// this namespace used to store global function for some stress operation +namespace StressTools +{ +// set upper matrix to whole matrix +void stress_fill(const double& lat0_, const double& omega_, ModuleBase::matrix& stress_matrix); +} // namespace StressTools \ No newline at end of file diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.cpp b/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.cpp index 5d4917d9e0f..db06c13f3a0 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.cpp +++ b/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.cpp @@ -452,7 +452,7 @@ void Wavefunc_in_pw::produce_local_basis_in_pw(const int& ik, delete[] sk; } // end for ia } // end for it - assert(iwall == GlobalV::NLOCAL); + assert(iwall == PARAM.globalv.nlocal); delete[] flq; delete[] aux; delete[] chiaux; diff --git a/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.h b/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.h index e716483b576..b513b16e9f6 100644 --- a/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.h +++ b/source/module_hamilt_lcao/hamilt_lcaodft/wavefunc_in_pw.h @@ -20,6 +20,15 @@ namespace Wavefunc_in_pw std::vector &orbital_files, ModuleBase::realArray &table_local); + void make_table_q( + const std::vector>> &orb_in, + ModuleBase::realArray &table_local); // used for exx abfs + + void write_table_local( + const ModuleBase::realArray &table_local, + std::string &filename + ); + void integral( const int meshr, // number of mesh points const double *psir, diff --git a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_interface.cpp b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_interface.cpp index a95ab763a0a..8b10d55d415 100644 --- a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_interface.cpp +++ b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_interface.cpp @@ -54,7 +54,7 @@ void LCAO_Deepks_Interface::out_deepks_labels(const double& etot, if (PARAM.inp.deepks_bandgap) { - const int nocc = GlobalV::nelec / 2; + const int nocc = PARAM.inp.nelec / 2; ModuleBase::matrix deepks_bands; deepks_bands.create(nks, 1); for (int iks = 0; iks < nks; ++iks) @@ -72,7 +72,7 @@ void LCAO_Deepks_Interface::out_deepks_labels(const double& etot, if (PARAM.inp.deepks_scf) { ModuleBase::matrix wg_hl; - wg_hl.create(nspin, GlobalV::NBANDS); + wg_hl.create(nspin, PARAM.inp.nbands); std::vector> dm_bandgap_gamma; @@ -275,7 +275,7 @@ void LCAO_Deepks_Interface::out_deepks_labels(const double& etot, if (PARAM.inp.deepks_bandgap) { - int nocc = GlobalV::nelec / 2; + int nocc = PARAM.inp.nelec / 2; ModuleBase::matrix deepks_bands; deepks_bands.create(nks, 1); for (int iks = 0; iks < nks; iks++) @@ -291,9 +291,9 @@ void LCAO_Deepks_Interface::out_deepks_labels(const double& etot, if (PARAM.inp.deepks_scf) { - int nocc = GlobalV::nelec / 2; + int nocc = PARAM.inp.nelec / 2; ModuleBase::matrix wg_hl; - wg_hl.create(nks, GlobalV::NBANDS); + wg_hl.create(nks, PARAM.inp.nbands); std::vector> dm_bandgap_k; dm_bandgap_k.resize(1); diff --git a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_odelta.cpp b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_odelta.cpp index e51f8a66d33..7f9885d76fd 100644 --- a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_odelta.cpp +++ b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_odelta.cpp @@ -19,9 +19,9 @@ void LCAO_Deepks::cal_o_delta(const std::vector> this->o_delta.zero_out(); for (int hl = 0; hl < 1; ++hl) { - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { const int mu = pv->global2local_row(j); const int nu = pv->global2local_col(i); @@ -54,9 +54,9 @@ void LCAO_Deepks::cal_o_delta_k(const std::vector o_delta_k=std::complex(0.0,0.0); - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { const int mu = pv->global2local_row(j); const int nu = pv->global2local_col(i); diff --git a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_vdelta.cpp b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_vdelta.cpp index 90b46877789..459ff5c10d8 100644 --- a/source/module_hamilt_lcao/module_deepks/LCAO_deepks_vdelta.cpp +++ b/source/module_hamilt_lcao/module_deepks/LCAO_deepks_vdelta.cpp @@ -22,9 +22,9 @@ void LCAO_Deepks::cal_e_delta_band(const std::vector>& dm) { ModuleBase::TITLE("LCAO_Deepks", "cal_e_delta_band"); this->e_delta_band = 0; - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { const int mu = pv->global2local_row(j); const int nu = pv->global2local_col(i); @@ -54,9 +54,9 @@ void LCAO_Deepks::cal_e_delta_band_k(const std::vector e_delta_band_k=std::complex(0.0,0.0); - for (int i = 0; i < GlobalV::NLOCAL; ++i) + for (int i = 0; i < PARAM.globalv.nlocal; ++i) { - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { const int mu = pv->global2local_row(j); const int nu = pv->global2local_col(i); diff --git a/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test.cpp b/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test.cpp index 59f2a540948..010da2073dc 100644 --- a/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test.cpp +++ b/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test.cpp @@ -45,11 +45,11 @@ void test_deepks::read_dm() { std::ifstream ifs("dm"); dm.resize(1); - dm[0].create(GlobalV::NLOCAL, GlobalV::NLOCAL); + dm[0].create(PARAM.sys.nlocal, PARAM.sys.nlocal); - for (int mu = 0; mu < GlobalV::NLOCAL; mu++) + for (int mu = 0; mu < PARAM.sys.nlocal; mu++) { - for (int nu = 0; nu < GlobalV::NLOCAL; nu++) + for (int nu = 0; nu < PARAM.sys.nlocal; nu++) { double c; ifs >> c; @@ -67,11 +67,11 @@ void test_deepks::read_dm_k(const int nks) ss.str(""); ss << "dm_" << ik; std::ifstream ifs(ss.str().c_str()); - dm_k[ik].create(GlobalV::NLOCAL, GlobalV::NLOCAL); + dm_k[ik].create(PARAM.sys.nlocal, PARAM.sys.nlocal); - for (int mu = 0; mu < GlobalV::NLOCAL; mu++) + for (int mu = 0; mu < PARAM.sys.nlocal; mu++) { - for (int nu = 0; nu < GlobalV::NLOCAL; nu++) + for (int nu = 0; nu < PARAM.sys.nlocal; nu++) { std::complex c; ifs >> c; diff --git a/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test_prep.cpp b/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test_prep.cpp index 593f628464d..f97e26a0ea8 100644 --- a/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test_prep.cpp +++ b/source/module_hamilt_lcao/module_deepks/test/LCAO_deepks_test_prep.cpp @@ -16,7 +16,7 @@ void test_deepks::preparation() this->set_orbs(ucell.lat0); this->prep_neighbour(); - this->ParaO.set_serial(GlobalV::NLOCAL, GlobalV::NLOCAL); + this->ParaO.set_serial(PARAM.sys.nlocal, PARAM.sys.nlocal); } void test_deepks::set_parameters() diff --git a/source/module_hamilt_lcao/module_deltaspin/cal_mw_from_lambda.cpp b/source/module_hamilt_lcao/module_deltaspin/cal_mw_from_lambda.cpp index 4c5d5ab5350..bda9ce7ebdf 100644 --- a/source/module_hamilt_lcao/module_deltaspin/cal_mw_from_lambda.cpp +++ b/source/module_hamilt_lcao/module_deltaspin/cal_mw_from_lambda.cpp @@ -13,7 +13,7 @@ void SpinConstrain, base_device::DEVICE_CPU>::cal_mw_from_l // diagonalization without update charge hsolver::HSolverLCAO> hsolver_lcao_obj(this->ParaV, this->KS_SOLVER); - hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, this->KS_SOLVER, true); + hsolver_lcao_obj.solve(this->p_hamilt, this->psi[0], this->pelec, true); elecstate::ElecStateLCAO>* pelec_lcao = dynamic_cast>*>(this->pelec); diff --git a/source/module_hamilt_lcao/module_deltaspin/test/prepare_unitcell.h b/source/module_hamilt_lcao/module_deltaspin/test/prepare_unitcell.h index aa8221a8fe0..ec95f740871 100644 --- a/source/module_hamilt_lcao/module_deltaspin/test/prepare_unitcell.h +++ b/source/module_hamilt_lcao/module_deltaspin/test/prepare_unitcell.h @@ -232,8 +232,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(const UcellTestPrepare &utp): diff --git a/source/module_hamilt_lcao/module_dftu/dftu.cpp b/source/module_hamilt_lcao/module_dftu/dftu.cpp index d3a6e09dc0d..5bae2551220 100644 --- a/source/module_hamilt_lcao/module_dftu/dftu.cpp +++ b/source/module_hamilt_lcao/module_dftu/dftu.cpp @@ -57,7 +57,7 @@ void DFTU::init(UnitCell& cell, // unitcell class // needs reconstructions in future // global parameters, need to be removed in future const int npol = PARAM.globalv.npol; // number of polarization directions - const int nlocal = GlobalV::NLOCAL; // number of total local orbitals + const int nlocal = PARAM.globalv.nlocal; // number of total local orbitals const int nspin = PARAM.inp.nspin; // number of spins this->EU = 0.0; diff --git a/source/module_hamilt_lcao/module_dftu/dftu_force.cpp b/source/module_hamilt_lcao/module_dftu/dftu_force.cpp index 15d9d029021..89ac1b81922 100644 --- a/source/module_hamilt_lcao/module_dftu/dftu_force.cpp +++ b/source/module_hamilt_lcao/module_dftu/dftu_force.cpp @@ -81,7 +81,7 @@ void DFTU::force_stress(const elecstate::ElecState* pelec, ModuleBase::TITLE("DFTU", "force_stress"); ModuleBase::timer::tick("DFTU", "force_stress"); - const int nlocal = GlobalV::NLOCAL; + const int nlocal = PARAM.globalv.nlocal; if (PARAM.inp.cal_force) { @@ -272,9 +272,9 @@ void DFTU::cal_force_k(ForceStressArrays& fsr, #ifdef __MPI pzgemm_(&transN, &transC, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one, &dSm_k[0], &one_int, @@ -310,9 +310,9 @@ void DFTU::cal_force_k(ForceStressArrays& fsr, #ifdef __MPI pzgemm_(&transN, &transN, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one, &dSm_k[0], &one_int, @@ -384,7 +384,7 @@ void DFTU::cal_stress_k(ForceStressArrays& fsr, ModuleBase::TITLE("DFTU", "cal_stress_k"); ModuleBase::timer::tick("DFTU", "cal_stress_k"); - const int nlocal = GlobalV::NLOCAL; + const int nlocal = PARAM.globalv.nlocal; const char transN = 'N'; const int one_int = 1; @@ -483,9 +483,9 @@ void DFTU::cal_force_gamma(const double* rho_VU, #ifdef __MPI pdgemm_(&transN, &transT, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one, tmp_ptr, &one_int, @@ -521,9 +521,9 @@ void DFTU::cal_force_gamma(const double* rho_VU, #ifdef __MPI pdgemm_(&transN, &transT, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one, tmp_ptr, &one_int, @@ -610,7 +610,7 @@ void DFTU::cal_stress_gamma(const UnitCell& ucell, std::vector dSR_gamma(pv.nloc); std::vector dm_VU_sover(pv.nloc); - const int nlocal = GlobalV::NLOCAL; + const int nlocal = PARAM.globalv.nlocal; for (int dim1 = 0; dim1 < 3; dim1++) { diff --git a/source/module_hamilt_lcao/module_dftu/dftu_hamilt.cpp b/source/module_hamilt_lcao/module_dftu/dftu_hamilt.cpp index 717dcb853c5..c350aef5298 100644 --- a/source/module_hamilt_lcao/module_dftu/dftu_hamilt.cpp +++ b/source/module_hamilt_lcao/module_dftu/dftu_hamilt.cpp @@ -1,5 +1,6 @@ #include "dftu.h" #include "module_base/scalapack_connector.h" +#include "module_parameter/parameter.h" #include "module_base/timer.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" @@ -34,7 +35,7 @@ void DFTU::cal_eff_pot_mat_complex(const int ik, std::complex* eff_pot, #ifdef __MPI pzgemm_(&transN, &transN, - &GlobalV::NLOCAL, &GlobalV::NLOCAL, &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &half, ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), &one_int, &one_int, this->paraV->desc, sk, &one_int, &one_int, this->paraV->desc, @@ -46,7 +47,7 @@ void DFTU::cal_eff_pot_mat_complex(const int ik, std::complex* eff_pot, VU[irc] = eff_pot[irc]; #ifdef __MPI - pztranc_(&GlobalV::NLOCAL, &GlobalV::NLOCAL, + pztranc_(&PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &one, &VU[0], &one_int, &one_int, this->paraV->desc, &one, @@ -83,7 +84,7 @@ void DFTU::cal_eff_pot_mat_real(const int ik, double* eff_pot, const std::vector #ifdef __MPI pdgemm_(&transN, &transN, - &GlobalV::NLOCAL, &GlobalV::NLOCAL, &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &half, ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), &one_int, &one_int, this->paraV->desc, sk, &one_int, &one_int, this->paraV->desc, @@ -95,7 +96,7 @@ void DFTU::cal_eff_pot_mat_real(const int ik, double* eff_pot, const std::vector VU[irc] = eff_pot[irc]; #ifdef __MPI - pdtran_(&GlobalV::NLOCAL, &GlobalV::NLOCAL, + pdtran_(&PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &one, &VU[0], &one_int, &one_int, const_cast(this->paraV->desc), &one, @@ -117,7 +118,7 @@ void DFTU::cal_eff_pot_mat_R_double(const int ispin, double* SR, double* HR) #ifdef __MPI pdgemm_(&transN, &transN, - &GlobalV::NLOCAL, &GlobalV::NLOCAL, &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &half, ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), &one_int, &one_int, this->paraV->desc, SR, &one_int, &one_int, this->paraV->desc, @@ -125,7 +126,7 @@ void DFTU::cal_eff_pot_mat_R_double(const int ispin, double* SR, double* HR) HR, &one_int, &one_int, this->paraV->desc); pdgemm_(&transN, &transN, - &GlobalV::NLOCAL, &GlobalV::NLOCAL, &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &half, SR, &one_int, &one_int, this->paraV->desc, ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), &one_int, &one_int, this->paraV->desc, @@ -147,7 +148,7 @@ void DFTU::cal_eff_pot_mat_R_complex_double(const int ispin, std::complexparaV->desc, SR, &one_int, &one_int, this->paraV->desc, @@ -155,7 +156,7 @@ void DFTU::cal_eff_pot_mat_R_complex_double(const int ispin, std::complexparaV->desc); pzgemm_(&transN, &transN, - &GlobalV::NLOCAL, &GlobalV::NLOCAL, &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &PARAM.globalv.nlocal, &half, SR, &one_int, &one_int, this->paraV->desc, ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), &one_int, &one_int, this->paraV->desc, diff --git a/source/module_hamilt_lcao/module_dftu/dftu_occup.cpp b/source/module_hamilt_lcao/module_dftu/dftu_occup.cpp index 8e3b2ee2063..396fd7355f1 100644 --- a/source/module_hamilt_lcao/module_dftu/dftu_occup.cpp +++ b/source/module_hamilt_lcao/module_dftu/dftu_occup.cpp @@ -175,9 +175,9 @@ void DFTU::cal_occup_m_k(const int iter, #ifdef __MPI pzgemm_(&transN, &transT, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &alpha, s_k_pointer, &one_int, @@ -376,9 +376,9 @@ void DFTU::cal_occup_m_gamma(const int iter, const std::vectorgridt->max_atom > 0) { #ifdef __CUDA - if (PARAM.globalv.device_flag == "gpu" + if (PARAM.inp.device == "gpu" && (inout->job == Gint_Tools::job_type::vlocal || inout->job == Gint_Tools::job_type::rho || inout->job == Gint_Tools::job_type::force)) { @@ -133,15 +133,15 @@ void Gint::prep_grid(const Grid_Technique& gt, return; } -void Gint::initialize_pvpR(const UnitCell& ucell_in, Grid_Driver* gd) { +void Gint::initialize_pvpR(const UnitCell& ucell_in, Grid_Driver* gd, const int& nspin) { ModuleBase::TITLE("Gint", "initialize_pvpR"); int npol = 1; // there is the only resize code of DMRGint if (this->DMRGint.size() == 0) { - this->DMRGint.resize(PARAM.inp.nspin); + this->DMRGint.resize(nspin); } - if (PARAM.inp.nspin != 4) { + if (nspin != 4) { if (this->hRGint != nullptr) { delete this->hRGint; } @@ -153,7 +153,7 @@ void Gint::initialize_pvpR(const UnitCell& ucell_in, Grid_Driver* gd) { } this->hRGintCd = new hamilt::HContainer>(ucell_in.nat); - for (int is = 0; is < PARAM.inp.nspin; is++) { + for (int is = 0; is < nspin; is++) { if (this->DMRGint[is] != nullptr) { delete this->DMRGint[is]; } @@ -186,7 +186,7 @@ void Gint::initialize_pvpR(const UnitCell& ucell_in, Grid_Driver* gd) { } } - if (PARAM.globalv.gamma_only_local && PARAM.inp.nspin != 4) { + if (PARAM.globalv.gamma_only_local && nspin != 4) { this->hRGint->fix_gamma(); } for (int T1 = 0; T1 < ucell_in.ntype; ++T1) { @@ -321,6 +321,26 @@ void Gint::initialize_pvpR(const UnitCell& ucell_in, Grid_Driver* gd) { } } +void Gint::reset_DMRGint(const int& nspin) +{ + if (this->hRGint) + { + for (auto& d : this->DMRGint) { delete d; } + this->DMRGint.resize(nspin); + this->DMRGint.shrink_to_fit(); + for (auto& d : this->DMRGint) { d = new hamilt::HContainer(*this->hRGint); } + if (nspin == 4) + { + for (auto& d : this->DMRGint) { d->allocate(nullptr, false); } +#ifdef __MPI + delete this->DMRGint_full; + this->DMRGint_full = new hamilt::HContainer(*this->hRGint); + this->DMRGint_full->allocate(nullptr, false); +#endif + } + } +} + void Gint::transfer_DM2DtoGrid(std::vector*> DM2D) { ModuleBase::TITLE("Gint", "transfer_DMR"); diff --git a/source/module_hamilt_lcao/module_gint/gint.h b/source/module_hamilt_lcao/module_gint/gint.h index dddb11be88b..6be8adbc20d 100644 --- a/source/module_hamilt_lcao/module_gint/gint.h +++ b/source/module_hamilt_lcao/module_gint/gint.h @@ -49,7 +49,12 @@ class Gint { * @brief calculate the neighbor atoms of each atom in this processor * size of BaseMatrix with be the non-parallel version */ - void initialize_pvpR(const UnitCell& unitcell, Grid_Driver* gd); + void initialize_pvpR(const UnitCell& unitcell, Grid_Driver* gd, const int& nspin); + + /** + * @brief resize DMRGint to nspin and reallocate the memory + */ + void reset_DMRGint(const int& nspin); /** * @brief transfer DMR (2D para) to DMR (Grid para) in elecstate_lcao.cpp diff --git a/source/module_hamilt_lcao/module_gint/gint_force_gpu.cu b/source/module_hamilt_lcao/module_gint/gint_force_gpu.cu index 9ab974660f1..ac7f9e89c85 100644 --- a/source/module_hamilt_lcao/module_gint/gint_force_gpu.cu +++ b/source/module_hamilt_lcao/module_gint/gint_force_gpu.cu @@ -31,11 +31,7 @@ void gint_fvl_gpu(const hamilt::HContainer* dm, const Grid_Technique& gridt, const UnitCell& ucell) { -#ifdef __MPI - const int dev_id = base_device::information::set_device_by_rank(); -#else - const int dev_id = 0; -#endif + checkCuda(cudaSetDevice(gridt.dev_id)); // checkCuda(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync)); const int nbzp = gridt.nbzp; @@ -99,7 +95,7 @@ void gint_fvl_gpu(const hamilt::HContainer* dm, { // 20240620 Note that it must be set again here because // cuda's device is not safe in a multi-threaded environment. - checkCuda(cudaSetDevice(dev_id)); + checkCuda(cudaSetDevice(gridt.dev_id)); const int sid = omp_get_thread_num(); int max_m = 0; diff --git a/source/module_hamilt_lcao/module_gint/gint_k_sparse1.cpp b/source/module_hamilt_lcao/module_gint/gint_k_sparse1.cpp index 24caf2e7bab..9f1db918fc2 100644 --- a/source/module_hamilt_lcao/module_gint/gint_k_sparse1.cpp +++ b/source/module_hamilt_lcao/module_gint/gint_k_sparse1.cpp @@ -58,7 +58,7 @@ void Gint_k::distribute_pvdpR_sparseMatrix( // Parallel_Reduce::reduce_pool(minus_nonzero_num, total_R_num); double* tmp = nullptr; - tmp = new double[GlobalV::NLOCAL]; + tmp = new double[PARAM.globalv.nlocal]; count = 0; for (auto& R_coor: HS_Arrays.all_R_coor) @@ -67,9 +67,9 @@ void Gint_k::distribute_pvdpR_sparseMatrix( { auto minus_R_coor = -1 * R_coor; - for (int row = 0; row < GlobalV::NLOCAL; ++row) + for (int row = 0; row < PARAM.globalv.nlocal; ++row) { - ModuleBase::GlobalFunc::ZEROS(tmp, GlobalV::NLOCAL); + ModuleBase::GlobalFunc::ZEROS(tmp, PARAM.globalv.nlocal); auto iter = pvdpR_sparseMatrix.find(R_coor); if (iter != pvdpR_sparseMatrix.end()) @@ -108,11 +108,11 @@ void Gint_k::distribute_pvdpR_sparseMatrix( } } - Parallel_Reduce::reduce_pool(tmp, GlobalV::NLOCAL); + Parallel_Reduce::reduce_pool(tmp, PARAM.globalv.nlocal); if (pv->global2local_row(row) >= 0) { - for (int col = 0; col < GlobalV::NLOCAL; ++col) + for (int col = 0; col < PARAM.globalv.nlocal; ++col) { if (pv->global2local_col(col) >= 0) { @@ -212,7 +212,7 @@ void Gint_k::distribute_pvdpR_soc_sparseMatrix( // Parallel_Reduce::reduce_pool(minus_nonzero_num, total_R_num); std::complex* tmp_soc = nullptr; - tmp_soc = new std::complex[GlobalV::NLOCAL]; + tmp_soc = new std::complex[PARAM.globalv.nlocal]; count = 0; for (auto& R_coor: HS_Arrays.all_R_coor) @@ -221,9 +221,9 @@ void Gint_k::distribute_pvdpR_soc_sparseMatrix( { auto minus_R_coor = -1 * R_coor; - for (int row = 0; row < GlobalV::NLOCAL; ++row) + for (int row = 0; row < PARAM.globalv.nlocal; ++row) { - ModuleBase::GlobalFunc::ZEROS(tmp_soc, GlobalV::NLOCAL); + ModuleBase::GlobalFunc::ZEROS(tmp_soc, PARAM.globalv.nlocal); auto iter = pvdpR_soc_sparseMatrix.find(R_coor); if (iter != pvdpR_soc_sparseMatrix.end()) @@ -261,11 +261,11 @@ void Gint_k::distribute_pvdpR_soc_sparseMatrix( } } - Parallel_Reduce::reduce_pool(tmp_soc, GlobalV::NLOCAL); + Parallel_Reduce::reduce_pool(tmp_soc, PARAM.globalv.nlocal); if (pv->global2local_row(row) >= 0) { - for (int col = 0; col < GlobalV::NLOCAL; ++col) + for (int col = 0; col < PARAM.globalv.nlocal; ++col) { if (pv->global2local_col(col) >= 0) { diff --git a/source/module_hamilt_lcao/module_gint/gint_rho_cpu_interface.cpp b/source/module_hamilt_lcao/module_gint/gint_rho_cpu_interface.cpp index 354de748579..160df1377b5 100644 --- a/source/module_hamilt_lcao/module_gint/gint_rho_cpu_interface.cpp +++ b/source/module_hamilt_lcao/module_gint/gint_rho_cpu_interface.cpp @@ -54,7 +54,7 @@ void Gint::gint_kernel_rho(Gint_inout* inout) { cal_flag.get_ptr_2D(), psir_ylm.get_ptr_2D()); - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < inout->nspin_rho; ++is) { ModuleBase::Array_Pool psir_DM(this->bxyz, LD_pool); ModuleBase::GlobalFunc::ZEROS(psir_DM.get_ptr_1D(), this->bxyz * LD_pool); diff --git a/source/module_hamilt_lcao/module_gint/gint_rho_gpu.cu b/source/module_hamilt_lcao/module_gint/gint_rho_gpu.cu index 2093105c58b..4b18d50438e 100644 --- a/source/module_hamilt_lcao/module_gint/gint_rho_gpu.cu +++ b/source/module_hamilt_lcao/module_gint/gint_rho_gpu.cu @@ -17,11 +17,7 @@ void gint_rho_gpu(const hamilt::HContainer* dm, const UnitCell& ucell, double* rho) { -#ifdef __MPI - const int dev_id = base_device::information::set_device_by_rank(); -#else - const int dev_id = 0; -#endif + checkCuda(cudaSetDevice(gridt.dev_id)); // checkCuda(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync)); const int nbzp = gridt.nbzp; @@ -80,7 +76,7 @@ void gint_rho_gpu(const hamilt::HContainer* dm, // 20240620 Note that it must be set again here because // cuda's device is not safe in a multi-threaded environment. - checkCuda(cudaSetDevice(dev_id)); + checkCuda(cudaSetDevice(gridt.dev_id)); // get stream id const int sid = omp_get_thread_num(); diff --git a/source/module_hamilt_lcao/module_gint/gint_tools.h b/source/module_hamilt_lcao/module_gint/gint_tools.h index cfc0a2da0a3..7466cac2a2c 100644 --- a/source/module_hamilt_lcao/module_gint/gint_tools.h +++ b/source/module_hamilt_lcao/module_gint/gint_tools.h @@ -39,6 +39,7 @@ class Gint_inout bool isforce; bool isstress; int ispin; + int nspin_rho; // usually, but not always, equal to global nspin bool if_symm = false; // if true, use dsymv in gint_kernel_rho; if false, use dgemv. // output @@ -48,10 +49,11 @@ class Gint_inout Gint_Tools::job_type job; // electron density and kin_r, multi-k - Gint_inout(double** rho_in, Gint_Tools::job_type job_in, bool if_symm_in = true) + Gint_inout(double** rho_in, Gint_Tools::job_type job_in, const int& nspin_rho_in, bool if_symm_in = true) { rho = rho_in; job = job_in; + nspin_rho = nspin_rho_in; if_symm = if_symm_in; } @@ -110,15 +112,6 @@ class Gint_inout job = job_in; } - // electron density and kin_r, gamma point - Gint_inout(double*** DM_in, double** rho_in, Gint_Tools::job_type job_in, bool if_symm_in = true) - { - DM = DM_in; - rho = rho_in; - job = job_in; - if_symm = if_symm_in; - } - // vlocal, gamma point Gint_inout(const double* vl_in, Gint_Tools::job_type job_in) { diff --git a/source/module_hamilt_lcao/module_gint/gint_vl_gpu.cu b/source/module_hamilt_lcao/module_gint/gint_vl_gpu.cu index 40d06dd1865..145f37417d9 100644 --- a/source/module_hamilt_lcao/module_gint/gint_vl_gpu.cu +++ b/source/module_hamilt_lcao/module_gint/gint_vl_gpu.cu @@ -29,11 +29,7 @@ void gint_vl_gpu(hamilt::HContainer* hRGint, double* pvpR, const bool is_gamma_only) { -#ifdef __MPI - const int dev_id = base_device::information::set_device_by_rank(); -#else - const int dev_id = 0; -#endif + checkCuda(cudaSetDevice(gridt.dev_id)); // checkCuda(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync)); const int nbzp = gridt.nbzp; const int num_streams = gridt.nstreams; @@ -51,7 +47,8 @@ void gint_vl_gpu(hamilt::HContainer* hRGint, checkCuda(cudaStreamCreate(&streams[i])); } - Cuda_Mem_Wrapper grid_vlocal_g(hRGint->get_nnr(), 1, false); + const int nnrg = is_gamma_only ? hRGint->get_nnr() : gridt.nnrg; + Cuda_Mem_Wrapper grid_vlocal_g(nnrg, 1, false); grid_vlocal_g.memset_device_sync(); Cuda_Mem_Wrapper dr_part(max_atom_per_z * 3, num_streams, true); @@ -81,7 +78,7 @@ void gint_vl_gpu(hamilt::HContainer* hRGint, { // 20240620 Note that it must be set again here because // cuda's device is not safe in a multi-threaded environment. - checkCuda(cudaSetDevice(dev_id)); + checkCuda(cudaSetDevice(gridt.dev_id)); const int sid = omp_get_thread_num(); int max_m = 0; @@ -193,7 +190,7 @@ void gint_vl_gpu(hamilt::HContainer* hRGint, checkCuda(cudaMemcpy( hRGint->get_wrapper(), grid_vlocal_g.get_device_pointer(), - hRGint->get_nnr() * sizeof(double), + nnrg * sizeof(double), cudaMemcpyDeviceToHost)); } else @@ -201,7 +198,7 @@ void gint_vl_gpu(hamilt::HContainer* hRGint, checkCuda(cudaMemcpy( pvpR, grid_vlocal_g.get_device_pointer(), - hRGint->get_nnr() * sizeof(double), + nnrg * sizeof(double), cudaMemcpyDeviceToHost)); } for (int i = 0; i < num_streams; i++) diff --git a/source/module_hamilt_lcao/module_gint/grid_technique.cpp b/source/module_hamilt_lcao/module_gint/grid_technique.cpp index c66c47a24f5..59680ba7e33 100644 --- a/source/module_hamilt_lcao/module_gint/grid_technique.cpp +++ b/source/module_hamilt_lcao/module_gint/grid_technique.cpp @@ -13,7 +13,7 @@ Grid_Technique::Grid_Technique() { allocate_find_R2 = false; #if ((defined __CUDA) /* || (defined __ROCM) */) - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.device == "gpu") { is_malloced = false; } #endif @@ -22,7 +22,7 @@ Grid_Technique::Grid_Technique() { Grid_Technique::~Grid_Technique() { #if ((defined __CUDA) /* || (defined __ROCM) */) - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.device == "gpu") { free_gpu_gint_variables(this->nat); } #endif @@ -118,7 +118,7 @@ void Grid_Technique::set_pbc_grid( this->cal_trace_lo(ucell); #if ((defined __CUDA) /* || (defined __ROCM) */) - if (PARAM.globalv.device_flag == "gpu") { + if (PARAM.inp.device == "gpu") { this->init_gpu_gint_variables(ucell, num_stream); } #endif @@ -485,8 +485,8 @@ void Grid_Technique::cal_trace_lo(const UnitCell& ucell) { // save the atom information in trace_lo, // in fact the trace_lo dimension can be reduced // to ucell.nat, but I think this is another way. - this->trace_lo = std::vector(GlobalV::NLOCAL, -1); - ModuleBase::Memory::record("GT::trace_lo", sizeof(int) * GlobalV::NLOCAL); + this->trace_lo = std::vector(PARAM.globalv.nlocal, -1); + ModuleBase::Memory::record("GT::trace_lo", sizeof(int) * PARAM.globalv.nlocal); this->lnat = 0; this->lgd = 0; @@ -533,7 +533,7 @@ void Grid_Technique::cal_trace_lo(const UnitCell& ucell) { } assert(iw_local == lgd); - assert(iw_all == GlobalV::NLOCAL); + assert(iw_all == PARAM.globalv.nlocal); return; } @@ -562,7 +562,7 @@ int Grid_Technique::find_offset(const int id1, const int id2, const int iat1, co void Grid_Technique::init_gpu_gint_variables(const UnitCell& ucell, const int num_stream) { #ifdef __MPI - base_device::information::set_device_by_rank(); + dev_id = base_device::information::set_device_by_rank(); #endif if (is_malloced) { free_gpu_gint_variables(this->nat); diff --git a/source/module_hamilt_lcao/module_gint/grid_technique.h b/source/module_hamilt_lcao/module_gint/grid_technique.h index ec37922765a..cffcc99aaa4 100644 --- a/source/module_hamilt_lcao/module_gint/grid_technique.h +++ b/source/module_hamilt_lcao/module_gint/grid_technique.h @@ -177,6 +177,7 @@ class Grid_Technique : public Grid_MeshBall { double* rcut_g; double*mcell_pos_g; + int dev_id = 0; int nstreams = 4; // streams[nstreams] // TODO it needs to be implemented through configuration files diff --git a/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt b/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt index d6f58c71822..65db746a84d 100644 --- a/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt +++ b/source/module_hamilt_lcao/module_hcontainer/CMakeLists.txt @@ -1,3 +1,5 @@ +if(ENABLE_LCAO) + list(APPEND objects base_matrix.cpp atom_pair.cpp @@ -22,4 +24,6 @@ IF (BUILD_TESTING) if(ENABLE_MPI) add_subdirectory(test) endif() +endif() + endif() \ No newline at end of file diff --git a/source/module_hamilt_lcao/module_hcontainer/test/prepare_unitcell.h b/source/module_hamilt_lcao/module_hcontainer/test/prepare_unitcell.h index 0fdce8f66bd..70d9eebaea6 100644 --- a/source/module_hamilt_lcao/module_hcontainer/test/prepare_unitcell.h +++ b/source/module_hamilt_lcao/module_hcontainer/test/prepare_unitcell.h @@ -308,8 +308,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_hamilt_lcao/module_tddft/evolve_elec.cpp b/source/module_hamilt_lcao/module_tddft/evolve_elec.cpp index 4ecca906cf3..7be680cfffc 100644 --- a/source/module_hamilt_lcao/module_tddft/evolve_elec.cpp +++ b/source/module_hamilt_lcao/module_tddft/evolve_elec.cpp @@ -36,8 +36,8 @@ void Evolve_elec::solve_psi(const int& istep, int propagator, const int& nks) { - ModuleBase::TITLE("Evolve_elec", "eveolve_psi"); - ModuleBase::timer::tick("Evolve_elec", "evolve_psi"); + ModuleBase::TITLE("Evolve_elec", "solve_psi"); + ModuleBase::timer::tick("Evolve_elec", "solve_psi"); for (int ik = 0; ik < nks; ik++) { @@ -82,7 +82,7 @@ void Evolve_elec::solve_psi(const int& istep, ModuleBase::timer::tick("Efficience", "evolve_k"); } // end k - ModuleBase::timer::tick("Evolve_elec", "evolve_psi"); + ModuleBase::timer::tick("Evolve_elec", "solve_psi"); return; } } // namespace module_tddft \ No newline at end of file diff --git a/source/module_hamilt_lcao/module_tddft/td_velocity.cpp b/source/module_hamilt_lcao/module_tddft/td_velocity.cpp index 5f951384833..a6f8b7b14b2 100644 --- a/source/module_hamilt_lcao/module_tddft/td_velocity.cpp +++ b/source/module_hamilt_lcao/module_tddft/td_velocity.cpp @@ -1,7 +1,7 @@ #include "td_velocity.h" -#include "module_parameter/parameter.h" #include "module_elecstate/potentials/H_TDDFT_pw.h" +#include "module_parameter/parameter.h" bool TD_Velocity::tddft_velocity = false; bool TD_Velocity::out_mat_R = false; @@ -63,7 +63,7 @@ void TD_Velocity::output_cart_At(const std::string& out_dir) // divide by 2.0 to get the atomic unit for (int i = 0; i < 3; i++) { - ofs << std::scientific << std::setprecision(4) << std::setw(15) << cart_At[i] ; + ofs << std::scientific << std::setprecision(4) << std::setw(15) << cart_At[i]; } ofs << std::endl; ofs.close(); @@ -81,7 +81,7 @@ void TD_Velocity::cal_cart_At(const ModuleBase::Vector3& At) else { // transfrom into atomic unit - this->cart_At = At/2.0; + this->cart_At = At / 2.0; } // output the vector potential if needed if (out_vecpot == true) @@ -173,7 +173,8 @@ void TD_Velocity::initialize_current_term(const hamilt::HContainercurrent_term[dir]->allocate(nullptr, true); } - ModuleBase::timer::tick("TDEkinetic", "initialize_HR_tmp"); + + ModuleBase::timer::tick("TD_Velocity", "initialize_current_term"); } void TD_Velocity::destroy_HS_R_td_sparse(void) diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.cpp b/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.cpp index 7ee5d172363..06f253c55c8 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.cpp +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.cpp @@ -47,8 +47,9 @@ double KEDF_LKT::get_energy(const double* const* prho, ModulePW::PW_Basis* pw_rh Parallel_Reduce::reduce_all(this->lkt_energy); delete[] as; - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { delete[] nabla_rho[i]; +} delete[] nabla_rho; return energy; @@ -79,13 +80,46 @@ double KEDF_LKT::get_energy_density(const double* const* prho, int is, int ir, M energy_den = this->c_tf_ * pow(prho[is][ir], 5. / 3.) / std::cosh(as[ir]); delete[] as; - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { delete[] nabla_rho[i]; +} delete[] nabla_rho; return energy_den; } +void KEDF_LKT::tau_lkt(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_lkt) +{ + double* as = new double[pw_rho->nrxx]; // a*s + double** nabla_rho = new double*[3]; + for (int i = 0; i < 3; ++i) + { + nabla_rho[i] = new double[pw_rho->nrxx]; + } + + if (PARAM.inp.nspin == 1) + { + this->nabla(prho[0], pw_rho, nabla_rho); + this->get_as(prho[0], nabla_rho, pw_rho->nrxx, as); + + for (int ir = 0; ir < pw_rho->nrxx; ++ir) + { + double coshas = std::cosh(as[ir]); + rtau_lkt[ir] += std::pow(prho[0][ir], 5. / 3.) / coshas * this->c_tf_; + } + } + else if (PARAM.inp.nspin == 2) + { + // Waiting for update + } + + delete[] as; + for (int i = 0; i < 3; ++i) { + delete[] nabla_rho[i]; +} + delete[] nabla_rho; +} + /** * @brief Get the potential of LKT KEDF, and add it into rpotential, * and the LKT energy will be calculated and stored in this->lkt_energy @@ -153,8 +187,9 @@ void KEDF_LKT::lkt_potential(const double* const* prho, ModulePW::PW_Basis* pw_r } delete[] as; - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { delete[] nabla_rho[i]; +} delete[] nabla_rho; delete[] nabla_term; @@ -227,8 +262,9 @@ void KEDF_LKT::get_stress(const double* const* prho, ModulePW::PW_Basis* pw_rho) } delete[] as; - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { delete[] nabla_rho[i]; +} delete[] nabla_rho; delete[] nabla_term; } diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.h b/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.h index 8ad7c3349eb..6df93bfb33e 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.h +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_lkt.h @@ -1,7 +1,7 @@ #ifndef KEDF_LKT_H #define KEDF_LKT_H -#include -#include +#include +#include #include "module_base/global_function.h" #include "module_base/global_variable.h" @@ -29,6 +29,7 @@ class KEDF_LKT double get_energy(const double* const* prho, ModulePW::PW_Basis* pw_rho); double get_energy_density(const double* const* prho, int is, int ir, ModulePW::PW_Basis* pw_rho); + void tau_lkt(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_lkt); void lkt_potential(const double* const* prho, ModulePW::PW_Basis* pw_rho, ModuleBase::matrix& rpotential); void get_stress(const double* const* prho, ModulePW::PW_Basis* pw_rho); diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.cpp b/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.cpp index fa39db5920f..97c0f65f2fc 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.cpp +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.cpp @@ -62,6 +62,34 @@ double KEDF_TF::get_energy_density(const double* const* prho, int is, int ir) return energyDen; } +/** + * @brief Get the kinetic energy of TF KEDF, and add it onto rtau_tf + * \f[ \tau_{TF} = c_{TF} * \prho^{5/3} \f] + * + * @param prho charge density + * @param rtau_tf rtau_tf => rtau_tf + tau_tf + */ +void KEDF_TF::tau_tf(const double* const* prho, double* rtau_tf) +{ + if (PARAM.inp.nspin == 1) + { + for (int ir = 0; ir < this->nx_; ++ir) + { + rtau_tf[ir] += this->c_tf_ * std::pow(prho[0][ir], 5.0 / 3.0); + } + } + else if (PARAM.inp.nspin == 2) + { + for (int is = 0; is < PARAM.inp.nspin; ++is) + { + for (int ir = 0; ir < this->nx_; ++ir) + { + rtau_tf[ir] += 0.5 * this->c_tf_ * std::pow(2.0 * prho[is][ir], 5.0 / 3.0); + } + } + } +} + /** * @brief Get the potential of TF KEDF, and add it into rpotential, * and the TF energy will be calculated and stored in this->tf_energy diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.h b/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.h index a73af4d3cd7..b9c247cecc9 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.h +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_tf.h @@ -29,6 +29,7 @@ class KEDF_TF double get_energy(const double* const* prho); double get_energy_density(const double* const* prho, int is, int ir); + void tau_tf(const double* const* prho, double* rtau_tf); void tf_potential(const double* const* prho, ModuleBase::matrix& rpotential); void get_stress(double cell_vol); diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.cpp b/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.cpp index cc37c73a7c5..5dc344223b4 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.cpp +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.cpp @@ -33,8 +33,9 @@ double KEDF_vW::get_energy(double** pphi, ModulePW::PW_Basis* pw_rho) } double** LapPhi = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { LapPhi[is] = new double[pw_rho->nrxx]; +} this->laplacian_phi(tempPhi, LapPhi, pw_rho); double energy = 0.; // in Ry @@ -95,8 +96,9 @@ double KEDF_vW::get_energy_density(double** pphi, int is, int ir, ModulePW::PW_B } double** LapPhi = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { LapPhi[is] = new double[pw_rho->nrxx]; +} this->laplacian_phi(tempPhi, LapPhi, pw_rho); double energyDen = 0.; // in Ry @@ -113,6 +115,42 @@ double KEDF_vW::get_energy_density(double** pphi, int is, int ir, ModulePW::PW_B return energyDen; } +/** + * @brief Get the positive definite energy density of vW KEDF + * \f[ \tau_{vW} = |\nabla \rho|^2 / (8 \rho) \f] + * + * @param prho charge density + * @param pw_rho pw basis + * @param rtau_vw rtau_vw => rtau_vw + tau_vw + */ +void KEDF_vW::tau_vw(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_vw) +{ + for (int is = 0; is < PARAM.inp.nspin; ++is) + { + std::vector> nabla_rho(3, std::vector(pw_rho->nrxx, 0.)); + + std::vector> recip_rho(pw_rho->npw, 0.); + std::vector> recip_nabla_rho(pw_rho->npw, 0.); + pw_rho->real2recip(prho[is], recip_rho.data()); + + std::complex img(0.0, 1.0); + for (int j = 0; j < 3; ++j) + { + for (int ip = 0; ip < pw_rho->npw; ++ip) + { + recip_nabla_rho[ip] = img * pw_rho->gcar[ip][j] * recip_rho[ip] * pw_rho->tpiba; + } + + pw_rho->recip2real(recip_nabla_rho.data(), nabla_rho[j].data()); + + for (int ir = 0; ir < pw_rho->nrxx; ++ir) + { + rtau_vw[ir] += nabla_rho[j][ir] * nabla_rho[j][ir] / (8. * prho[is][ir]) * 2.0; // convert Ha to Ry. + } + } + } +} + /** * @brief Get the potential of vW KEDF, and add it into rpotential, * and the vW energy will be calculated and stored in this->vw_energy @@ -141,8 +179,9 @@ void KEDF_vW::vw_potential(const double* const* pphi, ModulePW::PW_Basis* pw_rho // calculate the minus \nabla^2 sqrt(rho) double** LapPhi = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { LapPhi[is] = new double[pw_rho->nrxx]; +} this->laplacian_phi(tempPhi, LapPhi, pw_rho); // calculate potential diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.h b/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.h index cb386512e66..6c883f7e535 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.h +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_vw.h @@ -1,7 +1,7 @@ #ifndef KEDF_vW_H #define KEDF_vW_H -#include -#include +#include +#include #include "module_base/global_function.h" #include "module_base/global_variable.h" @@ -29,6 +29,7 @@ class KEDF_vW double get_energy(double** pphi, ModulePW::PW_Basis* pw_rho); double get_energy_density(double** pphi, int is, int ir, ModulePW::PW_Basis* pw_rho); + void tau_vw(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_vw); void vw_potential(const double* const* pphi, ModulePW::PW_Basis* pw_rho, ModuleBase::matrix& rpotential); void get_stress(const double* const* pphi, ModulePW::PW_Basis* pw_rho); diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.cpp b/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.cpp index 2af9e78623a..312d4a28900 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.cpp +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.cpp @@ -58,11 +58,12 @@ void KEDF_WT::set_para(double dV, delete[] this->kernel_; this->kernel_ = new double[pw_rho->npw]; - if (read_kernel) + if (read_kernel) { this->read_kernel(kernel_file, pw_rho); - else + } else { this->fill_kernel(tf_weight, vw_weight, pw_rho); } +} /** * @brief Get the energy of WT KEDF @@ -75,8 +76,9 @@ void KEDF_WT::set_para(double dV, double KEDF_WT::get_energy(const double* const* prho, ModulePW::PW_Basis* pw_rho) { double** kernelRhoBeta = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { kernelRhoBeta[is] = new double[pw_rho->nrxx]; +} this->multi_kernel(prho, kernelRhoBeta, this->beta_, pw_rho); double energy = 0.; // in Ry @@ -124,8 +126,9 @@ double KEDF_WT::get_energy(const double* const* prho, ModulePW::PW_Basis* pw_rho double KEDF_WT::get_energy_density(const double* const* prho, int is, int ir, ModulePW::PW_Basis* pw_rho) { double** kernelRhoBeta = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { kernelRhoBeta[is] = new double[pw_rho->nrxx]; +} this->multi_kernel(prho, kernelRhoBeta, this->beta_, pw_rho); double result = this->c_tf_ * std::pow(prho[is][ir], this->alpha_) * kernelRhoBeta[is][ir]; @@ -138,6 +141,41 @@ double KEDF_WT::get_energy_density(const double* const* prho, int is, int ir, Mo return result; } +/** + * @brief Get the kinetic energy of WT KEDF, and add it onto rtau_wt + * \f[ \tau_{WT} = c_{TF} * \rho^\alpha * \int{W(r - r') * \rho^\beta dr'} \f] + * + * @param prho charge density + * @param pw_rho pw basis + * @param rtau_wt rtau_wt => rtau_wt + tau_wt + */ +void KEDF_WT::tau_wt(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_wt) +{ + double** kernelRhoBeta = new double*[PARAM.inp.nspin]; + for (int is = 0; is < PARAM.inp.nspin; ++is) { + kernelRhoBeta[is] = new double[pw_rho->nrxx]; +} + this->multi_kernel(prho, kernelRhoBeta, this->beta_, pw_rho); + + if (PARAM.inp.nspin == 1) + { + for (int ir = 0; ir < pw_rho->nrxx; ++ir) + { + rtau_wt[ir] += std::pow(prho[0][ir], this->alpha_) * kernelRhoBeta[0][ir] * this->c_tf_; + } + } + else if (PARAM.inp.nspin == 2) + { + // Waiting for update + } + + for (int is = 0; is < PARAM.inp.nspin; ++is) + { + delete[] kernelRhoBeta[is]; + } + delete[] kernelRhoBeta; +} + /** * @brief Get the potential of WT KEDF, and add it into rpotential, * and the WT energy will be calculated and stored in this->wt_energy @@ -153,13 +191,15 @@ void KEDF_WT::wt_potential(const double* const* prho, ModulePW::PW_Basis* pw_rho ModuleBase::timer::tick("KEDF_WT", "wt_potential"); double** kernelRhoBeta = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { kernelRhoBeta[is] = new double[pw_rho->nrxx]; +} this->multi_kernel(prho, kernelRhoBeta, this->beta_, pw_rho); double** kernelRhoAlpha = new double*[PARAM.inp.nspin]; - for (int is = 0; is < PARAM.inp.nspin; ++is) + for (int is = 0; is < PARAM.inp.nspin; ++is) { kernelRhoAlpha[is] = new double[pw_rho->nrxx]; +} this->multi_kernel(prho, kernelRhoAlpha, this->alpha_, pw_rho); for (int is = 0; is < PARAM.inp.nspin; ++is) @@ -271,8 +311,9 @@ void KEDF_WT::get_stress(const double* const* prho, ModulePW::PW_Basis* pw_rho, else { this->stress(a, b) += -diff * pw_rho->gcar[ip][a] * pw_rho->gcar[ip][b] / pw_rho->gg[ip]; - if (a == b) + if (a == b) { this->stress(a, b) += diff * coef; +} } } } @@ -468,8 +509,9 @@ void KEDF_WT::read_kernel(std::string file_name, ModulePW::PW_Basis* pw_rho) std::ifstream ifs(file_name.c_str(), std::ios::in); GlobalV::ofs_running << "Read WT kernel from " << file_name << std::endl; - if (!ifs) + if (!ifs) { ModuleBase::WARNING_QUIT("kedf_wt.cpp", "The kernel file of WT KEDF not found"); +} int kineType = 0; double kF_in = 0.; @@ -504,11 +546,11 @@ void KEDF_WT::read_kernel(std::string file_name, ModulePW::PW_Basis* pw_rho) eta = sqrt(pw_rho->gg[ig]) * pw_rho->tpiba / this->tkf_; maxEta = std::max(eta, maxEta); - if (eta <= eta_in[0]) + if (eta <= eta_in[0]) { this->kernel_[ig] = w0_in[0]; - else if (eta > maxEta_in) + } else if (eta > maxEta_in) { this->kernel_[ig] = w0_in[nq_in - 1]; - else + } else { ind1 = 1; ind2 = nq_in; @@ -531,8 +573,9 @@ void KEDF_WT::read_kernel(std::string file_name, ModulePW::PW_Basis* pw_rho) } } - if (maxEta > maxEta_in) + if (maxEta > maxEta_in) { ModuleBase::WARNING("kedf_wt.cpp", "Please increase the maximal eta value in KEDF kernel file"); +} delete[] eta_in; delete[] w0_in; diff --git a/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.h b/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.h index dc373997262..a08f08c05e6 100644 --- a/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.h +++ b/source/module_hamilt_pw/hamilt_ofdft/kedf_wt.h @@ -1,7 +1,7 @@ #ifndef KEDF_WT_H #define KEDF_WT_H -#include -#include +#include +#include #include "module_base/global_function.h" #include "module_base/global_variable.h" @@ -40,6 +40,7 @@ class KEDF_WT double get_energy(const double* const* prho, ModulePW::PW_Basis* pw_rho); double get_energy_density(const double* const* prho, int is, int ir, ModulePW::PW_Basis* pw_rho); + void tau_wt(const double* const* prho, ModulePW::PW_Basis* pw_rho, double* rtau_wt); void wt_potential(const double* const* prho, ModulePW::PW_Basis* pw_rho, ModuleBase::matrix& rpotential); void get_stress(const double* const* prho, ModulePW::PW_Basis* pw_rho, double vw_weight); double wt_energy = 0.; diff --git a/source/module_hamilt_pw/hamilt_pwdft/VNL_in_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/VNL_in_pw.cpp index b27b62459ef..1b3f92b60a3 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/VNL_in_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/VNL_in_pw.cpp @@ -32,7 +32,7 @@ void pseudopot_cell_vnl::release_memory() if (this->nhm <= 0 || memory_released) { return; } - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { @@ -153,7 +153,7 @@ void pseudopot_cell_vnl::init(const int ntype, this->deeq_nc.create(PARAM.inp.nspin, GlobalC::ucell.nat, this->nhm, this->nhm); this->qq_nt.create(ntype, this->nhm, this->nhm); this->qq_so.create(ntype, 4, this->nhm, this->nhm); - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { @@ -270,7 +270,7 @@ void pseudopot_cell_vnl::init(const int ntype, ModuleBase::Memory::record("VNL::tab_at", ntype * nchix_nc * PARAM.globalv.nqx * sizeof(double)); } } - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { @@ -464,7 +464,7 @@ void pseudopot_cell_vnl::getvnl(Device* ctx, const int& ik, std::complex { _gk[ig] = this->wfcpw->getgpluskcar(ik, ig); } - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { resmem_int_op()(ctx, atom_nh, GlobalC::ucell.ntype); resmem_int_op()(ctx, atom_nb, GlobalC::ucell.ntype); @@ -721,7 +721,7 @@ void pseudopot_cell_vnl::init_vnl(UnitCell& cell, const ModulePW::PW_Basis* rho_ // g) It computes the qq terms which define the S matrix. // compute Clebsch-Gordan coefficients - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { ModuleBase::Clebsch_Gordan::clebsch_gordan(lmaxkb + 1, ap, lpx, lpl); } @@ -861,7 +861,7 @@ void pseudopot_cell_vnl::init_vnl(UnitCell& cell, const ModulePW::PW_Basis* rho_ delete[] aux; delete[] jl; } - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { @@ -1387,7 +1387,7 @@ void pseudopot_cell_vnl::cal_effective_D(const ModuleBase::matrix& veff, 3. rotate to effective matrix when spin-orbital coupling is used */ - if (!GlobalV::use_uspp) + if (!PARAM.globalv.use_uspp) { for (int iat = 0; iat < cell.nat; iat++) { @@ -1479,7 +1479,7 @@ void pseudopot_cell_vnl::cal_effective_D(const ModuleBase::matrix& veff, } } } - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { if (PARAM.inp.precision == "single") { diff --git a/source/module_hamilt_pw/hamilt_pwdft/elecond.cpp b/source/module_hamilt_pw/hamilt_pwdft/elecond.cpp index 43070182605..f7ac5000d47 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/elecond.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/elecond.cpp @@ -97,7 +97,7 @@ void EleCond::KG(const int& smear_type, const double& fwhmin, const double& wcut void EleCond::jjresponse_ks(const int ik, const int nt, const double dt, const double decut, ModuleBase::matrix& wg, hamilt::Velocity& velop, double* ct11, double* ct12, double* ct22) { - const int nbands = GlobalV::NBANDS; + const int nbands = PARAM.inp.nbands; if (wg(ik, 0) - wg(ik, nbands - 1) < 1e-8 || nbands == 0) { return; } diff --git a/source/module_hamilt_pw/hamilt_pwdft/forces.cpp b/source/module_hamilt_pw/hamilt_pwdft/forces.cpp index 0e7ed6b229e..589fc71009f 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/forces.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/forces.cpp @@ -69,7 +69,7 @@ void Forces::cal_force(ModuleBase::matrix& force, this->npwx = wfc_basis->npwk_max; Forces::cal_force_nl(forcenl, wg, ekb, pkv, wfc_basis, p_sf, &GlobalC::ppcell, GlobalC::ucell, psi_in); - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { this->cal_force_us(forcenl, rho_basis, &GlobalC::ppcell, elec, GlobalC::ucell); } @@ -134,9 +134,9 @@ void Forces::cal_force(ModuleBase::matrix& force, psi_in[0].fix_k(ik); double *weight, *epsilon; - weight = new double[GlobalV::NBANDS]; - epsilon = new double[GlobalV::NBANDS]; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + weight = new double[PARAM.inp.nbands]; + epsilon = new double[PARAM.inp.nbands]; + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { weight[ib] = wg(ik, ib); epsilon[ib] = ekb(ik, ib); @@ -144,7 +144,7 @@ void Forces::cal_force(ModuleBase::matrix& force, GlobalC::paw_cell.paw_nl_force(reinterpret_cast*>(psi_in[0].get_pointer()), epsilon, weight, - GlobalV::NBANDS, + PARAM.inp.nbands, forcenl.c); delete[] weight; diff --git a/source/module_hamilt_pw/hamilt_pwdft/forces_cc.cpp b/source/module_hamilt_pw/hamilt_pwdft/forces_cc.cpp index 4b5e7a2aff0..f2f36620c4b 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/forces_cc.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/forces_cc.cpp @@ -23,6 +23,9 @@ #include "module_cell/module_paw/paw_cell.h" #endif +#ifdef USE_LIBXC +#include "module_hamilt_general/module_xc/xc_functional_libxc.h" +#endif template @@ -56,7 +59,7 @@ void Forces::cal_force_cc(ModuleBase::matrix& forcecc, { #ifdef USE_LIBXC const auto etxc_vtxc_v - = XC_Functional::v_xc_meta(rho_basis->nrxx, ucell_in.omega, ucell_in.tpiba, chr); + = XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), rho_basis->nrxx, ucell_in.omega, ucell_in.tpiba, chr); // etxc = std::get<0>(etxc_vtxc_v); // vtxc = std::get<1>(etxc_vtxc_v); diff --git a/source/module_hamilt_pw/hamilt_pwdft/forces_nl.cpp b/source/module_hamilt_pw/hamilt_pwdft/forces_nl.cpp index 04caefd1bfe..92733745b4f 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/forces_nl.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/forces_nl.cpp @@ -45,7 +45,7 @@ void Forces::cal_force_nl(ModuleBase::matrix& forcenl, break; } } - const int npm = ucell_in.get_npol() * nbands_occ; + const int npm = nbands_occ; // calculate becp = for all beta functions nl_tools.cal_becp(ik, npm); for (int ipol = 0; ipol < 3; ipol++) diff --git a/source/module_hamilt_pw/hamilt_pwdft/fs_nonlocal_tools.cpp b/source/module_hamilt_pw/hamilt_pwdft/fs_nonlocal_tools.cpp index 5e4d54b86f1..4dbdbc558f9 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/fs_nonlocal_tools.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/fs_nonlocal_tools.cpp @@ -32,7 +32,7 @@ FS_Nonlocal_tools::FS_Nonlocal_tools(const pseudopot_cell_vnl* n // There is a contribution for jh<>ih in US case or multi projectors case // Actually, the judge of nondiagonal should be done on every atom type - this->nondiagonal = (GlobalV::use_uspp || this->nlpp_->multi_proj) ? true : false; + this->nondiagonal = (PARAM.globalv.use_uspp || this->nlpp_->multi_proj) ? true : false; // allocate memory this->allocate_memory(wg, ekb); @@ -108,12 +108,6 @@ void FS_Nonlocal_tools::allocate_memory(const ModuleBase::matrix this->atom_na = h_atom_na.data(); this->ppcell_vkb = this->nlpp_->vkb.c; } - - // prepare the memory of the becp and dbecp: - // becp: - // dbecp: - resmem_complex_op()(this->ctx, becp, this->nbands * nkb, "Stress::becp"); - resmem_complex_op()(this->ctx, dbecp, 6 * this->nbands * nkb, "Stress::dbecp"); } template @@ -163,9 +157,12 @@ void FS_Nonlocal_tools::cal_becp(int ik, int npm) { ModuleBase::TITLE("FS_Nonlocal_tools", "cal_becp"); ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_becp"); + const int npol = this->ucell_->get_npol(); + const int size_becp = this->nbands * npol * this->nkb; + const int size_becp_act = npm * npol * this->nkb; if (this->becp == nullptr) { - resmem_complex_op()(this->ctx, becp, this->nbands * this->nkb); + resmem_complex_op()(this->ctx, becp, size_becp); } // prepare math tools @@ -249,11 +246,12 @@ void FS_Nonlocal_tools::cal_becp(int ik, int npm) } const char transa = 'C'; const char transb = 'N'; + int npm_npol = npm * npol; gemm_op()(this->ctx, transa, transb, nkb, - npm, + npm_npol, npw, &ModuleBase::ONE, ppcell_vkb, @@ -268,15 +266,15 @@ void FS_Nonlocal_tools::cal_becp(int ik, int npm) if (this->device == base_device::GpuDevice) { std::complex* h_becp = nullptr; - resmem_complex_h_op()(this->cpu_ctx, h_becp, this->nbands * nkb); - syncmem_complex_d2h_op()(this->cpu_ctx, this->ctx, h_becp, becp, this->nbands * nkb); - Parallel_Reduce::reduce_pool(h_becp, this->nbands * nkb); - syncmem_complex_h2d_op()(this->ctx, this->cpu_ctx, becp, h_becp, this->nbands * nkb); + resmem_complex_h_op()(this->cpu_ctx, h_becp, size_becp_act); + syncmem_complex_d2h_op()(this->cpu_ctx, this->ctx, h_becp, becp, size_becp_act); + Parallel_Reduce::reduce_pool(h_becp, size_becp_act); + syncmem_complex_h2d_op()(this->ctx, this->cpu_ctx, becp, h_becp, size_becp_act); delmem_complex_h_op()(this->cpu_ctx, h_becp); } else { - Parallel_Reduce::reduce_pool(becp, this->nbands * this->nkb); + Parallel_Reduce::reduce_pool(becp, size_becp_act); } ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_becp"); } @@ -287,9 +285,12 @@ void FS_Nonlocal_tools::cal_dbecp_s(int ik, int npm, int ipol, i { ModuleBase::TITLE("FS_Nonlocal_tools", "cal_dbecp_s"); ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_dbecp_s"); + const int npol = this->ucell_->get_npol(); + const int size_becp = this->nbands * npol * this->nkb; + const int npm_npol = npm * npol; if (this->dbecp == nullptr) { - resmem_complex_op()(this->ctx, dbecp, this->nbands * this->nkb); + resmem_complex_op()(this->ctx, dbecp, size_becp); } // prepare math tools @@ -401,7 +402,7 @@ void FS_Nonlocal_tools::cal_dbecp_s(int ik, int npm, int ipol, i transa, transb, nkb, - npm, + npm_npol, npw, &ModuleBase::ONE, ppcell_vkb, @@ -412,43 +413,68 @@ void FS_Nonlocal_tools::cal_dbecp_s(int ik, int npm, int ipol, i dbecp, nkb); // calculate stress for target (ipol, jpol) - const int current_spin = this->kv_->isk[ik]; - cal_stress_nl_op()(this->ctx, - nondiagonal, - ipol, - jpol, - nkb, - npm, - this->ntype, - current_spin, // uspp only - this->nbands, - ik, - this->nlpp_->deeq.getBound2(), - this->nlpp_->deeq.getBound3(), - this->nlpp_->deeq.getBound4(), - atom_nh, - atom_na, - d_wg, - d_ekb, - qq_nt, - deeq, - becp, - dbecp, - stress); + if(npol == 1) + { + const int current_spin = this->kv_->isk[ik]; + cal_stress_nl_op()(this->ctx, + nondiagonal, + ipol, + jpol, + nkb, + npm, + this->ntype, + current_spin, // uspp only + this->nlpp_->deeq.getBound2(), + this->nlpp_->deeq.getBound3(), + this->nlpp_->deeq.getBound4(), + atom_nh, + atom_na, + d_wg + this->nbands * ik, + d_ekb + this->nbands * ik, + qq_nt, + deeq, + becp, + dbecp, + stress); + } + else + { + cal_stress_nl_op()(this->ctx, + ipol, + jpol, + nkb, + npm, + this->ntype, + this->nlpp_->deeq_nc.getBound2(), + this->nlpp_->deeq_nc.getBound3(), + this->nlpp_->deeq_nc.getBound4(), + atom_nh, + atom_na, + d_wg + this->nbands * ik, + d_ekb + this->nbands * ik, + qq_nt, + this->nlpp_->template get_deeq_nc_data(), + becp, + dbecp, + stress); + } ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_dbecp_s"); } template void FS_Nonlocal_tools::cal_dbecp_f(int ik, int npm, int ipol) { - ModuleBase::TITLE("FS_Nonlocal_tools", "cal_dbecp_s"); + ModuleBase::TITLE("FS_Nonlocal_tools", "cal_dbecp_f"); ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_dbecp_f"); + const int npol = this->ucell_->get_npol(); + const int npm_npol = npm * npol; + const int size_becp = this->nbands * npol * this->nkb; if (this->dbecp == nullptr) { - resmem_complex_op()(this->ctx, dbecp, 3 * this->nbands * this->nkb); + resmem_complex_op()(this->ctx, dbecp, 3 * size_becp); } - std::complex* dbecp_ptr = this->dbecp + ipol * this->nbands * this->nkb; + std::complex* dbecp_ptr = this->dbecp + ipol * size_becp; const std::complex* vkb_ptr = this->ppcell_vkb; std::complex* vkb_deri_ptr = this->ppcell_vkb; @@ -481,7 +507,7 @@ void FS_Nonlocal_tools::cal_dbecp_f(int ik, int npm, int ipol) transa, transb, this->nkb, - npm, + npm_npol, npw, &ModuleBase::ONE, vkb_deri_ptr, @@ -491,7 +517,6 @@ void FS_Nonlocal_tools::cal_dbecp_f(int ik, int npm, int ipol) &ModuleBase::ZERO, dbecp_ptr, nkb); - this->revert_vkb(npw, ipol); this->pre_ik_f = ik; ModuleBase::timer::tick("FS_Nonlocal_tools", "cal_dbecp_f"); @@ -634,29 +659,52 @@ void FS_Nonlocal_tools::cal_force(int ik, int npm, FPTYPE* force const int current_spin = this->kv_->isk[ik]; const int force_nc = 3; // calculate the force - cal_force_nl_op()(this->ctx, - nondiagonal, - npm, - this->nbands, - this->ntype, - current_spin, - this->nlpp_->deeq.getBound2(), - this->nlpp_->deeq.getBound3(), - this->nlpp_->deeq.getBound4(), - force_nc, - this->nbands, - ik, - nkb, - atom_nh, - atom_na, - this->ucell_->tpiba, - d_wg, - d_ekb, - qq_nt, - deeq, - becp, - dbecp, - force); + if(this->ucell_->get_npol() == 1) + { + cal_force_nl_op()(this->ctx, + nondiagonal, + npm, + this->ntype, + current_spin, + this->nlpp_->deeq.getBound2(), + this->nlpp_->deeq.getBound3(), + this->nlpp_->deeq.getBound4(), + force_nc, + this->nbands, + nkb, + atom_nh, + atom_na, + this->ucell_->tpiba, + d_wg + this->nbands * ik, + d_ekb + this->nbands * ik, + qq_nt, + deeq, + becp, + dbecp, + force); + } + else + { + cal_force_nl_op()(this->ctx, + npm, + this->ntype, + this->nlpp_->deeq_nc.getBound2(), + this->nlpp_->deeq_nc.getBound3(), + this->nlpp_->deeq_nc.getBound4(), + force_nc, + this->nbands, + nkb, + atom_nh, + atom_na, + this->ucell_->tpiba, + d_wg + this->nbands * ik, + d_ekb + this->nbands * ik, + qq_nt, + this->nlpp_->template get_deeq_nc_data(), + becp, + dbecp, + force); + } } // template instantiation diff --git a/source/module_hamilt_pw/hamilt_pwdft/hamilt_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/hamilt_pw.cpp index 725591c9904..db877bac07c 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/hamilt_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/hamilt_pw.cpp @@ -225,7 +225,7 @@ void HamiltPW::sPsi(const T* psi_in, // psi } syncmem_op()(this->ctx, this->ctx, spsi, psi_in, static_cast(nbands * nrow)); - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { T* becp = nullptr; T* ps = nullptr; diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/ekinetic_op.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/ekinetic_op.cu index 46b1b5af213..c7b34c2d4a1 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/ekinetic_op.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/ekinetic_op.cu @@ -13,6 +13,7 @@ template __global__ void ekinetic_pw( const int npw, const int max_npw, + const bool is_first_node, const FPTYPE tpiba2, const FPTYPE* gk2, thrust::complex* hpsi, @@ -20,9 +21,24 @@ __global__ void ekinetic_pw( { const int block_idx = blockIdx.x; const int thread_idx = threadIdx.x; - for (int ii = thread_idx; ii < npw; ii+= blockDim.x) { - hpsi[block_idx * max_npw + ii] - += gk2[ii] * tpiba2 * psi[block_idx * max_npw + ii]; + const int start_idx = block_idx * max_npw; + if(is_first_node) + { + for (int ii = thread_idx; ii < npw; ii += blockDim.x) + { + hpsi[start_idx + ii] = gk2[ii] * tpiba2 * psi[start_idx + ii]; + } + for (int ii = npw + thread_idx; ii < max_npw; ii += blockDim.x) + { + hpsi[start_idx + ii] = 0.0; + } + } + else + { + for (int ii = thread_idx; ii < npw; ii += blockDim.x) + { + hpsi[start_idx + ii] += gk2[ii] * tpiba2 * psi[start_idx + ii]; + } } } @@ -31,6 +47,7 @@ void hamilt::ekinetic_pw_op::operator()(const b const int& nband, const int& npw, const int& max_npw, + const bool& is_first_node, const FPTYPE& tpiba2, const FPTYPE* gk2_ik, std::complex* tmhpsi, @@ -39,7 +56,7 @@ void hamilt::ekinetic_pw_op::operator()(const b // denghui implement 20221019 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ekinetic_pw<<>>( - npw, max_npw, tpiba2, // control params + npw, max_npw, is_first_node, tpiba2, // control params gk2_ik, // array of data reinterpret_cast*>(tmhpsi), // array of data reinterpret_cast*>(tmpsi_in)); // array of data diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/force_op.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/force_op.cu index f8df7b30293..dddf889de1a 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/force_op.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/force_op.cu @@ -35,7 +35,6 @@ __global__ void cal_vkb1_nl( template __global__ void cal_force_nl( const bool nondiagonal, - const int wg_nc, const int ntype, const int spin, const int deeq_2, @@ -43,7 +42,6 @@ __global__ void cal_force_nl( const int deeq_4, const int forcenl_nc, const int nbands, - const int ik, const int nkb, const int *atom_nh, const int *atom_na, @@ -65,11 +63,11 @@ __global__ void cal_force_nl( sum += atom_na[ii] * atom_nh[ii]; } - int Nprojs = atom_nh[it]; - FPTYPE fac = d_wg[ik * wg_nc + ib] * 2.0 * tpiba; - FPTYPE ekb_now = d_ekb[ik * wg_nc + ib]; + int nproj = atom_nh[it]; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; for (int ia = 0; ia < atom_na[it]; ia++) { - for (int ip = threadIdx.x; ip < Nprojs; ip += blockDim.x) { + for (int ip = threadIdx.x; ip < nproj; ip += blockDim.x) { // FPTYPE ps = GlobalC::ppcell.deeq[spin, iat, ip, ip]; FPTYPE ps = deeq[((spin * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip] - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip * deeq_4 + ip]; @@ -85,8 +83,8 @@ __global__ void cal_force_nl( } if (nondiagonal) { - //for (int ip2=0; ip2 void cal_force_nl_op::operator()(const base_device::DEVICE_GPU* ctx, const bool& nondiagonal, const int& nbands_occ, - const int& wg_nc, const int& ntype, const int& spin, const int& deeq_2, @@ -142,7 +139,6 @@ void cal_force_nl_op::operator()(const base_dev const int& deeq_4, const int& forcenl_nc, const int& nbands, - const int& ik, const int& nkb, const int* atom_nh, const int* atom_na, @@ -157,9 +153,9 @@ void cal_force_nl_op::operator()(const base_dev { cal_force_nl<<>>( nondiagonal, - wg_nc, ntype, spin, + ntype, spin, deeq_2, deeq_3, deeq_4, - forcenl_nc, nbands, ik, nkb, + forcenl_nc, nbands, nkb, atom_nh, atom_na, tpiba, d_wg, d_ekb, qq_nt, deeq, @@ -170,6 +166,106 @@ void cal_force_nl_op::operator()(const base_dev cudaCheckOnDebug(); } +template +__global__ void cal_force_nl( + const int ntype, + const int deeq_2, + const int deeq_3, + const int deeq_4, + const int forcenl_nc, + const int nbands, + const int nkb, + const int *atom_nh, + const int *atom_na, + const FPTYPE tpiba, + const FPTYPE *d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const thrust::complex *deeq_nc, + const thrust::complex *becp, + const thrust::complex *dbecp, + FPTYPE *force) +{ + const int ib = blockIdx.x / ntype; + const int ib2 = ib * 2; + const int it = blockIdx.x % ntype; + + int iat = 0, sum = 0; + for (int ii = 0; ii < it; ii++) { + iat += atom_na[ii]; + sum += atom_na[ii] * atom_nh[ii]; + } + + int nproj = atom_nh[it]; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; + for (int ia = 0; ia < atom_na[it]; ia++) { + for (int ip = threadIdx.x; ip < nproj; ip += blockDim.x) { + const int inkb = sum + ip; + for (int ip2 = 0; ip2 < nproj; ip2++) + { + // Effective values of the D-eS coefficients + const thrust::complex ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip * deeq_4 + ip2]; + const int jnkb = sum + ip2; + const thrust::complex ps0 = deeq_nc[((0 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + const thrust::complex ps1 = deeq_nc[((1 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + const thrust::complex ps2 = deeq_nc[((2 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + const thrust::complex ps3 = deeq_nc[((3 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + + for (int ipol = 0; ipol < 3; ipol++) { + const int index0 = ipol * nbands * 2 * nkb + ib2 * nkb + inkb; + const int index1 = ib2 * nkb + jnkb; + const thrust::complex dbb0 = conj(dbecp[index0]) * becp[index1]; + const thrust::complex dbb1 = conj(dbecp[index0]) * becp[index1 + nkb]; + const thrust::complex dbb2 = conj(dbecp[index0 + nkb]) * becp[index1]; + const thrust::complex dbb3 = conj(dbecp[index0 + nkb]) * becp[index1 + nkb]; + const FPTYPE tmp = - fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + atomicAdd(force + iat * forcenl_nc + ipol, tmp); + } + } + } + iat += 1; + sum += nproj; + } +} + +// interface for nspin=4 only +template +void cal_force_nl_op::operator()(const base_device::DEVICE_GPU* ctx, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int& forcenl_nc, + const int& nbands, + const int& nkb, + const int* atom_nh, + const int* atom_na, + const FPTYPE& tpiba, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* force) +{ + cal_force_nl<<>>( + ntype, + deeq_2, deeq_3, deeq_4, + forcenl_nc, nbands, nkb, + atom_nh, atom_na, + tpiba, + d_wg, d_ekb, qq_nt, + reinterpret_cast*>(deeq_nc), + reinterpret_cast*>(becp), + reinterpret_cast*>(dbecp), + force);// array of data + + cudaCheckOnDebug(); +} + template __global__ void saveVkbValues_( const int *gcar_zero_ptrs, diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/nonlocal_op.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/nonlocal_op.cu index 275fbfe1362..89a74f3c5f7 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/nonlocal_op.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/nonlocal_op.cu @@ -54,8 +54,8 @@ __global__ void nonlocal_pw( thrust::complex* ps, const thrust::complex* becp) { - const int ii = blockIdx.x / l2; - const int jj = blockIdx.x % l2; + const int ii = blockIdx.x * 2 / l2; + const int jj = blockIdx.x * 2 % l2; for (int kk = threadIdx.x; kk < l3; kk += blockDim.x) { thrust::complex res1(0.0, 0.0); thrust::complex res2(0.0, 0.0); @@ -121,7 +121,7 @@ void hamilt::nonlocal_pw_op::operator()(const b { // denghui implement 20221109 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - nonlocal_pw<<>>( + nonlocal_pw<<>>( l1, l2, l3, // loop size sum, iat, nkb, // control params deeq_x, deeq_y, deeq_z, @@ -138,4 +138,4 @@ void hamilt::nonlocal_pw_op::operator()(const b template struct nonlocal_pw_op; template struct nonlocal_pw_op; -} // namespace hamilt \ No newline at end of file +} // namespace hamilt diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/stress_op.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/stress_op.cu index e965446d77a..e566126876e 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/stress_op.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/cuda/stress_op.cu @@ -107,8 +107,6 @@ __global__ void cal_stress_nl( const int nkb, const int ntype, const int spin, - const int wg_nc, - const int ik, const int deeq_2, const int deeq_3, const int deeq_4, @@ -125,22 +123,25 @@ __global__ void cal_stress_nl( int ib = blockIdx.x / ntype; int it = blockIdx.x % ntype; - int iat = 0, sum = 0; + int iat = 0; + int sum = 0; for (int ii = 0; ii < it; ii++) { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; } - FPTYPE stress_var = 0, fac = d_wg[ik * wg_nc + ib] * 1.0, ekb_now = d_ekb[ik * wg_nc + ib]; - const int Nprojs = atom_nh[it]; + FPTYPE stress_var = 0; + const FPTYPE fac = d_wg[ib]; + const FPTYPE ekb_now = d_ekb[ib]; + const int nproj = atom_nh[it]; for (int ia = 0; ia < atom_na[it]; ia++) { - for (int ii = threadIdx.x; ii < Nprojs * Nprojs; ii += blockDim.x) { - int ip1 = ii / Nprojs, ip2 = ii % Nprojs; + for (int ii = threadIdx.x; ii < nproj * nproj; ii += blockDim.x) { + const int ip1 = ii / nproj, ip2 = ii % nproj; if(!nondiagonal && ip1 != ip2) { continue; } - FPTYPE ps = deeq[((spin * deeq_2 + iat) * deeq_3 + ip1) * deeq_4 + ip2] + const FPTYPE ps = deeq[((spin * deeq_2 + iat) * deeq_3 + ip1) * deeq_4 + ip2] - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip1 * deeq_4 + ip2]; const int inkb1 = sum + ip1; const int inkb2 = sum + ip2; @@ -149,7 +150,7 @@ __global__ void cal_stress_nl( stress_var -= ps * fac * dbb; } ++iat; - sum+=Nprojs; + sum+=nproj; }//ia __syncwarp(); warp_reduce(stress_var); @@ -204,8 +205,6 @@ void cal_stress_nl_op::operator()(const base_de const int& nbands_occ, const int& ntype, const int& spin, - const int& wg_nc, - const int& ik, const int& deeq_2, const int& deeq_3, const int& deeq_4, @@ -226,8 +225,6 @@ void cal_stress_nl_op::operator()(const base_de nkb, ntype, spin, - wg_nc, - ik, deeq_2, deeq_3, deeq_4, @@ -244,6 +241,110 @@ void cal_stress_nl_op::operator()(const base_de cudaCheckOnDebug(); } +template +__global__ void cal_stress_nl( + const int ipol, + const int jpol, + const int nkb, + const int ntype, + const int deeq_2, + const int deeq_3, + const int deeq_4, + const int *atom_nh, + const int *atom_na, + const FPTYPE *d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const thrust::complex *deeq_nc, + const thrust::complex *becp, + const thrust::complex *dbecp, + FPTYPE *stress) +{ + const int ib = blockIdx.x / ntype; // index of loop-nbands + const int ib2 = ib * 2; + const int it = blockIdx.x % ntype; // index of loop-ntype + + int iat = 0; // calculate the begin of atomic index + int sum = 0; // calculate the begin of atomic-orbital index + for (int ii = 0; ii < it; ii++) { + iat += atom_na[ii]; + sum += atom_na[ii] * atom_nh[ii]; + } + + FPTYPE stress_var = 0; + const FPTYPE fac = d_wg[ib]; + const FPTYPE ekb_now = d_ekb[ib]; + const int nproj = atom_nh[it]; + for (int ia = 0; ia < atom_na[it]; ia++) + { + for (int ii = threadIdx.x; ii < nproj * nproj; ii += blockDim.x) { + const int ip1 = ii / nproj; + const int ip2 = ii % nproj; + const thrust::complex ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip1 * deeq_4 + ip2]; + const thrust::complex ps0 = deeq_nc[((iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + const thrust::complex ps1 = deeq_nc[((1 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + const thrust::complex ps2 = deeq_nc[((2 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + const thrust::complex ps3 = deeq_nc[((3 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + const int inkb1 = sum + ip1; + const int inkb2 = sum + ip2; + //out<<"\n ps = "< dbb0 = conj(dbecp[ib2 * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const thrust::complex dbb1 = conj(dbecp[ib2 * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + const thrust::complex dbb2 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const thrust::complex dbb3 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + stress_var -= fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + } + ++iat; + sum+=nproj; + }//ia + __syncwarp(); + warp_reduce(stress_var); + if (threadIdx.x % WARP_SIZE == 0) { + atomicAdd(stress + ipol * 3 + jpol, stress_var); + } +} + +template +void cal_stress_nl_op::operator()(const base_device::DEVICE_GPU* ctx, + const int& ipol, + const int& jpol, + const int& nkb, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int* atom_nh, + const int* atom_na, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* stress) +{ + cal_stress_nl<<>>( + ipol, + jpol, + nkb, + ntype, + deeq_2, + deeq_3, + deeq_4, + atom_nh, + atom_na, + d_wg, + d_ekb, + qq_nt, + reinterpret_cast*>(deeq_nc), + reinterpret_cast*>(becp), + reinterpret_cast*>(dbecp), + stress);// array of data + + cudaCheckOnDebug(); +} + template void cal_stress_mgga_op::operator()( const int& spin, @@ -710,34 +811,6 @@ void cal_force_npw_op::operator()( } -// template -// void prepare_vkb_deri_ptr_op::operator()( -// const base_device::DEVICE_GPU* ctx, -// int nbeta, double* nhtol, int nhtol_nc, int npw, int it, -// int ipol, int jpol, -// std::complex*vkb_out, std::complex** vkb_ptrs, -// FPTYPE* ylm_in, FPTYPE** ylm_ptrs, -// FPTYPE* ylm_deri_in, FPTYPE** ylm_deri_ptr1s, FPTYPE** ylm_deri_ptr2s, -// FPTYPE* vq_in, FPTYPE** vq_ptrs, -// FPTYPE* vq_deri_in, FPTYPE** vq_deri_ptrs -// ) -// { -// const int block = (npw + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; -// dim3 gridsize(block,nbeta); - - -// prepare_vkb_deri_ptr<<<1,1>>>( -// nbeta, nhtol, nhtol_nc, npw, it, ipol, jpol, -// reinterpret_cast*>(vkb_out), -// reinterpret_cast*>(vkb_ptrs), -// ylm_in, ylm_ptrs, ylm_deri_in, ylm_deri_ptr1s, ylm_deri_ptr2s, -// vq_in, vq_ptrs, vq_deri_in, vq_deri_ptrs -// ); - -// return ; -// } - - template <> void pointer_array_malloc::operator()( void **ptr, diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.cpp index 707f67d4680..f909412bf88 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.cpp @@ -9,20 +9,45 @@ struct ekinetic_pw_op const int& nband, const int& npw, const int& max_npw, + const bool& is_first_node, const FPTYPE& tpiba2, const FPTYPE* gk2_ik, std::complex* tmhpsi, const std::complex* tmpsi_in) { + if (is_first_node) + { #ifdef _OPENMP -#pragma omp parallel for collapse(2) schedule(static, 4096/sizeof(FPTYPE)) +#pragma omp parallel for #endif - for (int ib = 0; ib < nband; ++ib) { - for (int ig = 0; ig < npw; ++ig) { - tmhpsi[ib * max_npw + ig] += gk2_ik[ig] * tpiba2 * tmpsi_in[ib * max_npw + ig]; - } + for (int ib = 0; ib < nband; ++ib) + { + const int ig0 = ib * max_npw; + for (int ig = 0; ig < npw; ++ig) + { + tmhpsi[ig + ig0] = gk2_ik[ig] * tpiba2 * tmpsi_in[ig + ig0]; + } + for (int ig = npw; ig < max_npw; ++ig) + { + tmhpsi[ig + ig0] = 0.0; + } + } + } + else + { +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int ib = 0; ib < nband; ++ib) + { + const int ig0 = ib * max_npw; + for (int ig = 0; ig < npw; ++ig) + { + tmhpsi[ig + ig0] += gk2_ik[ig] * tpiba2 * tmpsi_in[ig + ig0]; + } + } + } } - } }; template struct ekinetic_pw_op; diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.h b/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.h index e9ae525390e..7142fd40317 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.h +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/ekinetic_op.h @@ -26,6 +26,7 @@ struct ekinetic_pw_op { const int& nband, const int& npw, const int& max_npw, + const bool& is_first_node, const FPTYPE& tpiba2, const FPTYPE* gk2_ik, std::complex* tmhpsi, @@ -41,6 +42,7 @@ struct ekinetic_pw_op const int& nband, const int& npw, const int& max_npw, + const bool& is_first_node, const FPTYPE& tpiba2, const FPTYPE* gk2_ik, std::complex* tmhpsi, diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.cpp index 1584c5c6816..2ee9cb45303 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.cpp @@ -42,7 +42,6 @@ struct cal_force_nl_op void operator()(const base_device::DEVICE_CPU* ctx, const bool& nondiagonal, const int& nbands_occ, - const int& wg_nc, const int& ntype, const int& spin, const int& deeq_2, @@ -50,7 +49,6 @@ struct cal_force_nl_op const int& deeq_4, const int& forcenl_nc, const int& nbands, - const int& ik, const int& nkb, const int* atom_nh, const int* atom_na, @@ -71,7 +69,7 @@ struct cal_force_nl_op int sum0 = 0; for (int it = 0; it < ntype; it++) { - const int Nprojs = atom_nh[it]; + const int nproj = atom_nh[it]; #ifdef _OPENMP #pragma omp for collapse(2) #endif @@ -80,11 +78,11 @@ struct cal_force_nl_op for (int ib = 0; ib < nbands_occ; ib++) { FPTYPE local_force[3] = {0, 0, 0}; - FPTYPE fac = d_wg[ik * wg_nc + ib] * 2.0 * tpiba; - FPTYPE ekb_now = d_ekb[ik * wg_nc + ib]; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; int iat = iat0 + ia; - int sum = sum0 + ia * Nprojs; - for (int ip = 0; ip < Nprojs; ip++) + int sum = sum0 + ia * nproj; + for (int ip = 0; ip < nproj; ip++) { // Effective values of the D-eS coefficients FPTYPE ps = deeq[((spin * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip] @@ -102,7 +100,7 @@ struct cal_force_nl_op } if (nondiagonal) { - for (int ip2 = 0; ip2 < Nprojs; ip2++) + for (int ip2 = 0; ip2 < nproj; ip2++) { if (ip != ip2) { @@ -141,7 +139,104 @@ struct cal_force_nl_op } } // end ia iat0 += atom_na[it]; - sum0 += atom_na[it] * Nprojs; + sum0 += atom_na[it] * nproj; + } // end it +#ifdef _OPENMP + } +#endif + }; + + void operator()(const base_device::DEVICE_CPU* ctx, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int& forcenl_nc, + const int& nbands, + const int& nkb, + const int* atom_nh, + const int* atom_na, + const FPTYPE& tpiba, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* force) + { +#ifdef _OPENMP +#pragma omp parallel + { +#endif + int iat0 = 0; + int sum0 = 0; + for (int it = 0; it < ntype; it++) + { + const int nprojs = atom_nh[it]; +#ifdef _OPENMP +#pragma omp for collapse(2) +#endif + for (int ia = 0; ia < atom_na[it]; ia++) + { + for (int ib = 0; ib < nbands_occ; ib++) + { + const int ib2 = ib*2; + FPTYPE local_force[3] = {0, 0, 0}; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; + int iat = iat0 + ia; + int sum = sum0 + ia * nprojs; + for (int ip = 0; ip < nprojs; ip++) + { + const int inkb = sum + ip; + // out<<"\n ps = "< ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip * deeq_4 + ip2]; + const int jnkb = sum + ip2; + std::complex ps0 = deeq_nc[((0 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + std::complex ps1 = deeq_nc[((1 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + std::complex ps2 = deeq_nc[((2 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + std::complex ps3 = deeq_nc[((3 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + + + for (int ipol = 0; ipol < 3; ipol++) + { + const int index0 = ipol * nbands * 2 * nkb + ib2 * nkb + inkb; + const int index1 = ib2 * nkb + jnkb; + const std::complex dbb0 = conj(dbecp[index0]) * becp[index1]; + const std::complex dbb1 = conj(dbecp[index0]) * becp[index1 + nkb]; + const std::complex dbb2 = conj(dbecp[index0 + nkb]) * becp[index1]; + const std::complex dbb3 = conj(dbecp[index0 + nkb]) * becp[index1 + nkb]; + + local_force[ipol] -= fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + } + } + } +#ifdef _OPENMP + if (omp_get_num_threads() > 1) + { + for (int ipol = 0; ipol < 3; ++ipol) + { +#pragma omp atomic + force[iat * forcenl_nc + ipol] += local_force[ipol]; + } + } + else +#endif + { + for (int ipol = 0; ipol < 3; ++ipol) + { + force[iat * forcenl_nc + ipol] += local_force[ipol]; + } + } + } + } // end ia + iat0 += atom_na[it]; + sum0 += atom_na[it] * nprojs; } // end it #ifdef _OPENMP } diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.h b/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.h index b04b769df86..c68df7bd0f7 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.h +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/force_op.h @@ -1,5 +1,6 @@ #ifndef W_ABACUS_DEVELOP_ABACUS_DEVELOP_SOURCE_MODULE_HAMILT_PW_HAMILT_PWDFT_KERNELS_FORCE_OP_H #define W_ABACUS_DEVELOP_ABACUS_DEVELOP_SOURCE_MODULE_HAMILT_PW_HAMILT_PWDFT_KERNELS_FORCE_OP_H +#include "module_parameter/parameter.h" #include "module_psi/psi.h" @@ -47,7 +48,6 @@ struct cal_force_nl_op /// @param ctx - which device this function runs on /// @param nondiagonal - control flag /// @param nbands_occ - number of occupied bands - /// @param wg_nc - the second dimension of matrix wg /// @param ntype - total atomic type /// @param spin - current spin /// @param deeq_2 - the second dimension of deeq @@ -55,7 +55,6 @@ struct cal_force_nl_op /// @param deeq_4 - the forth dimension of deeq /// @param forcenl_nc - the second dimension of matrix forcenl /// @param nbands - NBANDS - /// @param ik - current k point /// @param nkb - number of k point /// @param atom_nh - GlobalC::ucell.atoms[ii].ncpp.nh /// @param atom_na - GlobalC::ucell.atoms[ii].na @@ -64,15 +63,14 @@ struct cal_force_nl_op /// @param d_ekb - input parameter ekb /// @param qq_nt - GlobalC::ppcell.qq_nt /// @param deeq - GlobalC::ppcell.deeq - /// @param becp - intermediate matrix with GlobalV::NBANDS * nkb - /// @param dbecp - intermediate matrix with 3 * GlobalV::NBANDS * nkb + /// @param becp - intermediate matrix with PARAM.inp.nbands * nkb + /// @param dbecp - intermediate matrix with 3 * PARAM.inp.nbands * nkb /// /// Output Parameters /// @param force - output forces void operator()(const base_device::DEVICE_CPU* ctx, const bool& nondiagonal, const int& nbands_occ, - const int& wg_nc, const int& ntype, const int& spin, const int& deeq_2, @@ -80,7 +78,6 @@ struct cal_force_nl_op const int& deeq_4, const int& forcenl_nc, const int& nbands, - const int& ik, const int& nkb, const int* atom_nh, const int* atom_na, @@ -92,6 +89,26 @@ struct cal_force_nl_op const std::complex* becp, const std::complex* dbecp, FPTYPE* force); + // interface for nspin=4 only + void operator()(const base_device::DEVICE_CPU* ctx, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int& forcenl_nc, + const int& nbands, + const int& nkb, + const int* atom_nh, + const int* atom_na, + const FPTYPE& tpiba, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* force); }; #if __CUDA || __UT_USE_CUDA || __ROCM || __UT_USE_ROCM @@ -116,7 +133,6 @@ struct cal_force_nl_op void operator()(const base_device::DEVICE_GPU* ctx, const bool& nondiagonal, const int& nbands_occ, - const int& wg_nc, const int& ntype, const int& spin, const int& deeq_2, @@ -124,7 +140,6 @@ struct cal_force_nl_op const int& deeq_4, const int& forcenl_nc, const int& nbands, - const int& ik, const int& nkb, const int* atom_nh, const int* atom_na, @@ -136,6 +151,26 @@ struct cal_force_nl_op const std::complex* becp, const std::complex* dbecp, FPTYPE* force); + // interface for nspin=4 only + void operator()(const base_device::DEVICE_GPU* ctx, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int& forcenl_nc, + const int& nbands, + const int& nkb, + const int* atom_nh, + const int* atom_na, + const FPTYPE& tpiba, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* force); }; /** diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/ekinetic_op.hip.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/ekinetic_op.hip.cu index 9922b789ffd..841dfe0fcba 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/ekinetic_op.hip.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/ekinetic_op.hip.cu @@ -13,6 +13,7 @@ template __global__ void ekinetic_pw( const int npw, const int max_npw, + const bool is_first_node, const FPTYPE tpiba2, const FPTYPE* gk2, thrust::complex* hpsi, @@ -20,10 +21,26 @@ __global__ void ekinetic_pw( { const int block_idx = blockIdx.x; const int thread_idx = threadIdx.x; - for (int ii = thread_idx; ii < npw; ii+= blockDim.x) { - hpsi[block_idx * max_npw + ii] - += gk2[ii] * tpiba2 * psi[block_idx * max_npw + ii]; + const int start_idx = block_idx * max_npw; + if(is_first_node) + { + for (int ii = thread_idx; ii < npw; ii += blockDim.x) + { + hpsi[start_idx + ii] = gk2[ii] * tpiba2 * psi[start_idx + ii]; + } + for (int ii = npw + thread_idx; ii < max_npw; ii += blockDim.x) + { + hpsi[start_idx + ii] = 0.0; + } } + else + { + for (int ii = thread_idx; ii < npw; ii += blockDim.x) + { + hpsi[start_idx + ii] += gk2[ii] * tpiba2 * psi[start_idx + ii]; + } + } + } template @@ -31,6 +48,7 @@ void hamilt::ekinetic_pw_op::operator()(const b const int& nband, const int& npw, const int& max_npw, + const bool& is_first_node, const FPTYPE& tpiba2, const FPTYPE* gk2_ik, std::complex* tmhpsi, @@ -39,7 +57,7 @@ void hamilt::ekinetic_pw_op::operator()(const b // denghui implement 20221019 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< hipLaunchKernelGGL(HIP_KERNEL_NAME(ekinetic_pw), dim3(nband), dim3(THREADS_PER_BLOCK), 0, 0, - npw, max_npw, tpiba2, // control params + npw, max_npw, is_first_node, tpiba2, // control params gk2_ik, // array of data reinterpret_cast*>(tmhpsi), // array of data reinterpret_cast*>(tmpsi_in)); // array of data diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/force_op.hip.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/force_op.hip.cu index fa03fa2a5da..da45a375e79 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/force_op.hip.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/force_op.hip.cu @@ -31,7 +31,6 @@ __global__ void cal_vkb1_nl( template __global__ void cal_force_nl( const bool nondiagonal, - const int wg_nc, const int ntype, const int spin, const int deeq_2, @@ -39,7 +38,6 @@ __global__ void cal_force_nl( const int deeq_4, const int forcenl_nc, const int nbands, - const int ik, const int nkb, const int *atom_nh, const int *atom_na, @@ -55,17 +53,18 @@ __global__ void cal_force_nl( const int ib = blockIdx.x / ntype; const int it = blockIdx.x % ntype; - int iat = 0, sum = 0; + int iat = 0; + int sum = 0; for (int ii = 0; ii < it; ii++) { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; } - int Nprojs = atom_nh[it]; - FPTYPE fac = d_wg[ik * wg_nc + ib] * 2.0 * tpiba; - FPTYPE ekb_now = d_ekb[ik * wg_nc + ib]; + int nproj = atom_nh[it]; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; for (int ia = 0; ia < atom_na[it]; ia++) { - for (int ip = threadIdx.x; ip < Nprojs; ip += blockDim.x) { + for (int ip = threadIdx.x; ip < nproj; ip += blockDim.x) { // FPTYPE ps = GlobalC::ppcell.deeq[spin, iat, ip, ip]; FPTYPE ps = deeq[((spin * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip] - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip * deeq_4 + ip]; @@ -81,8 +80,8 @@ __global__ void cal_force_nl( } if (nondiagonal) { - //for (int ip2=0; ip2 void cal_force_nl_op::operator()(const base_device::DEVICE_GPU* ctx, const bool& nondiagonal, const int& nbands_occ, - const int& wg_nc, const int& ntype, const int& spin, const int& deeq_2, @@ -138,7 +136,6 @@ void cal_force_nl_op::operator()(const base_dev const int& deeq_4, const int& forcenl_nc, const int& nbands, - const int& ik, const int& nkb, const int* atom_nh, const int* atom_na, @@ -153,9 +150,9 @@ void cal_force_nl_op::operator()(const base_dev { hipLaunchKernelGGL(HIP_KERNEL_NAME(cal_force_nl), dim3(nbands_occ * ntype), dim3(THREADS_PER_BLOCK), 0, 0, nondiagonal, - wg_nc, ntype, spin, + ntype, spin, deeq_2, deeq_3, deeq_4, - forcenl_nc, nbands, ik, nkb, + forcenl_nc, nbands, nkb, atom_nh, atom_na, tpiba, d_wg, d_ekb, qq_nt, deeq, @@ -166,6 +163,107 @@ void cal_force_nl_op::operator()(const base_dev hipCheckOnDebug(); } +template +__global__ void cal_force_nl( + const int ntype, + const int deeq_2, + const int deeq_3, + const int deeq_4, + const int forcenl_nc, + const int nbands, + const int nkb, + const int *atom_nh, + const int *atom_na, + const FPTYPE tpiba, + const FPTYPE *d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const thrust::complex *deeq_nc, + const thrust::complex *becp, + const thrust::complex *dbecp, + FPTYPE *force) +{ + const int ib = blockIdx.x / ntype; + const int ib2 = ib * 2; + const int it = blockIdx.x % ntype; + + int iat = 0; + int sum = 0; + for (int ii = 0; ii < it; ii++) { + iat += atom_na[ii]; + sum += atom_na[ii] * atom_nh[ii]; + } + + int nproj = atom_nh[it]; + FPTYPE fac = d_wg[ib] * 2.0 * tpiba; + FPTYPE ekb_now = d_ekb[ib]; + for (int ia = 0; ia < atom_na[it]; ia++) { + for (int ip = threadIdx.x; ip < nproj; ip += blockDim.x) { + const int inkb = sum + ip; + for (int ip2 = 0; ip2 < nproj; ip2++) + { + // Effective values of the D-eS coefficients + const thrust::complex ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip * deeq_4 + ip2]; + const int jnkb = sum + ip2; + const thrust::complex ps0 = deeq_nc[((0 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + const thrust::complex ps1 = deeq_nc[((1 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + const thrust::complex ps2 = deeq_nc[((2 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2]; + const thrust::complex ps3 = deeq_nc[((3 * deeq_2 + iat) * deeq_3 + ip) * deeq_4 + ip2] + ps_qq; + + for (int ipol = 0; ipol < 3; ipol++) { + const int index0 = ipol * nbands * 2 * nkb + ib2 * nkb + inkb; + const int index1 = ib2 * nkb + jnkb; + const thrust::complex dbb0 = conj(dbecp[index0]) * becp[index1]; + const thrust::complex dbb1 = conj(dbecp[index0]) * becp[index1 + nkb]; + const thrust::complex dbb2 = conj(dbecp[index0 + nkb]) * becp[index1]; + const thrust::complex dbb3 = conj(dbecp[index0 + nkb]) * becp[index1 + nkb]; + const FPTYPE tmp = - fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + atomicAdd(force + iat * forcenl_nc + ipol, tmp); + } + } + } + iat += 1; + sum += nproj; + } +} + +// interface for nspin=4 only +template +void cal_force_nl_op::operator()(const base_device::DEVICE_GPU* ctx, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int& forcenl_nc, + const int& nbands, + const int& nkb, + const int* atom_nh, + const int* atom_na, + const FPTYPE& tpiba, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* force) +{ + hipLaunchKernelGGL(HIP_KERNEL_NAME(cal_force_nl), dim3(nbands_occ * ntype), dim3(THREADS_PER_BLOCK), 0, 0, + ntype, + deeq_2, deeq_3, deeq_4, + forcenl_nc, nbands, nkb, + atom_nh, atom_na, + tpiba, + d_wg, d_ekb, qq_nt, + reinterpret_cast*>(deeq_nc), + reinterpret_cast*>(becp), + reinterpret_cast*>(dbecp), + force);// array of data + + hipCheckOnDebug(); +} + template __global__ void saveVkbValues_( const int *gcar_zero_ptrs, diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/nonlocal_op.hip.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/nonlocal_op.hip.cu index 93df9fe58d0..9a43f64ea6a 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/nonlocal_op.hip.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/nonlocal_op.hip.cu @@ -54,8 +54,8 @@ __global__ void nonlocal_pw( thrust::complex* ps, const thrust::complex* becp) { - const int ii = blockIdx.x / l2; - const int jj = blockIdx.x % l2; + const int ii = blockIdx.x * 2 / l2; + const int jj = blockIdx.x * 2 % l2; for (int kk = threadIdx.x; kk < l3; kk += blockDim.x) { thrust::complex res1(0.0, 0.0); thrust::complex res2(0.0, 0.0); @@ -122,7 +122,7 @@ void hamilt::nonlocal_pw_op::operator()(const b { // denghui implement 20221109 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - hipLaunchKernelGGL(HIP_KERNEL_NAME(nonlocal_pw), dim3(l1 * l2), dim3(THREADS_PER_BLOCK), 0, 0, + hipLaunchKernelGGL(HIP_KERNEL_NAME(nonlocal_pw), dim3(l1 * l2 / 2), dim3(THREADS_PER_BLOCK), 0, 0, l1, l2, l3, // loop size sum, iat, nkb, // control params deeq_x, deeq_y, deeq_z, @@ -140,4 +140,4 @@ void hamilt::nonlocal_pw_op::operator()(const b namespace hamilt{ template struct nonlocal_pw_op; template struct nonlocal_pw_op; -} \ No newline at end of file +} diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/stress_op.hip.cu b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/stress_op.hip.cu index 17cfae404af..68809875465 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/stress_op.hip.cu +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/rocm/stress_op.hip.cu @@ -102,8 +102,6 @@ __global__ void cal_stress_nl( const int nkb, const int ntype, const int spin, - const int wg_nc, - const int ik, const int deeq_2, const int deeq_3, const int deeq_4, @@ -120,18 +118,21 @@ __global__ void cal_stress_nl( int ib = blockIdx.x / ntype; int it = blockIdx.x % ntype; - int iat = 0, sum = 0; + int iat = 0; + int sum = 0; for (int ii = 0; ii < it; ii++) { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; } - FPTYPE stress_var = 0, fac = d_wg[ik * wg_nc + ib] * 1.0, ekb_now = d_ekb[ik * wg_nc + ib]; - const int Nprojs = atom_nh[it]; + FPTYPE stress_var = 0; + FPTYPE fac = d_wg[ib]; + FPTYPE ekb_now = d_ekb[ib]; + const int nproj = atom_nh[it]; for (int ia = 0; ia < atom_na[it]; ia++) { - for (int ii = threadIdx.x; ii < Nprojs * Nprojs; ii += blockDim.x) { - int ip1 = ii / Nprojs, ip2 = ii % Nprojs; + for (int ii = threadIdx.x; ii < nproj * nproj; ii += blockDim.x) { + int ip1 = ii / nproj, ip2 = ii % nproj; if(!nondiagonal && ip1 != ip2) { continue; } @@ -144,7 +145,7 @@ __global__ void cal_stress_nl( stress_var -= ps * fac * dbb; } ++iat; - sum+=Nprojs; + sum+=nproj; }//ia warp_reduce(stress_var); if (threadIdx.x % WARP_SIZE == 0) { @@ -198,8 +199,6 @@ void cal_stress_nl_op::operator()(const base_de const int& nbands_occ, const int& ntype, const int& spin, - const int& wg_nc, - const int& ik, const int& deeq_2, const int& deeq_3, const int& deeq_4, @@ -220,8 +219,6 @@ void cal_stress_nl_op::operator()(const base_de nkb, ntype, spin, - wg_nc, - ik, deeq_2, deeq_3, deeq_4, @@ -238,6 +235,110 @@ void cal_stress_nl_op::operator()(const base_de hipCheckOnDebug(); } +template +__global__ void cal_stress_nl( + const int ipol, + const int jpol, + const int nkb, + const int ntype, + const int deeq_2, + const int deeq_3, + const int deeq_4, + const int *atom_nh, + const int *atom_na, + const FPTYPE *d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const thrust::complex *deeq_nc, + const thrust::complex *becp, + const thrust::complex *dbecp, + FPTYPE *stress) +{ + int ib = blockIdx.x / ntype; + const int ib2 = ib * 2; + int it = blockIdx.x % ntype; + + int iat = 0; + int sum = 0; + for (int ii = 0; ii < it; ii++) { + iat += atom_na[ii]; + sum += atom_na[ii] * atom_nh[ii]; + } + + FPTYPE stress_var = 0; + FPTYPE fac = d_wg[ib]; + FPTYPE ekb_now = d_ekb[ib]; + const int nproj = atom_nh[it]; + for (int ia = 0; ia < atom_na[it]; ia++) + { + for (int ii = threadIdx.x; ii < nproj * nproj; ii += blockDim.x) { + const int ip1 = ii / nproj; + const int ip2 = ii % nproj; + const thrust::complex ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip1 * deeq_4 + ip2]; + const thrust::complex ps0 = deeq_nc[((iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + const thrust::complex ps1 = deeq_nc[((1 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + const thrust::complex ps2 = deeq_nc[((2 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + const thrust::complex ps3 = deeq_nc[((3 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + const int inkb1 = sum + ip1; + const int inkb2 = sum + ip2; + //out<<"\n ps = "< dbb0 = conj(dbecp[ib2 * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const thrust::complex dbb1 = conj(dbecp[ib2 * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + const thrust::complex dbb2 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const thrust::complex dbb3 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + stress_var -= fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + } + ++iat; + sum+=nproj; + }//ia + __syncwarp(); + warp_reduce(stress_var); + if (threadIdx.x % WARP_SIZE == 0) { + atomicAdd(stress + ipol * 3 + jpol, stress_var); + } +} + +template +void cal_stress_nl_op::operator()(const base_device::DEVICE_GPU* ctx, + const int& ipol, + const int& jpol, + const int& nkb, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int* atom_nh, + const int* atom_na, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* stress) +{ + hipLaunchKernelGGL(HIP_KERNEL_NAME(cal_stress_nl), dim3(nbands_occ * ntype), dim3(THREADS_PER_BLOCK), 0, 0, + ipol, + jpol, + nkb, + ntype, + deeq_2, + deeq_3, + deeq_4, + atom_nh, + atom_na, + d_wg, + d_ekb, + qq_nt, + reinterpret_cast*>(deeq_nc), + reinterpret_cast*>(becp), + reinterpret_cast*>(dbecp), + stress);// array of data + + hipCheckOnDebug(); +} + template void cal_stress_mgga_op::operator()( const int& spin, @@ -743,4 +844,7 @@ template struct cal_dbecp_noevc_nl_op; template struct cal_stress_nl_op; template struct cal_stress_nl_op; +template struct cal_force_npw_op; +template struct cal_force_npw_op; + } // namespace hamilt \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.cpp index c3a8008e045..f36f2e8316f 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.cpp @@ -77,8 +77,6 @@ struct cal_stress_nl_op const int& nbands_occ, const int& ntype, const int& spin, - const int& wg_nc, - const int& ik, const int& deeq_2, const int& deeq_3, const int& deeq_4, @@ -97,10 +95,11 @@ struct cal_stress_nl_op #pragma omp parallel reduction(+ : local_stress) { #endif - int iat = 0, sum = 0; + int iat = 0; + int sum = 0; for (int it = 0; it < ntype; it++) { - const int Nprojs = atom_nh[it]; + const int nproj = atom_nh[it]; #ifdef _OPENMP #pragma omp for collapse(4) #endif @@ -108,20 +107,20 @@ struct cal_stress_nl_op { for (int ia = 0; ia < atom_na[it]; ia++) { - for (int ip1 = 0; ip1 < Nprojs; ip1++) + for (int ip1 = 0; ip1 < nproj; ip1++) { - for (int ip2 = 0; ip2 < Nprojs; ip2++) + for (int ip2 = 0; ip2 < nproj; ip2++) { if (!nondiagonal && ip1 != ip2) { continue; } - FPTYPE fac = d_wg[ik * wg_nc + ib] * 1.0; - FPTYPE ekb_now = d_ekb[ik * wg_nc + ib]; + FPTYPE fac = d_wg[ib] * 1.0; + FPTYPE ekb_now = d_ekb[ib]; FPTYPE ps = deeq[((spin * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip1 * deeq_4 + ip2]; - const int inkb1 = sum + ia * Nprojs + ip1; - const int inkb2 = sum + ia * Nprojs + ip2; + const int inkb1 = sum + ia * nproj + ip1; + const int inkb2 = sum + ia * nproj + ip2; // out<<"\n ps = "< } // end ip } // ia } - sum += atom_na[it] * Nprojs; + sum += atom_na[it] * nproj; + iat += atom_na[it]; + } // end it +#ifdef _OPENMP + } +#endif + stress[ipol * 3 + jpol] += local_stress; + }; + + void operator()(const base_device::DEVICE_CPU* ctx, + const int& ipol, + const int& jpol, + const int& nkb, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int* atom_nh, + const int* atom_na, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* stress) + { + FPTYPE local_stress = 0; +#ifdef _OPENMP +#pragma omp parallel reduction(+ : local_stress) + { +#endif + int iat = 0, sum = 0; + for (int it = 0; it < ntype; it++) + { + const int nproj = atom_nh[it]; +#ifdef _OPENMP +#pragma omp for collapse(4) +#endif + for (int ib = 0; ib < nbands_occ; ib++) + { + for (int ia = 0; ia < atom_na[it]; ia++) + { + for (int ip1 = 0; ip1 < nproj; ip1++) + { + for (int ip2 = 0; ip2 < nproj; ip2++) + { + const int ib2 = ib*2; + FPTYPE fac = d_wg[ib] * 1.0; + FPTYPE ekb_now = d_ekb[ib]; + std::complex ps_qq = - ekb_now * qq_nt[it * deeq_3 * deeq_4 + ip1 * deeq_4 + ip2]; + std::complex ps0 = deeq_nc[((iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + std::complex ps1 = deeq_nc[((1 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + std::complex ps2 = deeq_nc[((2 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2]; + std::complex ps3 = deeq_nc[((3 * deeq_2 + iat + ia) * deeq_3 + ip1) * deeq_4 + ip2] + ps_qq; + const int inkb1 = sum + ia * nproj + ip1; + const int inkb2 = sum + ia * nproj + ip2; + // out<<"\n ps = "< dbb0 = conj(dbecp[ib2 * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const std::complex dbb1 = conj(dbecp[ib2 * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + const std::complex dbb2 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[ib2 * nkb + inkb2]; + const std::complex dbb3 = conj(dbecp[(ib2+1) * nkb + inkb1]) * becp[(ib2+1) * nkb + inkb2]; + local_stress -= fac * (ps0 * dbb0 + ps1 * dbb1 + ps2 * dbb2 + ps3 * dbb3).real(); + } + } // end ip + } // ia + } + sum += atom_na[it] * nproj; iat += atom_na[it]; } // end it #ifdef _OPENMP diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.h b/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.h index 62e373f1ff3..2f4bbd09896 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.h +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/stress_op.h @@ -1,5 +1,6 @@ #ifndef SRC_PW_STRESS_MULTI_DEVICE_H #define SRC_PW_STRESS_MULTI_DEVICE_H +#include "module_parameter/parameter.h" #include "module_psi/psi.h" @@ -65,8 +66,6 @@ struct cal_stress_nl_op /// @param nbands_occ - number of occupied bands /// @param ntype - total atomic type /// @param spin - current spin - /// @param wg_nc - the second dimension of matrix wg - /// @param ik - current k point /// @param deeq_2 - the second dimension of deeq /// @param deeq_3 - the third dimension of deeq /// @param deeq_4 - the forth dimension of deeq @@ -76,8 +75,8 @@ struct cal_stress_nl_op /// @param d_ekb - input parameter ekb /// @param qq_nt - GlobalC::ppcell.qq_nt /// @param deeq - GlobalC::ppcell.deeq - /// @param becp - intermediate matrix with GlobalV::NBANDS * nkb - /// @param dbecp - intermediate matrix with 3 * GlobalV::NBANDS * nkb + /// @param becp - intermediate matrix with PARAM.inp.nbands * nkb + /// @param dbecp - intermediate matrix with 3 * PARAM.inp.nbands * nkb /// /// Output Parameters /// @param stress - output stresses @@ -89,8 +88,6 @@ struct cal_stress_nl_op const int& nbands_occ, const int& ntype, const int& spin, - const int& wg_nc, - const int& ik, const int& deeq_2, const int& deeq_3, const int& deeq_4, @@ -103,6 +100,25 @@ struct cal_stress_nl_op const std::complex* becp, const std::complex* dbecp, FPTYPE* stress); + // interface for nspin=4 only + void operator()(const Device* ctx, + const int& ipol, + const int& jpol, + const int& nkb, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int* atom_nh, + const int* atom_na, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* stress); }; template @@ -236,8 +252,6 @@ struct cal_stress_nl_op const int& nbands_occ, const int& ntype, const int& spin, - const int& wg_nc, - const int& ik, const int& deeq_2, const int& deeq_3, const int& deeq_4, @@ -250,6 +264,25 @@ struct cal_stress_nl_op const std::complex* becp, const std::complex* dbecp, FPTYPE* stress); + // interface for nspin=4 only + void operator()(const base_device::DEVICE_GPU* ctx, + const int& ipol, + const int& jpol, + const int& nkb, + const int& nbands_occ, + const int& ntype, + const int& deeq_2, + const int& deeq_3, + const int& deeq_4, + const int* atom_nh, + const int* atom_na, + const FPTYPE* d_wg, + const FPTYPE* d_ekb, + const FPTYPE* qq_nt, + const std::complex* deeq_nc, + const std::complex* becp, + const std::complex* dbecp, + FPTYPE* stress); }; // cpu version first, gpu version later diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/ekinetic_op_test.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/ekinetic_op_test.cpp index 03a5792bed5..324d4fb7521 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/ekinetic_op_test.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/ekinetic_op_test.cpp @@ -70,7 +70,7 @@ class TestModuleHamiltEkinetic : public ::testing::Test TEST_F(TestModuleHamiltEkinetic, ekinetic_pw_op_cpu) { std::vector > hpsi(expected_hpsi.size(), std::complex(0.0, 0.0)); - ekinetic_cpu_op()(cpu_ctx, band, dim, dim, tpiba2, gk2.data(), hpsi.data(), psi.data()); + ekinetic_cpu_op()(cpu_ctx, band, dim, dim, false, tpiba2, gk2.data(), hpsi.data(), psi.data()); for (int ii = 0; ii < hpsi.size(); ii++) { EXPECT_LT(std::abs(hpsi[ii] - expected_hpsi[ii]), 1e-6); } @@ -89,7 +89,7 @@ TEST_F(TestModuleHamiltEkinetic, ekinetic_pw_op_gpu) syncmem_d_h2d_op()(gpu_ctx, cpu_ctx, gk2_dev, gk2.data(), gk2.size()); syncmem_cd_h2d_op()(gpu_ctx, cpu_ctx, psi_dev, psi.data(), psi.size()); // ekinetic_cpu_op()(cpu_ctx, band, dim, dim, tpiba2, gk2.data(), hpsi.data(), psi.data()); - ekinetic_gpu_op()(gpu_ctx, band, dim, dim, tpiba2, gk2_dev, hpsi_dev, psi_dev); + ekinetic_gpu_op()(gpu_ctx, band, dim, dim, false, tpiba2, gk2_dev, hpsi_dev, psi_dev); syncmem_cd_d2h_op()(cpu_ctx, gpu_ctx, hpsi.data(), hpsi_dev, hpsi.size()); for (int ii = 0; ii < hpsi.size(); ii++) { diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/force_op_test.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/force_op_test.cpp index a791fd933ba..3da3ca3b196 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/force_op_test.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/force_op_test.cpp @@ -2887,7 +2887,6 @@ TEST_F(TestSrcPWForceMultiDevice, cal_force_nl_op_cpu) hamilt::cal_force_nl_op()(cpu_ctx, multi_proj, nbands_occ, - wg_nc, ntype, spin, deeq_2, @@ -2895,7 +2894,6 @@ TEST_F(TestSrcPWForceMultiDevice, cal_force_nl_op_cpu) deeq_4, forcenl_nc, nbands, - ik, nkb, atom_nh.data(), atom_na.data(), @@ -2980,7 +2978,6 @@ TEST_F(TestSrcPWForceMultiDevice, cal_force_nl_op_gpu) hamilt::cal_force_nl_op()(gpu_ctx, multi_proj, nbands_occ, - wg_nc, ntype, spin, deeq_2, @@ -2988,7 +2985,6 @@ TEST_F(TestSrcPWForceMultiDevice, cal_force_nl_op_gpu) deeq_4, forcenl_nc, nbands, - ik, nkb, d_atom_nh, d_atom_na, diff --git a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/stress_op_test.cpp b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/stress_op_test.cpp index a6e482cdae0..4f84fa098d0 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/kernels/test/stress_op_test.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/kernels/test/stress_op_test.cpp @@ -13,7 +13,7 @@ TEST(TestSrcPWStressMultiDevice, cal_dbecp_noevc_nl_op_cpu) const double tpiba = 0.61599855952741045; std::vector gcar = {2.0000000000000000, -2.0000000000000000, -2.0000000000000000, 1.0000000000000000, -1.0000000000000000, -1.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0000000000000000, -1.0000000000000000, 1.0000000000000000, 1.0000000000000000, -2.0000000000000000, 2.0000000000000000, 2.0000000000000000, 2.0000000000000000, -2.0000000000000000, 0.0000000000000000, 1.0000000000000000, -1.0000000000000000, 1.0000000000000000, 0.0000000000000000, 0.0000000000000000, 2.0000000000000000, -1.0000000000000000, 1.0000000000000000, 3.0000000000000000, 2.0000000000000000, -2.0000000000000000, 2.0000000000000000, 1.0000000000000000, -1.0000000000000000, 3.0000000000000000, -1.0000000000000000, 1.0000000000000000, -3.0000000000000000, -2.0000000000000000, 2.0000000000000000, -2.0000000000000000, 1.0000000000000000, -1.0000000000000000, -3.0000000000000000, 0.0000000000000000, 0.0000000000000000, -2.0000000000000000, -1.0000000000000000, 1.0000000000000000, -1.0000000000000000, -2.0000000000000000, 2.0000000000000000, 0.0000000000000000, 2.0000000000000000, 0.0000000000000000, -2.0000000000000000, 1.0000000000000000, 1.0000000000000000, -1.0000000000000000, 0.0000000000000000, 2.0000000000000000, 0.0000000000000000, -1.0000000000000000, 3.0000000000000000, 1.0000000000000000, 3.0000000000000000, -1.0000000000000000, -1.0000000000000000, 2.0000000000000000, 0.0000000000000000, 0.0000000000000000, 1.0000000000000000, 1.0000000000000000, 1.0000000000000000, 0.0000000000000000, 2.0000000000000000, 2.0000000000000000, 3.0000000000000000, -1.0000000000000000, 1.0000000000000000, 2.0000000000000000, 0.0000000000000000, 2.0000000000000000, 1.0000000000000000, 1.0000000000000000, 3.0000000000000000, 1.0000000000000000, 1.0000000000000000, -3.0000000000000000, 0.0000000000000000, 2.0000000000000000, -2.0000000000000000, -1.0000000000000000, 3.0000000000000000, -1.0000000000000000, 2.0000000000000000, 2.0000000000000000, -2.0000000000000000, 1.0000000000000000, 3.0000000000000000, -1.0000000000000000, 3.0000000000000000, 1.0000000000000000, -1.0000000000000000, 2.0000000000000000, 2.0000000000000000, 0.0000000000000000, 1.0000000000000000, 3.0000000000000000, 1.0000000000000000, 3.0000000000000000, 1.0000000000000000, 1.0000000000000000, 2.0000000000000000, 2.0000000000000000, 2.0000000000000000, -1.0000000000000000, -3.0000000000000000, 1.0000000000000000, -2.0000000000000000, -2.0000000000000000, 2.0000000000000000, -2.0000000000000000, -2.0000000000000000, -2.0000000000000000, -3.0000000000000000, -1.0000000000000000, -1.0000000000000000, -1.0000000000000000, -3.0000000000000000, -1.0000000000000000, -2.0000000000000000, -2.0000000000000000, 0.0000000000000000, -3.0000000000000000, -1.0000000000000000, 1.0000000000000000, 1.0000000000000000, -3.0000000000000000, -1.0000000000000000, 0.0000000000000000, -2.0000000000000000, 0.0000000000000000, -1.0000000000000000, -1.0000000000000000, 1.0000000000000000, -2.0000000000000000, 0.0000000000000000, 2.0000000000000000, 1.0000000000000000, -3.0000000000000000, 1.0000000000000000, 0.0000000000000000, -2.0000000000000000, 2.0000000000000000, -1.0000000000000000, -1.0000000000000000, 3.0000000000000000, -1.0000000000000000, -1.0000000000000000, -3.0000000000000000, -2.0000000000000000, 0.0000000000000000, -2.0000000000000000, -3.0000000000000000, 1.0000000000000000, -1.0000000000000000, 0.0000000000000000, -2.0000000000000000, -2.0000000000000000, -1.0000000000000000, -1.0000000000000000, -1.0000000000000000, -2.0000000000000000, 0.0000000000000000, 0.0000000000000000, -3.0000000000000000, 1.0000000000000000, 1.0000000000000000}; - std::vector kvec_c = {0.0000000000000000}; + std::vector kvec_c = {0.0000000000000000, 0.0000000000000000, 0.0000000000000000}; std::vector> vkb = {{0.1959277889216247, 0.0000000000000000}, {0.3292263195311197, 0.0000000000000000}, {0.3833320420712772, -0.0000000000000000}, {0.3292263195311197, -0.0000000000000000}, {0.1959277889216247, -0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.3292263195311197, -0.0000000000000000}, {0.3121883316125419, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.1959277889216247, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.1959277889216247, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.3121883316125419, 0.0000000000000000}, {0.3292263195311197, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.3292263195311197, -0.0000000000000000}, {0.3121883316125419, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.3121883316125419, -0.0000000000000000}, {0.3292263195311197, -0.0000000000000000}, {0.2495383154917130, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2495383154917130, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.1959277889216247, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2495383154917130, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.2084900583919441, -0.0000000000000000}, {0.1959277889216247, -0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.1959277889216247, 0.0000000000000000}, {0.1959277889216247, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.3121883316125419, 0.0000000000000000}, {0.3292263195311197, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.3292263195311197, 0.0000000000000000}, {0.3121883316125419, 0.0000000000000000}, {0.2084900583919441, 0.0000000000000000}, {0.1588244263337111, 0.0000000000000000}, {0.2318163335599036, 0.0000000000000000}, {0.2916492898304017, 0.0000000000000000}, {0.2605982137021648, 0.0000000000000000}, {0.1588244263337111, 0.0000000000000000}, {0.2605982137021648, 0.0000000000000000}, {0.3602727707771828, 0.0000000000000000}, {0.3602727707771828, 0.0000000000000000}, {0.2605982137021648, 0.0000000000000000}, {0.2768133075187308, 0.0000000000000000}, {0.2117172164531642, 0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1191161929559753}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.1319268716568682}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1191161929559753}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.1007653341101891}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1007653341101891}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.1007653341101891}, {0.0000000000000000, -0.1319268716568682}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1007653341101891}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0839101408927066}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1007653341101891}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.1007653341101891}, {0.0000000000000000, -0.1319268716568682}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1007653341101891}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.1007653341101891}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.1074700120541082}, {-0.0000000000000000, 0.1429603824496169}, {-0.0000000000000000, 0.1132688983356121}, {-0.0000000000000000, 0.0520569223767372}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.1041138447534744}, {-0.0000000000000000, 0.0660471629375616}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0520569223767372}, {0.0000000000000000, -0.0680879572845678}, {0.0000000000000000, -0.0667352877462083}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.0839101408927066}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0839101408927066}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1007653341101892}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1191161929559753}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, -0.0439756238856228}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.0439756238856228}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.1319268716568682}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1007653341101892}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.1319268716568682}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, -0.1191161929559753}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.0716466747027388}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0566344491678060}, {0.0000000000000000, -0.1041138447534745}, {0.0000000000000000, -0.1074700120541082}, {-0.0000000000000000, 0.0520569223767372}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0660471629375617}, {0.0000000000000000, -0.1041138447534745}, {0.0000000000000000, -0.0953231401983950}, {0.0000000000000000, -0.1112254795770137}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.0619166231573246}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.1191161929559753}, {-0.0000000000000000, 0.1319268716568682}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0619166231573246}, {-0.0000000000000000, 0.1007653341101892}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.1319268716568682}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.1191161929559753}, {0.0000000000000000, -0.0619166231573246}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.1319268716568682}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.0439756238856227}, {0.0000000000000000, -0.0439756238856227}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0439756238856227}, {0.0000000000000000, -0.1007653341101892}, {0.0000000000000000, -0.0619166231573246}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0439756238856227}, {-0.0000000000000000, 0.0537350060270541}, {0.0000000000000000, -0.0238267304082695}, {-0.0000000000000000, 0.0283172245839030}, {-0.0000000000000000, 0.0780853835651058}, {-0.0000000000000000, 0.0895583433784236}, {0.0000000000000000, -0.0780853835651058}, {0.0000000000000000, -0.0330235814687808}, {-0.0000000000000000, 0.0330235814687808}, {-0.0000000000000000, 0.0780853835651058}, {-0.0000000000000000, 0.0680879572845679}, {-0.0000000000000000, 0.0667352877462083}, {-0.1959277889216247, 0.0000000000000000}, {0.0000000000000000, 0.3292263195311197}, {0.3833320420712772, -0.0000000000000000}, {0.0000000000000000, -0.3292263195311197}, {-0.1959277889216247, -0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.0000000000000000, -0.3292263195311197}, {-0.3121883316125419, -0.0000000000000000}, {-0.0000000000000000, 0.2084900583919441}, {-0.1959277889216247, -0.0000000000000000}, {-0.0000000000000000, 0.2084900583919441}, {-0.0000000000000000, -0.2084900583919441}, {-0.1959277889216247, 0.0000000000000000}, {-0.0000000000000000, -0.2084900583919441}, {-0.3121883316125419, 0.0000000000000000}, {0.0000000000000000, 0.3292263195311197}, {0.2495383154917130, 0.0000000000000000}, {0.2495383154917130, 0.0000000000000000}, {0.0000000000000000, -0.3292263195311197}, {-0.3121883316125419, -0.0000000000000000}, {-0.0000000000000000, 0.2084900583919441}, {0.0000000000000000, -0.2084900583919441}, {-0.3121883316125419, -0.0000000000000000}, {-0.0000000000000001, 0.3292263195311197}, {0.2495383154917130, 0.0000000000000001}, {-0.0000000000000000, 0.2084900583919441}, {0.2495383154917130, 0.0000000000000001}, {0.0000000000000001, -0.2084900583919441}, {0.0000000000000000, 0.2084900583919441}, {0.2495383154917130, 0.0000000000000000}, {0.0000000000000000, -0.2084900583919441}, {-0.1959277889216247, -0.0000000000000000}, {-0.0000000000000000, 0.2084900583919441}, {-0.0000000000000000, 0.2084900583919441}, {0.2495383154917130, 0.0000000000000001}, {0.0000000000000001, -0.2084900583919441}, {0.0000000000000001, -0.2084900583919441}, {-0.1959277889216247, -0.0000000000000001}, {-0.0000000000000000, -0.2084900583919441}, {-0.1959277889216247, 0.0000000000000000}, {-0.1959277889216247, 0.0000000000000001}, {0.0000000000000001, 0.2084900583919441}, {0.0000000000000001, 0.2084900583919441}, {0.2495383154917130, -0.0000000000000001}, {-0.0000000000000000, -0.2084900583919441}, {-0.0000000000000000, -0.2084900583919441}, {-0.3121883316125419, 0.0000000000000000}, {0.0000000000000000, 0.3292263195311197}, {0.2495383154917130, 0.0000000000000000}, {0.0000000000000000, 0.2084900583919441}, {0.2495383154917130, 0.0000000000000000}, {0.0000000000000000, -0.2084900583919441}, {0.0000000000000001, 0.2084900583919441}, {0.2495383154917130, -0.0000000000000001}, {-0.0000000000000000, -0.2084900583919441}, {0.2495383154917130, -0.0000000000000001}, {-0.0000000000000001, -0.3292263195311197}, {-0.3121883316125419, 0.0000000000000000}, {0.0000000000000000, 0.2084900583919441}, {0.1123058288786304, -0.1123058288786304}, {0.1639189014500104, -0.1639189014500105}, {-0.2062271905673179, -0.2062271905673178}, {-0.1842707640739018, 0.1842707640739018}, {0.1123058288786304, 0.1123058288786304}, {-0.1842707640739018, -0.1842707640739018}, {-0.2547513192934127, 0.2547513192934126}, {0.2547513192934126, 0.2547513192934127}, {0.1842707640739018, -0.1842707640739018}, {0.1059318666456010, -0.2557421491433081}, {0.1497066794479725, -0.1497066794479725}, {-0.0000000000000000, -0.0839101408927066}, {-0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0619166231573246, -0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, 0.0000000000000000}, {-0.0619166231573246, -0.0000000000000000}, {-0.0000000000000000, 0.1191161929559753}, {0.1319268716568682, 0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {0.1319268716568682, 0.0000000000000000}, {0.1319268716568682, -0.0000000000000000}, {-0.0000000000000000, -0.0839101408927066}, {0.1319268716568682, -0.0000000000000000}, {-0.0000000000000000, -0.1191161929559753}, {-0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.1007653341101891}, {0.0619166231573246, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101891}, {0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101891}, {-0.1319268716568682, -0.0000000000000000}, {-0.1319268716568682, 0.0000000000000000}, {-0.0000000000000000, 0.1007653341101891}, {0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.0439756238856227, -0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {-0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, -0.0839101408927066}, {-0.0439756238856227, 0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101891}, {0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101891}, {-0.1319268716568682, -0.0000000000000000}, {-0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, 0.1007653341101891}, {0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, 0.1007653341101891}, {0.0619166231573246, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {0.0759927742976599, 0.0759927742976599}, {0.1010882558711464, 0.1010882558711464}, {0.0800932061106409, -0.0800932061106410}, {-0.0368098028202926, -0.0368098028202926}, {0.0000000000000000, 0.0000000000000000}, {0.0736196056405852, -0.0736196056405852}, {-0.0467023967912827, -0.0467023967912827}, {0.0000000000000000, 0.0000000000000000}, {-0.0368098028202926, -0.0368098028202926}, {-0.0629050701457150, -0.0260561331963860}, {-0.0471889745097794, -0.0471889745097794}, {-0.0000000000000000, -0.0839101408927066}, {-0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0619166231573246, -0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {-0.0000000000000000, 0.1007653341101892}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.0439756238856227, -0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, 0.0839101408927066}, {0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101892}, {-0.0000000000000000, 0.1007653341101892}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, -0.1191161929559753}, {-0.0619166231573246, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.1319268716568682, -0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {0.0439756238856227, 0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.0439756238856227, -0.0000000000000000}, {-0.1319268716568682, -0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {0.0439756238856227, 0.0000000000000000}, {0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.0439756238856228, 0.0000000000000000}, {0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, 0.0839101408927066}, {0.1319268716568682, -0.0000000000000000}, {0.0439756238856228, -0.0000000000000000}, {-0.0000000000000000, -0.1007653341101892}, {-0.1319268716568682, 0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, -0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101892}, {-0.0439756238856227, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, -0.1007653341101892}, {-0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, 0.1191161929559753}, {0.1319268716568682, 0.0000000000000000}, {-0.0506618495317733, -0.0506618495317733}, {0.0000000000000000, 0.0000000000000000}, {-0.0400466030553205, 0.0400466030553205}, {0.0736196056405853, 0.0736196056405852}, {0.0759927742976599, -0.0759927742976599}, {0.0368098028202926, -0.0368098028202926}, {-0.0000000000000000, -0.0000000000000000}, {0.0467023967912827, -0.0467023967912827}, {-0.0736196056405852, -0.0736196056405853}, {-0.0880670982040010, -0.0364785864749405}, {-0.0786482908496323, -0.0786482908496323}, {0.0000000000000000, 0.0839101408927066}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {0.0000000000000000, -0.1007653341101892}, {-0.0619166231573246, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, 0.0839101408927066}, {0.0439756238856227, 0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, -0.0839101408927066}, {-0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0619166231573246, 0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {-0.0000000000000000, 0.0000000000000000}, {0.0619166231573246, 0.0000000000000000}, {0.0000000000000000, -0.1191161929559753}, {-0.1319268716568682, -0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0619166231573246, -0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {0.0439756238856227, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.1319268716568682, -0.0000000000000000}, {-0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, 0.1007653341101892}, {0.1319268716568682, 0.0000000000000000}, {0.0439756238856227, 0.0000000000000000}, {0.0000000000000000, -0.0839101408927066}, {-0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, 0.0839101408927066}, {0.0000000000000000, 0.0839101408927066}, {0.0439756238856227, -0.0000000000000000}, {0.1319268716568682, -0.0000000000000000}, {-0.0000000000000000, -0.1007653341101892}, {-0.0439756238856227, 0.0000000000000000}, {-0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, 0.1191161929559753}, {0.0619166231573246, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.1319268716568682, 0.0000000000000000}, {0.0000000000000000, -0.1007653341101892}, {-0.0439756238856227, -0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0439756238856227, -0.0000000000000000}, {-0.0000000000000000, -0.1007653341101892}, {-0.0619166231573246, 0.0000000000000000}, {-0.0000000000000000, -0.0000000000000000}, {-0.0439756238856227, 0.0000000000000000}, {0.0379963871488300, 0.0379963871488300}, {-0.0168480426451911, -0.0168480426451910}, {0.0200233015276602, -0.0200233015276602}, {-0.0552147042304389, -0.0552147042304389}, {-0.0633273119147166, 0.0633273119147166}, {-0.0552147042304389, 0.0552147042304389}, {0.0233511983956413, 0.0233511983956413}, {-0.0233511983956413, 0.0233511983956413}, {0.0552147042304389, 0.0552147042304389}, {0.0629050701457150, 0.0260561331963861}, {0.0471889745097794, 0.0471889745097794}}; std::vector> vkb0i = {{0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0119933519685976}, {-0.0000000000000000, 0.0139850234834634}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0139850234834634}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0251913335271091}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0251913335271091}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0039977839895325}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0039977839895325}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0139850234834634}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0139850234834634}, {-0.0000000000000000, 0.0139850234834634}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0039977839895325}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0251913335271091}, {-0.0000000000000000, 0.0039977839895325}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0119933519685976}, {-0.0000000000000000, 0.0119933519685976}, {-0.0000000000000000, 0.0251913335271091}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0279700469621601}, {-0.0000000000000000, 0.0412777487684869}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0412777487720041}, {-0.0000000000000000, 0.0279700469645434}, {-0.0000000000000000, 0.0251913335271091}, {-0.0000000000000000, 0.0412777487684869}, {-0.0000000000000000, 0.0595607437938820}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0279700469621601}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0279700469645434}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0595607437938820}, {-0.0000000000000000, 0.0412777487720041}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0412777487684869}, {-0.0000000000000000, 0.0595580964730781}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0079955679815631}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0412777487684869}, {-0.0000000000000000, 0.0503826670509438}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0503826670509438}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0279700469621601}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0251913335271091}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0279700469621601}, {-0.0000000000000000, 0.0399778398878310}, {-0.0000000000000000, 0.0279700469645434}, {-0.0000000000000000, 0.0279700469645434}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0399778398878310}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0595580964869841}, {-0.0000000000000000, 0.0412777487720041}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0399778398965743}, {-0.0000000000000000, 0.0503826670553068}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0399778398953252}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0079955679815631}, {-0.0000000000000000, 0.0503826670553068}, {-0.0000000000000000, 0.0412777487720041}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0079955679815631}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0139850234834634}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0206388743912779}, {-0.0000000000000000, 0.0139850234858467}, {-0.0000000000000000, 0.0251913335299711}, {-0.0000000000000000, 0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0039977839895325}, {-0.0000000000000000, 0.0139850234834634}, {-0.0000000000000000, 0.0039977839895325}, {-0.0000000000000000, 0.0039977839895325}, {-0.0000000000000000, 0.0139850234858467}, {-0.0000000000000000, 0.0039977839895325}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0206388743912779}, {-0.0000000000000000, 0.0251913335242470}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0119933519636014}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0119933519636014}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0119933519636014}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0251913335299711}, {0.0000000000000000, -0.0119933519636014}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0119933519611033}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0139850234834634}, {0.0000000000000000, -0.0119933519685976}, {0.0000000000000000, -0.0119933519611033}, {0.0000000000000000, -0.0251913335242470}, {0.0000000000000000, -0.0119933519685976}, {-0.0000000000000000, 0.0119933519636014}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0119933519636014}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0039977839895325}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0206388743877607}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0119933519685976}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0139850234834634}, {0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0206388743877607, -0.0000000000000000}, {-0.0000000000000000, 0.0139850234834634}, {0.0000000000000000, 0.0000000000000000}, {0.0206388743877607, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, -0.0139850234834634}, {-0.0119933519685976, -0.0000000000000000}, {0.0119933519685976, -0.0000000000000000}, {-0.0000000000000000, -0.0139850234834634}, {-0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, -0.0251913335271091}, {-0.0206388743877607, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0039977839895325, 0.0000000000000000}, {-0.0119933519685976, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0206388743877607, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0119933519685976, -0.0000000000000000}, {-0.0000000000000000, 0.0251913335271091}, {0.0119933519685976, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0039977839895325, 0.0000000000000000}, {-0.0000000000000000, 0.0139850234834634}, {0.0039977839895325, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0039977839895325, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, -0.0139850234834634}, {-0.0039977839895325, 0.0000000000000000}, {0.0000000000000000, 0.0139850234834634}, {-0.0000000000000000, -0.0139850234834634}, {-0.0119933519685976, 0.0000000000000000}, {-0.0039977839895325, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0119933519685976, 0.0000000000000000}, {-0.0039977839895325, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, -0.0251913335271091}, {-0.0039977839895325, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0119933519685976, -0.0000000000000000}, {-0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0251913335271091}, {0.0119933519685976, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0206388743877607, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, -0.0279700469621601}, {-0.0412777487684869, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0412777487720041, 0.0000000000000000}, {0.0000000000000000, -0.0279700469645434}, {-0.0000000000000000, 0.0251913335271091}, {0.0412777487684869, 0.0000000000000000}, {0.0000000000000000, -0.0595607437938820}, {-0.0399778398965743, -0.0000000000000000}, {0.0000000000000000, -0.0279700469621601}, {-0.0399778398953252, -0.0000000000000000}, {0.0399778398965743, -0.0000000000000000}, {-0.0000000000000000, -0.0279700469645434}, {0.0399778398953252, -0.0000000000000000}, {-0.0000000000000000, -0.0595607437938820}, {-0.0412777487720041, 0.0000000000000000}, {-0.0000000000000000, 0.0251913335242470}, {-0.0000000000000000, 0.0251913335242470}, {0.0412777487684869, 0.0000000000000000}, {0.0000000000000000, -0.0595580964730781}, {-0.0399778398965743, -0.0000000000000000}, {0.0079955679815631, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0412777487684869, -0.0000000000000000}, {-0.0000000000000000, 0.0503826670509438}, {-0.0079955679815631, -0.0000000000000000}, {-0.0000000000000000, 0.0251913335242470}, {0.0399778398953252, 0.0000000000000000}, {-0.0399778398953252, 0.0000000000000000}, {-0.0000000000000000, 0.0503826670509438}, {0.0399778398965743, 0.0000000000000000}, {0.0000000000000000, -0.0279700469621601}, {-0.0399778398965743, -0.0000000000000000}, {-0.0079955679815631, -0.0000000000000000}, {-0.0000000000000000, 0.0251913335271091}, {0.0399778398965743, 0.0000000000000000}, {0.0079955679815631, 0.0000000000000000}, {0.0000000000000000, -0.0279700469621601}, {0.0399778398878310, -0.0000000000000000}, {-0.0000000000000000, -0.0279700469645434}, {-0.0000000000000000, -0.0279700469645434}, {-0.0079955679815631, 0.0000000000000000}, {-0.0399778398878310, 0.0000000000000000}, {0.0000000000000000, 0.0251913335242470}, {0.0079955679815631, -0.0000000000000000}, {0.0399778398965743, -0.0000000000000000}, {-0.0000000000000000, -0.0595580964869841}, {-0.0412777487720041, 0.0000000000000000}, {-0.0000000000000000, 0.0251913335242470}, {-0.0399778398965743, 0.0000000000000000}, {-0.0000000000000000, 0.0503826670553068}, {0.0399778398953252, 0.0000000000000000}, {-0.0399778398953252, 0.0000000000000000}, {0.0000000000000000, 0.0251913335242470}, {0.0079955679815631, -0.0000000000000000}, {0.0000000000000000, 0.0503826670553068}, {0.0412777487720041, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0079955679815631, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0000000000000000, -0.0139850234834634}, {-0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {0.0206388743912779, 0.0000000000000000}, {0.0000000000000000, -0.0139850234858467}, {-0.0000000000000000, 0.0251913335299711}, {0.0206388743877607, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0039977839895325, -0.0000000000000000}, {0.0000000000000000, -0.0139850234834634}, {-0.0039977839895325, -0.0000000000000000}, {0.0039977839895325, -0.0000000000000000}, {-0.0000000000000000, -0.0139850234858467}, {0.0039977839895325, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0206388743912779, 0.0000000000000000}, {-0.0000000000000000, 0.0251913335242470}, {0.0000000000000000, 0.0000000000000000}, {-0.0206388743877607, -0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {-0.0119933519636014, -0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {-0.0000000000000000, 0.0000000000000000}, {0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0119933519685976, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0039977839895325, -0.0000000000000000}, {0.0039977839895325, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0119933519636014, 0.0000000000000000}, {-0.0000000000000000, 0.0139850234834634}, {0.0119933519636014, 0.0000000000000000}, {0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, -0.0251913335299711}, {-0.0119933519636014, -0.0000000000000000}, {-0.0119933519685976, -0.0000000000000000}, {-0.0000000000000000, 0.0139850234834634}, {-0.0119933519611033, 0.0000000000000000}, {0.0000000000000000, 0.0139850234834634}, {0.0000000000000000, 0.0139850234834634}, {0.0119933519685976, -0.0000000000000000}, {0.0119933519611033, -0.0000000000000000}, {-0.0000000000000000, -0.0251913335242470}, {-0.0119933519685976, 0.0000000000000000}, {0.0119933519636014, -0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0119933519636014, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0039977839895325, -0.0000000000000000}, {0.0039977839895325, -0.0000000000000000}, {-0.0000000000000000, -0.0000000000000000}, {0.0119933519685976, -0.0000000000000000}, {0.0000000000000000, -0.0000000000000000}, {-0.0206388743877607, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {-0.0119933519685976, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}, {0.0000000000000000, 0.0000000000000000}}; @@ -96,8 +96,6 @@ TEST(TestSrcPWStressMultiDevice, cal_stress_nl_op_cpu) nbands_occ, ntype, spin, - wg_nc, - ik, deeq_2, deeq_3, deeq_4, @@ -271,8 +269,6 @@ TEST(TestSrcPWStressMultiDevice, cal_stress_nl_op_gpu) nbands_occ, ntype, spin, - wg_nc, - ik, deeq_2, deeq_3, deeq_4, diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/CMakeLists.txt b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/CMakeLists.txt index c8370d10831..83f7955dbb7 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/CMakeLists.txt +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/CMakeLists.txt @@ -7,12 +7,13 @@ list(APPEND operator_ks_pw_srcs velocity_pw.cpp ) -add_library( - operator_ks_pw - OBJECT - ${operator_ks_pw_srcs} -) +# this library is included in hamilt_pwdft now +#add_library( +# operator_ks_pw +# OBJECT +# ${operator_ks_pw_srcs} +#) -if(ENABLE_COVERAGE) - add_coverage(operator_ks_pw) -endif() +#if(ENABLE_COVERAGE) +# add_coverage(operator_ks_pw) +#endif() diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.cpp index 54f04da14d6..65b6c5b3dc3 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.cpp @@ -37,14 +37,15 @@ void Ekinetic>::act( const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { ModuleBase::timer::tick("Operator", "EkineticPW"); int max_npw = nbasis / npol; const Real *gk2_ik = &(this->gk2[this->ik * this->gk2_col]); // denghui added 20221019 - ekinetic_op()(this->ctx, nbands, ngk_ik, max_npw, tpiba2, gk2_ik, tmhpsi, tmpsi_in); + ekinetic_op()(this->ctx, nbands, ngk_ik, max_npw, is_first_node, tpiba2, gk2_ik, tmhpsi, tmpsi_in); // for (int ib = 0; ib < nbands; ++ib) // { // for (int ig = 0; ig < ngk_ik; ++ig) diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.h b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.h index f6787a48dc1..8061ae6e2dd 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.h +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/ekinetic_pw.h @@ -42,7 +42,8 @@ class Ekinetic> : public OperatorPW const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik = 0)const override; + const int ngk_ik = 0, + const bool is_first_node = false)const override; // denghuilu added for copy construct at 20221105 int get_gk2_row() const {return this->gk2_row;} diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.cpp index 80abb10e949..1046a90c9a1 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.cpp @@ -43,7 +43,8 @@ void Meta>::act( const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { if (XC_Functional::get_func_type() != 3) { @@ -51,6 +52,10 @@ void Meta>::act( } ModuleBase::timer::tick("Operator", "MetaPW"); + if(is_first_node) + { + setmem_complex_op()(this->ctx, tmhpsi, 0, nbasis*nbands/npol); + } const int current_spin = this->isk[this->ik]; int max_npw = nbasis / npol; diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.h b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.h index a3e526cf910..21fc574f5b9 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.h +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/meta_pw.h @@ -43,7 +43,8 @@ class Meta> : public OperatorPW const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk = 0)const override; + const int ngk_ik = 0, + const bool is_first_node = false)const override; // denghui added for copy constructor at 20221105 Real get_tpiba() const @@ -83,6 +84,7 @@ class Meta> : public OperatorPW using vector_mul_vector_op = hsolver::vector_mul_vector_op; using resmem_complex_op = base_device::memory::resize_memory_op; using delmem_complex_op = base_device::memory::delete_memory_op; + using setmem_complex_op = base_device::memory::set_memory_op; }; } // namespace hamilt diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.cpp index 7377dffbc69..96e3db88eef 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.cpp @@ -214,9 +214,14 @@ void Nonlocal>::act( const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { ModuleBase::timer::tick("Operator", "NonlocalPW"); + if(is_first_node) + { + setmem_complex_op()(this->ctx, tmhpsi, 0, nbasis*nbands/npol); + } if(!PARAM.inp.use_paw) { this->npw = ngk_ik; diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.h b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.h index c23a1cc82ea..91e760920a6 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.h +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/nonlocal_pw.h @@ -43,7 +43,8 @@ class Nonlocal> : public OperatorPW const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk = 0)const override; + const int ngk_ik = 0, + const bool is_first_node = false)const override; const int *get_isk() const {return this->isk;} const pseudopot_cell_vnl *get_ppcell() const {return this->ppcell;} diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/projop_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/projop_pw.cpp index 2543f78662f..b419d9ce88e 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/projop_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/projop_pw.cpp @@ -19,7 +19,7 @@ #ifdef __MPI #include "module_base/parallel_reduce.h" #endif - +#include "module_io/orb_io.h" /** * =============================================================================================== * @@ -137,7 +137,7 @@ void init_proj(const std::string& orbital_dir, double dr_ = -1.0; std::vector nzeta; // number of radials for each l std::vector> radials; // radials arranged in serial - AtomicRadials::read_abacus_orb(ifs, elem, ecut, nr_, dr_, nzeta, radials); + ModuleIO::read_abacus_orb(ifs, elem, ecut, nr_, dr_, nzeta, radials); #ifdef __DEBUG assert(elem != ""); assert(ecut != -1.0); diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.cpp index 8fed260c1c5..63ead6d57f0 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.cpp @@ -41,9 +41,14 @@ void Veff>::act( const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { ModuleBase::timer::tick("Operator", "VeffPW"); + if(is_first_node) + { + setmem_complex_op()(this->ctx, tmhpsi, 0, nbasis*nbands/npol); + } int max_npw = nbasis / npol; const int current_spin = this->isk[this->ik]; diff --git a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.h b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.h index c8b19047f4f..5ec042282f8 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.h +++ b/source/module_hamilt_pw/hamilt_pwdft/operator_pw/veff_pw.h @@ -41,7 +41,8 @@ class Veff> : public OperatorPW const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik = 0)const override; + const int ngk_ik = 0, + const bool is_first_node = false)const override; // denghui added for copy constructor at 20221105 const Real *get_veff() const {return this->veff;} @@ -72,6 +73,7 @@ class Veff> : public OperatorPW using resmem_complex_op = base_device::memory::resize_memory_op; using delmem_complex_op = base_device::memory::delete_memory_op; + using setmem_complex_op = base_device::memory::set_memory_op; }; } // namespace hamilt diff --git a/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp b/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp index e4c7fca0eae..829029e4bba 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.cpp @@ -35,10 +35,6 @@ void Parallel_Grid::init( const int &bz_in) { -#ifndef __MPI - return; -#endif - ModuleBase::TITLE("Parallel_Grid","init"); this->ncx = ncx_in; @@ -47,7 +43,7 @@ void Parallel_Grid::init( this->nczp = nczp_in; this->nrxx = nrxx_in; this->nbz = nbz_in; - this->bz = bz_in; + this->bz = bz_in; if(nczp<0) { @@ -60,7 +56,11 @@ void Parallel_Grid::init( assert(ncz > 0); this->ncxy = ncx * ncy; - this->ncxyz = ncxy * ncz; + this->ncxyz = ncxy * ncz; + +#ifndef __MPI + return; +#endif // enable to call this function again liuyu 2023-03-10 if(this->allocate) @@ -84,14 +84,16 @@ void Parallel_Grid::init( this->nproc_in_pool = new int[GlobalV::KPAR]; int nprocgroup; - if(PARAM.inp.esolver_type == "sdft") nprocgroup = GlobalV::NPROC_IN_STOGROUP; - else nprocgroup = GlobalV::NPROC; + if(PARAM.inp.esolver_type == "sdft") { nprocgroup = GlobalV::NPROC_IN_STOGROUP; + } else { nprocgroup = GlobalV::NPROC; +} const int remain_pro = nprocgroup%GlobalV::KPAR; for(int i=0; inproc_in_pool[i]++; + if(inproc_in_pool[i]++; +} } this->numz = new int*[GlobalV::KPAR]; @@ -115,7 +117,7 @@ void Parallel_Grid::init( return; } -void Parallel_Grid::z_distribution(void) +void Parallel_Grid::z_distribution() { assert(allocate); @@ -126,7 +128,8 @@ void Parallel_Grid::z_distribution(void) // GlobalV::ofs_running << "\n now POOL=" << ip; const int nproc = nproc_in_pool[ip]; - if(ip>0) startp[ip] = startp[ip-1] + nproc_in_pool[ip-1]; + if(ip>0) { startp[ip] = startp[ip-1] + nproc_in_pool[ip-1]; +} // (1) how many z on each 'proc' in each 'pool' for(int iz=0; iz zpiece(ncxy); + for (int iz = 0; iz < this->ncz; ++iz) + { + ModuleBase::GlobalFunc::ZEROS(zpiece.data(), ncxy); + if (rank == 0) + { + for (int ix = 0; ix < ncx; ix++) + { + for (int iy = 0; iy < ncy; iy++) + { + const int ixy = ix * ncy + iy; + zpiece[ixy] = data_global[ixy * ncz + iz]; + } + } + } + this->zpiece_to_all(zpiece.data(), iz, data_local); + } +} + +void Parallel_Grid::zpiece_to_all(double* zpiece, const int& iz, double* rho) const { if(PARAM.inp.esolver_type == "sdft") { @@ -256,7 +280,7 @@ void Parallel_Grid::zpiece_to_all(double *zpiece, const int &iz, double *rho) #endif #ifdef __MPI -void Parallel_Grid::zpiece_to_stogroup(double *zpiece, const int &iz, double *rho) +void Parallel_Grid::zpiece_to_stogroup(double *zpiece, const int &iz, double *rho) const { assert(allocate); //TITLE("Parallel_Grid","zpiece_to_all"); @@ -323,9 +347,9 @@ void Parallel_Grid::zpiece_to_stogroup(double *zpiece, const int &iz, double *rh return; } -void Parallel_Grid::reduce_to_fullrho(double *rhotot, double *rhoin) +void Parallel_Grid::reduce(double* rhotot, const double* const rhoin)const { - //ModuleBase::TITLE("Parallel_Grid","reduce_to_fullrho"); + //ModuleBase::TITLE("Parallel_Grid","reduce"); // if not the first pool, wait here until processpr 0 // send the Barrier command. @@ -374,13 +398,9 @@ void Parallel_Grid::reduce_to_fullrho(double *rhotot, double *rhoin) if(GlobalV::MY_RANK==0) { - for(int ix=0; ixncx; ix++) - { - for(int iy=0; iyncy; iy++) - { - const int ir = ix * this->ncy + iy; - rhotot[ix * ncy * ncz + iy * ncz + iz] = zpiece[ir]; - } + for (int ixy = 0; ixy < this->ncxy;++ixy) + { + rhotot[ixy * ncz + iz] = zpiece[ixy]; } } } @@ -397,10 +417,6 @@ void Parallel_Grid::init_final_scf(const int &ncx_in, const int &ncy_in, const i const int &nrxx_in, const int &nbz_in, const int &bz_in) { -#ifndef __MPI - return; -#endif - ModuleBase::TITLE("Parallel_Grid","init"); this->ncx = ncx_in; @@ -409,7 +425,7 @@ const int &nrxx_in, const int &nbz_in, const int &bz_in) this->nczp = nczp_in; this->nrxx = nrxx_in; this->nbz = nbz_in; - this->bz = bz_in; + this->bz = bz_in; if(nczp<0) { @@ -422,7 +438,11 @@ const int &nrxx_in, const int &nbz_in, const int &bz_in) assert(ncz > 0); this->ncxy = ncx * ncy; - this->ncxyz = ncxy * ncz; + this->ncxyz = ncxy * ncz; + +#ifndef __MPI + return; +#endif // (2) assert(allocate_final_scf==false); @@ -433,7 +453,8 @@ const int &nrxx_in, const int &nbz_in, const int &bz_in) for(int i=0; inproc_in_pool[i]++; + if(inproc_in_pool[i]++; +} } this->numz = new int*[GlobalV::KPAR]; diff --git a/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.h b/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.h index 222c304baa7..f6e4811c030 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.h +++ b/source/module_hamilt_pw/hamilt_pwdft/parallel_grid.h @@ -11,8 +11,14 @@ class Parallel_Grid friend class Efield; friend class Symmetry_rho; - Parallel_Grid(); - ~Parallel_Grid(); + Parallel_Grid(); + Parallel_Grid(const int ncx_in, const int ncy_in, const int ncz_in, const int nczp_in, const int nrxx_in, const int nbz_in, const int bz_in) + :ncx(ncx_in), ncy(ncy_in), ncz(ncz_in), nczp(nczp_in), nrxx(nrxx_in), nbz(nbz_in), bz(bz_in), + ncxy(ncx_in* ncy_in), ncxyz(ncx_in* ncy_in* ncz_in) + { + assert(ncx > 0 && ncy > 0 && ncz > 0 && nczp >= 0 && nrxx > 0 && nbz > 0 && bz > 0); + } + ~Parallel_Grid(); void init(const int &ncx, const int &ncy, const int &ncz, const int &nczp, const int &nrxx, const int &nbz, const int &bz); @@ -21,12 +27,19 @@ class Parallel_Grid const int &nczp, const int &nrxx, const int &nbz, const int &bz); //LiuXh add 20180606 #ifdef __MPI - void zpiece_to_all(double *zpiece, const int &iz, double *rho); - void zpiece_to_stogroup(double *zpiece, const int &iz, double *rho); //qainrui add for sto-dft 2021-7-21 - - void reduce_to_fullrho(double *rhotot, double *rhoin); + void zpiece_to_all(double* zpiece, const int& iz, double* rho) const; + void zpiece_to_stogroup(double* zpiece, const int& iz, double* rho) const; //qainrui add for sto-dft 2021-7-21 + + /// @brief Broadcast data from root to all processors. The index order is [x][y][z]. + void bcast(const double* const data_global, double* data_local, const int& rank)const; + /// @brief Reduce data from all processors to root. The index order is [x][y][z]. + void reduce(double* rhotot, const double* constrhoin)const; #endif - + + const int& nx = this->ncx; + const int& ny = this->ncy; + const int& nz = this->ncz; + private: void z_distribution(void); @@ -41,13 +54,13 @@ class Parallel_Grid int ncz; int ncxy; int ncxyz; - int nczp; // different processors have different values. + int nczp; // number of z-layers (xy-planes) in each processor int nrxx; int nbz; int bz; - bool allocate; - bool allocate_final_scf; //LiuXh add 20180619 + bool allocate = false; + bool allocate_final_scf = false; //LiuXh add 20180619 }; #endif diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_func_cc.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_func_cc.cpp index 2850c58ef77..26d5e66c378 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_func_cc.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_func_cc.cpp @@ -5,6 +5,11 @@ #include "module_base/timer.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#ifdef USE_LIBXC +#include "module_hamilt_general/module_xc/xc_functional_libxc.h" +#endif + + //NLCC term, need to be tested template void Stress_Func::stress_cc(ModuleBase::matrix& sigma, @@ -47,7 +52,7 @@ void Stress_Func::stress_cc(ModuleBase::matrix& sigma, { #ifdef USE_LIBXC const auto etxc_vtxc_v - = XC_Functional::v_xc_meta(rho_basis->nrxx, GlobalC::ucell.omega, GlobalC::ucell.tpiba, chr); + = XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), rho_basis->nrxx, GlobalC::ucell.omega, GlobalC::ucell.tpiba, chr); // etxc = std::get<0>(etxc_vtxc_v); // vtxc = std::get<1>(etxc_vtxc_v); diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_func_kin.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_func_kin.cpp index bca76a5ff07..489e1fe0f89 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_func_kin.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_func_kin.cpp @@ -1,5 +1,6 @@ #include "stress_func.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_parameter/parameter.h" #include "module_base/timer.h" //calculate the kinetic stress in PW base @@ -29,8 +30,9 @@ void Stress_Func::stress_kin(ModuleBase::matrix& sigma, int npwx=0; for (int ik = 0; ik < p_kv->get_nks(); ik++) { - if (npwx < p_kv->ngk[ik]) + if (npwx < p_kv->ngk[ik]) { npwx = p_kv->ngk[ik]; +} } gk[0]= new FPTYPE[npwx]; @@ -39,6 +41,7 @@ void Stress_Func::stress_kin(ModuleBase::matrix& sigma, FPTYPE tpiba = ModuleBase::TWO_PI / GlobalC::ucell.lat0; FPTYPE twobysqrtpi = 2.0 / std::sqrt(ModuleBase::PI); FPTYPE* kfac = new FPTYPE[npwx]; + const int npol = GlobalC::ucell.get_npol(); for (int ik = 0; ik < p_kv->get_nks(); ik++) { @@ -69,10 +72,10 @@ void Stress_Func::stress_kin(ModuleBase::matrix& sigma, { for (int m = 0; m < l + 1; m++) { - for (int ibnd = 0; ibnd < GlobalV::NBANDS; ibnd++) + for (int ibnd = 0; ibnd < PARAM.inp.nbands; ibnd++) { - if (std::fabs(wg(ik, ibnd)) < ModuleBase::threshold_wg * wg(ik, 0)) - continue; + if (wg(ik, ibnd) == 0.0) { continue; +} const std::complex* ppsi = nullptr; ppsi = &(psi_in[0](ik, ibnd, 0)); @@ -85,6 +88,18 @@ void Stress_Func::stress_kin(ModuleBase::matrix& sigma, sum += wg(ik, ibnd) * gk[l][i] * gk[m][i] * kfac[i] * (FPTYPE((conj(ppsi[i]) * ppsi[i]).real())); } + if(npol == 2) + { + ppsi = &(psi_in[0](ik, ibnd, npwx)); +#ifdef _OPENMP +#pragma omp parallel for reduction(+ : sum) +#endif + for (int i = 0; i < npw; i++) + { + sum += wg(ik, ibnd) * gk[l][i] * gk[m][i] * kfac[i] + * (FPTYPE((conj(ppsi[i]) * ppsi[i]).real())); + } + } s_kin[l][m] += sum; } } diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_func_loc.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_func_loc.cpp index 7a0d614f6fa..d214c99ba1f 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_func_loc.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_func_loc.cpp @@ -23,10 +23,10 @@ void Stress_Func::stress_loc(ModuleBase::matrix& sigma, const int nspin_rho = (PARAM.inp.nspin == 2) ? 2 : 1; - if (PARAM.globalv.gamma_only_pw && is_pw) { fact=2.0; -} - - + if (PARAM.inp.gamma_only && is_pw) + { + fact=2.0; + } std::vector> aux(rho_basis->nmaxgr); @@ -52,11 +52,11 @@ void Stress_Func::stress_loc(ModuleBase::matrix& sigma, aux[ir] = std::complex(chr->rho[0][ir], 0.0 ); } } - for (int is = 1; is < nspin_rho; is++) + if(nspin_rho == 2) { for (int ir = irb; ir < ir_end; ++ir) { // accumulate aux - aux[ir] += std::complex(chr->rho[is][ir], 0.0 ); + aux[ir] += std::complex(chr->rho[1][ir], 0.0 ); } } } diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_func_mgga.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_func_mgga.cpp index 56ef7ebd866..352634bee1c 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_func_mgga.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_func_mgga.cpp @@ -19,8 +19,9 @@ void Stress_Func::stress_mgga(ModuleBase::matrix& sigma, { ModuleBase::timer::tick("Stress_Func", "stress_mgga"); - if (PARAM.inp.nspin == 4) + if (PARAM.inp.nspin == 4) { ModuleBase::WARNING_QUIT("stress_mgga", "noncollinear stress + mGGA not implemented"); +} int current_spin = 0; const int nrxx = wfc_basis->nrxx; @@ -44,11 +45,12 @@ void Stress_Func::stress_mgga(ModuleBase::matrix& sigma, auto cal_stress_mgga_solver = hamilt::cal_stress_mgga_op, Device>(); for (int ik = 0; ik < p_kv->get_nks(); ik++) { - if (PARAM.inp.nspin == 2) + if (PARAM.inp.nspin == 2) { current_spin = p_kv->isk[ik]; +} const int npw = p_kv->ngk[ik]; - for (int ibnd = 0; ibnd < GlobalV::NBANDS; ibnd++) + for (int ibnd = 0; ibnd < PARAM.inp.nbands; ibnd++) { const FPTYPE w1 = wg(ik, ibnd) / GlobalC::ucell.omega; const std::complex* psi = &psi_in[0](ik, ibnd, 0); @@ -85,8 +87,9 @@ void Stress_Func::stress_mgga(ModuleBase::matrix& sigma, for (int iy = 0; iy < 3; iy++) { FPTYPE delta = 0.0; - if (ix == iy) + if (ix == iy) { delta = 1.0; +} for (int ir = 0; ir < nrxx; ir++) { FPTYPE x diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_func_nl.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_func_nl.cpp index d3cbb068857..5b177b37b65 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_func_nl.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_func_nl.cpp @@ -49,7 +49,7 @@ void Stress_Func::stress_nl(ModuleBase::matrix& sigma, break; } } - const int npm = ucell_in.get_npol() * nbands_occ; + const int npm = nbands_occ; // calculate becp = for all beta functions nl_tools.cal_becp(ik, npm); diff --git a/source/module_hamilt_pw/hamilt_pwdft/stress_pw.cpp b/source/module_hamilt_pw/hamilt_pwdft/stress_pw.cpp index 2f1d90361ef..b56553c7085 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/stress_pw.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/stress_pw.cpp @@ -99,7 +99,7 @@ void Stress_PW::cal_stress(ModuleBase::matrix& sigmatot, this->stress_nl(sigmanl, this->pelec->wg, this->pelec->ekb, p_sf, p_kv, p_symm, wfc_basis, d_psi_in, nlpp, ucell); // add US term from augmentation charge derivatives - if (GlobalV::use_uspp) + if (PARAM.globalv.use_uspp) { this->stress_us(sigmanl, rho_basis, &GlobalC::ppcell, ucell); } diff --git a/source/module_hamilt_pw/hamilt_pwdft/structure_factor.cpp b/source/module_hamilt_pw/hamilt_pwdft/structure_factor.cpp index 575cb53508b..dd3663cbd0c 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/structure_factor.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/structure_factor.cpp @@ -16,12 +16,16 @@ Structure_Factor::Structure_Factor() { - + // LCAO basis doesn't support GPU acceleration on this function currently. + if(PARAM.inp.basis_type == "pw") + { + this->device = PARAM.inp.device; + } } Structure_Factor::~Structure_Factor() { - if (PARAM.globalv.device_flag == "gpu") { + if (device == "gpu") { if (PARAM.inp.precision == "single") { delmem_cd_op()(gpu_ctx, this->c_eigts1); delmem_cd_op()(gpu_ctx, this->c_eigts2); @@ -145,7 +149,7 @@ void Structure_Factor::setup_structure_factor(UnitCell* Ucell, const ModulePW::P inat++; } } - if (PARAM.globalv.device_flag == "gpu") { + if (device == "gpu") { if (PARAM.inp.precision == "single") { resmem_cd_op()(gpu_ctx, this->c_eigts1, Ucell->nat * (2 * rho_basis->nx + 1)); resmem_cd_op()(gpu_ctx, this->c_eigts2, Ucell->nat * (2 * rho_basis->ny + 1)); diff --git a/source/module_hamilt_pw/hamilt_pwdft/structure_factor.h b/source/module_hamilt_pw/hamilt_pwdft/structure_factor.h index 23b08c253e2..5fc4e8a1298 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/structure_factor.h +++ b/source/module_hamilt_pw/hamilt_pwdft/structure_factor.h @@ -56,5 +56,6 @@ class Structure_Factor std::complex * c_eigts1 = nullptr, * c_eigts2 = nullptr, * c_eigts3 = nullptr; std::complex * z_eigts1 = nullptr, * z_eigts2 = nullptr, * z_eigts3 = nullptr; const ModulePW::PW_Basis* rho_basis = nullptr; + std::string device = "cpu"; }; #endif //PlaneWave class diff --git a/source/module_hamilt_pw/hamilt_pwdft/test/CMakeLists.txt b/source/module_hamilt_pw/hamilt_pwdft/test/CMakeLists.txt index ed60c0ec817..c1b56517b70 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/test/CMakeLists.txt +++ b/source/module_hamilt_pw/hamilt_pwdft/test/CMakeLists.txt @@ -15,6 +15,7 @@ AddTest( ../../../module_base/global_file.cpp ../../../module_base/memory.cpp ../../../module_base/timer.cpp + ../../../module_base/blas_connector.cpp ../../../module_base/parallel_global.cpp ../../../module_base/parallel_comm.cpp ../../../module_base/parallel_common.cpp diff --git a/source/module_hamilt_pw/hamilt_pwdft/wavefunc.cpp b/source/module_hamilt_pw/hamilt_pwdft/wavefunc.cpp index 00c0bded367..41e110885cd 100644 --- a/source/module_hamilt_pw/hamilt_pwdft/wavefunc.cpp +++ b/source/module_hamilt_pw/hamilt_pwdft/wavefunc.cpp @@ -55,15 +55,15 @@ psi::Psi>* wavefunc::allocate(const int nkstot, const int n if (PARAM.inp.calculation == "nscf" && this->mem_saver == 1) { // initial psi rather than evc - psi_out = new psi::Psi>(1, GlobalV::NBANDS, npwx * PARAM.globalv.npol, ngk); + psi_out = new psi::Psi>(1, PARAM.inp.nbands, npwx * PARAM.globalv.npol, ngk); if (PARAM.inp.basis_type == "lcao_in_pw") { - wanf2[0].create(GlobalV::NLOCAL, npwx * PARAM.globalv.npol); - const size_t memory_cost = GlobalV::NLOCAL * (PARAM.globalv.npol * npwx) * sizeof(std::complex); + wanf2[0].create(PARAM.globalv.nlocal, npwx * PARAM.globalv.npol); + const size_t memory_cost = PARAM.globalv.nlocal * (PARAM.globalv.npol * npwx) * sizeof(std::complex); std::cout << " Memory for wanf2 (MB): " << double(memory_cost) / 1024.0 / 1024.0 << std::endl; ModuleBase::Memory::record("WF::wanf2", memory_cost); } - const size_t memory_cost = GlobalV::NBANDS * (PARAM.globalv.npol * npwx) * sizeof(std::complex); + const size_t memory_cost = PARAM.inp.nbands * (PARAM.globalv.npol * npwx) * sizeof(std::complex); std::cout << " MEMORY FOR PSI (MB) : " << double(memory_cost) / 1024.0 / 1024.0 << std::endl; ModuleBase::Memory::record("Psi_PW", memory_cost); } @@ -79,10 +79,10 @@ psi::Psi>* wavefunc::allocate(const int nkstot, const int n for (int ik = 0; ik < nks2; ik++) { - this->wanf2[ik].create(GlobalV::NLOCAL, npwx * PARAM.globalv.npol); + this->wanf2[ik].create(PARAM.globalv.nlocal, npwx * PARAM.globalv.npol); } - const size_t memory_cost = nks2 * GlobalV::NLOCAL * (npwx * PARAM.globalv.npol) * sizeof(std::complex); + const size_t memory_cost = nks2 * PARAM.globalv.nlocal * (npwx * PARAM.globalv.npol) * sizeof(std::complex); std::cout << " Memory for wanf2 (MB): " << double(memory_cost) / 1024.0 / 1024.0 << std::endl; ModuleBase::Memory::record("WF::wanf2", memory_cost); } @@ -90,8 +90,8 @@ psi::Psi>* wavefunc::allocate(const int nkstot, const int n else { // initial psi rather than evc - psi_out = new psi::Psi>(nks2, GlobalV::NBANDS, npwx * PARAM.globalv.npol, ngk); - const size_t memory_cost = nks2 * GlobalV::NBANDS * (PARAM.globalv.npol * npwx) * sizeof(std::complex); + psi_out = new psi::Psi>(nks2, PARAM.inp.nbands, npwx * PARAM.globalv.npol, ngk); + const size_t memory_cost = nks2 * PARAM.inp.nbands * (PARAM.globalv.npol * npwx) * sizeof(std::complex); std::cout << " MEMORY FOR PSI (MB) : " << double(memory_cost) / 1024.0 / 1024.0 << std::endl; ModuleBase::Memory::record("Psi_PW", memory_cost); } @@ -117,7 +117,7 @@ void wavefunc::wfcinit(psi::Psi>* psi_in, ModulePW::PW_Basi this->irindex = new int[wfc_basis->fftnxy]; wfc_basis->getfftixy2is(this->irindex); #if defined(__CUDA) || defined(__ROCM) - if (PARAM.globalv.device_flag == "gpu") + if (PARAM.inp.device == "gpu") { wfc_basis->get_ig2ixyz_k(); } @@ -131,11 +131,11 @@ int wavefunc::get_starting_nw() const { if (init_wfc == "file") { - return GlobalV::NBANDS; + return PARAM.inp.nbands; } else if (init_wfc.substr(0, 6) == "atomic") { - if (GlobalC::ucell.natomwfc >= GlobalV::NBANDS) + if (GlobalC::ucell.natomwfc >= PARAM.inp.nbands) { if (PARAM.inp.test_wf) { @@ -147,11 +147,11 @@ int wavefunc::get_starting_nw() const if (PARAM.inp.test_wf) { GlobalV::ofs_running << " Start wave functions are atomic + " - << GlobalV::NBANDS - GlobalC::ucell.natomwfc << " random wave functions." + << PARAM.inp.nbands - GlobalC::ucell.natomwfc << " random wave functions." << std::endl; } } - return std::max(GlobalC::ucell.natomwfc, GlobalV::NBANDS); + return std::max(GlobalC::ucell.natomwfc, PARAM.inp.nbands); } else if (init_wfc == "random") { @@ -159,7 +159,7 @@ int wavefunc::get_starting_nw() const { GlobalV::ofs_running << " Start wave functions are all random." << std::endl; } - return GlobalV::NBANDS; + return PARAM.inp.nbands; } else { @@ -728,7 +728,7 @@ void wavefunc::init_after_vc(const int nks) assert(this->npwx > 0); assert(nks > 0); - assert(GlobalV::NBANDS > 0); + assert(PARAM.inp.nbands > 0); const int nks2 = nks; const int nbasis = this->npwx * PARAM.globalv.npol; @@ -742,7 +742,7 @@ void wavefunc::init_after_vc(const int nks) this->wanf2 = new ModuleBase::ComplexMatrix[nks2]; for (int ik = 0; ik < nks2; ik++) { - this->wanf2[ik].create(GlobalV::NLOCAL, nbasis); + this->wanf2[ik].create(PARAM.globalv.nlocal, nbasis); } } diff --git a/source/module_hamilt_pw/hamilt_stodft/CMakeLists.txt b/source/module_hamilt_pw/hamilt_stodft/CMakeLists.txt index 60279531da7..d28439ef38b 100644 --- a/source/module_hamilt_pw/hamilt_stodft/CMakeLists.txt +++ b/source/module_hamilt_pw/hamilt_stodft/CMakeLists.txt @@ -1,6 +1,6 @@ list(APPEND hamilt_stodft_srcs + hamilt_sdft_pw.cpp sto_iter.cpp - sto_hchi.cpp sto_che.cpp sto_wf.cpp sto_func.cpp diff --git a/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.cpp b/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.cpp new file mode 100644 index 00000000000..272a8c15398 --- /dev/null +++ b/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.cpp @@ -0,0 +1,80 @@ +#include "hamilt_sdft_pw.h" +#include "module_base/timer.h" + +namespace hamilt +{ + +template +HamiltSdftPW::HamiltSdftPW(elecstate::Potential* pot_in, + ModulePW::PW_Basis_K* wfc_basis, + K_Vectors* p_kv, + const int& npol, + double* emin_in, + double* emax_in) + : HamiltPW(pot_in, wfc_basis, p_kv), ngk(p_kv->ngk) +{ + this->classname = "HamiltSdftPW"; + this->npwk_max = wfc_basis->npwk_max; + this->npol = npol; + this->emin = emin_in; + this->emax = emax_in; +} + +template +void HamiltSdftPW::hPsi(const T* psi_in, T* hpsi, const int& nbands) +{ + auto call_act = [&, this](const Operator* op, const bool& is_first_node) -> void { + op->act(nbands, this->npwk_max, this->npol, psi_in, hpsi, this->ngk[op->get_ik()], is_first_node); + }; + + ModuleBase::timer::tick("HamiltSdftPW", "hPsi"); + call_act(this->ops, true); // first node + Operator* node((Operator*)this->ops->next_op); + while (node != nullptr) + { + call_act(node, false); // other nodes + node = (Operator*)(node->next_op); + } + ModuleBase::timer::tick("HamiltSdftPW", "hPsi"); + + return; +} + +template +void HamiltSdftPW::hPsi_norm(const T* psi_in, T* hpsi_norm, const int& nbands) +{ + ModuleBase::timer::tick("HamiltSdftPW", "hPsi_norm"); + + this->hPsi(psi_in, hpsi_norm, nbands); + + const int ik = this->ops->get_ik(); + const int npwk_max = this->npwk_max; + const int npwk = this->ngk[ik]; + using Real = typename GetTypeReal::type; + const Real emin = *this->emin; + const Real emax = *this->emax; + const Real Ebar = (emin + emax) / 2; + const Real DeltaE = (emax - emin) / 2; + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int ib = 0; ib < nbands; ++ib) + { + const int ig0 = ib * npwk_max; + for (int ig = 0; ig < npwk; ++ig) + { + hpsi_norm[ig + ig0] = (hpsi_norm[ig + ig0] - Ebar * psi_in[ig + ig0]) / DeltaE; + } + } + ModuleBase::timer::tick("HamiltSdftPW", "hPsi_norm"); +} + +template class HamiltSdftPW, base_device::DEVICE_CPU>; +template class HamiltSdftPW, base_device::DEVICE_CPU>; +#if ((defined __CUDA) || (defined __ROCM)) +template class HamiltSdftPW, base_device::DEVICE_GPU>; +template class HamiltSdftPW, base_device::DEVICE_GPU>; +#endif + +} // namespace hamilt \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h b/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h new file mode 100644 index 00000000000..ce07ea32220 --- /dev/null +++ b/source/module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h @@ -0,0 +1,70 @@ +#ifndef HAMILTSDFTPW_H +#define HAMILTSDFTPW_H + +#include "module_hamilt_pw/hamilt_pwdft/hamilt_pw.h" + +namespace hamilt +{ + +template +class HamiltSdftPW : public HamiltPW +{ + public: + /** + * @brief Construct a new Hamilt Sdft P W object + * + * @param pot_in potential + * @param wfc_basis pw basis for wave functions + * @param p_kv k vectors + * @param npol the length of wave function is npol * npwk_max + * @param emin_in Emin of the Hamiltonian + * @param emax_in Emax of the Hamiltonian + */ + HamiltSdftPW(elecstate::Potential* pot_in, + ModulePW::PW_Basis_K* wfc_basis, + K_Vectors* p_kv, + const int& npol, + double* emin_in, + double* emax_in); + /** + * @brief Destroy the Hamilt Sdft P W object + * + */ + ~HamiltSdftPW(){}; + + // void update_emin_emax(const double& emin, const double& emax) + // { + // this->emin = &emin; + // this->emax = &emax; + // } + + /** + * @brief Calculate \hat{H}|psi> + * + * @param psi_in input wave function + * @param hpsi output wave function + * @param nbands number of bands + */ + void hPsi(const T* psi_in, T* hpsi, const int& nbands = 1); + + /** + * @brief Calculate \hat{H}|psi> and normalize it + * + * @param psi_in input wave function + * @param hpsi output wave function + * @param nbands number of bands + */ + void hPsi_norm(const T* psi_in, T* hpsi, const int& nbands = 1); + + double* emin = nullptr; ///< Emin of the Hamiltonian + double* emax = nullptr; ///< Emax of the Hamiltonian + + private: + int npwk_max = 0; ///< maximum number of plane waves + int npol = 0; ///< number of polarizations + std::vector& ngk; ///< number of G vectors +}; + +} // namespace hamilt + +#endif \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_dos.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_dos.cpp index 145f7bb89c2..dc520deaa1c 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_dos.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_dos.cpp @@ -1,8 +1,8 @@ #include "sto_dos.h" -#include "module_parameter/parameter.h" #include "module_base/timer.h" #include "module_base/tool_title.h" +#include "module_parameter/parameter.h" #include "sto_tool.h" Sto_DOS::~Sto_DOS() { @@ -14,18 +14,18 @@ Sto_DOS::Sto_DOS(ModulePW::PW_Basis_K* p_wfcpw_in, psi::Psi>* p_psi_in, hamilt::Hamilt>* p_hamilt_in, StoChe& stoche, - Stochastic_WF* p_stowf_in) + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf_in) { this->p_wfcpw = p_wfcpw_in; this->p_kv = p_kv_in; this->p_elec = p_elec_in; this->p_psi = p_psi_in; this->p_hamilt = p_hamilt_in; + this->p_hamilt_sto = static_cast>*>(p_hamilt_in); this->p_stowf = p_stowf_in; this->nbands_ks = p_psi_in->get_nbands(); this->nbands_sto = p_stowf_in->nchi; this->method_sto = stoche.method_sto; - this->stohchi.init(p_wfcpw_in, p_kv_in, &stoche.emin_sto, &stoche.emax_sto); this->stofunc.set_E_range(&stoche.emin_sto, &stoche.emax_sto); } void Sto_DOS::decide_param(const int& dos_nche, @@ -38,21 +38,14 @@ void Sto_DOS::decide_param(const int& dos_nche, const double& dos_scale) { this->dos_nche = dos_nche; - check_che(this->dos_nche, - emin_sto, - emax_sto, - this->nbands_sto, - this->p_kv, - this->p_stowf, - this->p_hamilt, - this->stohchi); + check_che(this->dos_nche, emin_sto, emax_sto, this->nbands_sto, this->p_kv, this->p_stowf, this->p_hamilt_sto); if (dos_setemax) { this->emax = dos_emax_ev; } else { - this->emax = *stohchi.Emax * ModuleBase::Ry_to_eV; + this->emax = *p_hamilt_sto->emax * ModuleBase::Ry_to_eV; } if (dos_setemin) { @@ -60,7 +53,7 @@ void Sto_DOS::decide_param(const int& dos_nche, } else { - this->emin = *stohchi.Emin * ModuleBase::Ry_to_eV; + this->emin = *p_hamilt_sto->emin * ModuleBase::Ry_to_eV; } if (!dos_setemax && !dos_setemin) @@ -103,12 +96,11 @@ void Sto_DOS::caldos(const double sigmain, const double de, const int npart) { this->p_hamilt->updateHk(ik); } - stohchi.current_ik = ik; const int npw = p_kv->ngk[ik]; const int nchipk = this->p_stowf->nchip[ik]; std::complex* pchi; - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { p_stowf->chiortho->fix_k(ik); pchi = p_stowf->chiortho->get_pointer(); @@ -118,11 +110,11 @@ void Sto_DOS::caldos(const double sigmain, const double de, const int npart) p_stowf->chi0->fix_k(ik); pchi = p_stowf->chi0->get_pointer(); } - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3); + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW>::hPsi_norm, + p_hamilt_sto, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3); if (this->method_sto == 1) { che.tracepolyA(hchi_norm, pchi, npw, npwx, nchipk); @@ -149,12 +141,7 @@ void Sto_DOS::caldos(const double sigmain, const double de, const int npart) } ModuleBase::GlobalFunc::ZEROS(allorderchi.data(), nchipk_new * npwx * dos_nche); std::complex* tmpchi = pchi + start_nchipk * npwx; - che.calpolyvec_complex(hchi_norm, - tmpchi, - allorderchi.data(), - npw, - npwx, - nchipk_new); + che.calpolyvec_complex(hchi_norm, tmpchi, allorderchi.data(), npw, npwx, nchipk_new); double* vec_all = (double*)allorderchi.data(); int LDA = npwx * nchipk_new * 2; int M = npwx * nchipk_new * 2; @@ -195,12 +182,12 @@ void Sto_DOS::caldos(const double sigmain, const double de, const int npart) che.calcoef_real(nroot_gauss); tmpsto = vTMv(che.coef_real, spolyv.data(), dos_nche); } - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { for (int ik = 0; ik < nk; ++ik) { double* en = &(this->p_elec->ekb(ik, 0)); - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { tmpks += this->stofunc.gauss(en[ib]) * p_kv->wk[ik] / 2; } diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_dos.h b/source/module_hamilt_pw/hamilt_stodft/sto_dos.h index 7941bc6bd92..7b717df07c9 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_dos.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_dos.h @@ -1,10 +1,9 @@ #ifndef STO_DOS #define STO_DOS #include "module_elecstate/elecstate.h" -#include "module_hamilt_general/hamilt.h" +#include "module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h" #include "module_hamilt_pw/hamilt_stodft/sto_che.h" #include "module_hamilt_pw/hamilt_stodft/sto_func.h" -#include "module_hamilt_pw/hamilt_stodft/sto_hchi.h" #include "module_hamilt_pw/hamilt_stodft/sto_wf.h" class Sto_DOS @@ -16,7 +15,7 @@ class Sto_DOS psi::Psi>* p_psi_in, hamilt::Hamilt>* p_hamilt_in, StoChe& stoche, - Stochastic_WF* p_stowf_in); + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf_in); ~Sto_DOS(); /** @@ -60,9 +59,12 @@ class Sto_DOS elecstate::ElecState* p_elec = nullptr; ///< pointer to the electronic state psi::Psi>* p_psi = nullptr; ///< pointer to the wavefunction hamilt::Hamilt>* p_hamilt; ///< pointer to the Hamiltonian - Stochastic_WF* p_stowf = nullptr; ///< pointer to the stochastic wavefunctions - Stochastic_hchi stohchi; ///< stochastic hchi - Sto_Func stofunc; ///< functions + + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf + = nullptr; ///< pointer to the stochastic wavefunctions + Sto_Func stofunc; ///< functions + + hamilt::HamiltSdftPW>* p_hamilt_sto = nullptr; ///< pointer to the Hamiltonian for sDFT }; #endif // STO_DOS \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_elecond.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_elecond.cpp index 37a42725718..8692a586ee7 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_elecond.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_elecond.cpp @@ -1,11 +1,11 @@ #include "sto_elecond.h" -#include "module_parameter/parameter.h" #include "module_base/complexmatrix.h" #include "module_base/constants.h" #include "module_base/memory.h" #include "module_base/timer.h" #include "module_base/vector3.h" +#include "module_parameter/parameter.h" #include "sto_tool.h" #include @@ -21,14 +21,14 @@ Sto_EleCond::Sto_EleCond(UnitCell* p_ucell_in, pseudopot_cell_vnl* p_ppcell_in, hamilt::Hamilt>* p_hamilt_in, StoChe& stoche, - Stochastic_WF* p_stowf_in) + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf_in) : EleCond(p_ucell_in, p_kv_in, p_elec_in, p_wfcpw_in, p_psi_in, p_ppcell_in) { this->p_hamilt = p_hamilt_in; + this->p_hamilt_sto = static_cast>*>(p_hamilt_in); this->p_stowf = p_stowf_in; this->nbands_ks = p_psi_in->get_nbands(); this->nbands_sto = p_stowf_in->nchi; - this->stohchi.init(p_wfcpw_in, p_kv_in, &stoche.emin_sto, &stoche.emax_sto); this->stofunc.set_E_range(&stoche.emin_sto, &stoche.emax_sto); } @@ -91,15 +91,14 @@ void Sto_EleCond::decide_nche(const double dt, int nche_new = 0; loop: - // re-set Emin & Emax both in stohchi & stofunc + // re-set Emin & Emax both in p_hamilt_sto & stofunc check_che(std::max(nche_old * 2, fd_nche), try_emin, try_emax, this->nbands_sto, this->p_kv, this->p_stowf, - this->p_hamilt, - this->stohchi); + this->p_hamilt_sto); // second try to find nche with new Emin & Emax getnche(nche_new); @@ -107,8 +106,8 @@ void Sto_EleCond::decide_nche(const double dt, if (nche_new > nche_old * 2) { nche_old = nche_new; - try_emin = *stohchi.Emin; - try_emax = *stohchi.Emax; + try_emin = *p_hamilt_sto->emin; + try_emax = *p_hamilt_sto->emax; goto loop; } @@ -177,8 +176,8 @@ void Sto_EleCond::cal_jmatrix(const psi::Psi>& kspsi_all, psi::Psi> f_rightchi(1, perbands_sto, npwx, p_kv->ngk.data()); psi::Psi> f_right_hchi(1, perbands_sto, npwx, p_kv->ngk.data()); - this->stohchi.hchi(leftchi.get_pointer(), left_hchi.get_pointer(), perbands_sto); - this->stohchi.hchi(rightchi.get_pointer(), right_hchi.get_pointer(), perbands_sto); + this->p_hamilt_sto->hPsi(leftchi.get_pointer(), left_hchi.get_pointer(), perbands_sto); + this->p_hamilt_sto->hPsi(rightchi.get_pointer(), right_hchi.get_pointer(), perbands_sto); convert_psi(rightchi, f_rightchi); convert_psi(right_hchi, f_right_hchi); right_hchi.resize(1, 1, 1); @@ -388,7 +387,9 @@ void Sto_EleCond::cal_jmatrix(const psi::Psi>& kspsi_all, remain -= tmpnb; startnb += tmpnb; if (remain == 0) + { break; + } } for (int id = 0; id < ndim; ++id) @@ -589,7 +590,6 @@ void Sto_EleCond::sKG(const int& smear_type, { this->p_hamilt->updateHk(ik); } - this->stohchi.current_ik = ik; const int npw = p_kv->ngk[ik]; // get allbands_ks @@ -733,8 +733,8 @@ void Sto_EleCond::sKG(const int& smear_type, auto nroot_fd = std::bind(&Sto_Func::nroot_fd, &this->stofunc, std::placeholders::_1); che.calcoef_real(nroot_fd); - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW>::hPsi_norm, + p_hamilt_sto, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); @@ -1014,8 +1014,3 @@ void Sto_EleCond::sKG(const int& smear_type, } ModuleBase::timer::tick("Sto_EleCond", "sKG"); } - -namespace GlobalTemp -{ -const ModuleBase::matrix* veff; -} diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_elecond.h b/source/module_hamilt_pw/hamilt_stodft/sto_elecond.h index a7a4e0f7a6b..77dccff7923 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_elecond.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_elecond.h @@ -17,7 +17,7 @@ class Sto_EleCond : protected EleCond pseudopot_cell_vnl* p_ppcell_in, hamilt::Hamilt>* p_hamilt_in, StoChe& stoche, - Stochastic_WF* p_stowf_in); + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf_in); ~Sto_EleCond(){}; /** * @brief Set the N order of Chebyshev expansion for conductivities @@ -59,9 +59,11 @@ class Sto_EleCond : protected EleCond int fd_nche = 0; ///< number of Chebyshev orders for Fermi-Dirac function int cond_dtbatch = 0; ///< number of time steps in a batch hamilt::Hamilt>* p_hamilt; ///< pointer to the Hamiltonian - Stochastic_WF* p_stowf = nullptr; ///< pointer to the stochastic wavefunctions - Stochastic_hchi stohchi; ///< stochastic hchi - Sto_Func stofunc; ///< functions + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf + = nullptr; ///< pointer to the stochastic wavefunctions + Sto_Func stofunc; ///< functions + + hamilt::HamiltSdftPW>* p_hamilt_sto = nullptr; ///< pointer to the Hamiltonian for sDFT protected: /** diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_forces.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_forces.cpp index 6984bfb33e1..8cb543b026c 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_forces.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_forces.cpp @@ -1,6 +1,5 @@ #include "sto_forces.h" -#include "module_parameter/parameter.h" #include "module_base/mathzone.h" #include "module_cell/module_symmetry/symmetry.h" #include "module_elecstate/elecstate.h" @@ -8,12 +7,13 @@ #include "module_elecstate/potentials/gatefield.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_io/output_log.h" +#include "module_parameter/parameter.h" // new -#include "module_hamilt_general/module_xc/xc_functional.h" #include "module_base/math_integral.h" #include "module_base/parallel_reduce.h" #include "module_base/timer.h" +#include "module_hamilt_general/module_xc/xc_functional.h" void Sto_Forces::cal_stoforce(ModuleBase::matrix& force, const elecstate::ElecState& elec, @@ -23,11 +23,11 @@ void Sto_Forces::cal_stoforce(ModuleBase::matrix& force, K_Vectors* pkv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf) + Stochastic_WF, base_device::DEVICE_CPU>& stowf) { - ModuleBase::timer::tick("Sto_Force","cal_force"); - ModuleBase::TITLE("Sto_Forces", "init"); - this->nat = GlobalC::ucell.nat; + ModuleBase::timer::tick("Sto_Force", "cal_force"); + ModuleBase::TITLE("Sto_Forces", "init"); + this->nat = GlobalC::ucell.nat; const ModuleBase::matrix& wg = elec.wg; const Charge* chr = elec.charge; force.create(nat, 3); @@ -43,56 +43,52 @@ void Sto_Forces::cal_stoforce(ModuleBase::matrix& force, this->cal_force_cc(forcecc, rho_basis, chr, GlobalC::ucell); this->cal_force_scc(forcescc, rho_basis, elec.vnew, elec.vnew_exist, GlobalC::ucell); - //impose total force = 0 + // impose total force = 0 int iat = 0; - ModuleBase::matrix force_e; - if(PARAM.inp.efield_flag) - { - force_e.create( GlobalC::ucell.nat, 3); - elecstate::Efield::compute_force(GlobalC::ucell, force_e); - } + ModuleBase::matrix force_e; + if (PARAM.inp.efield_flag) + { + force_e.create(GlobalC::ucell.nat, 3); + elecstate::Efield::compute_force(GlobalC::ucell, force_e); + } ModuleBase::matrix force_gate; - if(PARAM.inp.gate_flag) + if (PARAM.inp.gate_flag) { - force_gate.create( GlobalC::ucell.nat, 3); + force_gate.create(GlobalC::ucell.nat, 3); elecstate::Gatefield::compute_force(GlobalC::ucell, force_gate); } - for (int ipol = 0; ipol < 3; ipol++) - { - double sum = 0.0; - iat = 0; - - for (int it = 0;it < GlobalC::ucell.ntype;it++) - { - for (int ia = 0;ia < GlobalC::ucell.atoms[it].na;ia++) - { - force(iat, ipol) = - forcelc(iat, ipol) - + forceion(iat, ipol) - + forcenl(iat, ipol) - + forcecc(iat, ipol) - + forcescc(iat, ipol); - - if(PARAM.inp.efield_flag) - { - force(iat,ipol) = force(iat, ipol) + force_e(iat, ipol); - } - - if(PARAM.inp.gate_flag) + for (int ipol = 0; ipol < 3; ipol++) + { + double sum = 0.0; + iat = 0; + + for (int it = 0; it < GlobalC::ucell.ntype; it++) + { + for (int ia = 0; ia < GlobalC::ucell.atoms[it].na; ia++) + { + force(iat, ipol) = forcelc(iat, ipol) + forceion(iat, ipol) + forcenl(iat, ipol) + forcecc(iat, ipol) + + forcescc(iat, ipol); + + if (PARAM.inp.efield_flag) { - force(iat,ipol) = force(iat, ipol) + force_gate(iat, ipol); + force(iat, ipol) = force(iat, ipol) + force_e(iat, ipol); } - sum += force(iat, ipol); + if (PARAM.inp.gate_flag) + { + force(iat, ipol) = force(iat, ipol) + force_gate(iat, ipol); + } - iat++; - } - } + sum += force(iat, ipol); + + iat++; + } + } - if(!(PARAM.inp.gate_flag || PARAM.inp.efield_flag)) + if (!(PARAM.inp.gate_flag || PARAM.inp.efield_flag)) { double compen = sum / GlobalC::ucell.nat; for (int iat = 0; iat < GlobalC::ucell.nat; ++iat) @@ -100,74 +96,102 @@ void Sto_Forces::cal_stoforce(ModuleBase::matrix& force, force(iat, ipol) = force(iat, ipol) - compen; } } - } + } - if(PARAM.inp.gate_flag || PARAM.inp.efield_flag) + if (PARAM.inp.gate_flag || PARAM.inp.efield_flag) { GlobalV::ofs_running << "Atomic forces are not shifted if gate_flag or efield_flag == true!" << std::endl; } - - if(ModuleSymmetry::Symmetry::symm_flag == 1) + + if (ModuleSymmetry::Symmetry::symm_flag == 1) { double d1, d2, d3; - for(int iat=0; iatsymmetrize_vec3_nat(force.c); for (int iat = 0; iat < GlobalC::ucell.nat; iat++) { - ModuleBase::Mathzone::Direct_to_Cartesian(force(iat,0),force(iat,1),force(iat,2), - GlobalC::ucell.a1.x, GlobalC::ucell.a1.y, GlobalC::ucell.a1.z, - GlobalC::ucell.a2.x, GlobalC::ucell.a2.y, GlobalC::ucell.a2.z, - GlobalC::ucell.a3.x, GlobalC::ucell.a3.y, GlobalC::ucell.a3.z, - d1,d2,d3); - force(iat,0) = d1;force(iat,1) = d2;force(iat,2) = d3; + ModuleBase::Mathzone::Direct_to_Cartesian(force(iat, 0), + force(iat, 1), + force(iat, 2), + GlobalC::ucell.a1.x, + GlobalC::ucell.a1.y, + GlobalC::ucell.a1.z, + GlobalC::ucell.a2.x, + GlobalC::ucell.a2.y, + GlobalC::ucell.a2.z, + GlobalC::ucell.a3.x, + GlobalC::ucell.a3.y, + GlobalC::ucell.a3.z, + d1, + d2, + d3); + force(iat, 0) = d1; + force(iat, 1) = d2; + force(iat, 2) = d3; } } - GlobalV::ofs_running << setiosflags(std::ios::fixed) << std::setprecision(6) << std::endl; - if(PARAM.inp.test_force) - { + GlobalV::ofs_running << setiosflags(std::ios::fixed) << std::setprecision(6) << std::endl; + if (PARAM.inp.test_force) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "LOCAL FORCE (Ry/Bohr)", forcelc); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "NONLOCAL FORCE (Ry/Bohr)", forcenl); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "NLCC FORCE (Ry/Bohr)", forcecc); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "ION FORCE (Ry/Bohr)", forceion); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "SCC FORCE (Ry/Bohr)", forcescc); - if (PARAM.inp.efield_flag) { + if (PARAM.inp.efield_flag) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "EFIELD FORCE (Ry/Bohr)", force_e); -} - if (PARAM.inp.gate_flag) { + } + if (PARAM.inp.gate_flag) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "GATEFIELD FORCE (Ry/Bohr)", force_gate); -} + } } // output force in unit eV/Angstrom GlobalV::ofs_running << std::endl; - - if(PARAM.inp.test_force) - { + + if (PARAM.inp.test_force) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "LOCAL FORCE (eV/Angstrom)", forcelc, false); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "NONLOCAL FORCE (eV/Angstrom)", forcenl, false); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "NLCC FORCE (eV/Angstrom)", forcecc, false); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "ION FORCE (eV/Angstrom)", forceion, false); ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "SCC FORCE (eV/Angstrom)", forcescc, false); - if (PARAM.inp.efield_flag) { + if (PARAM.inp.efield_flag) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "EFIELD FORCE (eV/Angstrom)", force_e, false); -} - if (PARAM.inp.gate_flag) { + } + if (PARAM.inp.gate_flag) + { ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "GATEFIELD FORCE (eV/Angstrom)", force_gate, false); -} + } } ModuleIO::print_force(GlobalV::ofs_running, GlobalC::ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); ModuleBase::timer::tick("Sto_Force", "cal_force"); @@ -179,33 +203,36 @@ void Sto_Forces::cal_sto_force_nl(ModuleBase::matrix& forcenl, K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf) + Stochastic_WF, base_device::DEVICE_CPU>& stowf) { - ModuleBase::TITLE("Sto_Forces","cal_force_nl"); - ModuleBase::timer::tick("Sto_Forces","cal_force_nl"); + ModuleBase::TITLE("Sto_Forces", "cal_force_nl"); + ModuleBase::timer::tick("Sto_Forces", "cal_force_nl"); const int nkb = GlobalC::ppcell.nkb; int* nchip = stowf.nchip; - if(nkb == 0) { return; // mohan add 2010-07-25 -} - - const int npwx = wfc_basis->npwk_max; - // vkb1: |Beta(nkb,npw)> - ModuleBase::ComplexMatrix vkb1( nkb, npwx ); - int nksbands = psi_in->get_nbands(); - if(GlobalV::MY_STOGROUP != 0) { nksbands = 0; -} - + if (nkb == 0) + { + return; // mohan add 2010-07-25 + } + + const int npwx = wfc_basis->npwk_max; + // vkb1: |Beta(nkb,npw)> + ModuleBase::ComplexMatrix vkb1(nkb, npwx); + int nksbands = psi_in->get_nbands(); + if (GlobalV::MY_STOGROUP != 0) + { + nksbands = 0; + } - for (int ik = 0;ik < wfc_basis->nks;ik++) + for (int ik = 0; ik < wfc_basis->nks; ik++) { - const int nstobands = nchip[ik]; - const int nbandstot = nstobands + nksbands; - const int npw = wfc_basis->npwk[ik]; + const int nstobands = nchip[ik]; + const int nbandstot = nstobands + nksbands; + const int npw = wfc_basis->npwk[ik]; - // dbecp: conj( -iG * ) - ModuleBase::ComplexArray dbecp( 3, nbandstot, nkb); - ModuleBase::ComplexMatrix becp( nbandstot, nkb); + // dbecp: conj( -iG * ) + ModuleBase::ComplexArray dbecp(3, nbandstot, nkb); + ModuleBase::ComplexMatrix becp(nbandstot, nkb); const int current_spin = p_kv->isk[ik]; // generate vkb @@ -216,141 +243,181 @@ void Sto_Forces::cal_sto_force_nl(ModuleBase::matrix& forcenl, // get becp according to wave functions and vkb // important here ! becp must set zero!! - // vkb: Beta(nkb,npw) - // becp(nkb,nbnd): + // vkb: Beta(nkb,npw) + // becp(nkb,nbnd): becp.zero_out(); - char transa = 'C'; + char transa = 'C'; char transb = 'N'; - psi_in->fix_k(ik); - stowf.shchi->fix_k(ik); - //KS orbitals - int npmks = PARAM.globalv.npol * nksbands; - zgemm_(&transa,&transb,&nkb,&npmks,&npw,&ModuleBase::ONE, - GlobalC::ppcell.vkb.c,&npwx, - psi_in->get_pointer(),&npwx, - &ModuleBase::ZERO,becp.c,&nkb); - //stochastic orbitals - int npmsto = PARAM.globalv.npol * nstobands; - zgemm_(&transa,&transb,&nkb,&npmsto,&npw,&ModuleBase::ONE, - GlobalC::ppcell.vkb.c,&npwx, - stowf.shchi->get_pointer(),&npwx, - &ModuleBase::ZERO,&becp(nksbands,0),&nkb); - + psi_in->fix_k(ik); + stowf.shchi->fix_k(ik); + // KS orbitals + int npmks = PARAM.globalv.npol * nksbands; + zgemm_(&transa, + &transb, + &nkb, + &npmks, + &npw, + &ModuleBase::ONE, + GlobalC::ppcell.vkb.c, + &npwx, + psi_in->get_pointer(), + &npwx, + &ModuleBase::ZERO, + becp.c, + &nkb); + // stochastic orbitals + int npmsto = PARAM.globalv.npol * nstobands; + zgemm_(&transa, + &transb, + &nkb, + &npmsto, + &npw, + &ModuleBase::ONE, + GlobalC::ppcell.vkb.c, + &npwx, + stowf.shchi->get_pointer(), + &npwx, + &ModuleBase::ZERO, + &becp(nksbands, 0), + &nkb); + Parallel_Reduce::reduce_pool(becp.c, becp.size); - //out.printcm_real("becp",becp,1.0e-4); - // Calculate the derivative of beta, - // |dbeta> = -ig * |beta> + // out.printcm_real("becp",becp,1.0e-4); + // Calculate the derivative of beta, + // |dbeta> = -ig * |beta> dbecp.zero_out(); - for (int ipol = 0; ipol<3; ipol++) + for (int ipol = 0; ipol < 3; ipol++) { - for (int i = 0;i < nkb;i++) - { - std::complex* pvkb1 = &vkb1(i,0); - std::complex* pvkb = &GlobalC::ppcell.vkb(i,0); - if (ipol==0) - { - for (int ig=0; ig* pvkb1 = &vkb1(i, 0); + std::complex* pvkb = &GlobalC::ppcell.vkb(i, 0); + if (ipol == 0) + { + for (int ig = 0; ig < npw; ig++) + { pvkb1[ig] = pvkb[ig] * ModuleBase::NEG_IMAG_UNIT * wfc_basis->getgcar(ik, ig)[0]; -} + } } - if (ipol==1) - { - for (int ig=0; iggetgcar(ik,ig)[1]; -} + if (ipol == 1) + { + for (int ig = 0; ig < npw; ig++) + { + pvkb1[ig] = pvkb[ig] * ModuleBase::NEG_IMAG_UNIT * wfc_basis->getgcar(ik, ig)[1]; + } } - if (ipol==2) - { - for (int ig=0; iggetgcar(ik,ig)[2]; -} + if (ipol == 2) + { + for (int ig = 0; ig < npw; ig++) + { + pvkb1[ig] = pvkb[ig] * ModuleBase::NEG_IMAG_UNIT * wfc_basis->getgcar(ik, ig)[2]; + } } - } - //KS orbitals - zgemm_(&transa,&transb,&nkb,&npmks,&npw,&ModuleBase::ONE, - vkb1.c,&npwx, - psi_in->get_pointer(),&npwx, - &ModuleBase::ZERO,&dbecp(ipol, 0, 0),&nkb); - //stochastic orbitals - zgemm_(&transa,&transb,&nkb,&npmsto,&npw,&ModuleBase::ONE, - vkb1.c,&npwx, - stowf.shchi->get_pointer(),&npwx, - &ModuleBase::ZERO,&dbecp(ipol, nksbands, 0),&nkb); - }// end ipol - -// don't need to reduce here, keep dbecp different in each processor, -// and at last sum up all the forces. -// Parallel_Reduce::reduce_complex_double_pool( dbecp.ptr, dbecp.ndata); - -// double *cf = new double[ucell.nat*3]; -// ZEROS(cf, ucell.nat); - for (int ib=0; ibget_pointer(), + &npwx, + &ModuleBase::ZERO, + &dbecp(ipol, 0, 0), + &nkb); + // stochastic orbitals + zgemm_(&transa, + &transb, + &nkb, + &npmsto, + &npw, + &ModuleBase::ONE, + vkb1.c, + &npwx, + stowf.shchi->get_pointer(), + &npwx, + &ModuleBase::ZERO, + &dbecp(ipol, nksbands, 0), + &nkb); + } // end ipol + + // don't need to reduce here, keep dbecp different in each processor, + // and at last sum up all the forces. + // Parallel_Reduce::reduce_complex_double_pool( dbecp.ptr, dbecp.ndata); + + // double *cf = new double[ucell.nat*3]; + // ZEROS(cf, ucell.nat); + for (int ib = 0; ib < nbandstot; ib++) + { + double fac; + if (ib < nksbands) + { + fac = wg(ik, ib) * 2.0 * GlobalC::ucell.tpiba; + } + else + { fac = p_kv->wk[ik] * 2.0 * GlobalC::ucell.tpiba; -} + } int iat = 0; - int sum = 0; - for (int it=0; it< GlobalC::ucell.ntype; it++) - { - const int Nprojs = GlobalC::ucell.atoms[it].ncpp.nh; - for (int ia=0; ia< GlobalC::ucell.atoms[it].na; ia++) - { - for (int ip=0; ip * (4) cal_nl: contribution due to the non-local pseudopotential. * (4) cal_scc: contributino due to incomplete SCF calculation. */ - Sto_Forces(const int nat_in):Forces(nat_in){}; + Sto_Forces(const int nat_in) : Forces(nat_in){}; ~Sto_Forces(){}; void cal_stoforce(ModuleBase::matrix& force, @@ -28,7 +28,7 @@ class Sto_Forces : public Forces K_Vectors* pkv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf); + Stochastic_WF, base_device::DEVICE_CPU>& stowf); private: void cal_sto_force_nl(ModuleBase::matrix& forcenl, @@ -36,7 +36,7 @@ class Sto_Forces : public Forces K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf); + Stochastic_WF, base_device::DEVICE_CPU>& stowf); }; #endif diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_hchi.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_hchi.cpp deleted file mode 100644 index cc6b67015c8..00000000000 --- a/source/module_hamilt_pw/hamilt_stodft/sto_hchi.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "sto_hchi.h" - -#include "module_parameter/parameter.h" -#include "module_base/parallel_reduce.h" -#include "module_base/timer.h" -#include "module_base/tool_title.h" -#include "module_esolver/esolver_sdft_pw.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" - -Stochastic_hchi::Stochastic_hchi() -{ -} - -Stochastic_hchi::~Stochastic_hchi() -{ -} - -void Stochastic_hchi::init(ModulePW::PW_Basis_K* wfc_basis, K_Vectors* pkv_in, double* Emin_in, double* Emax_in) -{ - wfcpw = wfc_basis; - pkv = pkv_in; - Emin = Emin_in; - Emax = Emax_in; -} - -void Stochastic_hchi::hchi(complex* chig, complex* hchig, const int m) -{ - - //--------------------------------------------------- - - const int ik = this->current_ik; - const int current_spin = pkv->isk[ik]; - const int npwx = this->wfcpw->npwk_max; - const int npw = this->wfcpw->npwk[ik]; - const int npm = PARAM.globalv.npol * m; - const int inc = 1; - const double tpiba2 = GlobalC::ucell.tpiba2; - const int nrxx = this->wfcpw->nrxx; - //------------------------------------ - //(1) the kinetical energy. - //------------------------------------ - complex* chibg = chig; - complex* hchibg = hchig; - if (PARAM.inp.t_in_h) - { - for (int ib = 0; ib < m; ++ib) - { - for (int ig = 0; ig < npw; ++ig) - { - hchibg[ig] = this->wfcpw->getgk2(ik, ig) * tpiba2 * chibg[ig]; - } - chibg += npwx; - hchibg += npwx; - } - } - - //------------------------------------ - //(2) the local potential. - //------------------------------------ - ModuleBase::timer::tick("Stochastic_hchi", "vloc"); - std::complex* porter = new std::complex[nrxx]; - if (PARAM.inp.vl_in_h) - { - chibg = chig; - hchibg = hchig; - const double* pveff = &((*GlobalTemp::veff)(current_spin, 0)); - for (int ib = 0; ib < m; ++ib) - { - this->wfcpw->recip2real(chibg, porter, ik); - for (int ir = 0; ir < nrxx; ir++) - { - porter[ir] *= pveff[ir]; - } - this->wfcpw->real2recip(porter, hchibg, ik, true); - - chibg += npwx; - hchibg += npwx; - } - } - delete[] porter; - ModuleBase::timer::tick("Stochastic_hchi", "vloc"); - - //------------------------------------ - // (3) the nonlocal pseudopotential. - //------------------------------------ - ModuleBase::timer::tick("Stochastic_hchi", "vnl"); - if (PARAM.inp.vnl_in_h) - { - if (GlobalC::ppcell.nkb > 0) - { - int nkb = GlobalC::ppcell.nkb; - complex* becp = new complex[nkb * PARAM.globalv.npol * m]; - char transc = 'C'; - char transn = 'N'; - char transt = 'T'; - if (m == 1 && PARAM.globalv.npol == 1) - { - zgemv_(&transc, - &npw, - &nkb, - &ModuleBase::ONE, - GlobalC::ppcell.vkb.c, - &npwx, - chig, - &inc, - &ModuleBase::ZERO, - becp, - &inc); - } - else - { - zgemm_(&transc, - &transn, - &nkb, - &npm, - &npw, - &ModuleBase::ONE, - GlobalC::ppcell.vkb.c, - &npwx, - chig, - &npwx, - &ModuleBase::ZERO, - becp, - &nkb); - } - Parallel_Reduce::reduce_pool(becp, nkb * PARAM.globalv.npol * m); - - complex* Ps = new complex[nkb * PARAM.globalv.npol * m]; - ModuleBase::GlobalFunc::ZEROS(Ps, PARAM.globalv.npol * m * nkb); - - int sum = 0; - int iat = 0; - for (int it = 0; it < GlobalC::ucell.ntype; it++) - { - const int Nprojs = GlobalC::ucell.atoms[it].ncpp.nh; - for (int ia = 0; ia < GlobalC::ucell.atoms[it].na; ia++) - { - // each atom has Nprojs, means this is with structure factor; - // each projector (each atom) must multiply coefficient - // with all the other projectors. - for (int ip = 0; ip < Nprojs; ip++) - { - for (int ip2 = 0; ip2 < Nprojs; ip2++) - { - for (int ib = 0; ib < m; ++ib) - { - Ps[(sum + ip2) * m + ib] - += GlobalC::ppcell.deeq(current_spin, iat, ip, ip2) * becp[ib * nkb + sum + ip]; - } // end ib - } // end ih - } // end jh - sum += Nprojs; - ++iat; - } // end na - } // end nt - - if (PARAM.globalv.npol == 1 && m == 1) - { - zgemv_(&transn, - &npw, - &nkb, - &ModuleBase::ONE, - GlobalC::ppcell.vkb.c, - &npwx, - Ps, - &inc, - &ModuleBase::ONE, - hchig, - &inc); - } - else - { - zgemm_(&transn, - &transt, - &npw, - &npm, - &nkb, - &ModuleBase::ONE, - GlobalC::ppcell.vkb.c, - &npwx, - Ps, - &npm, - &ModuleBase::ONE, - hchig, - &npwx); - } - - delete[] becp; - delete[] Ps; - } - } - ModuleBase::timer::tick("Stochastic_hchi", "vnl"); - - return; -} -void Stochastic_hchi::hchi_norm(complex* chig, complex* hchig, const int m) -{ - ModuleBase::timer::tick("Stochastic_hchi", "hchi_norm"); - - this->hchi(chig, hchig, m); - - const int ik = this->current_ik; - const int npwx = this->wfcpw->npwk_max; - const int npw = this->wfcpw->npwk[ik]; - const double Ebar = (*Emin + *Emax) / 2; - const double DeltaE = (*Emax - *Emin) / 2; - for (int ib = 0; ib < m; ++ib) - { - for (int ig = 0; ig < npw; ++ig) - { - hchig[ib * npwx + ig] = (hchig[ib * npwx + ig] - Ebar * chig[ib * npwx + ig]) / DeltaE; - } - } - ModuleBase::timer::tick("Stochastic_hchi", "hchi_norm"); -} \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_hchi.h b/source/module_hamilt_pw/hamilt_stodft/sto_hchi.h deleted file mode 100644 index 2f195fc7c47..00000000000 --- a/source/module_hamilt_pw/hamilt_stodft/sto_hchi.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef STO_HCHI_H -#define STO_HCHI_H -#include "module_basis/module_pw/pw_basis_k.h" -#include "module_cell/klist.h" - -//----------------------------------------------------- -// h * chi -// chi: stochastic wave functions -// -// h: the normalized Hamiltonian matrix, which equals to (H - E\bar) / \DeltaE -// where H is decomposed into the electron kinetic, effective potential V(r), -// and the non-local pseudopotentials. -// The effective potential = Local pseudopotential + -// Hartree potential + Exchange-correlation potential -//------------------------------------------------------ -class Stochastic_hchi -{ - - public: - // constructor and deconstructor - Stochastic_hchi(); - ~Stochastic_hchi(); - - void init(ModulePW::PW_Basis_K* wfc_basis, K_Vectors* pkv, double* Emin_in, double* Emax_in); - - double* Emin = nullptr; - double* Emax = nullptr; - - void orthogonal_to_psi_reciprocal(std::complex* wfin, - std::complex* wfout, - const int& ikk); // wfin & wfout are wavefunctions in reciprocal space - void hchi(std::complex* wfin, - std::complex* wfout, - const int m = 1); // wfin & wfout are wavefunctions in reciprocal space - - void hchi_norm(std::complex* wfin, - std::complex* wfout, - const int m = 1); // wfin & wfout are wavefunctions in reciprocal space - - public: - int current_ik = 0; - ModulePW::PW_Basis_K* wfcpw = nullptr; - K_Vectors* pkv = nullptr; - - // chi should be orthogonal to psi (generated by diaganolization methods, - // such as CG) -}; - -#endif // Eelectrons_hchi diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_iter.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_iter.cpp index 13be8b08d20..d4d6aee52d5 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_iter.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_iter.cpp @@ -6,60 +6,65 @@ #include "module_base/tool_title.h" #include "module_elecstate/occupy.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_parameter/parameter.h" -Stochastic_Iter::Stochastic_Iter() +template +Stochastic_Iter::Stochastic_Iter() { change = false; mu0 = 0; method = 2; } -Stochastic_Iter::~Stochastic_Iter() +template +Stochastic_Iter::~Stochastic_Iter() { } -void Stochastic_Iter::init(K_Vectors* pkv_in, - ModulePW::PW_Basis_K* wfc_basis, - Stochastic_WF& stowf, - StoChe& stoche) +template +void Stochastic_Iter::init(K_Vectors* pkv_in, + ModulePW::PW_Basis_K* wfc_basis, + Stochastic_WF& stowf, + StoChe& stoche, + hamilt::HamiltSdftPW* p_hamilt_sto) { p_che = stoche.p_che; spolyv = stoche.spolyv; nchip = stowf.nchip; - targetne = GlobalV::nelec; + targetne = PARAM.inp.nelec; this->pkv = pkv_in; this->method = stoche.method_sto; - - this->stohchi.init(wfc_basis, pkv, &stoche.emin_sto, &stoche.emax_sto); + this->p_hamilt_sto = p_hamilt_sto; this->stofunc.set_E_range(&stoche.emin_sto, &stoche.emax_sto); } -void Stochastic_Iter::orthog(const int& ik, psi::Psi>& psi, Stochastic_WF& stowf) +template +void Stochastic_Iter::orthog(const int& ik, psi::Psi& psi, Stochastic_WF& stowf) { ModuleBase::TITLE("Stochastic_Iter", "orthog"); // orthogonal part - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { const int nchipk = stowf.nchip[ik]; const int npw = psi.get_current_nbas(); const int npwx = psi.get_nbasis(); stowf.chi0->fix_k(ik); stowf.chiortho->fix_k(ik); - std::complex*wfgin = stowf.chi0->get_pointer(), *wfgout = stowf.chiortho->get_pointer(); + T *wfgin = stowf.chi0->get_pointer(), *wfgout = stowf.chiortho->get_pointer(); for (int ig = 0; ig < npwx * nchipk; ++ig) { wfgout[ig] = wfgin[ig]; } // orthogonal part - std::complex* sum = new std::complex[GlobalV::NBANDS * nchipk]; + T* sum = new T[PARAM.inp.nbands * nchipk]; char transC = 'C'; char transN = 'N'; // sum(b zgemm_(&transC, &transN, - &GlobalV::NBANDS, + &PARAM.inp.nbands, &nchipk, &npw, &ModuleBase::ONE, @@ -69,20 +74,20 @@ void Stochastic_Iter::orthog(const int& ik, psi::Psi>& psi, &npwx, &ModuleBase::ZERO, sum, - &GlobalV::NBANDS); - Parallel_Reduce::reduce_pool(sum, GlobalV::NBANDS * nchipk); + &PARAM.inp.nbands); + Parallel_Reduce::reduce_pool(sum, PARAM.inp.nbands * nchipk); // psi -= psi * sum zgemm_(&transN, &transN, &npw, &nchipk, - &GlobalV::NBANDS, + &PARAM.inp.nbands, &ModuleBase::NEG_ONE, &psi(ik, 0, 0), &npwx, sum, - &GlobalV::NBANDS, + &PARAM.inp.nbands, &ModuleBase::ONE, wfgout, &npwx); @@ -90,7 +95,11 @@ void Stochastic_Iter::orthog(const int& ik, psi::Psi>& psi, } } -void Stochastic_Iter::checkemm(const int& ik, const int istep, const int iter, Stochastic_WF& stowf) +template +void Stochastic_Iter::checkemm(const int& ik, + const int istep, + const int iter, + Stochastic_WF& stowf) { ModuleBase::TITLE("Stochastic_Iter", "checkemm"); // iter = 1,2,... istep = 0,1,2,... @@ -113,7 +122,7 @@ void Stochastic_Iter::checkemm(const int& ik, const int istep, const int iter, S } const int norder = p_che->norder; - std::complex* pchi; + T* pchi; int ntest = 1; if (nchip[ik] < ntest) @@ -123,7 +132,7 @@ void Stochastic_Iter::checkemm(const int& ik, const int istep, const int iter, S for (int ichi = 0; ichi < ntest; ++ichi) { - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { pchi = &stowf.chiortho->operator()(ik, ichi, 0); } @@ -134,12 +143,13 @@ void Stochastic_Iter::checkemm(const int& ik, const int istep, const int iter, S while (true) { bool converge; - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW::hPsi_norm, + p_hamilt_sto, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); - converge = p_che->checkconverge(hchi_norm, pchi, npw, *stohchi.Emax, *stohchi.Emin, 5.0); + converge + = p_che->checkconverge(hchi_norm, pchi, npw, stowf.npwx, *p_hamilt_sto->emax, *p_hamilt_sto->emin, 5.0); if (!converge) { @@ -154,20 +164,21 @@ void Stochastic_Iter::checkemm(const int& ik, const int istep, const int iter, S if (ik == nks - 1) { #ifdef __MPI - MPI_Allreduce(MPI_IN_PLACE, stohchi.Emax, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, stohchi.Emin, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, p_hamilt_sto->emax, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, p_hamilt_sto->emin, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); MPI_Allreduce(MPI_IN_PLACE, &change, 1, MPI_CHAR, MPI_LOR, MPI_COMM_WORLD); #endif if (change) { - GlobalV::ofs_running << "New Emax Ry" << *stohchi.Emax << " ; new Emin " << *stohchi.Emin << " Ry" - << std::endl; + GlobalV::ofs_running << "New Emax Ry" << *p_hamilt_sto->emax << " ; new Emin " << *p_hamilt_sto->emin + << " Ry" << std::endl; } change = false; } } -void Stochastic_Iter::check_precision(const double ref, const double thr, const std::string info) +template +void Stochastic_Iter::check_precision(const double ref, const double thr, const std::string info) { //============================== // precision check @@ -209,7 +220,8 @@ void Stochastic_Iter::check_precision(const double ref, const double thr, const //=============================== } -void Stochastic_Iter::itermu(const int iter, elecstate::ElecState* pes) +template +void Stochastic_Iter::itermu(const int iter, elecstate::ElecState* pes) { ModuleBase::TITLE("Stochastic_Iter", "itermu"); ModuleBase::timer::tick("Stochastic_Iter", "itermu"); @@ -217,13 +229,13 @@ void Stochastic_Iter::itermu(const int iter, elecstate::ElecState* pes) if (iter == 1) { dmu = 2; - th_ne = 0.1 * PARAM.inp.scf_thr * GlobalV::nelec; + th_ne = 0.1 * PARAM.inp.scf_thr * PARAM.inp.nelec; // std::cout<<"th_ne "<stofunc.mu = mu0 - dmu; @@ -288,12 +300,12 @@ void Stochastic_Iter::itermu(const int iter, elecstate::ElecState* pes) this->check_precision(targetne, 10 * PARAM.inp.scf_thr, "Ne"); // Set wf.wg - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { for (int ikk = 0; ikk < this->pkv->get_nks(); ++ikk) { double* en = &pes->ekb(ikk, 0); - for (int iksb = 0; iksb < GlobalV::NBANDS; ++iksb) + for (int iksb = 0; iksb < PARAM.inp.nbands; ++iksb) { pes->wg(ikk, iksb) = stofunc.fd(en[iksb]) * this->pkv->wk[ikk]; } @@ -303,7 +315,8 @@ void Stochastic_Iter::itermu(const int iter, elecstate::ElecState* pes) return; } -void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) +template +void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) { ModuleBase::TITLE("Stochastic_Iter", "calPn"); ModuleBase::timer::tick("Stochastic_Iter", "calPn"); @@ -323,8 +336,8 @@ void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) ModuleBase::GlobalFunc::ZEROS(spolyv, norder * norder); } } - std::complex* pchi; - if (GlobalV::NBANDS > 0) + T* pchi; + if (PARAM.inp.nbands > 0) { stowf.chiortho->fix_k(ik); pchi = stowf.chiortho->get_pointer(); @@ -335,8 +348,8 @@ void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) pchi = stowf.chi0->get_pointer(); } - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW::hPsi_norm, + p_hamilt_sto, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); @@ -350,8 +363,8 @@ void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) } else { - p_che->calpolyvec_complex(hchi_norm, pchi, stowf.chiallorder[ik].c, npw, npwx, nchip_ik); - double* vec_all = (double*)stowf.chiallorder[ik].c; + p_che->calpolyvec_complex(hchi_norm, pchi, stowf.chiallorder[ik].get_pointer(), npw, npwx, nchip_ik); + double* vec_all = (double*)stowf.chiallorder[ik].get_pointer(); char trans = 'T'; char normal = 'N'; double one = 1; @@ -365,7 +378,8 @@ void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) return; } -double Stochastic_Iter::calne(elecstate::ElecState* pes) +template +double Stochastic_Iter::calne(elecstate::ElecState* pes) { ModuleBase::timer::tick("Stochastic_Iter", "calne"); double totne = 0; @@ -385,12 +399,12 @@ double Stochastic_Iter::calne(elecstate::ElecState* pes) p_che->calcoef_real(nroot_fd); sto_ne = vTMv(p_che->coef_real, spolyv, norder); } - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { for (int ikk = 0; ikk < this->pkv->get_nks(); ++ikk) { double* en = &pes->ekb(ikk, 0); - for (int iksb = 0; iksb < GlobalV::NBANDS; ++iksb) + for (int iksb = 0; iksb < PARAM.inp.nbands; ++iksb) { KS_ne += stofunc.fd(en[iksb]) * this->pkv->wk[ikk]; } @@ -407,34 +421,22 @@ double Stochastic_Iter::calne(elecstate::ElecState* pes) return totne; } -void Stochastic_Iter::calHsqrtchi(Stochastic_WF& stowf) +template +void Stochastic_Iter::calHsqrtchi(Stochastic_WF& stowf) { auto nroot_fd = std::bind(&Sto_Func::nroot_fd, &this->stofunc, std::placeholders::_1); p_che->calcoef_real(nroot_fd); for (int ik = 0; ik < this->pkv->get_nks(); ++ik) { - // init k - if (this->pkv->get_nks() > 1) - { - - if (GlobalC::ppcell.nkb > 0 - && (PARAM.inp.basis_type == "pw" - || PARAM.inp.basis_type == "lcao_in_pw")) // xiaohui add 2013-09-02. Attention... - { - GlobalC::ppcell.getvnl(ik, GlobalC::ppcell.vkb); - } - - } - stohchi.current_ik = ik; - this->calTnchi_ik(ik, stowf); } } -void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, - elecstate::ElecState* pes, - hamilt::Hamilt>* pHamilt, - ModulePW::PW_Basis_K* wfc_basis) +template +void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, + elecstate::ElecState* pes, + hamilt::Hamilt* pHamilt, + ModulePW::PW_Basis_K* wfc_basis) { ModuleBase::TITLE("Stochastic_Iter", "sum_stoband"); ModuleBase::timer::tick("Stochastic_Iter", "sum_stoband"); @@ -457,13 +459,13 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, stodemet = -vTMv(p_che->coef_real, spolyv, norder); } - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { for (int ikk = 0; ikk < this->pkv->get_nks(); ++ikk) { double* enb = &pes->ekb(ikk, 0); // number of electrons in KS orbitals - for (int iksb = 0; iksb < GlobalV::NBANDS; ++iksb) + for (int iksb = 0; iksb < PARAM.inp.nbands; ++iksb) { pes->f_en.demet += stofunc.fdlnfd(enb[iksb]) * this->pkv->wk[ikk]; } @@ -493,16 +495,15 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, const int nchip_ik = nchip[ik]; if (this->pkv->get_nks() > 1) { - pHamilt->updateHk(ik); + pHamilt->updateHk(ik); // can be merged with calTnchi_ik, but it does not nearly cost time. stowf.shchi->fix_k(ik); } - stohchi.current_ik = ik; const int npw = this->pkv->ngk[ik]; const double kweight = this->pkv->wk[ik]; - std::complex* hshchi = new std::complex[nchip_ik * npwx]; - std::complex* tmpin = stowf.shchi->get_pointer(); - std::complex* tmpout = hshchi; - stohchi.hchi(tmpin, tmpout, nchip_ik); + T* hshchi = new T[nchip_ik * npwx]; + T* tmpin = stowf.shchi->get_pointer(); + T* tmpout = hshchi; + p_hamilt_sto->hPsi(tmpin, tmpout, nchip_ik); for (int ichi = 0; ichi < nchip_ik; ++ichi) { sto_eband += kweight * ModuleBase::GlobalFunc::ddot_real(npw, tmpin, tmpout, false); @@ -521,15 +522,15 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, double dr3 = GlobalC::ucell.omega / wfc_basis->nxyz; double tmprho, tmpne; - std::complex outtem; + T outtem; double sto_ne = 0; ModuleBase::GlobalFunc::ZEROS(sto_rho, nrxx); - std::complex* porter = new std::complex[nrxx]; + T* porter = new T[nrxx]; double out2; double* ksrho = nullptr; - if (GlobalV::NBANDS > 0 && GlobalV::MY_STOGROUP == 0) + if (PARAM.inp.nbands > 0 && GlobalV::MY_STOGROUP == 0) { ksrho = new double[nrxx]; ModuleBase::GlobalFunc::DCOPY(pes->charge->rho[0], ksrho, nrxx); @@ -540,7 +541,7 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, { const int nchip_ik = nchip[ik]; stowf.shchi->fix_k(ik); - std::complex* tmpout = stowf.shchi->get_pointer(); + T* tmpout = stowf.shchi->get_pointer(); for (int ichi = 0; ichi < nchip_ik; ++ichi) { wfc_basis->recip2real(tmpout, porter, ik); @@ -582,7 +583,7 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, if (GlobalV::MY_STOGROUP == 0) { - if (GlobalV::NBANDS > 0) + if (PARAM.inp.nbands > 0) { ModuleBase::GlobalFunc::DCOPY(ksrho, pes->charge->rho[0], nrxx); } @@ -609,14 +610,15 @@ void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, return; } -void Stochastic_Iter::calTnchi_ik(const int& ik, Stochastic_WF& stowf) +template +void Stochastic_Iter::calTnchi_ik(const int& ik, Stochastic_WF& stowf) { const int npw = stowf.ngk[ik]; const int npwx = stowf.npwx; stowf.shchi->fix_k(ik); - std::complex* out = stowf.shchi->get_pointer(); - std::complex* pchi; - if (GlobalV::NBANDS > 0) + T* out = stowf.shchi->get_pointer(); + T* pchi; + if (PARAM.inp.nbands > 0) { stowf.chiortho->fix_k(ik); pchi = stowf.chiortho->get_pointer(); @@ -629,27 +631,33 @@ void Stochastic_Iter::calTnchi_ik(const int& ik, Stochastic_WF& stowf) if (this->method == 2) { char transa = 'N'; - std::complex one = 1; + T one = 1; int inc = 1; - std::complex zero = 0; + T zero = 0; int LDA = npwx * nchip[ik]; int M = npwx * nchip[ik]; int N = p_che->norder; - std::complex* coef_real = new std::complex[p_che->norder]; + T* coef_real = new T[p_che->norder]; for (int i = 0; i < p_che->norder; ++i) { coef_real[i] = p_che->coef_real[i]; } - zgemv_(&transa, &M, &N, &one, stowf.chiallorder[ik].c, &LDA, coef_real, &inc, &zero, out, &inc); + zgemv_(&transa, &M, &N, &one, stowf.chiallorder[ik].get_pointer(), &LDA, coef_real, &inc, &zero, out, &inc); delete[] coef_real; } else { - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, + if (this->pkv->get_nks() > 1) + { + p_hamilt_sto->updateHk(ik); // necessary, because itermu should be called before this function + } + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW::hPsi_norm, + p_hamilt_sto, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); p_che->calfinalvec_real(hchi_norm, pchi, out, npw, npwx, nchip[ik]); } } + +template class Stochastic_Iter, base_device::DEVICE_CPU>; diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_iter.h b/source/module_hamilt_pw/hamilt_stodft/sto_iter.h index a0349a0a987..2947f98e7fe 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_iter.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_iter.h @@ -3,10 +3,10 @@ #include "module_base/math_chebyshev.h" #include "module_elecstate/elecstate.h" #include "module_hamilt_general/hamilt.h" +#include "module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h" #include "module_psi/psi.h" #include "sto_che.h" #include "sto_func.h" -#include "sto_hchi.h" #include "sto_wf.h" //---------------------------------------------- @@ -17,6 +17,7 @@ // rho: charge density //---------------------------------------------- +template class Stochastic_Iter { @@ -33,29 +34,34 @@ class Stochastic_Iter * @param wfc_basis wfc pw basis * @param stowf stochastic wave function * @param stoche Chebyshev expansion for sDFT + * @param p_hamilt_sto hamiltonian for sDFT * */ - void init(K_Vectors* pkv_in, ModulePW::PW_Basis_K* wfc_basis, Stochastic_WF& stowf, StoChe& stoche); + void init(K_Vectors* pkv_in, + ModulePW::PW_Basis_K* wfc_basis, + Stochastic_WF& stowf, + StoChe& stoche, + hamilt::HamiltSdftPW* p_hamilt_sto); - void sum_stoband(Stochastic_WF& stowf, + void sum_stoband(Stochastic_WF& stowf, elecstate::ElecState* pes, - hamilt::Hamilt>* pHamilt, + hamilt::Hamilt* pHamilt, ModulePW::PW_Basis_K* wfc_basis); double calne(elecstate::ElecState* pes); void itermu(const int iter, elecstate::ElecState* pes); - void orthog(const int& ik, psi::Psi>& psi, Stochastic_WF& stowf); + void orthog(const int& ik, psi::Psi& psi, Stochastic_WF& stowf); - void checkemm(const int& ik, const int istep, const int iter, Stochastic_WF& stowf); + void checkemm(const int& ik, const int istep, const int iter, Stochastic_WF& stowf); void check_precision(const double ref, const double thr, const std::string info); ModuleBase::Chebyshev* p_che = nullptr; - Stochastic_hchi stohchi; Sto_Func stofunc; + hamilt::HamiltSdftPW* p_hamilt_sto = nullptr; double mu0; // chemical potential; unit in Ry bool change; @@ -71,11 +77,11 @@ class Stochastic_Iter public: int method; // different methods 1: slow, less memory 2: fast, more memory // cal shchi = \sqrt{f(\hat{H})}|\chi> - void calHsqrtchi(Stochastic_WF& stowf); + void calHsqrtchi(Stochastic_WF& stowf); // cal Pn = \sum_\chi <\chi|Tn(\hat{h})|\chi> - void calPn(const int& ik, Stochastic_WF& stowf); + void calPn(const int& ik, Stochastic_WF& stowf); // cal Tnchi = \sum_n C_n*T_n(\hat{h})|\chi> - void calTnchi_ik(const int& ik, Stochastic_WF& stowf); + void calTnchi_ik(const int& ik, Stochastic_WF& stowf); private: K_Vectors* pkv; diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.cpp index a0a00d8b9bb..73205edecdc 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.cpp @@ -1,10 +1,10 @@ #include "sto_stress_pw.h" -#include "module_parameter/parameter.h" #include "module_base/timer.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_hamilt_pw/hamilt_pwdft/structure_factor.h" #include "module_io/output_log.h" +#include "module_parameter/parameter.h" void Sto_Stress_PW::cal_stress(ModuleBase::matrix& sigmatot, const elecstate::ElecState& elec, @@ -14,7 +14,7 @@ void Sto_Stress_PW::cal_stress(ModuleBase::matrix& sigmatot, K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf, + Stochastic_WF, base_device::DEVICE_CPU>& stowf, const Charge* const chr, pseudopot_cell_vnl* nlpp_in, const UnitCell& ucell_in) @@ -99,7 +99,7 @@ void Sto_Stress_PW::sto_stress_kin(ModuleBase::matrix& sigma, K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf) + Stochastic_WF, base_device::DEVICE_CPU>& stowf) { ModuleBase::TITLE("Sto_Stress_PW", "cal_stress"); ModuleBase::timer::tick("Sto_Stress_PW", "cal_stress"); @@ -116,9 +116,10 @@ void Sto_Stress_PW::sto_stress_kin(ModuleBase::matrix& sigma, double twobysqrtpi = 2.0 / std::sqrt(ModuleBase::PI); double* kfac = new double[npwx]; int nksbands = psi_in->get_nbands(); - if (GlobalV::MY_STOGROUP != 0) { + if (GlobalV::MY_STOGROUP != 0) + { nksbands = 0; -} + } for (int ik = 0; ik < nks; ++ik) { @@ -220,7 +221,7 @@ void Sto_Stress_PW::sto_stress_nl(ModuleBase::matrix& sigma, K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf, + Stochastic_WF, base_device::DEVICE_CPU>& stowf, pseudopot_cell_vnl* nlpp_in) { ModuleBase::TITLE("Sto_Stress_Func", "stres_nl"); @@ -238,9 +239,10 @@ void Sto_Stress_PW::sto_stress_nl(ModuleBase::matrix& sigma, int* nchip = stowf.nchip; const int npwx = wfc_basis->npwk_max; int nksbands = psi_in->get_nbands(); - if (GlobalV::MY_STOGROUP != 0) { + if (GlobalV::MY_STOGROUP != 0) + { nksbands = 0; -} + } // vkb1: |Beta(nkb,npw)> ModuleBase::ComplexMatrix vkb1(nkb, npwx); @@ -366,11 +368,14 @@ void Sto_Stress_PW::sto_stress_nl(ModuleBase::matrix& sigma, { qvec = wfc_basis->getgpluskcar(ik, ig); double qm1; - if (qvec.norm2() > 1e-16) { + if (qvec.norm2() > 1e-16) + { qm1 = 1.0 / qvec.norm(); - } else { + } + else + { qm1 = 0; -} + } pdbecp_noevc[ig] -= 2.0 * pvkb[ig] * qvec0[ipol][0] * qvec0[jpol][0] * qm1 * this->ucell->tpiba; } // end ig } // end i @@ -407,11 +412,14 @@ void Sto_Stress_PW::sto_stress_nl(ModuleBase::matrix& sigma, for (int ib = 0; ib < nbandstot; ++ib) { double fac; - if (ib < nksbands) { + if (ib < nksbands) + { fac = wg(ik, ib); - } else { + } + else + { fac = p_kv->wk[ik]; -} + } int iat = 0; int sum = 0; for (int it = 0; it < this->ucell->ntype; ++it) diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.h b/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.h index 72d306756ee..e3fc3eadd6c 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_stress_pw.h @@ -22,7 +22,7 @@ class Sto_Stress_PW : public Stress_Func K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf, + Stochastic_WF, base_device::DEVICE_CPU>& stowf, const Charge* const chr, pseudopot_cell_vnl* nlpp_in, const UnitCell& ucell_in); @@ -34,7 +34,7 @@ class Sto_Stress_PW : public Stress_Func K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf); + Stochastic_WF, base_device::DEVICE_CPU>& stowf); void sto_stress_nl(ModuleBase::matrix& sigma, const ModuleBase::matrix& wg, @@ -43,7 +43,7 @@ class Sto_Stress_PW : public Stress_Func K_Vectors* p_kv, ModulePW::PW_Basis_K* wfc_basis, const psi::Psi>* psi_in, - Stochastic_WF& stowf, + Stochastic_WF, base_device::DEVICE_CPU>& stowf, pseudopot_cell_vnl* nlpp_in); }; #endif diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_tool.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_tool.cpp index 1f5675f6750..8b350c7777e 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_tool.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_tool.cpp @@ -1,8 +1,8 @@ #include "sto_tool.h" -#include "module_parameter/parameter.h" #include "module_base/math_chebyshev.h" #include "module_base/timer.h" +#include "module_parameter/parameter.h" #ifdef __MPI #include "mpi.h" #endif @@ -13,9 +13,8 @@ void check_che(const int& nche_in, const double& try_emax, const int& nbands_sto, K_Vectors* p_kv, - Stochastic_WF* p_stowf, - hamilt::Hamilt>* p_hamilt, - Stochastic_hchi& stohchi) + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf, + hamilt::HamiltSdftPW>* p_hamilt_sto) { //------------------------------ // Convergence test @@ -24,25 +23,24 @@ void check_che(const int& nche_in, const int nk = p_kv->get_nks(); ModuleBase::Chebyshev chetest(nche_in); int ntest0 = 5; - *stohchi.Emax = try_emax; - *stohchi.Emin = try_emin; - // if (GlobalV::NBANDS > 0) + *p_hamilt_sto->emax = try_emax; + *p_hamilt_sto->emin = try_emin; + // if (PARAM.inp.nbands > 0) // { // double tmpemin = 1e10; // for (int ik = 0; ik < nk; ++ik) // { - // tmpemin = std::min(tmpemin, this->pelec->ekb(ik, GlobalV::NBANDS - 1)); + // tmpemin = std::min(tmpemin, this->pelec->ekb(ik, PARAM.inp.nbands - 1)); // } - // stohchi.Emin = tmpemin; + // *p_hamilt_sto->emin = tmpemin; // } // else // { - // stohchi.Emin = 0; + // *p_hamilt_sto->emin = 0; // } for (int ik = 0; ik < nk; ++ik) { - p_hamilt->updateHk(ik); - stohchi.current_ik = ik; + p_hamilt_sto->updateHk(ik); const int npw = p_kv->ngk[ik]; std::complex* pchi = nullptr; std::vector> randchi; @@ -60,7 +58,7 @@ void check_che(const int& nche_in, pchi[ig] = std::complex(rr * cos(arg), rr * sin(arg)); } } - else if (GlobalV::NBANDS > 0) + else if (PARAM.inp.nbands > 0) { pchi = &p_stowf->chiortho[0](ik, i, 0); } @@ -71,12 +69,18 @@ void check_che(const int& nche_in, while (true) { bool converge; - auto hchi_norm = std::bind(&Stochastic_hchi::hchi_norm, - &stohchi, + auto hchi_norm = std::bind(&hamilt::HamiltSdftPW>::hPsi_norm, + p_hamilt_sto, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); - converge = chetest.checkconverge(hchi_norm, pchi, npw, *stohchi.Emax, *stohchi.Emin, 2.0); + converge = chetest.checkconverge(hchi_norm, + pchi, + npw, + p_stowf->npwx, + *p_hamilt_sto->emax, + *p_hamilt_sto->emin, + 2.0); if (!converge) { @@ -92,11 +96,11 @@ void check_che(const int& nche_in, if (ik == nk - 1) { #ifdef __MPI - MPI_Allreduce(MPI_IN_PLACE, stohchi.Emax, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, stohchi.Emin, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, p_hamilt_sto->emax, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, p_hamilt_sto->emin, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); #endif - GlobalV::ofs_running << "New Emax " << *stohchi.Emax << " Ry; new Emin " << *stohchi.Emin << " Ry" - << std::endl; + GlobalV::ofs_running << "New Emax " << *p_hamilt_sto->emax << " Ry; new Emin " << *p_hamilt_sto->emin + << " Ry" << std::endl; change = false; } } diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_tool.h b/source/module_hamilt_pw/hamilt_stodft/sto_tool.h index 69e501cb53f..83b941141e3 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_tool.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_tool.h @@ -1,6 +1,5 @@ #include "module_cell/klist.h" -#include "module_hamilt_general/hamilt.h" -#include "module_hamilt_pw/hamilt_stodft/sto_hchi.h" +#include "module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h" #include "module_hamilt_pw/hamilt_stodft/sto_wf.h" #include "module_psi/psi.h" /** @@ -16,9 +15,8 @@ void check_che(const int& nche_in, const double& try_emax, const int& nbands_sto, K_Vectors* p_kv, - Stochastic_WF* p_stowf, - hamilt::Hamilt>* p_hamilt, - Stochastic_hchi& stohchi); + Stochastic_WF, base_device::DEVICE_CPU>* p_stowf, + hamilt::HamiltSdftPW>* p_hamilt_sto); #ifndef PARALLEL_DISTRIBUTION #define PARALLEL_DISTRIBUTION diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_wf.cpp b/source/module_hamilt_pw/hamilt_stodft/sto_wf.cpp index 39f4697b567..1f596b06dbe 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_wf.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/sto_wf.cpp @@ -1,31 +1,38 @@ #include "sto_wf.h" +#include "module_base/memory.h" #include "module_parameter/parameter.h" -#include -#include "module_base/memory.h" +#include #include //---------Temporary------------------------------------ -#include "module_base/complexmatrix.h" #include "module_base/global_function.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" //------------------------------------------------------ -Stochastic_WF::Stochastic_WF() +template +Stochastic_WF::Stochastic_WF() { } -Stochastic_WF::~Stochastic_WF() +template +Stochastic_WF::~Stochastic_WF() { - delete chi0; + delete chi0_cpu; + Device* ctx = {}; + if (base_device::get_device_type(ctx) == base_device::GpuDevice) + { + delete chi0; + } delete shchi; delete chiortho; delete[] nchip; delete[] chiallorder; } -void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) +template +void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) { this->nks = p_kv->get_nks(); this->ngk = p_kv->ngk.data(); @@ -38,22 +45,26 @@ void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) } } -void Stochastic_WF::allocate_chiallorder(const int& norder) +template +void Stochastic_WF::allocate_chiallorder(const int& norder) { - this->chiallorder = new ModuleBase::ComplexMatrix[this->nks]; + this->chiallorder = new psi::Psi[this->nks]; for (int ik = 0; ik < this->nks; ++ik) { - chiallorder[ik].create(this->nchip[ik] * this->npwx, norder,true); + chiallorder[ik].resize(1, this->nchip[ik] * this->npwx, norder); + setmem_complex_op()(chiallorder[ik].get_device(), chiallorder[ik].get_pointer(), 0, chiallorder[ik].size()); } } -void Stochastic_WF::clean_chiallorder() +template +void Stochastic_WF::clean_chiallorder() { delete[] chiallorder; chiallorder = nullptr; } -void Init_Sto_Orbitals(Stochastic_WF& stowf, const int seed_in) +template +void Stochastic_WF::init_sto_orbitals(const int seed_in) { if (seed_in == 0 || seed_in == -1) { @@ -64,11 +75,12 @@ void Init_Sto_Orbitals(Stochastic_WF& stowf, const int seed_in) srand((unsigned)std::abs(seed_in) + GlobalV::MY_RANK * 10000); } - Allocate_Chi0(stowf); - Update_Sto_Orbitals(stowf, seed_in); + this->allocate_chi0(); + this->update_sto_orbitals(seed_in); } -void Allocate_Chi0(Stochastic_WF& stowf) +template +void Stochastic_WF::allocate_chi0() { bool firstrankmore = false; int igroup = 0; @@ -84,12 +96,12 @@ void Allocate_Chi0(Stochastic_WF& stowf) igroup = PARAM.inp.bndpar - GlobalV::MY_STOGROUP - 1; } const int nchi = PARAM.inp.nbands_sto; - const int npwx = stowf.npwx; - const int nks = stowf.nks; + const int npwx = this->npwx; + const int nks = this->nks; const int ngroup = PARAM.inp.bndpar; if (ngroup <= 0) { - ModuleBase::WARNING_QUIT("Init_Sto_Orbitals", "ngroup <= 0!"); + ModuleBase::WARNING_QUIT("init_sto_orbitals", "ngroup <= 0!"); } int tmpnchip = int(nchi / ngroup); if (igroup < nchi % ngroup) @@ -97,51 +109,65 @@ void Allocate_Chi0(Stochastic_WF& stowf) ++tmpnchip; } - stowf.nchip_max = tmpnchip; - size_t size = stowf.nchip_max * npwx * nks; - stowf.chi0 = new psi::Psi>(nks, stowf.nchip_max, npwx, stowf.ngk); - ModuleBase::Memory::record("SDFT::chi0", size * sizeof(std::complex)); + this->nchip_max = tmpnchip; + size_t size = this->nchip_max * npwx * nks; + this->chi0_cpu = new psi::Psi(nks, this->nchip_max, npwx, this->ngk); + ModuleBase::Memory::record("SDFT::chi0_cpu", size * sizeof(T)); for (int ik = 0; ik < nks; ++ik) { - stowf.nchip[ik] = tmpnchip; + this->nchip[ik] = tmpnchip; + } + + // allocate chi0 + Device* ctx = {}; + if (base_device::get_device_type(ctx) == base_device::GpuDevice) + { + this->chi0 = new psi::Psi(nks, this->nchip_max, npwx, this->ngk); + } + else + { + this->chi0 = reinterpret_cast*>(this->chi0_cpu); } } -void Update_Sto_Orbitals(Stochastic_WF& stowf, const int seed_in) +template +void Stochastic_WF::update_sto_orbitals(const int seed_in) { const int nchi = PARAM.inp.nbands_sto; - stowf.chi0->fix_k(0); + this->chi0_cpu->fix_k(0); if (seed_in >= 0) { - for (int i = 0; i < stowf.chi0->size(); ++i) + for (int i = 0; i < this->chi0_cpu->size(); ++i) { const double phi = 2 * ModuleBase::PI * rand() / double(RAND_MAX); - stowf.chi0->get_pointer()[i] = std::complex(cos(phi), sin(phi)) / sqrt(double(nchi)); + this->chi0_cpu->get_pointer()[i] = std::complex(cos(phi), sin(phi)) / sqrt(double(nchi)); } } else { - for (int i = 0; i < stowf.chi0->size(); ++i) + for (int i = 0; i < this->chi0_cpu->size(); ++i) { if (rand() / double(RAND_MAX) < 0.5) { - stowf.chi0->get_pointer()[i] = -1.0 / sqrt(double(nchi)); + this->chi0_cpu->get_pointer()[i] = -1.0 / sqrt(double(nchi)); } else { - stowf.chi0->get_pointer()[i] = 1.0 / sqrt(double(nchi)); + this->chi0_cpu->get_pointer()[i] = 1.0 / sqrt(double(nchi)); } } } + this->sync_chi0(); } #ifdef __MPI -void Init_Com_Orbitals(Stochastic_WF& stowf) +template +void Stochastic_WF::init_com_orbitals() { const bool firstrankmore = false; - const int npwx = stowf.npwx; - const int nks = stowf.nks; + const int npwx = this->npwx; + const int nks = this->nks; int igroup; // former processor calculate more bands if (firstrankmore) @@ -162,7 +188,7 @@ void Init_Com_Orbitals(Stochastic_WF& stowf) for (int ik = 0; ik < nks; ++ik) { int* npwip = new int[n_in_pool]; - const int npw = stowf.ngk[ik]; + const int npw = this->ngk[ik]; totnpw[ik] = 0; MPI_Allgather(&npw, 1, MPI_INT, npwip, 1, MPI_INT, POOL_WORLD); @@ -176,22 +202,22 @@ void Init_Com_Orbitals(Stochastic_WF& stowf) { ++tmpnchip; } - stowf.nchip[ik] = tmpnchip; - stowf.nchip_max = std::max(tmpnchip, stowf.nchip_max); + this->nchip[ik] = tmpnchip; + this->nchip_max = std::max(tmpnchip, this->nchip_max); delete[] npwip; } - size_t size = stowf.nchip_max * npwx * nks; - stowf.chi0 = new psi::Psi>(nks, stowf.nchip_max, npwx, stowf.ngk); - stowf.chi0->zero_out(); - ModuleBase::Memory::record("SDFT::chi0", size * sizeof(std::complex)); + size_t size = this->nchip_max * npwx * nks; + this->chi0_cpu = new psi::Psi>(nks, this->nchip_max, npwx, this->ngk); + this->chi0_cpu->zero_out(); + ModuleBase::Memory::record("SDFT::chi0_cpu", size * sizeof(std::complex)); for (int ik = 0; ik < nks; ++ik) { int* npwip = new int[n_in_pool]; - const int npw = stowf.ngk[ik]; + const int npw = this->ngk[ik]; MPI_Allgather(&npw, 1, MPI_INT, npwip, 1, MPI_INT, POOL_WORLD); const int re = totnpw[ik] % ngroup; int ip = 0, ig0 = 0; - const int nchipk = stowf.nchip[ik]; + const int nchipk = this->nchip[ik]; // give value to orbitals in one parallel group one by one. for (int ichi = 0; ichi < nchipk; ++ichi) { @@ -215,42 +241,64 @@ void Init_Com_Orbitals(Stochastic_WF& stowf) } if (i_in_pool == ip) { - stowf.chi0->operator()(ik, ichi, ig) = 1; + this->chi0_cpu->operator()(ik, ichi, ig) = 1; } } delete[] npwip; } delete[] totnpw; + // allocate chi0 + Device* ctx = {}; + if (base_device::get_device_type(ctx) == base_device::GpuDevice) + { + this->chi0 = new psi::Psi(nks, this->nchip_max, npwx, this->ngk); + } + else + { + this->chi0 = reinterpret_cast*>(this->chi0_cpu); + } } #else -void Init_Com_Orbitals(Stochastic_WF& stowf) +template +void Stochastic_WF::init_com_orbitals() { - const int npwx = stowf.npwx; - const int nks = stowf.nks; - size_t size = stowf.nchip_max * npwx * nks; - stowf.chi0 = new psi::Psi>(nks, npwx, npwx, stowf.ngk); - stowf.chi0->zero_out(); - ModuleBase::Memory::record("SDFT::chi0", size * sizeof(std::complex)); + const int npwx = this->npwx; + const int nks = this->nks; + size_t size = this->nchip_max * npwx * nks; + this->chi0_cpu = new psi::Psi>(nks, npwx, npwx, this->ngk); + this->chi0_cpu->zero_out(); + ModuleBase::Memory::record("SDFT::chi0_cpu", size * sizeof(std::complex)); for (int ik = 0; ik < nks; ++ik) { - const int npw = stowf.ngk[ik]; - stowf.nchip[ik] = npwx; - stowf.nchip_max = npwx; + const int npw = this->ngk[ik]; + this->nchip[ik] = npwx; + this->nchip_max = npwx; for (int ichi = 0; ichi < npw; ++ichi) { - stowf.chi0->operator()(ik, ichi, ichi) = 1; + this->chi0_cpu->operator()(ik, ichi, ichi) = 1; } } + + // allocate chi0 + Device* ctx = {}; + if (base_device::get_device_type(ctx) == base_device::GpuDevice) + { + this->chi0 = new psi::Psi(nks, this->nchip_max, npwx, this->ngk); + } + else + { + this->chi0 = reinterpret_cast*>(this->chi0_cpu); + } } #endif -void Init_Sto_Orbitals_Ecut(Stochastic_WF& stowf, - const int seed_in, - const K_Vectors& kv, - const ModulePW::PW_Basis_K& wfcpw, - const int max_ecut) +template +void Stochastic_WF::init_sto_orbitals_Ecut(const int seed_in, + const K_Vectors& kv, + const ModulePW::PW_Basis_K& wfcpw, + const int max_ecut) { - Allocate_Chi0(stowf); + this->allocate_chi0(); ModulePW::PW_Basis pwmax; #ifdef __MPI @@ -265,7 +313,7 @@ void Init_Sto_Orbitals_Ecut(Stochastic_WF& stowf, const int nchitot = PARAM.inp.nbands_sto; bool* updown = new bool[nx * ny * nz]; int* nrecv = new int[PARAM.inp.bndpar]; - const int nchiper = stowf.nchip[0]; + const int nchiper = this->nchip[0]; #ifdef __MPI MPI_Allgather(&nchiper, 1, MPI_INT, nrecv, 1, MPI_INT, PARAPW_WORLD); #endif @@ -306,11 +354,11 @@ void Init_Sto_Orbitals_Ecut(Stochastic_WF& stowf, { if (updown[ig2ixyz[ig]]) { - stowf.chi0->operator()(ik, ichi, ig) = -1.0 / sqrt(double(nchitot)); + this->chi0_cpu->operator()(ik, ichi, ig) = -1.0 / sqrt(double(nchitot)); } else { - stowf.chi0->operator()(ik, ichi, ig) = 1.0 / sqrt(double(nchitot)); + this->chi0_cpu->operator()(ik, ichi, ig) = 1.0 / sqrt(double(nchitot)); } } } @@ -319,3 +367,19 @@ void Init_Sto_Orbitals_Ecut(Stochastic_WF& stowf, delete[] nrecv; delete[] updown; } + +template +void Stochastic_WF::sync_chi0() +{ + Device* ctx = {}; + if (base_device::get_device_type(ctx) == base_device::GpuDevice) + { + syncmem_h2d_op()(this->chi0->get_device(), + this->chi0_cpu->get_device(), + this->chi0->get_pointer(), + this->chi0_cpu->get_pointer(), + this->chi0_cpu->size()); + } +} + +template class Stochastic_WF, base_device::DEVICE_CPU>; diff --git a/source/module_hamilt_pw/hamilt_stodft/sto_wf.h b/source/module_hamilt_pw/hamilt_stodft/sto_wf.h index f8811f8bb00..e6f954f9afc 100644 --- a/source/module_hamilt_pw/hamilt_stodft/sto_wf.h +++ b/source/module_hamilt_pw/hamilt_stodft/sto_wf.h @@ -1,7 +1,7 @@ #ifndef STOCHASTIC_WF_H #define STOCHASTIC_WF_H -#include "module_base/complexmatrix.h" +#include "module_base/module_container/ATen/tensor.h" #include "module_basis/module_pw/pw_basis_k.h" #include "module_cell/klist.h" #include "module_psi/psi.h" @@ -9,6 +9,7 @@ //---------------------------------------------- // Generate stochastic wave functions //---------------------------------------------- +template class Stochastic_WF { public: @@ -18,12 +19,14 @@ class Stochastic_WF void init(K_Vectors* p_kv, const int npwx_in); - // origin stochastic wavefunctions in real space - psi::Psi>* chi0 = nullptr; + // origin stochastic wavefunctions in CPU + psi::Psi* chi0_cpu = nullptr; + // origin stochastic wavefunctions in GPU or CPU + psi::Psi* chi0 = nullptr; // stochastic wavefunctions after in reciprocal space orthogonalized with KS wavefunctions - psi::Psi>* chiortho = nullptr; + psi::Psi* chiortho = nullptr; // sqrt(f(H))|chi> - psi::Psi>* shchi = nullptr; + psi::Psi* shchi = nullptr; int nchi = 0; ///< Total number of stochatic obitals int* nchip = nullptr; ///< The number of stochatic orbitals in current process of each k point. int nchip_max = 0; ///< Max number of stochastic orbitals among all k points. @@ -34,25 +37,32 @@ class Stochastic_WF int nbands_total = 0; ///< number of bands in total, nbands_total=nchi+nbands_diag; public: // Tn(H)|chi> - ModuleBase::ComplexMatrix* chiallorder = nullptr; + psi::Psi* chiallorder = nullptr; // allocate chiallorder void allocate_chiallorder(const int& norder); // chiallorder cost too much memories and should be cleaned after scf. void clean_chiallorder(); + + public: + // init stochastic orbitals + void init_sto_orbitals(const int seed_in); + // init stochastic orbitals from a large Ecut + // It can test the convergence of SDFT with respect to Ecut + void init_sto_orbitals_Ecut(const int seed_in, + const K_Vectors& kv, + const ModulePW::PW_Basis_K& wfcpw, + const int max_ecut); + // allocate chi0 + void allocate_chi0(); + // update stochastic orbitals + void update_sto_orbitals(const int seed_in); + // init complete orbitals + void init_com_orbitals(); + // sync chi0 from CPU to GPU + void sync_chi0(); + + protected: + using setmem_complex_op = base_device::memory::set_memory_op; + using syncmem_h2d_op = base_device::memory::synchronize_memory_op; }; -// init stochastic orbitals -void Init_Sto_Orbitals(Stochastic_WF& stowf, const int seed_in); -// init stochastic orbitals from a large Ecut -// It can test the convergence of SDFT with respect to Ecut -void Init_Sto_Orbitals_Ecut(Stochastic_WF& stowf, - const int seed_in, - const K_Vectors& kv, - const ModulePW::PW_Basis_K& wfcpw, - const int max_ecut); -// allocate chi0 -void Allocate_Chi0(Stochastic_WF& stowf); -// update stochastic orbitals -void Update_Sto_Orbitals(Stochastic_WF& stowf, const int seed_in); -// init complete orbitals -void Init_Com_Orbitals(Stochastic_WF& stowf); #endif diff --git a/source/module_hamilt_pw/hamilt_stodft/test/CMakeLists.txt b/source/module_hamilt_pw/hamilt_stodft/test/CMakeLists.txt index 3bf176b14c8..42fa38e0885 100644 --- a/source/module_hamilt_pw/hamilt_stodft/test/CMakeLists.txt +++ b/source/module_hamilt_pw/hamilt_stodft/test/CMakeLists.txt @@ -4,4 +4,10 @@ AddTest( TARGET Sto_Tool_UTs LIBS parameter ${math_libs} psi base device SOURCES ../sto_tool.cpp test_sto_tool.cpp +) + +AddTest( + TARGET Sto_Hamilt_UTs + LIBS parameter ${math_libs} psi base device planewave_serial + SOURCES ../hamilt_sdft_pw.cpp test_hamilt_sto.cpp ../../../module_hamilt_general/operator.cpp ) \ No newline at end of file diff --git a/source/module_hamilt_pw/hamilt_stodft/test/test_hamilt_sto.cpp b/source/module_hamilt_pw/hamilt_stodft/test/test_hamilt_sto.cpp new file mode 100644 index 00000000000..ed40e17d800 --- /dev/null +++ b/source/module_hamilt_pw/hamilt_stodft/test/test_hamilt_sto.cpp @@ -0,0 +1,144 @@ +#include "../hamilt_sdft_pw.h" +#include "module_hamilt_general/operator.h" + +#include "gtest/gtest.h" +#include + +K_Vectors::K_Vectors(){} +K_Vectors::~K_Vectors(){} +elecstate::Potential::~Potential(){} +void elecstate::Potential::cal_v_eff(Charge const*, UnitCell const*, ModuleBase::matrix&){} +void elecstate::Potential::cal_fixed_v(double*){} + +template +hamilt::HamiltPW::HamiltPW(elecstate::Potential* pot_in, ModulePW::PW_Basis_K* wfc_basis, K_Vectors* p_kv){} +template +hamilt::HamiltPW::~HamiltPW(){ + delete this->ops; +}; +template +void hamilt::HamiltPW::updateHk(int){} +template +void hamilt::HamiltPW::sPsi(T const*, T*, const int, const int, const int) const{} + +template class hamilt::HamiltPW, base_device::DEVICE_CPU>; +template class hamilt::HamiltPW, base_device::DEVICE_CPU>; +template class hamilt::HamiltPW, base_device::DEVICE_GPU>; +template class hamilt::HamiltPW, base_device::DEVICE_GPU>; + +/************************************************ + * unit test of hamilt_sto_pw.cpp + * - Tested Functions: + * - void hPsi(const T* psi_in, T* hpsi, const int& nbands) + * - void hPsi_norm(const T* psi_in, T* hpsi, const int& nbands) + ***********************************************/ + +template +class TestOp : public hamilt::Operator +{ + public: + virtual void act(const int nbands, + const int nbasis, + const int npol, + const T* tmpsi_in, + T* tmhpsi, + const int ngk_ik = 0, + const bool is_first_node = false) const override + { + for (int i = 0; i < nbands; i++) + { + for (int j = 0; j < nbasis; j++) + { + tmhpsi[i * nbasis + j] = tmpsi_in[i * nbasis + j]; + } + } + } +}; + +class TestHamiltSto : public ::testing::Test +{ + public: + TestHamiltSto() + { + const int nbands = 1; + const int nbasis = 2; + const int npol = 1; + // Initialize the hamilt_sto_pw + pot = new elecstate::Potential(); + wfc_basis = new ModulePW::PW_Basis_K(); + wfc_basis->npwk_max = 2; + p_kv = new K_Vectors(); + std::vector ngk = {2}; + p_kv->ngk = ngk; + hamilt_sto = new hamilt::HamiltSdftPW, base_device::DEVICE_CPU>(pot, wfc_basis, p_kv, npol, &emin, &emax); + hamilt_sto->ops = new TestOp, base_device::DEVICE_CPU>(); + } + + ~TestHamiltSto() + { + delete pot; + delete wfc_basis; + delete p_kv; + delete hamilt_sto; + } + + elecstate::Potential* pot; + ModulePW::PW_Basis_K* wfc_basis; + K_Vectors* p_kv; + hamilt::HamiltSdftPW, base_device::DEVICE_CPU>* hamilt_sto; + double emin = -2.0; + double emax = 2.0; +}; + +TEST_F(TestHamiltSto, hPsi) +{ + const int nbands = 1; + const int nbasis = 2; + // Prepare the input psi + std::vector> psi_in(nbands * nbasis); + std::vector> hpsi(nbands * nbasis); + + for (int i = 0; i < nbands; i++) + { + for (int j = 0; j < nbasis; j++) + { + psi_in[i * nbasis + j] = i + j; + } + } + hamilt_sto->hPsi(psi_in.data(), hpsi.data(), nbands); + // Check the result + for (int i = 0; i < nbands; i++) + { + for (int j = 0; j < nbasis; j++) + { + EXPECT_EQ(hpsi[i * nbasis + j], psi_in[i * nbasis + j]); + } + } +} + +TEST_F(TestHamiltSto, hPsi_norm) +{ + int nbands = 1; + int nbasis = 2; + std::vector> psi_in(nbands * nbasis); + std::vector> hpsi(nbands * nbasis); + + for (int i = 0; i < nbands; i++) + { + for (int j = 0; j < nbasis; j++) + { + psi_in[i * nbasis + j] = i + j; + } + } + + hamilt_sto->hPsi_norm(psi_in.data(), hpsi.data(), nbands); + + // Check the result + for (int i = 0; i < nbands; i++) + { + for (int j = 0; j < nbasis; j++) + { + EXPECT_EQ(hpsi[i * nbasis + j], psi_in[i * nbasis + j] * 0.5); + } + } +} diff --git a/source/module_hamilt_pw/hamilt_stodft/test/test_sto_tool.cpp b/source/module_hamilt_pw/hamilt_stodft/test/test_sto_tool.cpp index e57b74e4da7..817cdb7b527 100644 --- a/source/module_hamilt_pw/hamilt_stodft/test/test_sto_tool.cpp +++ b/source/module_hamilt_pw/hamilt_stodft/test/test_sto_tool.cpp @@ -7,10 +7,27 @@ * unit test of sto_tool.cpp ***********************************************/ -void Stochastic_hchi::hchi_norm(std::complex* chig, std::complex* hchig, const int m) -{ - return; -} +template +hamilt::HamiltPW::HamiltPW(elecstate::Potential* pot_in, ModulePW::PW_Basis_K* wfc_basis, K_Vectors* p_kv){} +template +hamilt::HamiltPW::~HamiltPW(){}; +template +void hamilt::HamiltPW::updateHk(int){} +template +void hamilt::HamiltPW::sPsi(T const*, T*, const int, const int, const int) const{} + +template +hamilt::HamiltSdftPW::HamiltSdftPW(elecstate::Potential* pot_in, + ModulePW::PW_Basis_K* wfc_basis, + K_Vectors* p_kv, + const int& npol, + double* emin_in, + double* emax_in): HamiltPW(pot_in, wfc_basis, p_kv), ngk(p_kv->ngk){} +template +void hamilt::HamiltSdftPW::hPsi_norm(const T* psi_in, T* hpsi, const int& nbands){} + +template class hamilt::HamiltPW, base_device::DEVICE_CPU>; +template class hamilt::HamiltSdftPW, base_device::DEVICE_CPU>; /** * - Tested Functions: diff --git a/source/module_hsolver/diag_const_nums.cpp b/source/module_hsolver/diag_const_nums.cpp index 2c9f926c467..8b459cbf7c3 100644 --- a/source/module_hsolver/diag_const_nums.cpp +++ b/source/module_hsolver/diag_const_nums.cpp @@ -9,27 +9,60 @@ template class const_nums>; // Specialize templates to support double types template <> -const_nums::const_nums() : zero(0.0), one(1.0), neg_one(-1.0) +const_nums::const_nums() { + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->zero, 1); + this->zero[0] = 0.0; + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->one, 1); + this->one[0] = 1.0; + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->neg_one, 1); + this->neg_one[0] = -1.0; } // Specialize templates to support double types template <> -const_nums::const_nums() : zero(0.0), one(1.0), neg_one(-1.0) +const_nums::const_nums() { + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->zero, 1); + this->zero[0] = 0.0; + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->one, 1); + this->one[0] = 1.0; + base_device::memory::resize_memory_op()( + this->cpu_ctx, this->neg_one, 1); + this->neg_one[0] = -1.0; } // Specialized templates to support std:: complextypes template <> const_nums>::const_nums() - : zero(std::complex(0.0, 0.0)), one(std::complex(1.0, 0.0)), - neg_one(std::complex(-1.0, 0.0)) { + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->zero, 1); + this->zero[0] = std::complex(0.0, 0.0); + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->one, 1); + this->one[0] = std::complex(1.0, 0.0); + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->neg_one, 1); + this->neg_one[0] = std::complex(-1.0, 0.0); } // Specialized templates to support std:: complextypes template <> const_nums>::const_nums() - : zero(std::complex(0.0, 0.0)), one(std::complex(1.0, 0.0)), neg_one(std::complex(-1.0, 0.0)) { -} + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->zero, 1); + this->zero[0] = std::complex(0.0, 0.0); + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->one, 1); + this->one[0] = std::complex(1.0, 0.0); + base_device::memory::resize_memory_op, base_device::DEVICE_CPU>()( + this->cpu_ctx, this->neg_one, 1); + this->neg_one[0] = std::complex(-1.0, 0.0); +} \ No newline at end of file diff --git a/source/module_hsolver/diag_const_nums.h b/source/module_hsolver/diag_const_nums.h index c5a97d4d612..24a33194e18 100644 --- a/source/module_hsolver/diag_const_nums.h +++ b/source/module_hsolver/diag_const_nums.h @@ -1,13 +1,15 @@ #ifndef DIAG_CONST_NUMS #define DIAG_CONST_NUMS +#include "module_base/module_device/memory_op.h" template struct const_nums { const_nums(); - T zero; - T one; - T neg_one; + base_device::DEVICE_CPU* cpu_ctx = {}; + T* zero = nullptr; + T* one = nullptr; + T* neg_one = nullptr; }; #endif \ No newline at end of file diff --git a/source/module_hsolver/diagh.h b/source/module_hsolver/diagh.h deleted file mode 100644 index 9ebc3f664f6..00000000000 --- a/source/module_hsolver/diagh.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef DIAGH_H -#define DIAGH_H - -#include "module_base/macros.h" -#include "module_hamilt_general/hamilt.h" -#include "module_psi/psi.h" -#include "module_hamilt_general/matrixblock.h" - -#include - -#ifdef __MPI -#include "mpi.h" -#endif - -// template -// struct const_nums -// { -// const_nums(); -// T zero; -// T one; -// T neg_one; -// }; - -namespace hsolver -{ - -template -class DiagH -{ - private: - using Real = typename GetTypeReal::type; - - public: - virtual ~DiagH(){}; - // virtual void init()=0; - std::string method = "none"; - - virtual void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) - { - ModuleBase::WARNING_QUIT("diagh", "diag method not implemented for the base class!"); - }; -#ifdef __MPI - // diagnolization used in parallel-k case - virtual void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm) - { - ModuleBase::WARNING_QUIT("diagh", "diag_pool method not implemented for the base class!"); - }; -#endif -}; - -} // namespace hsolver - -#endif \ No newline at end of file diff --git a/source/module_hsolver/diago_bpcg.h b/source/module_hsolver/diago_bpcg.h index 71040960c39..c14472de2ef 100644 --- a/source/module_hsolver/diago_bpcg.h +++ b/source/module_hsolver/diago_bpcg.h @@ -1,8 +1,7 @@ #ifndef DIAGO_BPCG_H_ #define DIAGO_BPCG_H_ -#include "diagh.h" -#include "module_base/complexmatrix.h" +#include "module_hamilt_general/hamilt.h" #include "module_hamilt_pw/hamilt_pwdft/structure_factor.h" #include "module_base/module_device/types.h" @@ -24,7 +23,7 @@ namespace hsolver { * @tparam Device The device used for calculations (e.g., cpu or gpu). */ template , typename Device = base_device::DEVICE_CPU> -class DiagoBPCG : public DiagH +class DiagoBPCG { private: // Note GetTypeReal::type will @@ -56,15 +55,15 @@ class DiagoBPCG : public DiagH void init_iter(const psi::Psi &psi_in); /** - * @brief Diagonalize the Hamiltonian using the CG method. + * @brief Diagonalize the Hamiltonian using the BPCG method. * - * This function is an override function for the CG method. It is called by the HsolverPW::solve() function. + * This function is called by the HsolverPW::solve() function. * * @param phm_in A pointer to the hamilt::Hamilt object representing the Hamiltonian operator. * @param psi The input wavefunction psi matrix with [dim: n_basis x n_band, column major]. * @param eigenvalue_in Pointer to the eigen array with [dim: n_band, column major]. */ - void diag(hamilt::Hamilt *phm_in, psi::Psi &psi, Real *eigenvalue_in) override; + void diag(hamilt::Hamilt *phm_in, psi::Psi &psi, Real *eigenvalue_in); private: diff --git a/source/module_hsolver/diago_cg.cpp b/source/module_hsolver/diago_cg.cpp index 23e7367d71b..18e3743b94b 100644 --- a/source/module_hsolver/diago_cg.cpp +++ b/source/module_hsolver/diago_cg.cpp @@ -8,6 +8,8 @@ #include #include #include +#include // ModuleBase::TITLE +#include // ModuleBase::GlobalFunc::NOTE #include using namespace hsolver; diff --git a/source/module_hsolver/diago_cg.h b/source/module_hsolver/diago_cg.h index bb106cd8c16..d5c8c4e2090 100644 --- a/source/module_hsolver/diago_cg.h +++ b/source/module_hsolver/diago_cg.h @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -13,7 +12,7 @@ namespace hsolver { template -class DiagoCG final : public DiagH +class DiagoCG final { // private: accessibility within class is private by default // Note GetTypeReal::type will @@ -36,11 +35,11 @@ class DiagoCG final : public DiagH const int& pw_diag_nmax, const int& nproc_in_pool); - ~DiagoCG() override; + ~DiagoCG(); // virtual void init(){}; // refactor hpsi_info - // this is the override function diag() for CG method + // this is the diag() function for CG method void diag(const Func& hpsi_func, const Func& spsi_func, ct::Tensor& psi, ct::Tensor& eigen, const ct::Tensor& prec = {}); private: diff --git a/source/module_hsolver/diago_cusolver.cpp b/source/module_hsolver/diago_cusolver.cpp index b8abf642d2a..5511ec941c7 100644 --- a/source/module_hsolver/diago_cusolver.cpp +++ b/source/module_hsolver/diago_cusolver.cpp @@ -1,5 +1,6 @@ #include "diago_cusolver.h" +#include "module_parameter/parameter.h" #include "module_base/blacs_connector.h" #include "module_base/global_variable.h" #include "module_base/scalapack_connector.h" @@ -140,7 +141,7 @@ void DiagoCusolver::diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* e #endif // Allocate memory for eigenvalues - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); // Start the timer for the cusolver operation ModuleBase::timer::tick("DiagoCusolver", "cusolver"); @@ -170,7 +171,7 @@ void DiagoCusolver::diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* e MPI_Barrier(MPI_COMM_WORLD); // broadcast eigenvalues to all processes - MPI_Bcast(eigen.data(), GlobalV::NBANDS, MPI_DOUBLE, root_proc, MPI_COMM_WORLD); + MPI_Bcast(eigen.data(), PARAM.inp.nbands, MPI_DOUBLE, root_proc, MPI_COMM_WORLD); // distribute psi to all processes distributePsi(this->ParaV->desc_wfc, psi.get_pointer(), psi_g.data()); @@ -194,7 +195,7 @@ void DiagoCusolver::diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* e // Copy the eigenvalues to the output arrays const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); } // Explicit instantiation of the DiagoCusolver class for real and complex numbers diff --git a/source/module_hsolver/diago_cusolver.h b/source/module_hsolver/diago_cusolver.h index 0b0d1f5fbab..ed67357f3fc 100644 --- a/source/module_hsolver/diago_cusolver.h +++ b/source/module_hsolver/diago_cusolver.h @@ -1,7 +1,8 @@ #ifndef DIAGOCUSOLVER_H #define DIAGOCUSOLVER_H -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" #include "module_basis/module_ao/parallel_orbitals.h" #include "module_hsolver/kernels/cuda/diag_cusolver.cuh" // #include "module_hsolver/kernels/cuda/dngvd_op.cu" @@ -9,9 +10,9 @@ namespace hsolver { -// DiagoCusolver class, derived from DiagH, for diagonalization using CUSOLVER +// DiagoCusolver class for diagonalization using CUSOLVER template -class DiagoCusolver : public DiagH +class DiagoCusolver { private: // Real is the real part of the complex type T @@ -24,7 +25,7 @@ class DiagoCusolver : public DiagH ~DiagoCusolver(); // Override the diag function for CUSOLVER diagonalization - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); // Static variable to keep track of the decomposition state static int DecomposedState; diff --git a/source/module_hsolver/diago_cusolvermp.cpp b/source/module_hsolver/diago_cusolvermp.cpp index 615ff8f2bbd..09aa85940bd 100644 --- a/source/module_hsolver/diago_cusolvermp.cpp +++ b/source/module_hsolver/diago_cusolvermp.cpp @@ -1,5 +1,6 @@ #ifdef __CUSOLVERMP +#include "module_parameter/parameter.h" #include "diago_cusolvermp.h" #include "module_base/timer.h" @@ -15,18 +16,21 @@ void DiagoCusolverMP::diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* hamilt::MatrixBlock h_mat, s_mat; phm_in->matrix(h_mat, s_mat); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); + std::vector eigenvectors(h_mat.row * h_mat.col); MPI_Comm COMM_DIAG = MPI_COMM_WORLD; // use all processes { Diag_CusolverMP_gvd es(COMM_DIAG, (const int)h_mat.row, (const int)h_mat.col, (const int*)h_mat.desc); ModuleBase::timer::tick("DiagoCusolverMP", "Diag_CusolverMP_gvd"); - es.generalized_eigenvector(h_mat.p, s_mat.p, eigen.data(), psi.get_pointer()); + es.generalized_eigenvector(h_mat.p, s_mat.p, eigen.data(), eigenvectors.data()); ModuleBase::timer::tick("DiagoCusolverMP", "Diag_CusolverMP_gvd"); } const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); + const int size = psi.get_nbands() * psi.get_nbasis(); + BlasConnector::copy(size, eigenvectors.data(), inc, psi.get_pointer(), inc); } template class DiagoCusolverMP; template class DiagoCusolverMP; diff --git a/source/module_hsolver/diago_cusolvermp.h b/source/module_hsolver/diago_cusolvermp.h index 971be3f3e0d..30dbfc5459f 100644 --- a/source/module_hsolver/diago_cusolvermp.h +++ b/source/module_hsolver/diago_cusolvermp.h @@ -2,15 +2,15 @@ #define DIAGO_CUSOLVERMPH #ifdef __CUSOLVERMP -#include "diagh.h" +#include "module_hamilt_general/hamilt.h" #include "module_base/macros.h" #include "module_basis/module_ao/parallel_orbitals.h" #include "module_hsolver/kernels/cuda/diag_cusolvermp.cuh" namespace hsolver { -// DiagoCusolverMP class, derived from DiagH, for diagonalization using CUSOLVERMP +// DiagoCusolverMP class, for diagonalization using CUSOLVERMP template -class DiagoCusolverMP : public DiagH +class DiagoCusolverMP { private: using Real = typename GetTypeReal::type; @@ -19,8 +19,8 @@ class DiagoCusolverMP : public DiagH DiagoCusolverMP() { } - // Override the diag function for CUSOLVERMP diagonalization - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + // the diag function for CUSOLVERMP diagonalization + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); }; } // namespace hsolver #endif // __CUSOLVERMP diff --git a/source/module_hsolver/diago_dav_subspace.cpp b/source/module_hsolver/diago_dav_subspace.cpp index bcb97802710..d11d7093f13 100644 --- a/source/module_hsolver/diago_dav_subspace.cpp +++ b/source/module_hsolver/diago_dav_subspace.cpp @@ -6,6 +6,7 @@ #include "module_base/timer.h" #include "module_hsolver/kernels/dngvd_op.h" #include "module_hsolver/kernels/math_kernel_op.h" +#include "module_base/kernels/dsp/dsp_connector.h" #include @@ -20,14 +21,14 @@ Diago_DavSubspace::Diago_DavSubspace(const std::vector& precond const int& diag_nmax_in, const bool& need_subspace_in, const diag_comm_info& diag_comm_in) - : n_band(nband_in), dim(nbasis_in), nbase_x(nband_in * david_ndim_in), - diag_thr(diag_thr_in), iter_nmax(diag_nmax_in), is_subspace(need_subspace_in), diag_comm(diag_comm_in), precondition(precondition_in) + : precondition(precondition_in), n_band(nband_in), dim(nbasis_in), nbase_x(nband_in * david_ndim_in), + diag_thr(diag_thr_in), iter_nmax(diag_nmax_in), is_subspace(need_subspace_in), diag_comm(diag_comm_in) { this->device = base_device::get_device_type(this->ctx); - this->one = &this->cs.one; - this->zero = &this->cs.zero; - this->neg_one = &this->cs.neg_one; + this->one = &one_; + this->zero = &zero_; + this->neg_one = &neg_one_; assert(david_ndim_in > 1); assert(david_ndim_in * nband_in < nbasis_in * this->diag_comm.nproc); @@ -59,7 +60,7 @@ Diago_DavSubspace::Diago_DavSubspace(const std::vector& precond if (this->device == base_device::GpuDevice) { resmem_real_op()(this->ctx, this->d_precondition, nbasis_in); - syncmem_var_h2d_op()(this->ctx, this->cpu_ctx, this->d_precondition, this->precondition.data(), nbasis_in); + // syncmem_var_h2d_op()(this->ctx, this->cpu_ctx, this->d_precondition, this->precondition.data(), nbasis_in); } #endif } @@ -87,7 +88,7 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, T* psi_in, const int psi_in_dmax, Real* eigenvalue_in_hsolver, - const std::vector& is_occupied) + const double* ethr_band) { ModuleBase::timer::tick("Diago_DavSubspace", "diag_once"); @@ -97,7 +98,7 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, // convflag[m] = true if the m th band is convergent std::vector convflag(this->n_band, false); - // unconv[m] store the index of the m th unconvergent band + // unconv[m] store the number of the m th unconvergent band std::vector unconv(this->n_band); // the dimension of the reduced psi set @@ -108,9 +109,6 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, ModuleBase::timer::tick("Diago_DavSubspace", "first"); - // copy psi_in to psi_in_iter for the first n_band bands - // NOTE: not the first nbase_x (nband * david_ndim) bands - // since psi_in_iter is zero-initialized, the rest bands are zero for (int m = 0; m < this->n_band; m++) { unconv[m] = m; @@ -124,22 +122,12 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, // compute h*psi_in_iter // NOTE: bands after the first n_band should yield zero - hpsi_func(this->psi_in_iter, this->hphi, this->nbase_x, this->dim, 0, this->nbase_x - 1); + // hphi[:, 0:nbase_x] = H * psi_in_iter[:, 0:nbase_x] + hpsi_func(this->psi_in_iter, this->hphi, this->dim, this->notconv); - // at this stage, notconv = n_band and nbase = 0 - // note that nbase of cal_elem is an inout parameter: nbase := nbase + notconv this->cal_elem(this->dim, nbase, this->notconv, this->psi_in_iter, this->hphi, this->hcc, this->scc); - // generalized eigenvalue problem (hcc, scc) for the first n_band bands - this->diag_zhegvx(nbase, - this->n_band, - this->hcc, - this->scc, - this->nbase_x, - &eigenvalue_iter, - this->vcc, - true, - this->is_subspace); + this->diag_zhegvx(nbase, this->notconv, this->hcc, this->scc, this->nbase_x, &eigenvalue_iter, this->vcc); for (size_t m = 0; m < this->n_band; m++) { @@ -154,7 +142,6 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, { dav_iter++; - // nbase is the effective subspace size this->cal_grad(hpsi_func, this->dim, nbase, @@ -167,15 +154,7 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, this->cal_elem(this->dim, nbase, this->notconv, this->psi_in_iter, this->hphi, this->hcc, this->scc); - this->diag_zhegvx(nbase, - this->n_band, - this->hcc, - this->scc, - this->nbase_x, - &eigenvalue_iter, - this->vcc, - false, - false); + this->diag_zhegvx(nbase, this->n_band, this->hcc, this->scc, this->nbase_x, &eigenvalue_iter, this->vcc); // check convergence and update eigenvalues ModuleBase::timer::tick("Diago_DavSubspace", "check_update"); @@ -183,15 +162,7 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, this->notconv = 0; for (int m = 0; m < this->n_band; m++) { - if (is_occupied[m]) // always true - { - convflag[m] = (std::abs(eigenvalue_iter[m] - eigenvalue_in_hsolver[m]) < this->diag_thr); - } - else - { - const double empty_ethr = std::max(this->diag_thr * 5.0, 1e-5); - convflag[m] = (std::abs(eigenvalue_iter[m] - eigenvalue_in_hsolver[m]) < empty_ethr); - } + convflag[m] = (std::abs(eigenvalue_iter[m] - eigenvalue_in_hsolver[m]) < ethr_band[m]); if (!convflag[m]) { @@ -211,7 +182,12 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, // updata eigenvectors of Hamiltonian setmem_complex_op()(this->ctx, psi_in, 0, n_band * psi_in_dmax); - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() // In order to not coding another whole template, using this method to minimize the code change. +#else + gemm_op() +#endif + (this->ctx, 'N', 'N', this->dim, @@ -230,26 +206,6 @@ int Diago_DavSubspace::diag_once(const HPsiFunc& hpsi_func, { // overall convergence or last iteration: exit the iteration - // update this->psi_in_iter according to psi_in - for (size_t i = 0; i < this->n_band; i++) - { - syncmem_complex_op()(this->ctx, - this->ctx, - this->psi_in_iter + i * this->dim, - psi_in + i * psi_in_dmax, - this->dim); - } - - this->refresh(this->dim, - this->n_band, - nbase, - eigenvalue_in_hsolver, - this->psi_in_iter, - this->hphi, - this->hcc, - this->scc, - this->vcc); - ModuleBase::timer::tick("Diago_DavSubspace", "last"); break; } @@ -312,96 +268,103 @@ void Diago_DavSubspace::cal_grad(const HPsiFunc& hpsi_func, } } - // psi_iter[:, nbase:nbase+notconv] - // = psi_iter[:, :nbase] * vcc[:nbase, :notconv] - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() +#else + gemm_op() +#endif + (this->ctx, 'N', 'N', this->dim, notconv, nbase, this->one, - psi_iter, + hphi, this->dim, vcc, this->nbase_x, this->zero, - psi_iter + nbase * this->dim, + psi_iter + (nbase) * this->dim, this->dim); - // for psi_iter[:, nbase:nbase+notconv], - // each column is multiplied by the corresponding (minus) eigenvalue - // NOTE: eigenvalue_iter[m] correspond to psi_iter[:, nbase+m] (to be verified) + std::vector e_temp_cpu(nbase, 0); + Real* e_temp_hd = e_temp_cpu.data(); + if(this->device == base_device::GpuDevice) + { + e_temp_hd = nullptr; + resmem_real_op()(this->ctx, e_temp_hd, nbase); + } for (int m = 0; m < notconv; m++) { - - std::vector e_temp_cpu(this->dim, ((-1) * (*eigenvalue_iter)[m])); - + e_temp_cpu.assign(nbase, (-1.0 * (*eigenvalue_iter)[m])); + if (this->device == base_device::GpuDevice) + { + syncmem_var_h2d_op()(this->ctx, this->cpu_ctx, e_temp_hd, e_temp_cpu.data(), nbase); + } vector_mul_vector_op()(this->ctx, - this->dim, - psi_iter + (nbase + m) * this->dim, - psi_iter + (nbase + m) * this->dim, - e_temp_cpu.data()); + nbase, + vcc + m * this->nbase_x, + vcc + m * this->nbase_x, + e_temp_hd); + } + if(this->device == base_device::GpuDevice) + { + delmem_real_op()(this->ctx, e_temp_hd); } - // psi_iter[:, nbase:nbase+notconv] += hphi[:, :nbase] * vcc[:nbase, :notconv] - // - // in terms of input, psi_iter should be - // psi_iter[:, nbase:nbase+notconv] := - // hpsi[:, :nbase] * vcc[:nbase, :notconv] - e[]*psi_iter[:, nbase:nbase+notconv]*vcc[:nbase, :notconv] - // TODO two gemm operations can be combined into one - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() +#else + gemm_op() +#endif + (this->ctx, 'N', 'N', this->dim, notconv, nbase, this->one, - hphi, + psi_iter, this->dim, vcc, this->nbase_x, this->one, - psi_iter + (nbase) * this->dim, + psi_iter + nbase * this->dim, this->dim); - // FIXME - // (QE dav solver -> isolver = 0) - // In QE, for davidson, h_diag is computed by g2kin + v_of_0 - // this is passed to g_psi, where the residual vector is element-wise - // multiplied by (h_diag - e * s_siag) - // - // There is a macro "TEST_NEW_PRECONDITIONING" in QE, which - // takes x = h_diag - e * s_siag and define - // denm = 0.5 * ( 1 + x + sqrt(1 + (x-1)^2) ) - // which then precondition the residual vector by psi := psi ./ denm - // note that this preconditioning recovers x when x is large, and - // approaches 0.5*(1+sqrt(2)) when x is close to 0. - // - // - // In the current version of ABACUS, "precondition" is simply g2kin, - // and the tested preconditioning of QE is always active. - // // "precondition!!!" std::vector pre(this->dim, 0.0); for (int m = 0; m < notconv; m++) { for (size_t i = 0; i < this->dim; i++) { - //double x = this->precondition[i] - (*eigenvalue_iter)[m]; + // pre[i] = std::abs(this->precondition[i] - (*eigenvalue_iter)[m]); double x = std::abs(this->precondition[i] - (*eigenvalue_iter)[m]); pre[i] = 0.5 * (1.0 + x + sqrt(1 + (x - 1.0) * (x - 1.0))); } - vector_div_vector_op()(this->ctx, - this->dim, - psi_iter + (nbase + m) * this->dim, - psi_iter + (nbase + m) * this->dim, - pre.data()); +#if defined(__CUDA) || defined(__ROCM) + if (this->device == base_device::GpuDevice) + { + syncmem_var_h2d_op()(this->ctx, this->cpu_ctx, this->d_precondition, pre.data(), this->dim); + vector_div_vector_op()(this->ctx, + this->dim, + psi_iter + (nbase + m) * this->dim, + psi_iter + (nbase + m) * this->dim, + this->d_precondition); + } + else +#endif + { + vector_div_vector_op()(this->ctx, + this->dim, + psi_iter + (nbase + m) * this->dim, + psi_iter + (nbase + m) * this->dim, + pre.data()); + } } // "normalize!!!" in order to improve numerical stability of subspace diagonalization - - // column-wise normalize psi_iter[:, nbase:nbase+notconv] std::vector psi_norm(notconv, 0.0); for (size_t i = 0; i < notconv; i++) { @@ -409,7 +372,7 @@ void Diago_DavSubspace::cal_grad(const HPsiFunc& hpsi_func, this->dim, psi_iter + (nbase + i) * this->dim, psi_iter + (nbase + i) * this->dim, - false); // FIXME why reduce is false? + true); assert(psi_norm[i] > 0.0); psi_norm[i] = sqrt(psi_norm[i]); @@ -421,7 +384,8 @@ void Diago_DavSubspace::cal_grad(const HPsiFunc& hpsi_func, } // update hpsi[:, nbase:nbase+notconv] - hpsi_func(psi_iter, &hphi[nbase * this->dim], this->nbase_x, this->dim, nbase, nbase + notconv - 1); + // hpsi[:, nbase:nbase+notconv] = H * psi_iter[:, nbase:nbase+notconv] + hpsi_func(psi_iter + nbase * dim, hphi + nbase * this->dim, this->dim, notconv); ModuleBase::timer::tick("Diago_DavSubspace", "cal_grad"); return; @@ -438,10 +402,12 @@ void Diago_DavSubspace::cal_elem(const int& dim, { ModuleBase::timer::tick("Diago_DavSubspace", "cal_elem"); - // hcc[:, nbase:] = psi_iter.H * hpsi_iter[:, nbase:] - // while psi_iter has nbase_x columns, only the first nbase + notconv columns are - // involved in the matrix multiplication - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() +#else + gemm_op() +#endif + (this->ctx, 'C', 'N', nbase + notconv, @@ -456,8 +422,12 @@ void Diago_DavSubspace::cal_elem(const int& dim, &hcc[nbase * this->nbase_x], this->nbase_x); - // scc[:, :nbase] := psi_iter.H * psi_iter[:, nbase:] - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() +#else + gemm_op() +#endif + (this->ctx, 'C', 'N', nbase + notconv, @@ -475,7 +445,12 @@ void Diago_DavSubspace::cal_elem(const int& dim, #ifdef __MPI if (this->diag_comm.nproc > 1) { +#ifdef __DSP + // Only on dsp hardware need an extra space to reduce data + dsp_dav_subspace_reduce(hcc, scc, nbase, this->nbase_x, this->notconv, this->diag_comm.comm); +#else auto* swap = new T[notconv * this->nbase_x]; + syncmem_complex_op()(this->ctx, this->ctx, swap, hcc + nbase * this->nbase_x, notconv * this->nbase_x); if (std::is_same::value) @@ -530,45 +505,13 @@ void Diago_DavSubspace::cal_elem(const int& dim, } } delete[] swap; +#endif } #endif const size_t last_nbase = nbase; // init: last_nbase = 0 nbase = nbase + notconv; - - // NOTE: nbase is an in & out parameter! nbase is updated to nbase + notconv - - for (size_t i = 0; i < nbase; i++) - { - if (i >= last_nbase) - { - // ensure the diagonal elements of hcc and scc are real - // NOTE: set_real_tocomplex convert a real to itself, and a complex to a new complex - // whose real part is the input's real part and imaginary part is zero - hcc[i * this->nbase_x + i] = set_real_tocomplex(hcc[i * this->nbase_x + i]); - scc[i * this->nbase_x + i] = set_real_tocomplex(scc[i * this->nbase_x + i]); - } - for (size_t j = std::max(i + 1, last_nbase); j < nbase; j++) - { - // ensure the hermicity of hcc and scc - hcc[i * this->nbase_x + j] = get_conj(hcc[j * this->nbase_x + i]); - scc[i * this->nbase_x + j] = get_conj(scc[j * this->nbase_x + i]); - } - } - - // make hcc[nbase:, nbase:] and scc[nbase:, nbase:] to be zero - for (size_t i = nbase; i < this->nbase_x; i++) - { - for (size_t j = nbase; j < this->nbase_x; j++) - { - hcc[i * this->nbase_x + j] = cs.zero; - scc[i * this->nbase_x + j] = cs.zero; - hcc[j * this->nbase_x + i] = cs.zero; - scc[j * this->nbase_x + i] = cs.zero; - } - } - ModuleBase::timer::tick("Diago_DavSubspace", "cal_elem"); return; } @@ -580,79 +523,68 @@ void Diago_DavSubspace::diag_zhegvx(const int& nbase, T* scc, const int& nbase_x, std::vector* eigenvalue_iter, - T* vcc, - bool init, - bool is_subspace) + T* vcc) { ModuleBase::timer::tick("Diago_DavSubspace", "diag_zhegvx"); - if (is_subspace == false) + if (this->diag_comm.rank == 0) { - if (this->diag_comm.rank == 0) - { - assert(nbase_x >= std::max(1, nbase)); - - std::vector> h_diag(nbase, std::vector(nbase, cs.zero)); - std::vector> s_diag(nbase, std::vector(nbase, cs.zero)); + assert(nbase_x >= std::max(1, nbase)); - for (size_t i = 0; i < nbase; i++) + if (this->device == base_device::GpuDevice) + { +#if defined(__CUDA) || defined(__ROCM) + Real* eigenvalue_gpu = nullptr; + resmem_real_op()(this->ctx, eigenvalue_gpu, this->nbase_x); + + syncmem_var_h2d_op()(this->ctx, this->cpu_ctx, eigenvalue_gpu, (*eigenvalue_iter).data(), this->nbase_x); + + T* hcc_gpu = nullptr; + T* scc_gpu = nullptr; + T* vcc_gpu = nullptr; + base_device::memory::resize_memory_op()(this->ctx, hcc_gpu, nbase * nbase); + base_device::memory::resize_memory_op()(this->ctx, scc_gpu, nbase * nbase); + base_device::memory::resize_memory_op()(this->ctx, vcc_gpu, nbase * nbase); + for(int i=0;inbase_x + j]; - s_diag[i][j] = scc[i * this->nbase_x + j]; - } + base_device::memory::synchronize_memory_op()(this->ctx, this->ctx, hcc_gpu + i * nbase, hcc + i * nbase_x, nbase); + base_device::memory::synchronize_memory_op()(this->ctx, this->ctx, scc_gpu + i * nbase, scc + i * nbase_x, nbase); } - - if (this->device == base_device::GpuDevice) + dngvd_op()(this->ctx, nbase, nbase, hcc_gpu, scc_gpu, eigenvalue_gpu, vcc_gpu); + for(int i=0;ictx, eigenvalue_gpu, this->nbase_x); - - syncmem_var_h2d_op()(this->ctx, - this->cpu_ctx, - eigenvalue_gpu, - (*eigenvalue_iter).data(), - this->nbase_x); - - dnevx_op()(this->ctx, nbase, this->nbase_x, this->hcc, nband, eigenvalue_gpu, this->vcc); + base_device::memory::synchronize_memory_op()(this->ctx, this->ctx, vcc + i * nbase_x, vcc_gpu + i * nbase, nbase); + } + delmem_complex_op()(this->ctx, hcc_gpu); + delmem_complex_op()(this->ctx, scc_gpu); + delmem_complex_op()(this->ctx, vcc_gpu); - syncmem_var_d2h_op()(this->cpu_ctx, - this->ctx, - (*eigenvalue_iter).data(), - eigenvalue_gpu, - this->nbase_x); + syncmem_var_d2h_op()(this->cpu_ctx, this->ctx, (*eigenvalue_iter).data(), eigenvalue_gpu, this->nbase_x); - delmem_real_op()(this->ctx, eigenvalue_gpu); + delmem_real_op()(this->ctx, eigenvalue_gpu); #endif - } - else + } + else + { + std::vector> h_diag(nbase, std::vector(nbase, *this->zero)); + std::vector> s_diag(nbase, std::vector(nbase, *this->zero)); + + for (size_t i = 0; i < nbase; i++) { - if (init) - { - dnevx_op()(this->ctx, - nbase, - this->nbase_x, - this->hcc, - nband, - (*eigenvalue_iter).data(), - this->vcc); - } - else + for (size_t j = 0; j < nbase; j++) { - - dngvx_op()(this->ctx, - nbase, - this->nbase_x, - this->hcc, - this->scc, - nband, - (*eigenvalue_iter).data(), - this->vcc); + h_diag[i][j] = hcc[i * this->nbase_x + j]; + s_diag[i][j] = scc[i * this->nbase_x + j]; } } - + dngvx_op()(this->ctx, + nbase, + this->nbase_x, + this->hcc, + this->scc, + nband, + (*eigenvalue_iter).data(), + this->vcc); // reset: for (size_t i = 0; i < nbase; i++) { @@ -664,42 +596,26 @@ void Diago_DavSubspace::diag_zhegvx(const int& nbase, for (size_t j = nbase; j < this->nbase_x; j++) { - hcc[i * this->nbase_x + j] = cs.zero; - hcc[j * this->nbase_x + i] = cs.zero; - scc[i * this->nbase_x + j] = cs.zero; - scc[j * this->nbase_x + i] = cs.zero; + hcc[i * this->nbase_x + j] = *this->zero; + hcc[j * this->nbase_x + i] = *this->zero; + scc[i * this->nbase_x + j] = *this->zero; + scc[j * this->nbase_x + i] = *this->zero; } } } - -#ifdef __MPI - if (this->diag_comm.nproc > 1) - { - // vcc: nbase * nband - for (int i = 0; i < nband; i++) - { - MPI_Bcast(&vcc[i * this->nbase_x], nbase, MPI_DOUBLE_COMPLEX, 0, this->diag_comm.comm); - } - MPI_Bcast((*eigenvalue_iter).data(), nband, MPI_DOUBLE, 0, this->diag_comm.comm); - } -#endif } - else if (is_subspace == true) - { - for (size_t m = 0; m < nband; m++) - { - (*eigenvalue_iter)[m] = get_real(hcc[m * this->nbase_x + m]); - - vcc[m * this->nbase_x + m] = set_real_tocomplex(1.0); - } #ifdef __MPI - if (this->diag_comm.nproc > 1) + if (this->diag_comm.nproc > 1) + { + // vcc: nbase * nband + for (int i = 0; i < nband; i++) { - MPI_Bcast((*eigenvalue_iter).data(), this->n_band, MPI_DOUBLE, 0, this->diag_comm.comm); + MPI_Bcast(&vcc[i * this->nbase_x], nbase, MPI_DOUBLE_COMPLEX, 0, this->diag_comm.comm); } -#endif + MPI_Bcast((*eigenvalue_iter).data(), nband, MPI_DOUBLE, 0, this->diag_comm.comm); } +#endif ModuleBase::timer::tick("Diago_DavSubspace", "diag_zhegvx"); return; @@ -719,7 +635,12 @@ void Diago_DavSubspace::refresh(const int& dim, { ModuleBase::timer::tick("Diago_DavSubspace", "refresh"); - gemm_op()(this->ctx, +#ifdef __DSP + gemm_op_mt() +#else + gemm_op() +#endif + (this->ctx, 'N', 'N', this->dim, @@ -805,7 +726,7 @@ int Diago_DavSubspace::diag(const HPsiFunc& hpsi_func, T* psi_in, const int psi_in_dmax, Real* eigenvalue_in_hsolver, - const std::vector& is_occupied, + const double* ethr_band, const bool& scf_type) { /// record the times of trying iterative diagonalization @@ -816,13 +737,8 @@ int Diago_DavSubspace::diag(const HPsiFunc& hpsi_func, do { - //printf("enter diag... is_subspace = %d, ntry = %d\n", this->is_subspace, ntry); - if (this->is_subspace || ntry > 0) - { - this->diagH_subspace(psi_in, eigenvalue_in_hsolver, hpsi_func, this->n_band, this->dim, psi_in_dmax); - } - sum_iter += this->diag_once(hpsi_func, psi_in, psi_in_dmax, eigenvalue_in_hsolver, is_occupied); + sum_iter += this->diag_once(hpsi_func, psi_in, psi_in_dmax, eigenvalue_in_hsolver, ethr_band); ++ntry; @@ -849,113 +765,12 @@ bool Diago_DavSubspace::test_exit_cond(const int& ntry, const int& no // In non-self consistent calculation, do until totally converged. const bool f2 = ((!scf && (notconv > 0))); - // if self consistent calculation, if not converged > 5, - // using diagH_subspace and cg method again. ntry++ + // if self consistent calculation, if not converged > 5 const bool f3 = ((scf && (notconv > 5))); return (f1 && (f2 || f3)); } -template -void Diago_DavSubspace::diagH_subspace(T* psi_pointer, // [in] & [out] wavefunction - Real* en, // [out] eigenvalues - const HPsiFunc hpsi_func, - const int n_band, - const int dmin, - const int dmax) -{ - ModuleBase::TITLE("Diago_DavSubspace", "subspace"); - ModuleBase::timer::tick("Diago_DavSubspace", "subspace"); - - const int nstart = n_band; - assert(n_band > 0); - - T* hcc = nullptr; - T* scc = nullptr; - T* vcc = nullptr; - resmem_complex_op()(ctx, hcc, nstart * nstart, "DAV::hcc"); - resmem_complex_op()(ctx, scc, nstart * nstart, "DAV::scc"); - resmem_complex_op()(ctx, vcc, nstart * nstart, "DAV::vcc"); - setmem_complex_op()(ctx, hcc, 0, nstart * nstart); - setmem_complex_op()(ctx, scc, 0, nstart * nstart); - setmem_complex_op()(ctx, vcc, 0, nstart * nstart); - - T* hphi = nullptr; - resmem_complex_op()(ctx, hphi, nstart * dmax, "DAV::hphi"); - setmem_complex_op()(ctx, hphi, 0, nstart * dmax); - - { - // do hPsi for all bands - hpsi_func(psi_pointer, hphi, n_band, dmax, 0, nstart - 1); - - gemm_op()(ctx, - 'C', - 'N', - nstart, - nstart, - dmin, - this->one, - psi_pointer, - dmax, - hphi, - dmax, - this->zero, - hcc, - nstart); - - gemm_op()(ctx, - 'C', - 'N', - nstart, - nstart, - dmin, - this->one, - psi_pointer, - dmax, - psi_pointer, - dmax, - this->zero, - scc, - nstart); - } - - if (GlobalV::NPROC_IN_POOL > 1) - { - Parallel_Reduce::reduce_pool(hcc, nstart * nstart); - Parallel_Reduce::reduce_pool(scc, nstart * nstart); - } - - // after generation of H and S matrix, diag them - DiagoIterAssist::diagH_LAPACK(nstart, n_band, hcc, scc, nstart, en, vcc); - - { // code block to calculate evc - gemm_op()(ctx, - 'N', - 'N', - dmin, - n_band, - nstart, - this->one, - psi_pointer, // dmin * nstart - dmax, - vcc, // nstart * n_band - nstart, - this->zero, - hphi, - dmin); - } - - matrixSetToAnother()(ctx, n_band, hphi, dmin, psi_pointer, dmax); - - delmem_complex_op()(ctx, hphi); - - delmem_complex_op()(ctx, hcc); - delmem_complex_op()(ctx, scc); - delmem_complex_op()(ctx, vcc); - - ModuleBase::timer::tick("Diago_DavSubspace", "diagH_subspace"); -} - namespace hsolver { diff --git a/source/module_hsolver/diago_dav_subspace.h b/source/module_hsolver/diago_dav_subspace.h index 78553f0174d..d93c2526025 100644 --- a/source/module_hsolver/diago_dav_subspace.h +++ b/source/module_hsolver/diago_dav_subspace.h @@ -1,17 +1,21 @@ #ifndef DIAGO_NEW_DAV_H #define DIAGO_NEW_DAV_H -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_base/module_device/device.h" // base_device +#include "module_base/module_device/memory_op.h"// base_device::memory" + #include "module_hsolver/diag_comm_info.h" #include "module_hsolver/diag_const_nums.h" +#include #include namespace hsolver { template , typename Device = base_device::DEVICE_CPU> -class Diago_DavSubspace : public DiagH +class Diago_DavSubspace { private: // Note GetTypeReal::type will @@ -29,15 +33,16 @@ class Diago_DavSubspace : public DiagH const bool& need_subspace_in, const diag_comm_info& diag_comm_in); - virtual ~Diago_DavSubspace() override; + ~Diago_DavSubspace(); - using HPsiFunc = std::function; + // See diago_david.h for information on the HPsiFunc function type + using HPsiFunc = std::function; int diag(const HPsiFunc& hpsi_func, T* psi_in, const int psi_in_dmax, Real* eigenvalue_in, - const std::vector& is_occupied, + const double* ethr_band, const bool& scf_type); private: @@ -110,13 +115,6 @@ class Diago_DavSubspace : public DiagH T* scc, T* vcc); - void diagH_subspace(T* psi_pointer, // [in] & [out] wavefunction - Real* en, // [out] eigenvalues - const HPsiFunc hpsi_func, - const int n_band, - const int dmin, - const int dmax); - // void diagH_LAPACK(const int nstart, // const int nbands, // const T* hcc, @@ -131,24 +129,32 @@ class Diago_DavSubspace : public DiagH T* scc, const int& nbase_x, std::vector* eigenvalue_iter, - T* vcc, - bool init, - bool is_subspace); + T* vcc); int diag_once(const HPsiFunc& hpsi_func, T* psi_in, const int psi_in_dmax, Real* eigenvalue_in, - const std::vector& is_occupied); + const double* ethr_band); bool test_exit_cond(const int& ntry, const int& notconv, const bool& scf); +#ifdef __DSP + using resmem_complex_op = base_device::memory::resize_memory_op_mt; + using delmem_complex_op = base_device::memory::delete_memory_op_mt; +#else using resmem_complex_op = base_device::memory::resize_memory_op; using delmem_complex_op = base_device::memory::delete_memory_op; +#endif using setmem_complex_op = base_device::memory::set_memory_op; +#ifdef __DSP + using resmem_real_op = base_device::memory::resize_memory_op_mt; + using delmem_real_op = base_device::memory::delete_memory_op_mt; +#else using resmem_real_op = base_device::memory::resize_memory_op; using delmem_real_op = base_device::memory::delete_memory_op; +#endif using setmem_real_op = base_device::memory::set_memory_op; using resmem_real_h_op = base_device::memory::resize_memory_op; @@ -162,8 +168,8 @@ class Diago_DavSubspace : public DiagH using syncmem_h2d_op = base_device::memory::synchronize_memory_op; using syncmem_d2h_op = base_device::memory::synchronize_memory_op; - const_nums cs; const T *one = nullptr, *zero = nullptr, *neg_one = nullptr; + const T one_ = static_cast(1.0), zero_ = static_cast(0.0), neg_one_ = static_cast(-1.0); }; } // namespace hsolver diff --git a/source/module_hsolver/diago_david.cpp b/source/module_hsolver/diago_david.cpp index a66b106c265..8f404da1358 100644 --- a/source/module_hsolver/diago_david.cpp +++ b/source/module_hsolver/diago_david.cpp @@ -1,6 +1,7 @@ #include "diago_david.h" -#include "module_base/timer.h" +#include "module_base/timer.h" // ModuleBase::timer::tick +#include "module_base/tool_title.h" // ModuleBase::TITLE #include "module_base/module_device/device.h" #include "module_hsolver/kernels/dngvd_op.h" @@ -98,8 +99,8 @@ DiagoDavid::DiagoDavid(const Real* precondition_in, setmem_complex_op()(this->ctx, this->hcc, 0, nbase_x * nbase_x); // scc(nbase_x, nbase_x); // Overlap on the reduced basis - resmem_complex_op()(this->ctx, this->scc, nbase_x * nbase_x, "DAV::scc"); - setmem_complex_op()(this->ctx, this->scc, 0, nbase_x * nbase_x); + // resmem_complex_op()(this->ctx, this->scc, nbase_x * nbase_x, "DAV::scc"); + // setmem_complex_op()(this->ctx, this->scc, 0, nbase_x * nbase_x); // vcc(nbase_x, nbase_x); // Eigenvectors of hcc resmem_complex_op()(this->ctx, this->vcc, nbase_x * nbase_x, "DAV::vcc"); @@ -134,7 +135,7 @@ DiagoDavid::~DiagoDavid() delmem_complex_op()(this->ctx, this->hpsi); delmem_complex_op()(this->ctx, this->spsi); delmem_complex_op()(this->ctx, this->hcc); - delmem_complex_op()(this->ctx, this->scc); + // delmem_complex_op()(this->ctx, this->scc); delmem_complex_op()(this->ctx, this->vcc); delmem_complex_op()(this->ctx, this->lagrange_matrix); base_device::memory::delete_memory_op()(this->cpu_ctx, this->eigenvalue); @@ -152,7 +153,7 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, const SPsiFunc& spsi_func, const int dim, const int nband, - const int ldPsi, + const int ld_psi, T *psi_in, Real* eigenvalue_in, const Real david_diag_thr, @@ -191,20 +192,20 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, if(this->use_paw) { #ifdef USE_PAW - GlobalC::paw_cell.paw_nl_psi(1, reinterpret_cast*> (psi_in + m*ldPsi), + GlobalC::paw_cell.paw_nl_psi(1, reinterpret_cast*> (psi_in + m*ld_psi), reinterpret_cast*>(&this->spsi[m * dim])); #endif } else { - // phm_in->sPsi(psi_in + m*ldPsi, &this->spsi[m * dim], dim, dim, 1); - spsi_func(psi_in + m*ldPsi,&this->spsi[m*dim],dim,dim,1); + // phm_in->sPsi(psi_in + m*ld_psi, &this->spsi[m * dim], dim, dim, 1); + spsi_func(psi_in + m*ld_psi,&this->spsi[m*dim],dim, 1); } } // begin SchmidtOrth for (int m = 0; m < nband; m++) { - syncmem_complex_op()(this->ctx, this->ctx, basis + dim*m, psi_in + m*ldPsi, dim); + syncmem_complex_op()(this->ctx, this->ctx, basis + dim*m, psi_in + m*ld_psi, dim); this->SchmidtOrth(dim, nband, @@ -223,14 +224,16 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, else { // phm_in->sPsi(basis + dim*m, &this->spsi[m * dim], dim, dim, 1); - spsi_func(basis + dim*m, &this->spsi[m * dim], dim, dim, 1); + spsi_func(basis + dim*m, &this->spsi[m * dim], dim, 1); } } // end of SchmidtOrth and calculate H|psi> // hpsi_info dav_hpsi_in(&basis, psi::Range(true, 0, 0, nband - 1), this->hpsi); // phm_in->ops->hPsi(dav_hpsi_in); - hpsi_func(basis, hpsi, nbase_x, dim, 0, nband - 1); + // hpsi[:, 0:nband] = H basis[:, 0:nband] + // slice index in this piece of code is in C manner. i.e. 0:id stands for [0,id) + hpsi_func(basis, hpsi, dim, nband); this->cal_elem(dim, nbase, nbase_x, this->notconv, this->hpsi, this->spsi, this->hcc, this->scc); @@ -287,7 +290,7 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, // update eigenvectors of Hamiltonian - setmem_complex_op()(this->ctx, psi_in, 0, nband * ldPsi); + setmem_complex_op()(this->ctx, psi_in, 0, nband * ld_psi); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< gemm_op()(this->ctx, 'N', @@ -302,7 +305,7 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, nbase_x, this->zero, psi_in, // C dim * nband - ldPsi + ld_psi ); if (!this->notconv || (dav_iter == david_maxiter)) @@ -322,7 +325,7 @@ int DiagoDavid::diag_once(const HPsiFunc& hpsi_func, nbase_x, eigenvalue_in, psi_in, - ldPsi, + ld_psi, this->hpsi, this->spsi, this->hcc, @@ -552,7 +555,7 @@ void DiagoDavid::cal_grad(const HPsiFunc& hpsi_func, else { // phm_in->sPsi(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, dim, 1); - spsi_func(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, dim, 1); + spsi_func(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, 1); } } // first nbase bands psi* dot notconv bands spsi to prepare lagrange_matrix @@ -593,7 +596,7 @@ void DiagoDavid::cal_grad(const HPsiFunc& hpsi_func, else { // phm_in->sPsi(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, dim, 1); - spsi_func(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, dim, 1); + spsi_func(basis + dim*(nbase + m), &spsi[(nbase + m) * dim], dim, 1); } } // calculate H|psi> for not convergence bands @@ -601,7 +604,8 @@ void DiagoDavid::cal_grad(const HPsiFunc& hpsi_func, // psi::Range(true, 0, nbase, nbase + notconv - 1), // &hpsi[nbase * dim]); // &hp(nbase, 0) // phm_in->ops->hPsi(dav_hpsi_in); - hpsi_func(basis, &hpsi[nbase * dim], nbase_x, dim, nbase, nbase + notconv - 1); + // hpsi[:, nbase:nbase+notcnv] = H basis[:, nbase:nbase+notcnv] + hpsi_func(basis + nbase * dim, hpsi + nbase * dim, dim, notconv); delmem_complex_op()(this->ctx, lagrange); delmem_complex_op()(this->ctx, vc_ev_vector); @@ -657,27 +661,27 @@ void DiagoDavid::cal_elem(const int& dim, hcc + nbase, // notconv * (nbase + notconv) nbase_x); // scc[nbase] = basis[nbase]' * spsi - gemm_op()(this->ctx, - 'C', - 'N', - notconv, - nbase + notconv, - dim, - this->one, - basis + dim*nbase, // dim * notconv - dim, - spsi, // dim * (nbase + notconv) - dim, - this->zero, - scc + nbase, // notconv * (nbase + notconv) - nbase_x); + // gemm_op()(this->ctx, + // 'C', + // 'N', + // notconv, + // nbase + notconv, + // dim, + // this->one, + // basis + dim*nbase, // dim * notconv + // dim, + // spsi, // dim * (nbase + notconv) + // dim, + // this->zero, + // scc + nbase, // notconv * (nbase + notconv) + // nbase_x); #ifdef __MPI if (diag_comm.nproc > 1) { matrixTranspose_op()(this->ctx, nbase_x, nbase_x, hcc, hcc); - matrixTranspose_op()(this->ctx, nbase_x, nbase_x, scc, scc); + // matrixTranspose_op()(this->ctx, nbase_x, nbase_x, scc, scc); auto* swap = new T[notconv * nbase_x]; syncmem_complex_op()(this->ctx, this->ctx, swap, hcc + nbase * nbase_x, notconv * nbase_x); @@ -693,12 +697,12 @@ void DiagoDavid::cal_elem(const int& dim, else { MPI_Reduce(swap, hcc + nbase * nbase_x, notconv * nbase_x, MPI_DOUBLE_COMPLEX, MPI_SUM, 0, diag_comm.comm); } - syncmem_complex_op()(this->ctx, this->ctx, swap, scc + nbase * nbase_x, notconv * nbase_x); + // syncmem_complex_op()(this->ctx, this->ctx, swap, scc + nbase * nbase_x, notconv * nbase_x); if (base_device::get_current_precision(swap) == "single") { - MPI_Reduce(swap, scc + nbase * nbase_x, notconv * nbase_x, MPI_COMPLEX, MPI_SUM, 0, diag_comm.comm); + // MPI_Reduce(swap, scc + nbase * nbase_x, notconv * nbase_x, MPI_COMPLEX, MPI_SUM, 0, diag_comm.comm); } else { - MPI_Reduce(swap, scc + nbase * nbase_x, notconv * nbase_x, MPI_DOUBLE_COMPLEX, MPI_SUM, 0, diag_comm.comm); + // MPI_Reduce(swap, scc + nbase * nbase_x, notconv * nbase_x, MPI_DOUBLE_COMPLEX, MPI_SUM, 0, diag_comm.comm); } } delete[] swap; @@ -707,7 +711,7 @@ void DiagoDavid::cal_elem(const int& dim, // Parallel_Reduce::reduce_complex_double_pool( scc + nbase * nbase_x, notconv * nbase_x ); matrixTranspose_op()(this->ctx, nbase_x, nbase_x, hcc, hcc); - matrixTranspose_op()(this->ctx, nbase_x, nbase_x, scc, scc); + // matrixTranspose_op()(this->ctx, nbase_x, nbase_x, scc, scc); } #endif @@ -785,7 +789,7 @@ void DiagoDavid::diag_zhegvx(const int& nbase, * @param nbase_x The maximum dimension of the reduced basis set. * @param eigenvalue_in Pointer to the array of eigenvalues. * @param psi_in Pointer to the array of wavefunctions. - * @param ldPsi The leading dimension of the wavefunction array. + * @param ld_psi The leading dimension of the wavefunction array. * @param hpsi Pointer to the output array for the updated basis set. * @param spsi Pointer to the output array for the updated basis set (nband-th column). * @param hcc Pointer to the output array for the updated reduced Hamiltonian. @@ -800,7 +804,7 @@ void DiagoDavid::refresh(const int& dim, const int nbase_x, // maximum dimension of the reduced basis set const Real* eigenvalue_in, const T *psi_in, - const int ldPsi, + const int ld_psi, T* hpsi, T* spsi, T* hcc, @@ -866,7 +870,7 @@ void DiagoDavid::refresh(const int& dim, for (int m = 0; m < nband; m++) { - syncmem_complex_op()(this->ctx, this->ctx, basis + dim*m,psi_in + m*ldPsi, dim); + syncmem_complex_op()(this->ctx, this->ctx, basis + dim*m,psi_in + m*ld_psi, dim); /*for (int ig = 0; ig < npw; ig++) basis(m, ig) = psi(m, ig);*/ } @@ -877,44 +881,44 @@ void DiagoDavid::refresh(const int& dim, setmem_complex_op()(this->ctx, hcc, 0, nbase_x * nbase_x); - setmem_complex_op()(this->ctx, scc, 0, nbase_x * nbase_x); + // setmem_complex_op()(this->ctx, scc, 0, nbase_x * nbase_x); if (this->device == base_device::GpuDevice) { #if defined(__CUDA) || defined(__ROCM) T* hcc_cpu = nullptr; - T* scc_cpu = nullptr; + // T* scc_cpu = nullptr; T* vcc_cpu = nullptr; base_device::memory::resize_memory_op()(this->cpu_ctx, hcc_cpu, nbase_x * nbase_x, "DAV::hcc"); - base_device::memory::resize_memory_op()(this->cpu_ctx, - scc_cpu, - nbase_x * nbase_x, - "DAV::scc"); + // base_device::memory::resize_memory_op()(this->cpu_ctx, + // scc_cpu, + // nbase_x * nbase_x, + // "DAV::scc"); base_device::memory::resize_memory_op()(this->cpu_ctx, vcc_cpu, nbase_x * nbase_x, "DAV::vcc"); syncmem_d2h_op()(this->cpu_ctx, this->ctx, hcc_cpu, hcc, nbase_x * nbase_x); - syncmem_d2h_op()(this->cpu_ctx, this->ctx, scc_cpu, scc, nbase_x * nbase_x); + // syncmem_d2h_op()(this->cpu_ctx, this->ctx, scc_cpu, scc, nbase_x * nbase_x); syncmem_d2h_op()(this->cpu_ctx, this->ctx, vcc_cpu, vcc, nbase_x * nbase_x); for (int i = 0; i < nbase; i++) { hcc_cpu[i * nbase_x + i] = eigenvalue_in[i]; - scc_cpu[i * nbase_x + i] = this->one[0]; + // scc_cpu[i * nbase_x + i] = this->one[0]; vcc_cpu[i * nbase_x + i] = this->one[0]; } syncmem_h2d_op()(this->ctx, this->cpu_ctx, hcc, hcc_cpu, nbase_x * nbase_x); - syncmem_h2d_op()(this->ctx, this->cpu_ctx, scc, scc_cpu, nbase_x * nbase_x); + // syncmem_h2d_op()(this->ctx, this->cpu_ctx, scc, scc_cpu, nbase_x * nbase_x); syncmem_h2d_op()(this->ctx, this->cpu_ctx, vcc, vcc_cpu, nbase_x * nbase_x); base_device::memory::delete_memory_op()(this->cpu_ctx, hcc_cpu); - base_device::memory::delete_memory_op()(this->cpu_ctx, scc_cpu); + // base_device::memory::delete_memory_op()(this->cpu_ctx, scc_cpu); base_device::memory::delete_memory_op()(this->cpu_ctx, vcc_cpu); #endif } @@ -924,7 +928,7 @@ void DiagoDavid::refresh(const int& dim, { hcc[i * nbase_x + i] = eigenvalue_in[i]; // sc(i, i) = this->one; - scc[i * nbase_x + i] = this->one[0]; + // scc[i * nbase_x + i] = this->one[0]; // vc(i, i) = this->one; vcc[i * nbase_x + i] = this->one[0]; } @@ -1149,11 +1153,13 @@ void DiagoDavid::planSchmidtOrth(const int nband, std::vector& p /** * @brief Performs iterative diagonalization using the David algorithm. * + * @warning Please see docs of `HPsiFunc` for more information about the hpsi mat-vec interface. + * * @tparam T The type of the elements in the matrix. * @tparam Device The device type (CPU or GPU). * @param hpsi_func The function object that computes the matrix-blockvector product H * psi. * @param spsi_func The function object that computes the matrix-blockvector product overlap S * psi. - * @param ldPsi The leading dimension of the psi_in array. + * @param ld_psi The leading dimension of the psi_in array. * @param psi_in The input wavefunction. * @param eigenvalue_in The array to store the eigenvalues. * @param david_diag_thr The convergence threshold for the diagonalization. @@ -1168,7 +1174,7 @@ void DiagoDavid::planSchmidtOrth(const int nband, std::vector& p template int DiagoDavid::diag(const HPsiFunc& hpsi_func, const SPsiFunc& spsi_func, - const int ldPsi, + const int ld_psi, T *psi_in, Real* eigenvalue_in, const Real david_diag_thr, @@ -1183,7 +1189,7 @@ int DiagoDavid::diag(const HPsiFunc& hpsi_func, int sum_dav_iter = 0; do { - sum_dav_iter += this->diag_once(hpsi_func, spsi_func, dim, nband, ldPsi, psi_in, eigenvalue_in, david_diag_thr, david_maxiter); + sum_dav_iter += this->diag_once(hpsi_func, spsi_func, dim, nband, ld_psi, psi_in, eigenvalue_in, david_diag_thr, david_maxiter); ++ntry; } while (!check_block_conv(ntry, this->notconv, ntry_max, notconv_max)); diff --git a/source/module_hsolver/diago_david.h b/source/module_hsolver/diago_david.h index 16bc471e2cc..62ffc2654f3 100644 --- a/source/module_hsolver/diago_david.h +++ b/source/module_hsolver/diago_david.h @@ -1,14 +1,20 @@ #ifndef DIAGODAVID_H #define DIAGODAVID_H -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_base/module_device/device.h" // base_device +#include "module_base/module_device/memory_op.h"// base_device::memory + #include "module_hsolver/diag_comm_info.h" +#include +#include + namespace hsolver { template , typename Device = base_device::DEVICE_CPU> -class DiagoDavid : public DiagH +class DiagoDavid { private: // Note GetTypeReal::type will @@ -25,53 +31,58 @@ class DiagoDavid : public DiagH const bool use_paw_in, const diag_comm_info& diag_comm_in); - virtual ~DiagoDavid() override; + ~DiagoDavid(); // declare type of matrix-blockvector functions. // the function type is defined as a std::function object. - // notice that hpsi and spsi functions require - // !different! order of input and output blockvectors. /** * @brief A function type representing the HX function. * * This function type is used to define a matrix-blockvector operator H. * For eigenvalue problem HX = λX or generalized eigenvalue problem HX = λSX, * this function computes the product of the Hamiltonian matrix H and a blockvector X. + * + * Called as follows: + * hpsi(X, HX, ld, nvec) where X and HX are (ld, nvec)-shaped blockvectors. + * Result HX = H * X is stored in HX. * - * @param[out] X Pointer to input blockvector of type `T*`. - * @param[in] HX Pointer to output blockvector of type `T*`. - * @param[in] neig Number of eigebpairs required. - * @param[in] dim Dimension of matrix. - * @param[in] id_start Start index of blockvector. - * @param[in] id_end End index of blockvector. + * @param[out] X Head address of input blockvector of type `T*`. + * @param[in] HX Head address of output blockvector of type `T*`. + * @param[in] ld Leading dimension of blockvector. + * @param[in] nvec Number of vectors in a block. + * + * @warning X and HX are the exact address to read input X and store output H*X, + * @warning both of size ld * nvec. */ - using HPsiFunc = std::function; + using HPsiFunc = std::function; /** * @brief A function type representing the SX function. + * + * nrow is leading dimension of spsi, npw is leading dimension of psi, nbands is number of vecs * * This function type is used to define a matrix-blockvector operator S. * For generalized eigenvalue problem HX = λSX, * this function computes the product of the overlap matrix S and a blockvector X. * - * @param[in] X Pointer to the input array. - * @param[out] SX Pointer to the output array. - * @param[in] nrow Dimension of SX: nbands * nrow. - * @param[in] npw Number of plane waves. - * @param[in] nbands Number of bands. + * @param[in] X Pointer to the input blockvector. + * @param[out] SX Pointer to the output blockvector. + * @param[in] ld_psi Leading dimension of psi and spsi. Dimension of X&SX: ld * nvec. + * @param[in] nvec Number of vectors. */ - using SPsiFunc = std::function; - - int diag(const HPsiFunc& hpsi_func, // function void hpsi(T*, T*, const int, const int, const int, const int) - const SPsiFunc& spsi_func, // function void spsi(T*, T*, const int, const int, const int) - const int ldPsi, // Leading dimension of the psi input - T *psi_in, // Pointer to eigenvectors - Real* eigenvalue_in, // Pointer to store the resulting eigenvalues - const Real david_diag_thr, // Convergence threshold for the Davidson iteration - const int david_maxiter, // Maximum allowed iterations for the Davidson method - const int ntry_max = 5, // Maximum number of diagonalization attempts (default is 5) - const int notconv_max = 0); // Maximum number of allowed non-converged eigenvectors + using SPsiFunc = std::function; + + int diag( + const HPsiFunc& hpsi_func, // function void hpsi(T*, T*, const int, const int) + const SPsiFunc& spsi_func, // function void spsi(T*, T*, const int, const int, const int) + const int ld_psi, // Leading dimension of the psi input + T *psi_in, // Pointer to eigenvectors + Real* eigenvalue_in, // Pointer to store the resulting eigenvalues + const Real david_diag_thr, // Convergence threshold for the Davidson iteration + const int david_maxiter, // Maximum allowed iterations for the Davidson method + const int ntry_max = 5, // Maximum number of diagonalization attempts (5 by default) + const int notconv_max = 0); // Maximum number of allowed non-converged eigenvectors private: bool use_paw = false; @@ -120,7 +131,7 @@ class DiagoDavid : public DiagH const SPsiFunc& spsi_func, const int dim, const int nband, - const int ldPsi, + const int ld_psi, T *psi_in, Real* eigenvalue_in, const Real david_diag_thr, @@ -153,7 +164,7 @@ class DiagoDavid : public DiagH const int nbase_x, const Real* eigenvalue, const T *psi_in, - const int ldPsi, + const int ld_psi, T* hpsi, T* spsi, T* hcc, @@ -161,12 +172,12 @@ class DiagoDavid : public DiagH T* vcc); void SchmidtOrth(const int& dim, - const int nband, - const int m, - const T* spsi, - T* lagrange_m, - const int mm_size, - const int mv_size); + const int nband, + const int m, + const T* spsi, + T* lagrange_m, + const int mm_size, + const int mv_size); void planSchmidtOrth(const int nband, std::vector& pre_matrix_mm_m, std::vector& pre_matrix_mv_m); @@ -194,7 +205,7 @@ class DiagoDavid : public DiagH using syncmem_h2d_op = base_device::memory::synchronize_memory_op; using syncmem_d2h_op = base_device::memory::synchronize_memory_op; - using hpsi_info = typename hamilt::Operator::hpsi_info; + // using hpsi_info = typename hamilt::Operator::hpsi_info; // Dependence of hpsi removed const T *one = nullptr, *zero = nullptr, *neg_one = nullptr; const T one_ = static_cast(1.0), zero_ = static_cast(0.0), neg_one_ = static_cast(-1.0); diff --git a/source/module_hsolver/diago_elpa.cpp b/source/module_hsolver/diago_elpa.cpp index fcfeed43efb..817c1737caf 100644 --- a/source/module_hsolver/diago_elpa.cpp +++ b/source/module_hsolver/diago_elpa.cpp @@ -1,5 +1,6 @@ #include "diago_elpa.h" +#include "module_parameter/parameter.h" #include "genelpa/elpa_solver.h" #include "module_base/blacs_connector.h" #include "module_base/global_variable.h" @@ -74,13 +75,13 @@ void DiagoElpa>::diag( matcd h_mat, s_mat; phm_in->matrix(h_mat, s_mat); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); bool isReal = false; MPI_Comm COMM_DIAG = setmpicomm(); // set mpi_comm needed ELPA_Solver es((const bool)isReal, COMM_DIAG, - (const int)GlobalV::NBANDS, + (const int)PARAM.inp.nbands, (const int)h_mat.row, (const int)h_mat.col, (const int*)h_mat.desc); @@ -96,7 +97,7 @@ void DiagoElpa>::diag( es.exit(); const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); #else ModuleBase::WARNING_QUIT("DiagoElpa", "DiagoElpa only can be used with macro __MPI"); @@ -112,15 +113,15 @@ void DiagoElpa::diag(hamilt::Hamilt* phm_in, matd h_mat, s_mat; phm_in->matrix(h_mat, s_mat); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); bool isReal = true; MPI_Comm COMM_DIAG = setmpicomm(); // set mpi_comm needed - // ELPA_Solver es(isReal, COMM_DIAG, GlobalV::NBANDS, h_mat.row, h_mat.col, + // ELPA_Solver es(isReal, COMM_DIAG, PARAM.inp.nbands, h_mat.row, h_mat.col, // h_mat.desc); ELPA_Solver es((const bool)isReal, COMM_DIAG, - (const int)GlobalV::NBANDS, + (const int)PARAM.inp.nbands, (const int)h_mat.row, (const int)h_mat.col, (const int*)h_mat.desc); @@ -136,7 +137,7 @@ void DiagoElpa::diag(hamilt::Hamilt* phm_in, const int inc = 1; ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "K-S equation was solved by genelpa2"); - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "eigenvalues were copied to ekb"); #else @@ -154,11 +155,11 @@ void DiagoElpa>::diag_pool(hamilt::MatrixBlock eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); bool isReal = false; ELPA_Solver es((const bool)isReal, comm, - (const int)GlobalV::NBANDS, + (const int)PARAM.inp.nbands, (const int)h_mat.row, (const int)h_mat.col, (const int*)h_mat.desc); @@ -173,7 +174,7 @@ void DiagoElpa>::diag_pool(hamilt::MatrixBlock @@ -183,14 +184,14 @@ void DiagoElpa::diag_pool(hamilt::MatrixBlock& h_mat, Real* eigenvalue_in, MPI_Comm& comm) { - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); bool isReal = true; - // ELPA_Solver es(isReal, COMM_DIAG, GlobalV::NBANDS, h_mat.row, h_mat.col, + // ELPA_Solver es(isReal, COMM_DIAG, PARAM.inp.nbands, h_mat.row, h_mat.col, // h_mat.desc); ELPA_Solver es((const bool)isReal, comm, - (const int)GlobalV::NBANDS, + (const int)PARAM.inp.nbands, (const int)h_mat.row, (const int)h_mat.col, (const int*)h_mat.desc); @@ -206,7 +207,7 @@ void DiagoElpa::diag_pool(hamilt::MatrixBlock& h_mat, const int inc = 1; ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "K-S equation was solved by genelpa2"); - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "eigenvalues were copied to ekb"); } diff --git a/source/module_hsolver/diago_elpa.h b/source/module_hsolver/diago_elpa.h index 49006d012b1..0ebe236ddbe 100644 --- a/source/module_hsolver/diago_elpa.h +++ b/source/module_hsolver/diago_elpa.h @@ -1,23 +1,24 @@ #ifndef DIAGOELPA_H #define DIAGOELPA_H -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" #include "module_basis/module_ao/parallel_orbitals.h" namespace hsolver { template -class DiagoElpa : public DiagH +class DiagoElpa { private: using Real = typename GetTypeReal::type; public: - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); #ifdef __MPI // diagnolization used in parallel-k case - void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm) override; + void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm); MPI_Comm setmpicomm(); // set mpi comm; static int elpa_num_thread; // need to set mpi_comm or not,-1 not,else the number of mpi needed #endif diff --git a/source/module_hsolver/diago_elpa_native.cpp b/source/module_hsolver/diago_elpa_native.cpp index fa73a1d1e07..213ac678191 100644 --- a/source/module_hsolver/diago_elpa_native.cpp +++ b/source/module_hsolver/diago_elpa_native.cpp @@ -56,11 +56,10 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, Real* eigenvalue_in, MPI_Comm& comm) { - std::vector eigen(GlobalV::NLOCAL, 0.0); ModuleBase::timer::tick("DiagoElpaNative", "elpa_solve"); - int nev = GlobalV::NBANDS; + int nev = PARAM.inp.nbands; int narows = h_mat.row; int nacols = h_mat.col; @@ -71,6 +70,8 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, int nprows, npcols, myprow, mypcol; Cblacs_gridinfo(cblacs_ctxt, &nprows, &npcols, &myprow, &mypcol); + std::vector eigen(PARAM.globalv.nlocal, 0.0); + std::vector eigenvectors(narows * nacols); if (elpa_init(20210430) != ELPA_OK) { @@ -80,7 +81,11 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, // elpa_init(20210430); int success; elpa_t handle = elpa_allocate(&success); +#ifdef _OPENMP int num_threads = omp_get_max_threads(); +#else + int num_threads = 1; +#endif elpa_set(handle, "omp_threads", num_threads, &success); elpa_set(handle, "na", (int)nFull, &success); elpa_set(handle, "nev", (int)nev, &success); @@ -94,11 +99,17 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, elpa_setup(handle); elpa_set(handle, "solver", ELPA_SOLVER_1STAGE, &success); -#ifdef __CUDA - if (PARAM.globalv.device_flag == "gpu") +/* ELPA_WITH_NVIDIA_GPU_VERSION is a symbol defined in elpa/elpa_configured_options.h + For example: + cat elpa/elpa_configured_options.h + #define ELPA_WITH_NVIDIA_GPU_VERSION 1 + #define ELPA_WITH_AMD_GPU_VERSION 0 + #define ELPA_WITH_SYCL_GPU_VERSION 0 + */ +#if ELPA_WITH_NVIDIA_GPU_VERSION + if (PARAM.inp.device == "gpu") { elpa_set(handle, "nvidia-gpu", 1, &success); - elpa_set(handle, "real_kernel", ELPA_2STAGE_REAL_NVIDIA_GPU, &success); elpa_setup_gpu(handle); } @@ -108,7 +119,7 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, h_mat.p, s_mat.p, eigen.data(), - psi.get_pointer(), + eigenvectors.data(), this->DecomposedState, &success); elpa_deallocate(handle, &success); @@ -127,7 +138,9 @@ void DiagoElpaNative::diag_pool(hamilt::MatrixBlock& h_mat, } const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); + const int size = psi.get_nbands() * psi.get_nbasis(); + BlasConnector::copy(size, eigenvectors.data(), inc, psi.get_pointer(), inc); } #endif diff --git a/source/module_hsolver/diago_elpa_native.h b/source/module_hsolver/diago_elpa_native.h index adbb0520233..63415b79a7b 100644 --- a/source/module_hsolver/diago_elpa_native.h +++ b/source/module_hsolver/diago_elpa_native.h @@ -1,23 +1,24 @@ #ifndef DIAGOELPANATIVE_H #define DIAGOELPANATIVE_H -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" #include "module_basis/module_ao/parallel_orbitals.h" namespace hsolver { template -class DiagoElpaNative : public DiagH +class DiagoElpaNative { private: using Real = typename GetTypeReal::type; public: - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); #ifdef __MPI // diagnolization used in parallel-k case - void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm) override; + void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm); MPI_Comm setmpicomm(); // set mpi comm; static int elpa_num_thread; // need to set mpi_comm or not,-1 not,else the number of mpi needed static int lastmpinum; // last using mpi; diff --git a/source/module_hsolver/diago_iter_assist.cpp b/source/module_hsolver/diago_iter_assist.cpp index 8d18aacf965..a092a8260ce 100644 --- a/source/module_hsolver/diago_iter_assist.cpp +++ b/source/module_hsolver/diago_iter_assist.cpp @@ -20,7 +20,7 @@ namespace hsolver // Produces on output n_band eigenvectors (n_band <= nstart) in evc. //---------------------------------------------------------------------- template -void DiagoIterAssist::diagH_subspace(hamilt::Hamilt* pHamilt, // hamiltonian operator carrier +void DiagoIterAssist::diagH_subspace(const hamilt::Hamilt* const pHamilt, // hamiltonian operator carrier const psi::Psi& psi, // [in] wavefunction psi::Psi& evc, // [out] wavefunction Real* en, // [out] eigenvalues diff --git a/source/module_hsolver/diago_iter_assist.h b/source/module_hsolver/diago_iter_assist.h index 43345a769d4..560b37d6824 100644 --- a/source/module_hsolver/diago_iter_assist.h +++ b/source/module_hsolver/diago_iter_assist.h @@ -29,7 +29,7 @@ class DiagoIterAssist static int SCF_ITER; // for psi::Psi structure - static void diagH_subspace(hamilt::Hamilt* pHamilt, + static void diagH_subspace(const hamilt::Hamilt* const pHamilt, const psi::Psi& psi, psi::Psi& evc, Real* en, diff --git a/source/module_hsolver/diago_lapack.cpp b/source/module_hsolver/diago_lapack.cpp index 3fc4154444b..33ce4f156c7 100644 --- a/source/module_hsolver/diago_lapack.cpp +++ b/source/module_hsolver/diago_lapack.cpp @@ -1,5 +1,6 @@ // Refactored according to diago_scalapack // This code will be futher refactored to remove the dependency of psi and hamilt +#include "module_parameter/parameter.h" #include "diago_lapack.h" @@ -24,7 +25,7 @@ void DiagoLapack::diag(hamilt::Hamilt* phm_in, psi::Psi& assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); // Diag this->dsygvx_diag(h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); @@ -45,7 +46,7 @@ void DiagoLapack>::diag(hamilt::Hamilt phm_in->matrix(h_mat, s_mat); assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); this->zhegvx_diag(h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); int size = eigen.size(); for (int i = 0; i < size; i++) @@ -72,7 +73,7 @@ int DiagoLapack::dsygvx_once(const int ncol, // Prepare caculate parameters const char jobz = 'V', range = 'I', uplo = 'U'; - const int itype = 1, il = 1, iu = GlobalV::NBANDS, one = 1; + const int itype = 1, il = 1, iu = PARAM.inp.nbands, one = 1; int M = 0, info = 0; double vl = 0, vu = 0; const double abstol = 0; @@ -81,14 +82,14 @@ int DiagoLapack::dsygvx_once(const int ncol, std::vector work(3, 0); std::vector iwork(1, 0); - std::vector ifail(GlobalV::NLOCAL, 0); + std::vector ifail(PARAM.globalv.nlocal, 0); // Original Lapack caculate, obelsete /*dsygvx_(&itype, &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, &ncol, s_tmp.c, @@ -121,11 +122,11 @@ int DiagoLapack::dsygvx_once(const int ncol, &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, s_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &vl, &vu, &il, @@ -143,7 +144,7 @@ int DiagoLapack::dsygvx_once(const int ncol, double *ev = new double[ncol * ncol]; - dsygv_(&itype, &jobz, &uplo, &GlobalV::NLOCAL, h_tmp.c, &ncol, s_tmp.c, &ncol, ekb, ev, &lwork, &info); + dsygv_(&itype, &jobz, &uplo, &PARAM.globalv.nlocal, h_tmp.c, &ncol, s_tmp.c, &ncol, ekb, ev, &lwork, &info); return info; } @@ -163,7 +164,7 @@ int DiagoLapack::zhegvx_once(const int ncol, memcpy(s_tmp.c, s_mat, sizeof(std::complex) * ncol * nrow); const char jobz = 'V', range = 'I', uplo = 'U'; - const int itype = 1, il = 1, iu = GlobalV::NBANDS, one = 1; + const int itype = 1, il = 1, iu = PARAM.inp.nbands, one = 1; int M = 0, lrwork = -1, info = 0; const double abstol = 0; @@ -173,7 +174,7 @@ int DiagoLapack::zhegvx_once(const int ncol, std::vector> work(1, 0); double *rwork = new double[3 * ncol - 2]; std::vector iwork(1, 0); - std::vector ifail(GlobalV::NLOCAL, 0); + std::vector ifail(PARAM.globalv.nlocal, 0); // Original Lapack caculate, obelsete /* @@ -181,11 +182,11 @@ int DiagoLapack::zhegvx_once(const int ncol, &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, s_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &vl, &vu, &il, @@ -219,11 +220,11 @@ int DiagoLapack::zhegvx_once(const int ncol, &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, s_tmp.c, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, &vl, &vu, &il, @@ -244,7 +245,7 @@ int DiagoLapack::zhegvx_once(const int ncol, std::complex *ev = new std::complex[ncol * ncol]; - zhegv_(&itype, &jobz, &uplo, &GlobalV::NLOCAL, h_tmp.c, &ncol, s_tmp.c, &ncol, ekb, ev, &lwork, rwork, &info); + zhegv_(&itype, &jobz, &uplo, &PARAM.globalv.nlocal, h_tmp.c, &ncol, s_tmp.c, &ncol, ekb, ev, &lwork, rwork, &info); return info; } diff --git a/source/module_hsolver/diago_lapack.h b/source/module_hsolver/diago_lapack.h index 7e87b84ea5f..f787b9054f1 100644 --- a/source/module_hsolver/diago_lapack.h +++ b/source/module_hsolver/diago_lapack.h @@ -8,8 +8,8 @@ #ifndef DIAGOLAPACK_H #define DIAGOLAPACK_H -#include "diagh.h" -#include "module_base/complexmatrix.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" #include "module_base/matrix.h" #include "module_basis/module_ao/parallel_orbitals.h" @@ -20,13 +20,13 @@ namespace hsolver { template -class DiagoLapack : public DiagH +class DiagoLapack { private: using Real = typename GetTypeReal::type; public: - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); void dsygvx_diag(const int ncol, const int nrow, diff --git a/source/module_hsolver/diago_pexsi.cpp b/source/module_hsolver/diago_pexsi.cpp index 431fe5660f6..85df14c9af7 100644 --- a/source/module_hsolver/diago_pexsi.cpp +++ b/source/module_hsolver/diago_pexsi.cpp @@ -66,7 +66,7 @@ void DiagoPexsi::diag(hamilt::Hamilt* phm_in, psi::Psi& ModuleBase::TITLE("DiagoPEXSI", "diag"); matd h_mat, s_mat; phm_in->matrix(h_mat, s_mat); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); int ik = psi.get_current_k(); this->ps->prepare(this->ParaV->blacs_ctxt, this->ParaV->nb, diff --git a/source/module_hsolver/diago_pexsi.h b/source/module_hsolver/diago_pexsi.h index 657471a9e50..e593e3b6699 100644 --- a/source/module_hsolver/diago_pexsi.h +++ b/source/module_hsolver/diago_pexsi.h @@ -3,7 +3,8 @@ #include #include -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" #include "module_base/global_variable.h" #include "module_basis/module_ao/parallel_orbitals.h" #include "module_pexsi/pexsi_solver.h" @@ -12,7 +13,7 @@ namespace hsolver { template -class DiagoPexsi : public DiagH +class DiagoPexsi { private: using Real = typename GetTypeReal::type; @@ -20,7 +21,7 @@ class DiagoPexsi : public DiagH public: DiagoPexsi(const Parallel_Orbitals* ParaV_in); - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); const Parallel_Orbitals* ParaV; std::vector DM; std::vector EDM; diff --git a/source/module_hsolver/diago_scalapack.cpp b/source/module_hsolver/diago_scalapack.cpp index e2c187a9acb..d29e3241540 100644 --- a/source/module_hsolver/diago_scalapack.cpp +++ b/source/module_hsolver/diago_scalapack.cpp @@ -1,5 +1,6 @@ //===================== // AUTHOR : Peize Lin +#include "module_parameter/parameter.h" // DATE : 2021-11-02 // REFACTORING AUTHOR : Daye Zheng // DATE : 2022-04-14 @@ -27,10 +28,10 @@ namespace hsolver matd h_mat, s_mat; phm_in->matrix(h_mat, s_mat); assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); this->pdsygvx_diag(h_mat.desc, h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); } template<> void DiagoScalapack>::diag(hamilt::Hamilt>* phm_in, psi::Psi>& psi, Real* eigenvalue_in) @@ -39,10 +40,10 @@ namespace hsolver matcd h_mat, s_mat; phm_in->matrix(h_mat, s_mat); assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); this->pzhegvx_diag(h_mat.desc, h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); } #ifdef __MPI @@ -55,10 +56,10 @@ namespace hsolver { ModuleBase::TITLE("DiagoScalapack", "diag_pool"); assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); this->pdsygvx_diag(h_mat.desc, h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); } template<> void DiagoScalapack>::diag_pool(hamilt::MatrixBlock>& h_mat, @@ -69,10 +70,10 @@ namespace hsolver { ModuleBase::TITLE("DiagoScalapack", "diag_pool"); assert(h_mat.col == s_mat.col && h_mat.row == s_mat.row && h_mat.desc == s_mat.desc); - std::vector eigen(GlobalV::NLOCAL, 0.0); + std::vector eigen(PARAM.globalv.nlocal, 0.0); this->pzhegvx_diag(h_mat.desc, h_mat.col, h_mat.row, h_mat.p, s_mat.p, eigen.data(), psi); const int inc = 1; - BlasConnector::copy(GlobalV::NBANDS, eigen.data(), inc, eigenvalue_in, inc); + BlasConnector::copy(PARAM.inp.nbands, eigen.data(), inc, eigenvalue_in, inc); } #endif @@ -91,13 +92,13 @@ namespace hsolver memcpy(s_tmp.c, s_mat, sizeof(double) * ncol * nrow); const char jobz = 'V', range = 'I', uplo = 'U'; - const int itype = 1, il = 1, iu = GlobalV::NBANDS, one = 1; + const int itype = 1, il = 1, iu = PARAM.inp.nbands, one = 1; int M = 0, NZ = 0, lwork = -1, liwork = -1, info = 0; double vl = 0, vu = 0; const double abstol = 0, orfac = -1; std::vector work(3, 0); std::vector iwork(1, 0); - std::vector ifail(GlobalV::NLOCAL, 0); + std::vector ifail(PARAM.globalv.nlocal, 0); std::vector iclustr(2 * GlobalV::DSIZE); std::vector gap(GlobalV::DSIZE); @@ -105,7 +106,7 @@ namespace hsolver &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, &one, &one, @@ -151,7 +152,7 @@ namespace hsolver &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, &one, &one, @@ -216,7 +217,7 @@ namespace hsolver memcpy(s_tmp.c, s_mat, sizeof(std::complex) * ncol * nrow); const char jobz = 'V', range = 'I', uplo = 'U'; - const int itype = 1, il = 1, iu = GlobalV::NBANDS, one = 1; + const int itype = 1, il = 1, iu = PARAM.inp.nbands, one = 1; int M = 0, NZ = 0, lwork = -1, lrwork = -1, liwork = -1, info = 0; const double abstol = 0, orfac = -1; //Note: pzhegvx_ has a bug @@ -226,7 +227,7 @@ namespace hsolver std::vector> work(1, 0); std::vector rwork(3, 0); std::vector iwork(1, 0); - std::vector ifail(GlobalV::NLOCAL, 0); + std::vector ifail(PARAM.globalv.nlocal, 0); std::vector iclustr(2 * GlobalV::DSIZE); std::vector gap(GlobalV::DSIZE); @@ -234,7 +235,7 @@ namespace hsolver &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, &one, &one, @@ -275,7 +276,7 @@ namespace hsolver // GlobalV::ofs_running<<"lwork="<degeneracy_max * GlobalV::NLOCAL; + lrwork = rwork[0] + this->degeneracy_max * PARAM.globalv.nlocal; int maxlrwork = std::max(lrwork,3); rwork.resize(maxlrwork, 0); liwork = iwork[0]; @@ -285,7 +286,7 @@ namespace hsolver &jobz, &range, &uplo, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, h_tmp.c, &one, &one, @@ -430,7 +431,7 @@ namespace hsolver const std::string str_M = "M = " + ModuleBase::GlobalFunc::TO_STRING(vec[0]) + ".\n"; const std::string str_NZ = "NZ = " + ModuleBase::GlobalFunc::TO_STRING(vec[1]) + ".\n"; const std::string str_NBANDS - = "GlobalV::NBANDS = " + ModuleBase::GlobalFunc::TO_STRING(GlobalV::NBANDS) + ".\n"; + = "PARAM.inp.nbands = " + ModuleBase::GlobalFunc::TO_STRING(PARAM.inp.nbands) + ".\n"; throw std::runtime_error(str_info_FILE + str_M + str_NZ + str_NBANDS); } else if (info / 16 % 2) diff --git a/source/module_hsolver/diago_scalapack.h b/source/module_hsolver/diago_scalapack.h index 192fae841e8..1ac2e31ab4a 100644 --- a/source/module_hsolver/diago_scalapack.h +++ b/source/module_hsolver/diago_scalapack.h @@ -12,7 +12,9 @@ #include #include -#include "diagh.h" +#include "module_base/macros.h" // GetRealType +#include "module_hamilt_general/hamilt.h" +#include "module_psi/psi.h" #include "module_base/complexmatrix.h" #include "module_base/matrix.h" #include "module_basis/module_ao/parallel_orbitals.h" @@ -20,15 +22,15 @@ namespace hsolver { template - class DiagoScalapack : public DiagH + class DiagoScalapack { private: using Real = typename GetTypeReal::type; public: - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) override; + void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in); #ifdef __MPI // diagnolization used in parallel-k case - void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm) override; + void diag_pool(hamilt::MatrixBlock& h_mat, hamilt::MatrixBlock& s_mat, psi::Psi& psi, Real* eigenvalue_in, MPI_Comm& comm); #endif private: diff --git a/source/module_hsolver/genelpa/elpa_new.h b/source/module_hsolver/genelpa/elpa_new.h index b002ea0bb6a..ff1648ed858 100644 --- a/source/module_hsolver/genelpa/elpa_new.h +++ b/source/module_hsolver/genelpa/elpa_new.h @@ -2,6 +2,8 @@ #include + + #if ELPA_API_VERSION >= 20221101 #include #else @@ -25,8 +27,16 @@ extern "C" #include // #include #undef complex + const char *elpa_strerr(int elpa_error); + +// This is a header file related to GPU support. +// This header file was not available in the early ELPA. +#if ELPA_API_VERSION >= 20231101 +#include +#endif } + #include "elpa_generic.hpp" // This is a wrapper for `elpa/elpa_generic.h`. #endif diff --git a/source/module_hsolver/hsolver.cpp b/source/module_hsolver/hsolver.cpp index a0b54ed9d94..1d0edb0e565 100644 --- a/source/module_hsolver/hsolver.cpp +++ b/source/module_hsolver/hsolver.cpp @@ -1,5 +1,6 @@ #include "hsolver.h" +#include "module_parameter/parameter.h" namespace hsolver { @@ -110,7 +111,7 @@ double set_diagethr_sdft(const std::string basis_type, } else { - if (nband_in > 0 && stoiter_ks_ne_in > 1e-6) //GlobalV::NBANDS > 0 && this->stoiter.KS_ne > 1e-6 + if (nband_in > 0 && stoiter_ks_ne_in > 1e-6) //PARAM.inp.nbands > 0 && this->stoiter.KS_ne > 1e-6 { res_diag_ethr = std::min(res_diag_ethr, 0.1 * drho / std::max(1.0, stoiter_ks_ne_in)); } diff --git a/source/module_hsolver/hsolver.h b/source/module_hsolver/hsolver.h index 079132eaca8..593b0526c22 100644 --- a/source/module_hsolver/hsolver.h +++ b/source/module_hsolver/hsolver.h @@ -1,7 +1,6 @@ #ifndef HSOLVER_H #define HSOLVER_H -#include "diagh.h" #include "module_base/macros.h" #include "module_elecstate/elecstate.h" #include "module_hamilt_general/hamilt.h" diff --git a/source/module_hsolver/hsolver_lcao.cpp b/source/module_hsolver/hsolver_lcao.cpp index 833a26fe187..741398faada 100644 --- a/source/module_hsolver/hsolver_lcao.cpp +++ b/source/module_hsolver/hsolver_lcao.cpp @@ -1,134 +1,110 @@ #include "hsolver_lcao.h" -#include "module_parameter/parameter.h" -#include "diago_cg.h" - #ifdef __MPI #include "diago_scalapack.h" +#include "module_base/scalapack_connector.h" #else #include "diago_lapack.h" #endif -#include "module_base/timer.h" -#include "module_hsolver/diago_iter_assist.h" -#include "module_hsolver/kernels/math_kernel_op.h" -#include "module_io/write_HS.h" - -#include "module_base/global_variable.h" - -#include -#include -#include #ifdef __CUSOLVERMP #include "diago_cusolvermp.h" -#endif // __CUSOLVERMP +#endif + #ifdef __ELPA #include "diago_elpa.h" #include "diago_elpa_native.h" #endif + #ifdef __CUDA #include "diago_cusolver.h" #endif + #ifdef __PEXSI #include "diago_pexsi.h" #include "module_elecstate/elecstate_lcao.h" #endif -#include "module_base/scalapack_connector.h" -#include "module_hsolver/parallel_k2d.h" +#include "module_base/global_variable.h" #include "module_base/memory.h" +#include "module_base/timer.h" +#include "module_hsolver/parallel_k2d.h" +#include "module_parameter/parameter.h" -#include - -namespace hsolver { +namespace hsolver +{ template void HSolverLCAO::solve(hamilt::Hamilt* pHamilt, psi::Psi& psi, elecstate::ElecState* pes, - const std::string method_in, const bool skip_charge) { ModuleBase::TITLE("HSolverLCAO", "solve"); ModuleBase::timer::tick("HSolverLCAO", "solve"); - // select the method of diagonalization - this->method = method_in; -#ifdef __PEXSI // other purification methods should follow this routine - if (this->method == "pexsi") + if (this->method != "pexsi") { - DiagoPexsi pe(ParaV); - for (int ik = 0; ik < psi.get_nk(); ++ik) { - /// update H(k) for each k point - pHamilt->updateHk(ik); - psi.fix_k(ik); - // solve eigenvector and eigenvalue for H(k) - pe.diag(pHamilt, psi, nullptr); - } - auto _pes = dynamic_cast*>(pes); - pes->f_en.eband = pe.totalFreeEnergy; - // maybe eferm could be dealt with in the future - _pes->dmToRho(pe.DM, pe.EDM); - ModuleBase::timer::tick("HSolverLCAO", "solve"); - return; - } + if (GlobalV::KPAR_LCAO > 1 + && (this->method == "genelpa" || this->method == "elpa" || this->method == "scalapack_gvx")) + { +#ifdef __MPI + this->parakSolve(pHamilt, psi, pes, GlobalV::KPAR_LCAO); #endif + } + else if (GlobalV::KPAR_LCAO == 1) + { + /// Loop over k points for solve Hamiltonian to eigenpairs(eigenvalues and eigenvectors). + for (int ik = 0; ik < psi.get_nk(); ++ik) + { + /// update H(k) for each k point + pHamilt->updateHk(ik); - // Zhang Xiaoyang : Please modify Pesxi usage later - if (this->method == "cg_in_lcao") - { - this->precondition_lcao.resize(psi.get_nbasis()); + /// find psi pointer for each k point + psi.fix_k(ik); - using Real = typename GetTypeReal::type; - // set precondition - for (size_t i = 0; i < precondition_lcao.size(); i++) { - precondition_lcao[i] = 1.0; + /// solve eigenvector and eigenvalue for H(k) + this->hamiltSolvePsiK(pHamilt, psi, &(pes->ekb(ik, 0))); + } + } + else + { + ModuleBase::WARNING_QUIT("HSolverLCAO::solve", + "This method and KPAR setting is not supported for lcao basis in ABACUS!"); } - } -#ifdef __MPI - if (GlobalV::KPAR_LCAO > 1 && - (this->method == "genelpa" || this->method == "elpa" || this->method == "scalapack_gvx")) - { - this->parakSolve(pHamilt, psi, pes, GlobalV::KPAR_LCAO); + if (!skip_charge) + { + // used in scf calculation + // calculate charge by eigenpairs(eigenvalues and eigenvectors) + pes->psiToRho(psi); + } + else + { + // used in nscf calculation + } } - else -#endif + else if (this->method == "pexsi") { - /// Loop over k points for solve Hamiltonian to charge density - for (int ik = 0; ik < psi.get_nk(); ++ik) { +#ifdef __PEXSI // other purification methods should follow this routine + DiagoPexsi pe(ParaV); + for (int ik = 0; ik < psi.get_nk(); ++ik) + { /// update H(k) for each k point pHamilt->updateHk(ik); - psi.fix_k(ik); - // solve eigenvector and eigenvalue for H(k) - this->hamiltSolvePsiK(pHamilt, psi, &(pes->ekb(ik, 0))); + pe.diag(pHamilt, psi, nullptr); } + auto _pes = dynamic_cast*>(pes); + pes->f_en.eband = pe.totalFreeEnergy; + // maybe eferm could be dealt with in the future + _pes->dmToRho(pe.DM, pe.EDM); +#endif } - if (this->method == "cg_in_lcao") { - this->is_first_scf = false; - } - - if (this->method != "genelpa" && this->method != "elpa" && this->method != "scalapack_gvx" && this->method != "lapack" - && this->method != "cusolver" && this->method != "cusolvermp" && this->method != "cg_in_lcao" - && this->method != "pexsi") - { - //delete this->pdiagh; - //this->pdiagh = nullptr; - } - - // used in nscf calculation - if (skip_charge) { - ModuleBase::timer::tick("HSolverLCAO", "solve"); - return; - } - - // calculate charge by psi - // called in scf calculation - pes->psiToRho(psi); ModuleBase::timer::tick("HSolverLCAO", "solve"); + return; } template @@ -162,145 +138,24 @@ void HSolverLCAO::hamiltSolvePsiK(hamilt::Hamilt* hm, psi::Psi& DiagoCusolver cs(this->ParaV); cs.diag(hm, psi, eigenvalue); } +#ifdef __CUSOLVERMP else if (this->method == "cusolvermp") { -#ifdef __CUSOLVERMP DiagoCusolverMP cm; cm.diag(hm, psi, eigenvalue); -#else - ModuleBase::WARNING_QUIT("HSolverLCAO", "CUSOLVERMP did not compiled!"); -#endif } #endif - else if (this->method == "lapack") - { +#endif #ifndef __MPI + else if (this->method == "lapack") // only for single core + { DiagoLapack la; la.diag(hm, psi, eigenvalue); -#else - ModuleBase::WARNING_QUIT("HSolverLCAO::solve", "This method of DiagH is not supported!"); -#endif } +#endif else { - - using ct_Device = typename ct::PsiToContainer::type; - - auto subspace_func = [](const ct::Tensor& psi_in, ct::Tensor& psi_out) { - // psi_in should be a 2D tensor: - // psi_in.shape() = [nbands, nbasis] - const auto ndim = psi_in.shape().ndim(); - REQUIRES_OK(ndim == 2, "dims of psi_in should be less than or equal to 2"); - }; - - DiagoCG cg(PARAM.inp.basis_type, - PARAM.inp.calculation, - DiagoIterAssist::need_subspace, - subspace_func, - DiagoIterAssist::PW_DIAG_THR, - DiagoIterAssist::PW_DIAG_NMAX, - GlobalV::NPROC_IN_POOL); - - hamilt::MatrixBlock h_mat, s_mat; - hm->matrix(h_mat, s_mat); - - // set h_mat & s_mat - for (int i = 0; i < h_mat.row; i++) - { - for (int j = i; j < h_mat.col; j++) - { - h_mat.p[h_mat.row * j + i] = hsolver::get_conj(h_mat.p[h_mat.row * i + j]); - s_mat.p[s_mat.row * j + i] = hsolver::get_conj(s_mat.p[s_mat.row * i + j]); - } - } - - const T *one_ = nullptr, *zero_ = nullptr; - one_ = new T(static_cast(1.0)); - zero_ = new T(static_cast(0.0)); - - auto hpsi_func = [h_mat, one_, zero_](const ct::Tensor& psi_in, ct::Tensor& hpsi_out) { - ModuleBase::timer::tick("DiagoCG_New", "hpsi_func"); - // psi_in should be a 2D tensor: - // psi_in.shape() = [nbands, nbasis] - const auto ndim = psi_in.shape().ndim(); - REQUIRES_OK(ndim <= 2, "dims of psi_in should be less than or equal to 2"); - - Device* ctx = {}; - - gemv_op()(ctx, - 'N', - h_mat.row, - h_mat.col, - one_, - h_mat.p, - h_mat.row, - psi_in.data(), - 1, - zero_, - hpsi_out.data(), - 1); - - ModuleBase::timer::tick("DiagoCG_New", "hpsi_func"); - }; - - auto spsi_func = [s_mat, one_, zero_](const ct::Tensor& psi_in, ct::Tensor& spsi_out) { - ModuleBase::timer::tick("DiagoCG_New", "spsi_func"); - // psi_in should be a 2D tensor: - // psi_in.shape() = [nbands, nbasis] - const auto ndim = psi_in.shape().ndim(); - REQUIRES_OK(ndim <= 2, "dims of psi_in should be less than or equal to 2"); - - Device* ctx = {}; - - gemv_op()(ctx, - 'N', - s_mat.row, - s_mat.col, - one_, - s_mat.p, - s_mat.row, - psi_in.data(), - 1, - zero_, - spsi_out.data(), - 1); - - ModuleBase::timer::tick("DiagoCG_New", "spsi_func"); - }; - - if (this->is_first_scf) - { - for (size_t i = 0; i < psi.get_nbands(); i++) - { - for (size_t j = 0; j < psi.get_nbasis(); j++) - { - psi(i, j) = *zero_; - } - psi(i, i) = *one_; - } - } - - auto psi_tensor = ct::TensorMap(psi.get_pointer(), - ct::DataTypeToEnum::value, - ct::DeviceTypeToEnum::value, - ct::TensorShape({psi.get_nbands(), psi.get_nbasis()})) - .slice({0, 0}, {psi.get_nbands(), psi.get_current_nbas()}); - - auto eigen_tensor = ct::TensorMap(eigenvalue, - ct::DataTypeToEnum::value, - ct::DeviceTypeToEnum::value, - ct::TensorShape({psi.get_nbands()})); - - auto prec_tensor = ct::TensorMap(this->precondition_lcao.data(), - ct::DataTypeToEnum::value, - ct::DeviceTypeToEnum::value, - ct::TensorShape({static_cast(this->precondition_lcao.size())})) - .slice({0}, {psi.get_current_nbas()}); - - cg.diag(hpsi_func, spsi_func, psi_tensor, eigen_tensor, prec_tensor); - - // TODO: Double check tensormap's potential problem - ct::TensorMap(psi.get_pointer(), psi_tensor, {psi.get_nbands(), psi.get_nbasis()}).sync(psi_tensor); + ModuleBase::WARNING_QUIT("HSolverLCAO::solve", "This method is not supported for lcao basis in ABACUS!"); } ModuleBase::timer::tick("HSolverLCAO", "hamiltSolvePsiK"); @@ -308,9 +163,9 @@ void HSolverLCAO::hamiltSolvePsiK(hamilt::Hamilt* hm, psi::Psi& template void HSolverLCAO::parakSolve(hamilt::Hamilt* pHamilt, - psi::Psi& psi, - elecstate::ElecState* pes, - int kpar) + psi::Psi& psi, + elecstate::ElecState* pes, + int kpar) { #ifdef __MPI ModuleBase::timer::tick("HSolverLCAO", "parakSolve"); @@ -320,32 +175,33 @@ void HSolverLCAO::parakSolve(hamilt::Hamilt* pHamilt, int nks = psi.get_nk(); int nrow = this->ParaV->get_global_row_size(); int nb2d = this->ParaV->get_block_size(); - k2d.set_para_env(psi.get_nk(), - nrow, - nb2d, - GlobalV::NPROC, - GlobalV::MY_RANK, - PARAM.inp.nspin); + k2d.set_para_env(psi.get_nk(), nrow, nb2d, GlobalV::NPROC, GlobalV::MY_RANK, PARAM.inp.nspin); /// set psi_pool const int zero = 0; - int ncol_bands_pool = numroc_(&(nbands), &(nb2d), &(k2d.get_p2D_pool()->coord[1]), &zero, &(k2d.get_p2D_pool()->dim1)); + int ncol_bands_pool + = numroc_(&(nbands), &(nb2d), &(k2d.get_p2D_pool()->coord[1]), &zero, &(k2d.get_p2D_pool()->dim1)); /// Loop over k points for solve Hamiltonian to charge density for (int ik = 0; ik < k2d.get_pKpoints()->get_max_nks_pool(); ++ik) { // if nks is not equal to the number of k points in the pool std::vector ik_kpar; int ik_avail = 0; - for (int i = 0; i < k2d.get_kpar(); i++) { - if (ik + k2d.get_pKpoints()->startk_pool[i] < nks && ik < k2d.get_pKpoints()->nks_pool[i]) { + for (int i = 0; i < k2d.get_kpar(); i++) + { + if (ik + k2d.get_pKpoints()->startk_pool[i] < nks && ik < k2d.get_pKpoints()->nks_pool[i]) + { ik_avail++; } } - if (ik_avail == 0) { - ModuleBase::WARNING_QUIT("HSolverLCAO::solve", - "ik_avail is 0!"); - } else { + if (ik_avail == 0) + { + ModuleBase::WARNING_QUIT("HSolverLCAO::solve", "ik_avail is 0!"); + } + else + { ik_kpar.resize(ik_avail); - for (int i = 0; i < ik_avail; i++) { + for (int i = 0; i < ik_avail; i++) + { ik_kpar[i] = ik + k2d.get_pKpoints()->startk_pool[i]; } } @@ -359,31 +215,35 @@ void HSolverLCAO::parakSolve(hamilt::Hamilt* pHamilt, /// local psi in pool psi_pool.fix_k(0); hamilt::MatrixBlock hk_pool = hamilt::MatrixBlock{k2d.hk_pool.data(), - (size_t)k2d.get_p2D_pool()->get_row_size(), (size_t)k2d.get_p2D_pool()->get_col_size(), k2d.get_p2D_pool()->desc}; + (size_t)k2d.get_p2D_pool()->get_row_size(), + (size_t)k2d.get_p2D_pool()->get_col_size(), + k2d.get_p2D_pool()->desc}; hamilt::MatrixBlock sk_pool = hamilt::MatrixBlock{k2d.sk_pool.data(), - (size_t)k2d.get_p2D_pool()->get_row_size(), (size_t)k2d.get_p2D_pool()->get_col_size(), k2d.get_p2D_pool()->desc}; + (size_t)k2d.get_p2D_pool()->get_row_size(), + (size_t)k2d.get_p2D_pool()->get_col_size(), + k2d.get_p2D_pool()->desc}; /// solve eigenvector and eigenvalue for H(k) if (this->method == "scalapack_gvx") { DiagoScalapack sa; - sa.diag_pool(hk_pool, sk_pool, psi_pool,&(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); + sa.diag_pool(hk_pool, sk_pool, psi_pool, &(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); } #ifdef __ELPA else if (this->method == "genelpa") { DiagoElpa el; - el.diag_pool(hk_pool, sk_pool, psi_pool,&(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); + el.diag_pool(hk_pool, sk_pool, psi_pool, &(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); } else if (this->method == "elpa") { DiagoElpaNative el; - el.diag_pool(hk_pool, sk_pool, psi_pool,&(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); + el.diag_pool(hk_pool, sk_pool, psi_pool, &(pes->ekb(ik_global, 0)), k2d.POOL_WORLD_K2D); } #endif else { ModuleBase::WARNING_QUIT("HSolverLCAO::solve", - "This method of DiagH for k-parallelism diagnolization is not supported!"); + "This type of eigensolver for k-parallelism diagnolization is not supported!"); } } MPI_Barrier(MPI_COMM_WORLD); @@ -394,21 +254,22 @@ void HSolverLCAO::parakSolve(hamilt::Hamilt* pHamilt, MPI_Bcast(&(pes->ekb(ik_kpar[ipool], 0)), nbands, MPI_DOUBLE, source, MPI_COMM_WORLD); int desc_pool[9]; std::copy(k2d.get_p2D_pool()->desc, k2d.get_p2D_pool()->desc + 9, desc_pool); - if (k2d.get_my_pool() != ipool) { + if (k2d.get_my_pool() != ipool) + { desc_pool[1] = -1; } psi.fix_k(ik_kpar[ipool]); Cpxgemr2d(nrow, - nbands, - psi_pool.get_pointer(), - 1, - 1, - desc_pool, - psi.get_pointer(), - 1, - 1, - k2d.get_p2D_global()->desc, - k2d.get_p2D_global()->blacs_ctxt); + nbands, + psi_pool.get_pointer(), + 1, + 1, + desc_pool, + psi.get_pointer(), + 1, + 1, + k2d.get_p2D_global()->desc, + k2d.get_p2D_global()->blacs_ctxt); } MPI_Barrier(MPI_COMM_WORLD); ModuleBase::timer::tick("HSolverLCAO", "collect_psi"); diff --git a/source/module_hsolver/hsolver_lcao.h b/source/module_hsolver/hsolver_lcao.h index 8dbb3e52f8e..10b8817f955 100644 --- a/source/module_hsolver/hsolver_lcao.h +++ b/source/module_hsolver/hsolver_lcao.h @@ -16,24 +16,16 @@ class HSolverLCAO void solve(hamilt::Hamilt* pHamilt, psi::Psi& psi, elecstate::ElecState* pes, - const std::string method_in, const bool skip_charge); private: - void hamiltSolvePsiK(hamilt::Hamilt* hm, psi::Psi& psi, double* eigenvalue); + void hamiltSolvePsiK(hamilt::Hamilt* hm, psi::Psi& psi, double* eigenvalue); // for kpar_lcao == 1 - const Parallel_Orbitals* ParaV; - - void parakSolve(hamilt::Hamilt* pHamilt, psi::Psi& psi, elecstate::ElecState* pes, int kpar); - - bool is_first_scf = true; + void parakSolve(hamilt::Hamilt* pHamilt, psi::Psi& psi, elecstate::ElecState* pes, int kpar); // for kpar_lcao > 1 - using Real = typename GetTypeReal::type; - std::vector precondition_lcao; - - DiagH* pdiagh = nullptr; // for single Hamiltonian matrix diagonal solver - - std::string method = "none"; + const Parallel_Orbitals* ParaV; + + const std::string method; }; } // namespace hsolver diff --git a/source/module_hsolver/hsolver_lcaopw.cpp b/source/module_hsolver/hsolver_lcaopw.cpp index c1261ff6955..f5dc48fe673 100644 --- a/source/module_hsolver/hsolver_lcaopw.cpp +++ b/source/module_hsolver/hsolver_lcaopw.cpp @@ -8,7 +8,6 @@ #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_hamilt_pw/hamilt_pwdft/hamilt_pw.h" #include "module_hamilt_pw/hamilt_pwdft/wavefunc.h" -#include "module_hsolver/diagh.h" #include "module_hsolver/diago_iter_assist.h" #include "module_parameter/parameter.h" @@ -193,11 +192,6 @@ void HSolverLIP::paw_func_after_kloop(psi::Psi& psi, elecstate::ElecState* } #endif -template -HSolverLIP::HSolverLIP(ModulePW::PW_Basis_K* wfc_basis_in) -{ - this->wfc_basis = wfc_basis_in; -} /* lcao_in_pw diff --git a/source/module_hsolver/hsolver_lcaopw.h b/source/module_hsolver/hsolver_lcaopw.h index 1694e6c62b1..fd82e7b8eb6 100644 --- a/source/module_hsolver/hsolver_lcaopw.h +++ b/source/module_hsolver/hsolver_lcaopw.h @@ -18,7 +18,7 @@ class HSolverLIP using Real = typename GetTypeReal::type; public: - HSolverLIP(ModulePW::PW_Basis_K* wfc_basis_in); + HSolverLIP(ModulePW::PW_Basis_K* wfc_basis_in) : wfc_basis(wfc_basis_in) {}; /// @brief solve function for lcao_in_pw /// @param pHamilt interface to hamilt @@ -33,9 +33,7 @@ class HSolverLIP const bool skip_charge); private: - ModulePW::PW_Basis_K* wfc_basis = nullptr; - - std::vector eigenvalues; + ModulePW::PW_Basis_K* wfc_basis; #ifdef USE_PAW void paw_func_in_kloop(const int ik); diff --git a/source/module_hsolver/hsolver_pw.cpp b/source/module_hsolver/hsolver_pw.cpp index d20718b7f33..5b384ea3c57 100644 --- a/source/module_hsolver/hsolver_pw.cpp +++ b/source/module_hsolver/hsolver_pw.cpp @@ -208,12 +208,49 @@ void HSolverPW::paw_func_after_kloop(psi::Psi& psi, elecst #endif +template +void HSolverPW::cal_ethr_band(const double& wk, const double* wg, const double& ethr, std::vector& ethrs) +{ + // threshold for classifying occupied and unoccupied bands + const double occ_threshold = 1e-2; + // diagonalization threshold limitation for unoccupied bands + const double ethr_limit = 1e-5; + if(wk > 0.0) + { + // Note: the idea of threshold for unoccupied bands (1e-5) comes from QE + // In ABACUS, We applied a smoothing process to this truncation to avoid abrupt changes in energy errors between different bands. + const double ethr_unocc = std::max(ethr_limit, ethr); + for (int i = 0; i < ethrs.size(); i++) + { + double band_weight = wg[i] / wk; + if (band_weight > occ_threshold) + { + ethrs[i] = ethr; + } + else if(band_weight > ethr_limit) + {// similar energy difference for different bands when band_weight in range [1e-5, 1e-2] + ethrs[i] = std::min(ethr_unocc, ethr / band_weight); + } + else + { + ethrs[i] = ethr_unocc; + } + } + } + else + { + for (int i = 0; i < ethrs.size(); i++) + { + ethrs[i] = ethr; + } + } +} + template void HSolverPW::solve(hamilt::Hamilt* pHamilt, psi::Psi& psi, elecstate::ElecState* pes, double* out_eigenvalues, - const std::vector& is_occupied_in, const int rank_in_pool_in, const int nproc_in_pool_in, const bool skip_charge) @@ -228,13 +265,13 @@ void HSolverPW::solve(hamilt::Hamilt* pHamilt, const std::initializer_list _methods = {"cg", "dav", "dav_subspace", "bpcg"}; if (std::find(std::begin(_methods), std::end(_methods), this->method) == std::end(_methods)) { - ModuleBase::WARNING_QUIT("HSolverPW::solve", "This method of DiagH is not supported!"); + ModuleBase::WARNING_QUIT("HSolverPW::solve", "This type of eigensolver is not supported!"); } // prepare for the precondition of diagonalization std::vector precondition(psi.get_nbasis(), 0.0); - // std::vector eigenvalues(pes->ekb.nr * pes->ekb.nc, 0.0); std::vector eigenvalues(this->wfc_basis->nks * psi.get_nbands(), 0.0); + ethr_band.resize(psi.get_nbands(), DiagoIterAssist::PW_DIAG_THR); /// Loop over k points for solve Hamiltonian to charge density for (int ik = 0; ik < this->wfc_basis->nks; ++ik) @@ -249,7 +286,17 @@ void HSolverPW::solve(hamilt::Hamilt* pHamilt, this->updatePsiK(pHamilt, psi, ik); // template add precondition calculating here - update_precondition(precondition, ik, this->wfc_basis->npwk[ik]); + update_precondition(precondition, ik, this->wfc_basis->npwk[ik], Real(pes->pot->get_vl_of_0())); + + // only dav_subspace method used smooth threshold for all bands now, + // for other methods, this trick can be added in the future to accelerate calculation without accuracy loss. + if (this->method == "dav_subspace") + { + this->cal_ethr_band(pes->klist->wk[ik], + &pes->wg(ik, 0), + DiagoIterAssist::PW_DIAG_THR, + ethr_band); + } #ifdef USE_PAW this->call_paw_cell_set_currentk(ik); @@ -323,7 +370,7 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, if (this->method == "cg") { - // warp the subspace_func into a lambda function + // wrap the subspace_func into a lambda function auto ngk_pointer = psi.get_ngk_pointer(); auto subspace_func = [hm, ngk_pointer](const ct::Tensor& psi_in, ct::Tensor& psi_out) { // psi_in should be a 2D tensor: @@ -355,10 +402,10 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, this->diag_iter_max, this->nproc_in_pool); - // warp the hpsi_func and spsi_func into a lambda function + // wrap the hpsi_func and spsi_func into a lambda function using ct_Device = typename ct::PsiToContainer::type; - // warp the hpsi_func and spsi_func into a lambda function + // wrap the hpsi_func and spsi_func into a lambda function auto hpsi_func = [hm, ngk_pointer](const ct::Tensor& psi_in, ct::Tensor& hpsi_out) { ModuleBase::timer::tick("DiagoCG_New", "hpsi_func"); // psi_in should be a 2D tensor: @@ -434,18 +481,17 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, else if (this->method == "dav_subspace") { auto ngk_pointer = psi.get_ngk_pointer(); - auto hpsi_func = [hm, ngk_pointer](T* psi_in, - T* hpsi_out, - const int nband_in, - const int nbasis_in, - const int band_index1, - const int band_index2) { + // hpsi_func (X, HX, ld, nvec) -> HX = H(X), X and HX blockvectors of size ld x nvec + auto hpsi_func = [hm, ngk_pointer](T *psi_in, + T *hpsi_out, + const int ld_psi, + const int nvec) { ModuleBase::timer::tick("DavSubspace", "hpsi_func"); // Convert "pointer data stucture" to a psi::Psi object - auto psi_iter_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_in, ngk_pointer); + auto psi_iter_wrapper = psi::Psi(psi_in, 1, nvec, ld_psi, ngk_pointer); - psi::Range bands_range(true, 0, band_index1, band_index2); + psi::Range bands_range(true, 0, 0, nvec-1); using hpsi_info = typename hamilt::Operator::hpsi_info; hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); @@ -454,7 +500,6 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, ModuleBase::timer::tick("DavSubspace", "hpsi_func"); }; bool scf = this->calculation_type == "nscf" ? false : true; - const std::vector is_occupied(psi.get_nbands(), true); Diago_DavSubspace dav_subspace(pre_condition, psi.get_nbands(), @@ -466,8 +511,8 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, this->need_subspace, comm_info); - DiagoIterAssist::avg_iter += static_cast( - dav_subspace.diag(hpsi_func, psi.get_pointer(), psi.get_nbasis(), eigenvalue, is_occupied, scf)); + DiagoIterAssist::avg_iter + += static_cast(dav_subspace.diag(hpsi_func, psi.get_pointer(), psi.get_nbasis(), eigenvalue, this->ethr_band.data(), scf)); } else if (this->method == "dav") { @@ -486,25 +531,23 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, // dimensions of matrix to be solved const int dim = psi.get_current_nbas(); /// dimension of matrix const int nband = psi.get_nbands(); /// number of eigenpairs sought - const int ldPsi = psi.get_nbasis(); /// leading dimension of psi + const int ld_psi = psi.get_nbasis(); /// leading dimension of psi // Davidson matrix-blockvector functions auto ngk_pointer = psi.get_ngk_pointer(); /// wrap hpsi into lambda function, Matrix \times blockvector - /// hpsi(X, HX, nband, dim, band_index1, band_index2) - auto hpsi_func = [hm, ngk_pointer](T* psi_in, - T* hpsi_out, - const int nband_in, - const int nbasis_in, - const int band_index1, - const int band_index2) { + // hpsi_func (X, HX, ld, nvec) -> HX = H(X), X and HX blockvectors of size ld x nvec + auto hpsi_func = [hm, ngk_pointer](T *psi_in, + T *hpsi_out, + const int ld_psi, + const int nvec) { ModuleBase::timer::tick("David", "hpsi_func"); - // Convert "pointer data stucture" to a psi::Psi object - auto psi_iter_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_in, ngk_pointer); + // Convert pointer of psi_in to a psi::Psi object + auto psi_iter_wrapper = psi::Psi(psi_in, 1, nvec, ld_psi, ngk_pointer); - psi::Range bands_range(true, 0, band_index1, band_index2); + psi::Range bands_range(true, 0, 0, nvec-1); using hpsi_info = typename hamilt::Operator::hpsi_info; hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); @@ -514,15 +557,16 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, }; /// wrap spsi into lambda function, Matrix \times blockvector - /// spsi(X, SX, nrow, npw, nbands) + /// spsi(X, SX, ld, nvec) + /// ld is leading dimension of psi and spsi auto spsi_func = [hm](const T* psi_in, T* spsi_out, - const int nrow, // dimension of spsi: nbands * nrow - const int npw, // number of plane waves - const int nbands // number of bands + const int ld_psi, // Leading dimension of psi and spsi. + const int nvec // Number of vectors(bands) ){ ModuleBase::timer::tick("David", "spsi_func"); - // sPsi determines S=I or not by GlobalV::use_uspp inside - hm->sPsi(psi_in, spsi_out, nrow, npw, nbands); + // sPsi determines S=I or not by PARAM.globalv.use_uspp inside + // sPsi(psi, spsi, nrow, npw, nbands) + hm->sPsi(psi_in, spsi_out, ld_psi, ld_psi, nvec); ModuleBase::timer::tick("David", "spsi_func"); }; @@ -535,7 +579,7 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, // do diag and add davidson iteration counts up to avg_iter DiagoIterAssist::avg_iter += static_cast(david.diag(hpsi_func, spsi_func, - ldPsi, + ld_psi, psi.get_pointer(), eigenvalue, david_diag_thr, @@ -547,7 +591,7 @@ void HSolverPW::hamiltSolvePsiK(hamilt::Hamilt* hm, } template -void HSolverPW::update_precondition(std::vector& h_diag, const int ik, const int npw) +void HSolverPW::update_precondition(std::vector& h_diag, const int ik, const int npw, const Real vl_of_0) { h_diag.assign(h_diag.size(), 1.0); int precondition_type = 2; @@ -574,7 +618,7 @@ void HSolverPW::update_precondition(std::vector& h_diag, const if (this->method == "dav_subspace") { - h_diag[ig] = g2kin; + h_diag[ig] = g2kin + vl_of_0; } else { diff --git a/source/module_hsolver/hsolver_pw.h b/source/module_hsolver/hsolver_pw.h index e4b220fbc1c..a9ccac33806 100644 --- a/source/module_hsolver/hsolver_pw.h +++ b/source/module_hsolver/hsolver_pw.h @@ -12,7 +12,7 @@ namespace hsolver template class HSolverPW { - private: + protected: // Note GetTypeReal::type will // return T if T is real type(float, double), // otherwise return the real type of T(complex, complex) @@ -21,20 +21,17 @@ class HSolverPW public: HSolverPW(ModulePW::PW_Basis_K* wfc_basis_in, wavefunc* pwf_in, - const std::string calculation_type_in, const std::string basis_type_in, const std::string method_in, const bool use_paw_in, const bool use_uspp_in, const int nspin_in, - const int scf_iter_in, const int diag_iter_max_in, const double diag_thr_in, const bool need_subspace_in, const bool initialed_psi_in) - : wfc_basis(wfc_basis_in), pwf(pwf_in), calculation_type(calculation_type_in), basis_type(basis_type_in), method(method_in), use_paw(use_paw_in), use_uspp(use_uspp_in), nspin(nspin_in), @@ -51,7 +48,6 @@ class HSolverPW psi::Psi& psi, elecstate::ElecState* pes, double* out_eigenvalues, - const std::vector& is_occupied_in, const int rank_in_pool_in, const int nproc_in_pool_in, const bool skip_charge); @@ -67,7 +63,7 @@ class HSolverPW void updatePsiK(hamilt::Hamilt* pHamilt, psi::Psi& psi, const int ik); // calculate the precondition array for diagonalization in PW base - void update_precondition(std::vector& h_diag, const int ik, const int npw); + void update_precondition(std::vector& h_diag, const int ik, const int npw, const Real vl_of_0); void output_iterInfo(); @@ -88,12 +84,17 @@ class HSolverPW const bool need_subspace; // for cg or dav_subspace const bool initialed_psi; - private: + protected: Device* ctx = {}; int rank_in_pool = 0; int nproc_in_pool = 1; + private: + /// @brief calculate the threshold for iterative-diagonalization for each band + void cal_ethr_band(const double& wk, const double* wg, const double& ethr, std::vector& ethrs); + std::vector ethr_band; + #ifdef USE_PAW void paw_func_in_kloop(const int ik); diff --git a/source/module_hsolver/hsolver_pw_sdft.cpp b/source/module_hsolver/hsolver_pw_sdft.cpp index 0f15879bb1b..d71e23d29b0 100644 --- a/source/module_hsolver/hsolver_pw_sdft.cpp +++ b/source/module_hsolver/hsolver_pw_sdft.cpp @@ -9,15 +9,15 @@ namespace hsolver { - -void HSolverPW_SDFT::solve(hamilt::Hamilt>* pHamilt, - psi::Psi>& psi, - elecstate::ElecState* pes, - ModulePW::PW_Basis_K* wfc_basis, - Stochastic_WF& stowf, - const int istep, - const int iter, - const bool skip_charge) +template +void HSolverPW_SDFT::solve(hamilt::Hamilt* pHamilt, + psi::Psi& psi, + elecstate::ElecState* pes, + ModulePW::PW_Basis_K* wfc_basis, + Stochastic_WF& stowf, + const int istep, + const int iter, + const bool skip_charge) { ModuleBase::TITLE("HSolverPW_SDFT", "solve"); ModuleBase::timer::tick("HSolverPW_SDFT", "solve"); @@ -33,7 +33,7 @@ void HSolverPW_SDFT::solve(hamilt::Hamilt>* pHamilt, const std::initializer_list _methods = {"cg", "dav", "dav_subspace", "bpcg"}; if (std::find(std::begin(_methods), std::end(_methods), this->method) == std::end(_methods)) { - ModuleBase::WARNING_QUIT("HSolverPW::solve", "This method of DiagH is not supported!"); + ModuleBase::WARNING_QUIT("HSolverPW::solve", "This type of eigensolver is not supported!"); } // part of KSDFT to get KS orbitals @@ -44,14 +44,12 @@ void HSolverPW_SDFT::solve(hamilt::Hamilt>* pHamilt, { this->updatePsiK(pHamilt, psi, ik); // template add precondition calculating here - update_precondition(precondition, ik, this->wfc_basis->npwk[ik]); + this->update_precondition(precondition, ik, this->wfc_basis->npwk[ik], pes->pot->get_vl_of_0()); /// solve eigenvector and eigenvalue for H(k) double* p_eigenvalues = &(pes->ekb(ik, 0)); this->hamiltSolvePsiK(pHamilt, psi, precondition, p_eigenvalues); } - stoiter.stohchi.current_ik = ik; - #ifdef __MPI if (nbands > 0) { @@ -64,19 +62,21 @@ void HSolverPW_SDFT::solve(hamilt::Hamilt>* pHamilt, } this->output_iterInfo(); - + for (int ik = 0; ik < nks; ik++) { // init k if (nks > 1) { - pHamilt->updateHk(ik); + pHamilt->updateHk(ik); // necessary , because emax and emin should be decided first } - stoiter.stohchi.current_ik = ik; stoiter.calPn(ik, stowf); } + // iterate to get mu stoiter.itermu(iter, pes); + + // prepare sqrt{f(\hat{H})}|\chi> to calculate density, force and stress stoiter.calHsqrtchi(stowf); if (skip_charge) { @@ -107,4 +107,6 @@ void HSolverPW_SDFT::solve(hamilt::Hamilt>* pHamilt, return; } +// template class HSolverPW_SDFT, base_device::DEVICE_CPU>; +template class HSolverPW_SDFT, base_device::DEVICE_CPU>; } // namespace hsolver \ No newline at end of file diff --git a/source/module_hsolver/hsolver_pw_sdft.h b/source/module_hsolver/hsolver_pw_sdft.h index aa342b03e1b..6fc0a39fec7 100644 --- a/source/module_hsolver/hsolver_pw_sdft.h +++ b/source/module_hsolver/hsolver_pw_sdft.h @@ -1,59 +1,58 @@ #ifndef HSOLVERPW_SDFT_H #define HSOLVERPW_SDFT_H #include "hsolver_pw.h" +#include "module_hamilt_pw/hamilt_stodft/hamilt_sdft_pw.h" #include "module_hamilt_pw/hamilt_stodft/sto_iter.h" namespace hsolver { -class HSolverPW_SDFT : public HSolverPW> +template +class HSolverPW_SDFT : public HSolverPW { public: HSolverPW_SDFT(K_Vectors* pkv, ModulePW::PW_Basis_K* wfc_basis_in, wavefunc* pwf_in, - Stochastic_WF& stowf, + Stochastic_WF& stowf, StoChe& stoche, - + hamilt::HamiltSdftPW* p_hamilt_sto, const std::string calculation_type_in, const std::string basis_type_in, const std::string method_in, const bool use_paw_in, const bool use_uspp_in, const int nspin_in, - const int scf_iter_in, const int diag_iter_max_in, const double diag_thr_in, - const bool need_subspace_in, const bool initialed_psi_in) - - : HSolverPW(wfc_basis_in, - pwf_in, - calculation_type_in, - basis_type_in, - method_in, - use_paw_in, - use_uspp_in, - nspin_in, - scf_iter_in, - diag_iter_max_in, - diag_thr_in, - need_subspace_in, - initialed_psi_in) + : HSolverPW(wfc_basis_in, + pwf_in, + calculation_type_in, + basis_type_in, + method_in, + use_paw_in, + use_uspp_in, + nspin_in, + scf_iter_in, + diag_iter_max_in, + diag_thr_in, + need_subspace_in, + initialed_psi_in) { - stoiter.init(pkv, wfc_basis_in, stowf, stoche); + stoiter.init(pkv, wfc_basis_in, stowf, stoche, p_hamilt_sto); } - virtual void solve(hamilt::Hamilt>* pHamilt, - psi::Psi>& psi, - elecstate::ElecState* pes, - ModulePW::PW_Basis_K* wfc_basis, - Stochastic_WF& stowf, - const int istep, - const int iter, - const bool skip_charge); + void solve(hamilt::Hamilt* pHamilt, + psi::Psi& psi, + elecstate::ElecState* pes, + ModulePW::PW_Basis_K* wfc_basis, + Stochastic_WF& stowf, + const int istep, + const int iter, + const bool skip_charge); - Stochastic_Iter stoiter; + Stochastic_Iter stoiter; }; } // namespace hsolver #endif \ No newline at end of file diff --git a/source/module_hsolver/kernels/cuda/diag_cusolver.cuh b/source/module_hsolver/kernels/cuda/diag_cusolver.cuh index ad9ba46eeb1..557cf9c3bd3 100644 --- a/source/module_hsolver/kernels/cuda/diag_cusolver.cuh +++ b/source/module_hsolver/kernels/cuda/diag_cusolver.cuh @@ -21,28 +21,28 @@ class Diag_Cusolver_gvd{ // private variables //------------------- - cusolverDnHandle_t cusolverH; + cusolverDnHandle_t cusolverH = nullptr; - cusolverEigType_t itype; //problem type: A*x = (lambda)*B*x - cusolverEigMode_t jobz; // compute eigenvalues and eigenvectors. - cublasFillMode_t uplo; + cusolverEigType_t itype = CUSOLVER_EIG_TYPE_1; //problem type: A*x = (lambda)*B*x + cusolverEigMode_t jobz = CUSOLVER_EIG_MODE_NOVECTOR; // compute eigenvalues and eigenvectors. + cublasFillMode_t uplo = CUBLAS_FILL_MODE_LOWER; - int m; - int lda; + int m = 0; + int lda = 0; - double *d_A; - double *d_B; - double *d_work; + double *d_A = nullptr; + double *d_B = nullptr; + double *d_work = nullptr; - cuDoubleComplex *d_A2; - cuDoubleComplex *d_B2; - cuDoubleComplex *d_work2; + cuDoubleComplex *d_A2 = nullptr; + cuDoubleComplex *d_B2 = nullptr; + cuDoubleComplex *d_work2 = nullptr; - double *d_W ; - int *devInfo; + double *d_W = nullptr; + int *devInfo = nullptr; - int lwork; - int info_gpu; + int lwork = 0; + int info_gpu = 0; // subroutines that are related to initializing the class: // - init_double : initializing relevant double type data structures and gpu apis' handle and memory @@ -55,7 +55,7 @@ class Diag_Cusolver_gvd{ void finalize(); // for recycling the usage of the static class Diag_Cusolver_gvd public: - int is_init; // For expensive gpu initialization only once when using cusolver for lcao + int is_init = 0; // For expensive gpu initialization only once when using cusolver for lcao Diag_Cusolver_gvd(); ~Diag_Cusolver_gvd(); diff --git a/source/module_hsolver/kernels/cuda/diag_cusolvermp.cu b/source/module_hsolver/kernels/cuda/diag_cusolvermp.cu index a0f74421856..25975e63035 100644 --- a/source/module_hsolver/kernels/cuda/diag_cusolvermp.cu +++ b/source/module_hsolver/kernels/cuda/diag_cusolvermp.cu @@ -10,13 +10,15 @@ extern "C" #include "module_hsolver/genelpa/Cblacs.h" } #include +#include #include "helper_cusolver.h" #include "module_base/global_function.h" #include "module_base/module_device/device.h" static calError_t allgather(void* src_buf, void* recv_buf, size_t size, void* data, void** request) { MPI_Request req; - int err = MPI_Iallgather(src_buf, size, MPI_BYTE, recv_buf, size, MPI_BYTE, (MPI_Comm)(data), &req); + intptr_t ptr = reinterpret_cast(data); + int err = MPI_Iallgather(src_buf, size, MPI_BYTE, recv_buf, size, MPI_BYTE, (MPI_Comm)ptr, &req); if (err != MPI_SUCCESS) { return CAL_ERROR; @@ -27,7 +29,8 @@ static calError_t allgather(void* src_buf, void* recv_buf, size_t size, void* da static calError_t request_test(void* request) { - MPI_Request req = (MPI_Request)(request); + intptr_t ptr = reinterpret_cast(request); + MPI_Request req = (MPI_Request)ptr; int completed; int err = MPI_Test(&req, &completed, MPI_STATUS_IGNORE); if (err != MPI_SUCCESS) diff --git a/source/module_hsolver/kernels/math_kernel_op.cpp b/source/module_hsolver/kernels/math_kernel_op.cpp index 3ad19bd4cc7..02deb41696d 100644 --- a/source/module_hsolver/kernels/math_kernel_op.cpp +++ b/source/module_hsolver/kernels/math_kernel_op.cpp @@ -281,6 +281,30 @@ struct gemm_op } }; +#ifdef __DSP +template +struct gemm_op_mt +{ + void operator()(const base_device::DEVICE_CPU* /*ctx*/, + const char& transa, + const char& transb, + const int& m, + const int& n, + const int& k, + const T* alpha, + const T* a, + const int& lda, + const T* b, + const int& ldb, + const T* beta, + T* c, + const int& ldc) + { + BlasConnector::gemm(transb, transa, n, m, k, *alpha, b, ldb, a, lda, *beta, c, ldc, base_device::AbacusDevice_t::DspDevice); + } +}; +#endif + template struct matrixTranspose_op { @@ -372,4 +396,8 @@ template struct matrixTranspose_op; template struct matrixSetToAnother; template struct constantvector_addORsub_constantVector_op; #endif +#ifdef __DSP +template struct gemm_op_mt, base_device::DEVICE_CPU>; +template struct gemm_op_mt, base_device::DEVICE_CPU>; +#endif } // namespace hsolver \ No newline at end of file diff --git a/source/module_hsolver/kernels/math_kernel_op.h b/source/module_hsolver/kernels/math_kernel_op.h index a23c9c329f1..0daf0e57187 100644 --- a/source/module_hsolver/kernels/math_kernel_op.h +++ b/source/module_hsolver/kernels/math_kernel_op.h @@ -264,6 +264,36 @@ template struct gemm_op { const T *beta, T *c, const int &ldc); }; +#ifdef __DSP +// compute C = alpha * op(A) * op(B) + beta * C on DSP Hardware +template struct gemm_op_mt { + /// @brief C = alpha * op(A) * op(B) + beta * C + /// + /// Input Parameters + /// \param d : the type of computing device + /// \param transa : whether to transpose matrix A + /// \param transb : whether to transpose matrix B + /// \param m : first dimension of matrix mulplication + /// \param n : second dimension of matrix mulplication + /// \param k : third dimension of matrix mulplication + /// \param alpha : input constant alpha + /// \param a : input matrix A + /// \param lda : leading dimention of A + /// \param b : input matrix B + /// \param ldb : leading dimention of A + /// \param beta : input constant beta + /// \param c : input matrix C + /// \param ldc : leading dimention of C + /// + /// Output Parameters + /// \param c : output matrix C + void operator()(const Device *d, const char &transa, const char &transb, + const int &m, const int &n, const int &k, const T *alpha, + const T *a, const int &lda, const T *b, const int &ldb, + const T *beta, T *c, const int &ldc); +}; +#endif + template struct matrixTranspose_op { /// @brief transpose the input matrix /// diff --git a/source/module_hsolver/kernels/test/CMakeLists.txt b/source/module_hsolver/kernels/test/CMakeLists.txt index 74d73364ce6..c8d1f2cdd91 100644 --- a/source/module_hsolver/kernels/test/CMakeLists.txt +++ b/source/module_hsolver/kernels/test/CMakeLists.txt @@ -11,7 +11,7 @@ elseif() AddTest( TARGET Hsolver_Kernels_UTs LIBS parameter ${math_libs} base device - SOURCES math_kernel_test.cpp + SOURCES math_kernel_test.cpp ../../../module_base/blas_connector.cpp ) endif() diff --git a/source/module_hsolver/module_pexsi/pexsi_solver.cpp b/source/module_hsolver/module_pexsi/pexsi_solver.cpp index 7a71e6ca012..e830eb2eaff 100644 --- a/source/module_hsolver/module_pexsi/pexsi_solver.cpp +++ b/source/module_hsolver/module_pexsi/pexsi_solver.cpp @@ -1,5 +1,6 @@ #include "module_base/parallel_global.h" #ifdef __PEXSI +#include "module_parameter/parameter.h" #include "pexsi_solver.h" #include @@ -78,14 +79,14 @@ int PEXSI_Solver::solve(double mu0) DIAG_WORLD, grid_group, this->blacs_text, - GlobalV::NLOCAL, + PARAM.globalv.nlocal, this->nb, this->nrow, this->ncol, 'c', this->h, this->s, - GlobalV::nelec, + PARAM.inp.nelec, "PEXSIOPTION", this->DM, this->EDM, diff --git a/source/module_hsolver/test/diago_david_float_test.cpp b/source/module_hsolver/test/diago_david_float_test.cpp index 20d50d4a603..da52b7272b3 100644 --- a/source/module_hsolver/test/diago_david_float_test.cpp +++ b/source/module_hsolver/test/diago_david_float_test.cpp @@ -46,8 +46,10 @@ void lapackEigen(int &npw, std::vector> &hm, float * e, bool char tmp_c1 = 'V', tmp_c2 = 'U'; cheev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, rwork, &info); end = clock(); - if(info) std::cout << "ERROR: Lapack solver, info=" << info <> dav(precondition, nband, dim, order, false, comm_info); hsolver::DiagoIterAssist>::PW_DIAG_NMAX = maxiter; @@ -108,19 +111,18 @@ class DiagoDavPrepare auto hpsi_func = [phm](std::complex* psi_in,std::complex* hpsi_out, - const int nband_in, const int nbasis_in, - const int band_index1, const int band_index2) + const int ld_psi, const int nvec) { - auto psi_iter_wrapper = psi::Psi>(psi_in, 1, nband_in, nbasis_in, nullptr); - psi::Range bands_range(1, 0, band_index1, band_index2); + auto psi_iter_wrapper = psi::Psi>(psi_in, 1, nvec, ld_psi, nullptr); + psi::Range bands_range(true, 0, 0, nvec-1); using hpsi_info = typename hamilt::Operator>::hpsi_info; hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); phm->ops->hPsi(info); }; - auto spsi_func = [phm](const std::complex* psi_in, std::complex* spsi_out,const int nrow, const int npw, const int nbands){ - phm->sPsi(psi_in, spsi_out, nrow, npw, nbands); + auto spsi_func = [phm](const std::complex* psi_in, std::complex* spsi_out,const int ld_psi, const int nbands){ + phm->sPsi(psi_in, spsi_out, ld_psi, ld_psi, nbands); }; - dav.diag(hpsi_func,spsi_func, ldPsi, phi.get_pointer(), en, eps, maxiter); + dav.diag(hpsi_func,spsi_func, ld_psi, phi.get_pointer(), en, eps, maxiter); #ifdef __MPI end = MPI_Wtime(); @@ -132,7 +134,8 @@ class DiagoDavPrepare if(mypnum == 0) { - if (DETAILINFO) std::cout<<"diag Run time: "<< use_time << std::endl; + if (DETAILINFO) { std::cout<<"diag Run time: "<< use_time << std::endl; +} for(int i=0;i {}; TEST_P(DiagoDavTest,RandomHamilt) { DiagoDavPrepare ddp = GetParam(); - if (DETAILINFO&&ddp.mypnum==0) std::cout << "npw=" << ddp.npw << ", nband=" << ddp.nband << ", sparsity=" + if (DETAILINFO&&ddp.mypnum==0) { std::cout << "npw=" << ddp.npw << ", nband=" << ddp.nband << ", sparsity=" << ddp.sparsity << ", eps=" << ddp.eps << std::endl; +} HPsi> hpsi(ddp.nband, ddp.npw, ddp.sparsity); DIAGOTEST::hmatrix_f = hpsi.hamilt(); @@ -237,7 +241,8 @@ int main(int argc, char **argv) testing::InitGoogleTest(&argc, argv); ::testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners(); - if (myrank != 0) delete listeners.Release(listeners.default_result_printer()); + if (myrank != 0) { delete listeners.Release(listeners.default_result_printer()); +} int result = RUN_ALL_TESTS(); if (myrank == 0 && result != 0) diff --git a/source/module_hsolver/test/diago_david_real_test.cpp b/source/module_hsolver/test/diago_david_real_test.cpp index a5be15ba70c..e451d45fbe2 100644 --- a/source/module_hsolver/test/diago_david_real_test.cpp +++ b/source/module_hsolver/test/diago_david_real_test.cpp @@ -48,8 +48,10 @@ void lapackEigen(int& npw, std::vector& hm, double* e, bool outtime = fa double* work2 = new double[lwork]; dsyev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, &info); end = clock(); - if (info) std::cout << "ERROR: Lapack solver, info=" << info << std::endl; - if (outtime) std::cout << "Lapack Run time: " << (double)(end - start) / CLOCKS_PER_SEC << " S" << std::endl; + if (info) { std::cout << "ERROR: Lapack solver, info=" << info << std::endl; +} + if (outtime) { std::cout << "Lapack Run time: " << (double)(end - start) / CLOCKS_PER_SEC << " S" << std::endl; +} delete[] work2; } class DiagoDavPrepare @@ -73,7 +75,8 @@ class DiagoDavPrepare //calculate eigenvalues by LAPACK; double* e_lapack = new double[npw]; double* ev; - if (mypnum == 0) lapackEigen(npw, DIAGOTEST::hmatrix_d, e_lapack, DETAILINFO); + if (mypnum == 0) { lapackEigen(npw, DIAGOTEST::hmatrix_d, e_lapack, DETAILINFO); +} //do Diago_David::diag() double* en = new double[npw]; @@ -88,7 +91,7 @@ class DiagoDavPrepare const int dim = phi.get_current_nbas(); const int nband = phi.get_nbands(); - const int ldPsi = phi.get_nbasis(); + const int ld_psi = phi.get_nbasis(); hsolver::DiagoDavid dav(precondition, nband, dim, order, false, comm_info); hsolver::DiagoIterAssist::PW_DIAG_NMAX = maxiter; @@ -107,19 +110,18 @@ class DiagoDavPrepare auto hpsi_func = [phm](double* psi_in,double* hpsi_out, - const int nband_in, const int nbasis_in, - const int band_index1, const int band_index2) + const int ld_psi, const int nvec) { - auto psi_iter_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_in, nullptr); - psi::Range bands_range(1, 0, band_index1, band_index2); + auto psi_iter_wrapper = psi::Psi(psi_in, 1, nvec, ld_psi, nullptr); + psi::Range bands_range(true, 0, 0, nvec-1); using hpsi_info = typename hamilt::Operator::hpsi_info; hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); phm->ops->hPsi(info); }; - auto spsi_func = [phm](const double* psi_in, double* spsi_out,const int nrow, const int npw, const int nbands){ - phm->sPsi(psi_in, spsi_out, nrow, npw, nbands); + auto spsi_func = [phm](const double* psi_in, double* spsi_out,const int ld_psi, const int nbands){ + phm->sPsi(psi_in, spsi_out, ld_psi, ld_psi, nbands); }; - dav.diag(hpsi_func,spsi_func, ldPsi, phi.get_pointer(), en, eps, maxiter); + dav.diag(hpsi_func,spsi_func, ld_psi, phi.get_pointer(), en, eps, maxiter); #ifdef __MPI end = MPI_Wtime(); @@ -131,7 +133,8 @@ class DiagoDavPrepare if (mypnum == 0) { - if (DETAILINFO) std::cout << "diag Run time: " << use_time << std::endl; + if (DETAILINFO) { std::cout << "diag Run time: " << use_time << std::endl; +} for (int i = 0;i < nband;i++) { EXPECT_NEAR(en[i], e_lapack[i], CONVTHRESHOLD); @@ -148,8 +151,9 @@ class DiagoDavTest : public ::testing::TestWithParam {}; TEST_P(DiagoDavTest, RandomHamilt) { DiagoDavPrepare ddp = GetParam(); - if (DETAILINFO && ddp.mypnum == 0) std::cout << "npw=" << ddp.npw << ", nband=" << ddp.nband << ", sparsity=" + if (DETAILINFO && ddp.mypnum == 0) { std::cout << "npw=" << ddp.npw << ", nband=" << ddp.nband << ", sparsity=" << ddp.sparsity << ", eps=" << ddp.eps << std::endl; +} HPsi hpsi(ddp.nband, ddp.npw, ddp.sparsity); DIAGOTEST::hmatrix_d = hpsi.hamilt(); @@ -236,7 +240,8 @@ int main(int argc, char** argv) testing::InitGoogleTest(&argc, argv); ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); - if (myrank != 0) delete listeners.Release(listeners.default_result_printer()); + if (myrank != 0) { delete listeners.Release(listeners.default_result_printer()); +} int result = RUN_ALL_TESTS(); if (myrank == 0 && result != 0) diff --git a/source/module_hsolver/test/diago_david_test.cpp b/source/module_hsolver/test/diago_david_test.cpp index 79b099c6f44..4911d40a4fe 100644 --- a/source/module_hsolver/test/diago_david_test.cpp +++ b/source/module_hsolver/test/diago_david_test.cpp @@ -91,7 +91,7 @@ class DiagoDavPrepare const int dim = phi.get_current_nbas(); const int nband = phi.get_nbands(); - const int ldPsi = phi.get_nbasis(); + const int ld_psi = phi.get_nbasis(); hsolver::DiagoDavid> dav(precondition, nband, dim, order, false, comm_info); hsolver::DiagoIterAssist>::PW_DIAG_NMAX = maxiter; @@ -110,19 +110,18 @@ class DiagoDavPrepare auto hpsi_func = [phm](std::complex* psi_in,std::complex* hpsi_out, - const int nband_in, const int nbasis_in, - const int band_index1, const int band_index2) + const int ld_psi, const int nvec) { - auto psi_iter_wrapper = psi::Psi>(psi_in, 1, nband_in, nbasis_in, nullptr); - psi::Range bands_range(1, 0, band_index1, band_index2); + auto psi_iter_wrapper = psi::Psi>(psi_in, 1, nvec, ld_psi, nullptr); + psi::Range bands_range(1, 0, 0, nvec-1); using hpsi_info = typename hamilt::Operator>::hpsi_info; hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); phm->ops->hPsi(info); }; - auto spsi_func = [phm](const std::complex* psi_in, std::complex* spsi_out,const int nrow, const int npw, const int nbands){ - phm->sPsi(psi_in, spsi_out, nrow, npw, nbands); + auto spsi_func = [phm](const std::complex* psi_in, std::complex* spsi_out,const int ld_psi, const int nbands){ + phm->sPsi(psi_in, spsi_out, ld_psi, ld_psi, nbands); }; - dav.diag(hpsi_func,spsi_func, ldPsi, phi.get_pointer(), en, eps, maxiter); + dav.diag(hpsi_func,spsi_func, ld_psi, phi.get_pointer(), en, eps, maxiter); #ifdef __MPI end = MPI_Wtime(); diff --git a/source/module_hsolver/test/diago_lapack_test.cpp b/source/module_hsolver/test/diago_lapack_test.cpp index 7e9d583e6b6..cb3eb3f4034 100644 --- a/source/module_hsolver/test/diago_lapack_test.cpp +++ b/source/module_hsolver/test/diago_lapack_test.cpp @@ -1,5 +1,8 @@ // Author: Zhang Xiaoyang // A modified version of diago_lcao_test.cpp +#define private public +#include "module_parameter/parameter.h" +#undef private // Remove some useless functions and dependencies. Serialized the full code // and refactored some function. @@ -116,7 +119,7 @@ class DiagoLapackPrepare : nlocal(nlocal), nbands(nbands), nb2d(nb2d), sparsity(sparsity), hfname(hfname), sfname(sfname), solutionfname(solutionfname) { - dh = new hsolver::DiagoLapack; + // dh = new hsolver::DiagoLapack; } int nlocal, nbands, nb2d, sparsity; @@ -124,7 +127,6 @@ class DiagoLapackPrepare std::vector h; std::vector s; HamiltTEST hmtest; - hsolver::DiagH* dh = nullptr; psi::Psi psi; std::vector e_solver; std::vector e_lapack; @@ -185,8 +187,8 @@ class DiagoLapackPrepare void set_env() { - GlobalV::NLOCAL = nlocal; - GlobalV::NBANDS = nbands; + PARAM.sys.nlocal = nlocal; + PARAM.input.nbands = nbands; } void diago() @@ -197,9 +199,11 @@ class DiagoLapackPrepare for (int i = 0; i < REPEATRUN; i++) { - dh->diag(&hmtest, psi, e_solver.data()); + hsolver::DiagoLapack dh; + dh.diag(&hmtest, psi, e_solver.data()); + // dh->diag(&hmtest, psi, e_solver.data()); } - delete dh; + // delete dh; } void read_SOLUTION() diff --git a/source/module_hsolver/test/diago_lcao_cusolver_test.cpp b/source/module_hsolver/test/diago_lcao_cusolver_test.cpp index b54cebe2519..40e62c6ecde 100644 --- a/source/module_hsolver/test/diago_lcao_cusolver_test.cpp +++ b/source/module_hsolver/test/diago_lcao_cusolver_test.cpp @@ -1,5 +1,8 @@ #include "module_hsolver/diago_scalapack.h" #include "module_hsolver/test/diago_elpa_utils.h" +#define private public +#include "module_parameter/parameter.h" +#undef private #include "mpi.h" #include "string.h" @@ -71,10 +74,10 @@ class DiagoPrepare MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (ks_solver == "scalapack_gvx") - dh = new hsolver::DiagoScalapack; + ;//dh = new hsolver::DiagoScalapack; #ifdef __CUDA else if (ks_solver == "cusolver") - dh = new hsolver::DiagoCusolver; + ;//dh = new hsolver::DiagoCusolver; #endif else { @@ -93,7 +96,7 @@ class DiagoPrepare std::vector s; std::vector h_local; std::vector s_local; - hsolver::DiagH* dh = 0; + // hsolver::DiagH* dh = 0; psi::Psi psi; std::vector e_solver; std::vector e_lapack; @@ -200,8 +203,8 @@ class DiagoPrepare void set_env() { - GlobalV::NLOCAL = nlocal; - GlobalV::NBANDS = nbands; + PARAM.sys.nlocal = nlocal; + PARAM.input.nbands = nbands; GlobalV::DSIZE = dsize; } @@ -219,11 +222,23 @@ class DiagoPrepare { hmtest.h_local = this->h_local; hmtest.s_local = this->s_local; - dh->diag(&hmtest, psi, e_solver.data()); + if (ks_solver == "scalapack_gvx") + { + hsolver::DiagoScalapack dh; + dh.diag(&hmtest, psi, e_solver.data()); + } + #ifdef __CUDA + else if (ks_solver == "cusolver") + { + hsolver::DiagoCusolver dh; + dh.diag(&hmtest, psi, e_solver.data()); + } + #endif + // dh->diag(&hmtest, psi, e_solver.data()); } endtime = MPI_Wtime(); hsolver_time = (endtime - starttime) / REPEATRUN; - delete dh; + // delete dh; } void diago_lapack() diff --git a/source/module_hsolver/test/diago_lcao_test.cpp b/source/module_hsolver/test/diago_lcao_test.cpp index de2e4c88b4f..8feefecfe3b 100644 --- a/source/module_hsolver/test/diago_lcao_test.cpp +++ b/source/module_hsolver/test/diago_lcao_test.cpp @@ -1,5 +1,8 @@ #include "module_hsolver/diago_scalapack.h" #include "module_hsolver/test/diago_elpa_utils.h" +#define private public +#include "module_parameter/parameter.h" +#undef private #include "mpi.h" #include "string.h" @@ -68,10 +71,12 @@ class DiagoPrepare MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (ks_solver == "scalapack_gvx") - dh = new hsolver::DiagoScalapack; + ; +// dh = new hsolver::DiagoScalapack; #ifdef __ELPA else if (ks_solver == "genelpa") - dh = new hsolver::DiagoElpa; + ; +// dh = new hsolver::DiagoElpa; #endif else { @@ -90,7 +95,6 @@ class DiagoPrepare std::vector s; std::vector h_local; std::vector s_local; - hsolver::DiagH* dh = 0; psi::Psi psi; std::vector e_solver; std::vector e_lapack; @@ -197,8 +201,8 @@ class DiagoPrepare void set_env() { - GlobalV::NLOCAL = nlocal; - GlobalV::NBANDS = nbands; + PARAM.sys.nlocal = nlocal; + PARAM.input.nbands = nbands; GlobalV::DSIZE = dsize; } @@ -216,11 +220,23 @@ class DiagoPrepare { hmtest.h_local = this->h_local; hmtest.s_local = this->s_local; - dh->diag(&hmtest, psi, e_solver.data()); + if (ks_solver == "scalapack_gvx") + { + hsolver::DiagoScalapack dh; + dh.diag(&hmtest, psi, e_solver.data()); + } + #ifdef __ELPA + else if (ks_solver == "genelpa") + { + hsolver::DiagoElpa dh; + dh.diag(&hmtest, psi, e_solver.data()); + } + #endif + // dh.diag(&hmtest, psi, e_solver.data()); } endtime = MPI_Wtime(); hsolver_time = (endtime - starttime) / REPEATRUN; - delete dh; + // delete dh; } void diago_lapack() diff --git a/source/module_hsolver/test/diago_mock.h b/source/module_hsolver/test/diago_mock.h index 40b55742471..07d500fdf06 100644 --- a/source/module_hsolver/test/diago_mock.h +++ b/source/module_hsolver/test/diago_mock.h @@ -87,33 +87,36 @@ namespace DIAGOTEST if(mypnum == 0) { - for(int j=0;j::value) + if (std::is_same::value) { MPI_Send(&(psi[start_point]),npw_local[j],MPI_DOUBLE,j,0,MPI_COMM_WORLD); - else if(std::is_same>::value) + } else if(std::is_same>::value) { MPI_Send(&(psi[start_point]),npw_local[j],MPI_DOUBLE_COMPLEX,j,0,MPI_COMM_WORLD); - else if (std::is_same::value) + } else if (std::is_same::value) { MPI_Send(&(psi[start_point]), npw_local[j], MPI_FLOAT, j, 0, MPI_COMM_WORLD); - else if (std::is_same>::value) + } else if (std::is_same>::value) { MPI_Send(&(psi[start_point]), npw_local[j], MPI_C_FLOAT_COMPLEX, j, 0, MPI_COMM_WORLD); +} start_point += npw_local[j]; } } else { int recv_len = mypnum < (npw%nprocs) ? npw/nprocs + 1 : npw/nprocs; - if (std::is_same::value) + if (std::is_same::value) { MPI_Recv(psi_local, npw_local[mypnum],MPI_DOUBLE,0,0,MPI_COMM_WORLD, MPI_STATUS_IGNORE); - else if(std::is_same>::value) + } else if(std::is_same>::value) { MPI_Recv(psi_local, npw_local[mypnum], MPI_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - else if (std::is_same::value) + } else if (std::is_same::value) { MPI_Recv(psi_local, npw_local[mypnum], MPI_FLOAT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - else if (std::is_same>::value) + } else if (std::is_same>::value) { MPI_Recv(psi_local, npw_local[mypnum], MPI_C_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); +} #endif } } @@ -128,8 +131,9 @@ namespace DIAGOTEST MPI_Comm_rank(MPI_COMM_WORLD, &mypnum); for(int i=0;i psitmp(1, nband, npw, ngk); for(int i=0;i::genhmatrix() DIAGOTEST::h_nc = npw; std::default_random_engine e(100); std::uniform_int_distribution u(min, max); - if (sparsity < 0) sparsity = 0; - if (sparsity > 10) sparsity = 10; + if (sparsity < 0) { sparsity = 0; +} + if (sparsity > 10) { sparsity = 10; +} for (int i = 0;i < npw;i++) { for (int j = 0;j <= i;j++) { double mincoef = 0.0; double realp = pow(-1.0, u(e) % 2) * static_cast(u(e)) / max; - if (int(u(e) % 10) > int(sparsity - 1)) mincoef = 1.0; - if (i == j) + if (int(u(e) % 10) > int(sparsity - 1)) { mincoef = 1.0; +} + if (i == j) { hmatrix[i * npw + j] = realp; - else + } else { hmatrix[j * npw + i] = hmatrix[i * npw + j] = mincoef * realp; +} } } } @@ -279,8 +288,10 @@ void HPsi>::genhmatrix() DIAGOTEST::h_nc = npw; std::default_random_engine e(100); std::uniform_int_distribution u(min, max); - if (sparsity < 0) sparsity = 0; - if (sparsity > 10) sparsity = 10; + if (sparsity < 0) { sparsity = 0; +} + if (sparsity > 10) { sparsity = 10; +} for (int i = 0;i < npw;i++) { for (int j = 0;j <= i;j++) @@ -288,7 +299,8 @@ void HPsi>::genhmatrix() double mincoef = 0.0; double realp = pow(-1.0, u(e) % 2) * static_cast(u(e)) / max; //double imagp= pow(-1.0,u(e)%2) * static_cast(u(e))/max; - if (int(u(e) % 10) > int(sparsity - 1)) mincoef = 1.0; + if (int(u(e) % 10) > int(sparsity - 1)) { mincoef = 1.0; +} if (i == j) { hmatrix[i * npw + j] = std::complex{ realp,0.0 }; @@ -310,15 +322,18 @@ void HPsi>::genhmatrix() DIAGOTEST::h_nc = npw; std::default_random_engine e(100); std::uniform_int_distribution u(min, max); - if (sparsity < 0) sparsity = 0; - if (sparsity > 10) sparsity = 10; + if (sparsity < 0) { sparsity = 0; +} + if (sparsity > 10) { sparsity = 10; +} for (int i = 0;i < npw;i++) { for (int j = 0;j <= i;j++) { float mincoef = 0.0; float realp = pow(-1.0, u(e) % 2) * static_cast(u(e)) / max; - if (int(u(e) % 10) > int(sparsity - 1)) mincoef = 1.0; + if (int(u(e) % 10) > int(sparsity - 1)) { mincoef = 1.0; +} if (i == j) { hmatrix[i * npw + j] = std::complex{ realp,0.0 }; @@ -339,9 +354,11 @@ void HPsi::genpsi() psimatrix.resize(nband * npw); std::default_random_engine e(10); std::uniform_int_distribution u(min, max); - for (int i = 0;i < nband;i++) - for (int j = 0;j < npw;j++) + for (int i = 0;i < nband;i++) { + for (int j = 0;j < npw;j++) { psimatrix[i * npw + j] = pow(-1.0, u(e) % 2) * static_cast(u(e)) / max; +} +} } } template<> @@ -447,7 +464,8 @@ class OperatorMock : public hamilt::Operator const int npol, const T* tmpsi_in, T* tmhpsi, - const int ngk_ik = 0)const; + const int ngk_ik = 0, + const bool is_first_node = false)const; }; template<> void OperatorMock::act( @@ -456,7 +474,8 @@ void OperatorMock::act( const int npol, const double* tmpsi_in, double* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { int nprocs = 1, mypnum = 0; #ifdef __MPI @@ -489,7 +508,8 @@ void OperatorMock>::act( const int npol, const std::complex* tmpsi_in, std::complex* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { int nprocs = 1, mypnum = 0; #ifdef __MPI @@ -522,7 +542,8 @@ void OperatorMock>::act( const int npol, const std::complex* tmpsi_in, std::complex* tmhpsi, - const int ngk_ik)const + const int ngk_ik, + const bool is_first_node)const { int nprocs = 1, mypnum = 0; #ifdef __MPI diff --git a/source/module_hsolver/test/diago_pexsi_test.cpp b/source/module_hsolver/test/diago_pexsi_test.cpp index 1c0f6e08ead..3b2ca3cb42a 100644 --- a/source/module_hsolver/test/diago_pexsi_test.cpp +++ b/source/module_hsolver/test/diago_pexsi_test.cpp @@ -183,8 +183,8 @@ class PexsiPrepare void set_env() { - GlobalV::NLOCAL = nlocal; - GlobalV::NBANDS = nbands; + PARAM.sys.nlocal = nlocal; + PARAM.input.nbands = nbands; GlobalV::DSIZE = dsize; PARAM.input.nspin = 1; DIAG_WORLD = MPI_COMM_WORLD; @@ -298,7 +298,7 @@ class PexsiPrepare return false; } - f_dm >> GlobalV::nelec >> mu; + f_dm >> PARAM.input.nelec >> mu; dm.resize(nread * nread); // T* edm = new T[nglobal*nglobal]; diff --git a/source/module_hsolver/test/hsolver_pw_sup.h b/source/module_hsolver/test/hsolver_pw_sup.h index bca46f585b5..0fc0e72eaae 100644 --- a/source/module_hsolver/test/hsolver_pw_sup.h +++ b/source/module_hsolver/test/hsolver_pw_sup.h @@ -153,9 +153,9 @@ DiagoDavid::~DiagoDavid() { } template -int DiagoDavid::diag(const std::function& hpsi_func, - const std::function& spsi_func, - const int ldPsi, +int DiagoDavid::diag(const std::function& hpsi_func, + const std::function& spsi_func, + const int ld_psi, T *psi_in, Real* eigenvalue_in, const Real david_diag_thr, diff --git a/source/module_hsolver/test/hsolver_supplementary_mock.h b/source/module_hsolver/test/hsolver_supplementary_mock.h index 8cee0698af3..59e07df85fd 100644 --- a/source/module_hsolver/test/hsolver_supplementary_mock.h +++ b/source/module_hsolver/test/hsolver_supplementary_mock.h @@ -1,5 +1,6 @@ #pragma once #include "module_elecstate/elecstate.h" +#include "module_hamilt_pw/hamilt_pwdft/wavefunc.h" namespace elecstate { @@ -11,9 +12,7 @@ const double* ElecState::getRho(int spin) const return &(this->charge->rho[spin][0]); } -void ElecState::fixed_weights(const std::vector& ocp_kb, - const int &nbands, - const double &nelec) +void ElecState::fixed_weights(const std::vector& ocp_kb, const int& nbands, const double& nelec) { return; } @@ -43,7 +42,10 @@ void ElecState::print_eigenvalue(std::ofstream& ofs) return; } -void ElecState::init_scf(const int istep, const ModuleBase::ComplexMatrix& strucfac, ModuleSymmetry::Symmetry&, const void*) +void ElecState::init_scf(const int istep, + const ModuleBase::ComplexMatrix& strucfac, + ModuleSymmetry::Symmetry&, + const void*) { return; } @@ -57,17 +59,24 @@ void ElecState::init_ks(Charge* chg_in, // pointer for class Charge return; } -void ElecState::cal_nbands() +Potential::~Potential() { - return; } -} // namespace elecstate +void Potential::cal_v_eff(const Charge* const chg, const UnitCell* const ucell, ModuleBase::matrix& v_eff) +{ +} + +void Potential::cal_fixed_v(double* vl_pseudo) +{ +} +} // namespace elecstate -//mock of Stochastic_WF +// mock of Stochastic_WF #include "module_hamilt_pw/hamilt_stodft/sto_wf.h" -Stochastic_WF::Stochastic_WF() +template +Stochastic_WF::Stochastic_WF() { chiortho = nullptr; chi0 = nullptr; @@ -75,7 +84,8 @@ Stochastic_WF::Stochastic_WF() nchip = nullptr; } -Stochastic_WF::~Stochastic_WF() +template +Stochastic_WF::~Stochastic_WF() { delete[] chi0; delete[] shchi; @@ -83,7 +93,8 @@ Stochastic_WF::~Stochastic_WF() delete[] nchip; } -void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) +template +void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) { /*chi0 = new ModuleBase::ComplexMatrix[nks_in]; shchi = new ModuleBase::ComplexMatrix[nks_in]; @@ -93,8 +104,12 @@ void Stochastic_WF::init(K_Vectors* p_kv, const int npwx_in) } #include "module_cell/klist.h" -K_Vectors::K_Vectors(){} -K_Vectors::~K_Vectors(){} +K_Vectors::K_Vectors() +{ +} +K_Vectors::~K_Vectors() +{ +} wavefunc::wavefunc() { } diff --git a/source/module_hsolver/test/test_hsolver.cpp b/source/module_hsolver/test/test_hsolver.cpp index 80ea102f978..8e2d993ecd2 100644 --- a/source/module_hsolver/test/test_hsolver.cpp +++ b/source/module_hsolver/test/test_hsolver.cpp @@ -3,8 +3,8 @@ #include #define protected public -#include "module_hsolver/hsolver.h" #include "hsolver_supplementary_mock.h" +#include "module_hsolver/hsolver.h" #include @@ -28,36 +28,36 @@ * - diag() for Psi(FPTYPE) case * - destructor of DiagH and HSolver * - * the definition of supplementary functions is added in hsolver_supplementary_mock.h + * the definition of supplementary functions is added in hsolver_supplementary_mock.h */ class TestHSolver : public ::testing::Test { -public: - // hsolver::HSolver, base_device::DEVICE_CPU> hs_cf; - // hsolver::HSolver, base_device::DEVICE_CPU> hs_cd; - // hsolver::HSolver hs_f; - // hsolver::HSolver hs_d; + public: + // hsolver::HSolver, base_device::DEVICE_CPU> hs_cf; + // hsolver::HSolver, base_device::DEVICE_CPU> hs_cd; + // hsolver::HSolver hs_f; + // hsolver::HSolver hs_d; - hamilt::Hamilt> hamilt_test_cd; - hamilt::Hamilt> hamilt_test_cf; - psi::Psi> psi_test_cd; - psi::Psi> psi_test_cf; + hamilt::Hamilt> hamilt_test_cd; + hamilt::Hamilt> hamilt_test_cf; + psi::Psi> psi_test_cd; + psi::Psi> psi_test_cf; - hamilt::Hamilt hamilt_test_d; - hamilt::Hamilt hamilt_test_f; - psi::Psi psi_test_d; - psi::Psi psi_test_f; + hamilt::Hamilt hamilt_test_d; + hamilt::Hamilt hamilt_test_f; + psi::Psi psi_test_d; + psi::Psi psi_test_f; - Stochastic_WF stowf_test; + Stochastic_WF> stowf_test; - elecstate::ElecState elecstate_test; + elecstate::ElecState elecstate_test; - ModulePW::PW_Basis_K* wfcpw; + ModulePW::PW_Basis_K* wfcpw; - std::string method_test = "none"; + std::string method_test = "none"; - std::ofstream temp_ofs; + std::ofstream temp_ofs; }; // TEST_F(TestHSolver, solve) @@ -83,28 +83,4 @@ class TestHSolver : public ::testing::Test // double test_diagethr_d = hs_d.set_diagethr(0.0, 0, 0, 0.0); // EXPECT_EQ(test_diagethr_d, 0.0); -// } -namespace hsolver -{ -template -class DiagH_mock : public DiagH -{ - private: - using Real = typename GetTypeReal::type; - - public: - DiagH_mock() - { - } - ~DiagH_mock() - { - } - - void diag(hamilt::Hamilt* phm_in, psi::Psi& psi, Real* eigenvalue_in) - { - return; - } - }; - template class DiagH_mock>; - template class DiagH_mock>; -} \ No newline at end of file +// } \ No newline at end of file diff --git a/source/module_hsolver/test/test_hsolver_pw.cpp b/source/module_hsolver/test/test_hsolver_pw.cpp index 2d8d5b4f071..5bbbc4bc0f2 100644 --- a/source/module_hsolver/test/test_hsolver_pw.cpp +++ b/source/module_hsolver/test/test_hsolver_pw.cpp @@ -43,7 +43,7 @@ class TestHSolverPW : public ::testing::Test { "pw", "cg", false, - GlobalV::use_uspp, + PARAM.sys.use_uspp, PARAM.input.nspin, hsolver::DiagoIterAssist, base_device::DEVICE_CPU>::SCF_ITER, hsolver::DiagoIterAssist, base_device::DEVICE_CPU>::PW_DIAG_NMAX, @@ -58,7 +58,7 @@ class TestHSolverPW : public ::testing::Test { "pw", "cg", false, - GlobalV::use_uspp, + PARAM.sys.use_uspp, PARAM.input.nspin, hsolver::DiagoIterAssist, base_device::DEVICE_CPU>::SCF_ITER, hsolver::DiagoIterAssist, base_device::DEVICE_CPU>::PW_DIAG_NMAX, @@ -84,22 +84,20 @@ class TestHSolverPW : public ::testing::Test { TEST_F(TestHSolverPW, solve) { // initial memory and data elecstate_test.ekb.create(1, 2); + elecstate_test.pot = new elecstate::Potential; this->ekb_f.resize(2); psi_test_cf.resize(1, 2, 3); psi_test_cd.resize(1, 2, 3); - GlobalV::nelec = 1.0; + PARAM.input.nelec = 1.0; // check solve() EXPECT_EQ(this->hs_f.initialed_psi, false); EXPECT_EQ(this->hs_d.initialed_psi, false); - std::vector is_occupied(1 * 2, true); - this->hs_f.solve(&hamilt_test_f, psi_test_cf, &elecstate_test, elecstate_test.ekb.c, - is_occupied, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL, @@ -118,7 +116,6 @@ TEST_F(TestHSolverPW, solve) { psi_test_cd, &elecstate_test, elecstate_test.ekb.c, - is_occupied, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL, @@ -220,6 +217,7 @@ TEST_F(TestHSolverPW, SolveLcaoInPW) { pwbk.nks = 1; // initial memory and data elecstate_test.ekb.create(1, 2); + elecstate_test.pot = new elecstate::Potential; // 1 kpt, 2 bands, 3 basis psi_test_cf.resize(1, 2, 3); psi_test_cd.resize(1, 2, 3); @@ -247,7 +245,7 @@ TEST_F(TestHSolverPW, SolveLcaoInPW) { psi_value_f += std::complex(1.0, 0.0); } } - GlobalV::nelec = 1.0; + PARAM.input.nelec = 1.0; // check solve() elecstate_test.ekb.c[0] = 1.0; diff --git a/source/module_hsolver/test/test_hsolver_sdft.cpp b/source/module_hsolver/test/test_hsolver_sdft.cpp index 19437010781..687bc38bc7e 100644 --- a/source/module_hsolver/test/test_hsolver_sdft.cpp +++ b/source/module_hsolver/test/test_hsolver_sdft.cpp @@ -7,107 +7,113 @@ #define private public #define protected public -#include "module_hsolver/hsolver_pw.h" -#include "hsolver_supplementary_mock.h" #include "hsolver_pw_sup.h" -#include "module_hsolver/hsolver_pw_sdft.h" +#include "hsolver_supplementary_mock.h" #include "module_base/global_variable.h" +#include "module_hsolver/hsolver_pw.h" +#include "module_hsolver/hsolver_pw_sdft.h" #undef private #undef protected -//mock for module_sdft -template -Sto_Func::Sto_Func(){} +// mock for module_sdft +template +Sto_Func::Sto_Func() +{ +} template class Sto_Func; -template +template StoChe::StoChe(const int& nche, const int& method, const REAL& emax_sto, const REAL& emin_sto) { this->nche = nche; } -template -StoChe::~StoChe(){} +template +StoChe::~StoChe() +{ +} template class StoChe; -Stochastic_hchi::Stochastic_hchi(){}; -Stochastic_hchi::~Stochastic_hchi(){}; - -Stochastic_Iter::Stochastic_Iter() +template +Stochastic_Iter::Stochastic_Iter() { change = false; mu0 = 0; method = 2; } -Stochastic_Iter::~Stochastic_Iter(){}; +template +Stochastic_Iter::~Stochastic_Iter(){}; +template class Stochastic_Iter, base_device::DEVICE_CPU>; -void Stochastic_Iter::init(K_Vectors* pkv, ModulePW::PW_Basis_K *wfc_basis, Stochastic_WF &stowf, StoChe &stoche) +template +void Stochastic_Iter::init(K_Vectors* pkv_in, + ModulePW::PW_Basis_K* wfc_basis, + Stochastic_WF& stowf, + StoChe& stoche, + hamilt::HamiltSdftPW* p_hamilt_sto) { - this->nchip = stowf.nchip;; + this->nchip = stowf.nchip; + ; this->targetne = 1; this->method = stoche.method_sto; } -void Stochastic_Iter::orthog(const int& ik, - psi::Psi& psi, - Stochastic_WF& stowf) +template +void Stochastic_Iter::orthog(const int& ik, psi::Psi& psi, Stochastic_WF& stowf) { - //do something to verify this function has been called - for(int i=0;i +void Stochastic_Iter::checkemm(const int& ik, + const int istep, + const int iter, + Stochastic_WF& stowf) { - //do something to verify this function has been called + // do something to verify this function has been called stowf.nchi++; return; } -void Stochastic_Iter::calPn( - const int &ik, - Stochastic_WF &stowf -) +template +void Stochastic_Iter::calPn(const int& ik, Stochastic_WF& stowf) { - //do something to verify this function has been called - stowf.nbands_diag ++; + // do something to verify this function has been called + stowf.nbands_diag++; return; } -void Stochastic_Iter::itermu( - int iter, - elecstate::ElecState *pes -) +template +void Stochastic_Iter::itermu(int iter, elecstate::ElecState* pes) { - //do something to verify this function has been called + // do something to verify this function has been called pes->f_en.eband += 1.2; return; } -void Stochastic_Iter::calHsqrtchi(Stochastic_WF &stowf) +template +void Stochastic_Iter::calHsqrtchi(Stochastic_WF& stowf) { - //do something to verify this function has been called + // do something to verify this function has been called stowf.nchip_max++; return; } -void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, - elecstate::ElecState* pes, - hamilt::Hamilt, base_device::DEVICE_CPU>* pHamilt, - ModulePW::PW_Basis_K* wfc_basis) +template +void Stochastic_Iter::sum_stoband(Stochastic_WF& stowf, + elecstate::ElecState* pes, + hamilt::Hamilt* pHamilt, + ModulePW::PW_Basis_K* wfc_basis) { - //do something to verify this function has been called - stowf.nbands_total ++; + // do something to verify this function has been called + stowf.nbands_total++; return; } @@ -129,74 +135,73 @@ Charge::~Charge(){}; */ class TestHSolverPW_SDFT : public ::testing::Test { - public: - TestHSolverPW_SDFT():stoche(8,1,0,0){} + public: + TestHSolverPW_SDFT() : stoche(8, 1, 0, 0) + { + } ModulePW::PW_Basis_K pwbk; - Stochastic_WF stowf; + Stochastic_WF> stowf; K_Vectors kv; wavefunc wf; StoChe stoche; - hsolver::HSolverPW_SDFT hs_d = hsolver::HSolverPW_SDFT(&kv, - &pwbk, - &wf, - stowf, - stoche, - - "scf", - "pw", - "cg", - false, - GlobalV::use_uspp, - PARAM.input.nspin, - hsolver::DiagoIterAssist>::SCF_ITER, - hsolver::DiagoIterAssist>::PW_DIAG_NMAX, - hsolver::DiagoIterAssist>::PW_DIAG_THR, - hsolver::DiagoIterAssist>::need_subspace, - false); + hamilt::HamiltSdftPW>* p_hamilt_sto = nullptr; + hsolver::HSolverPW_SDFT, base_device::DEVICE_CPU> hs_d + = hsolver::HSolverPW_SDFT, base_device::DEVICE_CPU>( + &kv, + &pwbk, + &wf, + stowf, + stoche, + p_hamilt_sto, + "scf", + "pw", + "cg", + false, + PARAM.sys.use_uspp, + PARAM.input.nspin, + hsolver::DiagoIterAssist>::SCF_ITER, + hsolver::DiagoIterAssist>::PW_DIAG_NMAX, + hsolver::DiagoIterAssist>::PW_DIAG_THR, + hsolver::DiagoIterAssist>::need_subspace, + false); hamilt::Hamilt> hamilt_test_d; - psi::Psi> psi_test_cd; + psi::Psi> psi_test_cd; psi::Psi> psi_test_no; - elecstate::ElecState elecstate_test; + elecstate::ElecState elecstate_test; - std::string method_test = "cg"; + std::string method_test = "cg"; - std::ofstream temp_ofs; + std::ofstream temp_ofs; }; TEST_F(TestHSolverPW_SDFT, solve) { - //initial memory and data - elecstate_test.ekb.create(1,2); + // initial memory and data + elecstate_test.ekb.create(1, 2); + elecstate_test.pot = new elecstate::Potential; elecstate_test.f_en.eband = 0.0; stowf.nbands_diag = 0; stowf.nbands_total = 0; stowf.nchi = 0; stowf.nchip_max = 0; - psi_test_cd.resize(1, 2, 3); - GlobalV::nelec = 1.0; + psi_test_cd.resize(1, 2, 3); + PARAM.input.nelec = 1.0; GlobalV::MY_STOGROUP = 0.0; int istep = 0; int iter = 0; - this->hs_d.solve(&hamilt_test_d, - psi_test_cd, - &elecstate_test, - &pwbk, - stowf, - istep, - iter, - false); - EXPECT_DOUBLE_EQ(hsolver::DiagoIterAssist>::avg_iter, 0.0); - EXPECT_DOUBLE_EQ(elecstate_test.ekb.c[0], 4.0); - EXPECT_DOUBLE_EQ(elecstate_test.ekb.c[1], 7.0); - for(int i=0;ihs_d.solve(&hamilt_test_d, psi_test_cd, &elecstate_test, &pwbk, stowf, istep, iter, false); + EXPECT_DOUBLE_EQ(hsolver::DiagoIterAssist>::avg_iter, 0.0); + EXPECT_DOUBLE_EQ(elecstate_test.ekb.c[0], 4.0); + EXPECT_DOUBLE_EQ(elecstate_test.ekb.c[1], 7.0); + for (int i = 0; i < psi_test_cd.size(); i++) + { + // std::cout<<__FILE__<<__LINE__<<" "<hs_d.solve(&hamilt_test_d, - psi_test_no, - &elecstate_test, - &pwbk, - stowf, - istep, - iter, - false - ); - EXPECT_DOUBLE_EQ(hsolver::DiagoIterAssist>::avg_iter, 0.0); + this->hs_d.solve(&hamilt_test_d, psi_test_no, &elecstate_test, &pwbk, stowf, istep, iter, false); + EXPECT_DOUBLE_EQ(hsolver::DiagoIterAssist>::avg_iter, 0.0); EXPECT_EQ(stowf.nbands_diag, 2); EXPECT_EQ(stowf.nbands_total, 1); EXPECT_EQ(stowf.nchi, 2); @@ -252,16 +250,8 @@ TEST_F(TestHSolverPW_SDFT, solve_noband_skipcharge) std::cout<<__FILE__<<__LINE__<<" "<hs_d.solve(&hamilt_test_d, - psi_test_no, - &elecstate_test, - &pwbk, - stowf, - istep, - iter, - true - ); + // test for skip charge + this->hs_d.solve(&hamilt_test_d, psi_test_no, &elecstate_test, &pwbk, stowf, istep, iter, true); EXPECT_EQ(stowf.nbands_diag, 4); EXPECT_EQ(stowf.nbands_total, 1); EXPECT_EQ(stowf.nchi, 4); @@ -271,27 +261,26 @@ TEST_F(TestHSolverPW_SDFT, solve_noband_skipcharge) delete[] elecstate_test.charge->rho[0]; delete[] elecstate_test.charge->rho; delete elecstate_test.charge; - } #ifdef __MPI -#include "mpi.h" #include "module_base/timer.h" -int main(int argc, char **argv) +#include "mpi.h" +int main(int argc, char** argv) { - ModuleBase::timer::disable(); - MPI_Init(&argc, &argv); - testing::InitGoogleTest(&argc, argv); + ModuleBase::timer::disable(); + MPI_Init(&argc, &argv); + testing::InitGoogleTest(&argc, argv); - MPI_Comm_size(MPI_COMM_WORLD,&GlobalV::NPROC); - MPI_Comm_rank(MPI_COMM_WORLD,&GlobalV::MY_RANK); + MPI_Comm_size(MPI_COMM_WORLD, &GlobalV::NPROC); + MPI_Comm_rank(MPI_COMM_WORLD, &GlobalV::MY_RANK); MPI_Comm_split(MPI_COMM_WORLD, 0, 1, &PARAPW_WORLD); - int result = RUN_ALL_TESTS(); - + int result = RUN_ALL_TESTS(); + MPI_Comm_free(&PARAPW_WORLD); - MPI_Finalize(); - - return result; + MPI_Finalize(); + + return result; } #endif \ No newline at end of file diff --git a/source/module_io/CMakeLists.txt b/source/module_io/CMakeLists.txt index 781057cb277..44e94bb0572 100644 --- a/source/module_io/CMakeLists.txt +++ b/source/module_io/CMakeLists.txt @@ -13,7 +13,6 @@ list(APPEND objects output.cpp print_info.cpp read_cube.cpp - read_rho.cpp rhog_io.cpp read_exit_file.cpp read_wfc_pw.cpp @@ -23,12 +22,14 @@ list(APPEND objects write_wfc_pw.cpp write_cube.cpp write_elecstat_pot.cpp + write_elf.cpp write_dipole.cpp td_current_io.cpp write_wfc_r.cpp output_log.cpp para_json.cpp parse_args.cpp + orb_io.cpp ) list(APPEND objects_advanced diff --git a/source/module_io/berryphase.cpp b/source/module_io/berryphase.cpp index 7324a228222..71b173b095e 100644 --- a/source/module_io/berryphase.cpp +++ b/source/module_io/berryphase.cpp @@ -24,14 +24,14 @@ berryphase::~berryphase() void berryphase::get_occupation_bands() { - double occupied_bands = static_cast(GlobalV::nelec / ModuleBase::DEGSPIN); + double occupied_bands = static_cast(PARAM.inp.nelec / ModuleBase::DEGSPIN); if ((occupied_bands - std::floor(occupied_bands)) > 0.0) { occupied_bands = std::floor(occupied_bands) + 1.0; } occ_nbands = (int)occupied_bands; - if (occ_nbands > GlobalV::NBANDS) + if (occ_nbands > PARAM.inp.nbands) { ModuleBase::WARNING_QUIT("berryphase::get_occupation_bands", "not enough bands for berryphase, increase band numbers."); diff --git a/source/module_io/cal_r_overlap_R.cpp b/source/module_io/cal_r_overlap_R.cpp index 04b8e060d5a..dec4cbabe83 100644 --- a/source/module_io/cal_r_overlap_R.cpp +++ b/source/module_io/cal_r_overlap_R.cpp @@ -194,11 +194,11 @@ void cal_r_overlap_R::construct_orbs_and_orb_r(const LCAO_Orbitals& orb) } } - iw2it.resize(GlobalV::NLOCAL); - iw2ia.resize(GlobalV::NLOCAL); - iw2iL.resize(GlobalV::NLOCAL); - iw2iN.resize(GlobalV::NLOCAL); - iw2im.resize(GlobalV::NLOCAL); + iw2it.resize(PARAM.globalv.nlocal); + iw2ia.resize(PARAM.globalv.nlocal); + iw2iL.resize(PARAM.globalv.nlocal); + iw2iN.resize(PARAM.globalv.nlocal); + iw2im.resize(PARAM.globalv.nlocal); int iw = 0; for (int it = 0; it < GlobalC::ucell.ntype; it++) @@ -341,12 +341,12 @@ void cal_r_overlap_R::out_rR(const int& istep) ModuleBase::Vector3 R_car = ModuleBase::Vector3(dRx, dRy, dRz) * GlobalC::ucell.latvec; int ir, ic; - for (int iw1 = 0; iw1 < GlobalV::NLOCAL; iw1++) + for (int iw1 = 0; iw1 < PARAM.globalv.nlocal; iw1++) { ir = this->ParaV->global2local_row(iw1); if (ir >= 0) { - for (int iw2 = 0; iw2 < GlobalV::NLOCAL; iw2++) + for (int iw2 = 0; iw2 < PARAM.globalv.nlocal; iw2++) { ic = this->ParaV->global2local_col(iw2); if (ic >= 0) @@ -502,6 +502,7 @@ void cal_r_overlap_R::out_rR(const int& istep) if (binary) { ofs_tem1.close(); + int nlocal = PARAM.globalv.nlocal; if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag && step) { out_r.open(ssr.str().c_str(), std::ios::binary | std::ios::app); @@ -511,7 +512,7 @@ void cal_r_overlap_R::out_rR(const int& istep) out_r.open(ssr.str().c_str(), std::ios::binary); } out_r.write(reinterpret_cast(&step), sizeof(int)); - out_r.write(reinterpret_cast(&GlobalV::NLOCAL), sizeof(int)); + out_r.write(reinterpret_cast(&nlocal), sizeof(int)); out_r.write(reinterpret_cast(&output_R_number), sizeof(int)); ifs_tem1.open(tem1.str().c_str(), std::ios::binary); @@ -531,7 +532,7 @@ void cal_r_overlap_R::out_rR(const int& istep) out_r.open(ssr.str().c_str()); } out_r << "STEP: " << step << std::endl; - out_r << "Matrix Dimension of r(R): " << GlobalV::NLOCAL << std::endl; + out_r << "Matrix Dimension of r(R): " << PARAM.globalv.nlocal << std::endl; out_r << "Matrix number of r(R): " << output_R_number << std::endl; ifs_tem1.open(tem1.str().c_str()); @@ -575,6 +576,7 @@ void cal_r_overlap_R::out_rR_other(const int& istep, const std::set(&step), sizeof(int)); - out_r.write(reinterpret_cast(&GlobalV::NLOCAL), sizeof(int)); + out_r.write(reinterpret_cast(&nlocal), sizeof(int)); out_r.write(reinterpret_cast(&output_R_number), sizeof(int)); } else @@ -598,7 +600,7 @@ void cal_r_overlap_R::out_rR_other(const int& istep, const std::setParaV->global2local_row(iw1); if (ir >= 0) { - for (int iw2 = 0; iw2 < GlobalV::NLOCAL; iw2++) + for (int iw2 = 0; iw2 < PARAM.globalv.nlocal; iw2++) { ic = this->ParaV->global2local_col(iw2); if (ic >= 0) diff --git a/source/module_io/cal_test.cpp b/source/module_io/cal_test.cpp index 9575b991f5d..680ba6028fc 100644 --- a/source/module_io/cal_test.cpp +++ b/source/module_io/cal_test.cpp @@ -1,5 +1,8 @@ #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_base/global_function.h" +#define private public +#include "module_parameter/parameter.h" +#undef private #include "module_base/global_variable.h" #include "module_base/memory.h" #include "cal_test.h" @@ -94,9 +97,9 @@ void Cal_Test::test_memory( mrhog_save = ModuleBase::Memory::calculate_mem( ngmc, "cdouble"); mrhog_core = ModuleBase::Memory::calculate_mem( ngmc, "cdouble"); - mhs = ModuleBase::Memory::calculate_mem( GlobalV::NLOCAL*GlobalV::NLOCAL, "double" ); - mwf = ModuleBase::Memory::calculate_mem( GlobalV::NLOCAL*GlobalV::NBANDS, "double" ); - mnonzero = ModuleBase::Memory::calculate_mem( GlobalV::NLOCAL*(GlobalV::NLOCAL+1)/2, "bool"); + mhs = ModuleBase::Memory::calculate_mem( PARAM.globalv.nlocal*PARAM.globalv.nlocal, "double" ); + mwf = ModuleBase::Memory::calculate_mem( PARAM.globalv.nlocal*PARAM.inp.nbands, "double" ); + mnonzero = ModuleBase::Memory::calculate_mem( PARAM.globalv.nlocal*(PARAM.globalv.nlocal+1)/2, "bool"); // mohan comment out 2021-02-11 // mspar_hsrho = Memory::calculate_mem( Hnnz*3, "double"); @@ -109,18 +112,18 @@ void Cal_Test::test_memory( meigts123 = ModuleBase::Memory::calculate_mem( GlobalC::ucell.nat * (2*rhopw->nx+1+2*rhopw->ny+1+2*rhopw->nz+1), "cdouble"); //(3) Memory for H,S matrix. - std::cout << " NLOCAL = " << GlobalV::NLOCAL << std::endl; - std::cout << " NBANDS = " << GlobalV::NBANDS << std::endl; + std::cout << " NLOCAL = " << PARAM.globalv.nlocal << std::endl; + std::cout << " NBANDS = " << PARAM.inp.nbands << std::endl; std::cout << " Memory for H,S matrix ( " - << GlobalV::NLOCAL << ", " - << GlobalV::NLOCAL << ") = " + << PARAM.globalv.nlocal << ", " + << PARAM.globalv.nlocal << ") = " << mhs << " MB" << std::endl; //(4) Memory for wave functions. std::cout << " Memory for wave functions ( " - << GlobalV::NLOCAL << ", " - << GlobalV::NBANDS << ") = " + << PARAM.globalv.nlocal << ", " + << PARAM.inp.nbands << ") = " << mwf << " MB" << std::endl; print_mem(1); @@ -223,6 +226,6 @@ void Cal_Test::print_mem(const int &nproc) std::cout << " TOTAL MEMORY : " << std::setw(15) << mtot/nproc << " MB" << std::endl; std::cout << " MEMORY FOR nonzero : " << std::setw(15) - << (double)GlobalV::NLOCAL*(GlobalV::NLOCAL+1)/1028/1028/2.0/nproc + << (double)PARAM.globalv.nlocal*(PARAM.globalv.nlocal+1)/1028/1028/2.0/nproc << " MB" << std::endl; } diff --git a/source/module_io/cube_io.h b/source/module_io/cube_io.h index c5606329c25..d7e6b706a63 100644 --- a/source/module_io/cube_io.h +++ b/source/module_io/cube_io.h @@ -2,51 +2,65 @@ #define CUBE_IO_H #include #include "module_cell/unitcell.h" -#ifdef __MPI -#include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" -#endif +class Parallel_Grid; namespace ModuleIO { -bool read_cube( -#ifdef __MPI - Parallel_Grid* Pgrid, -#endif - int my_rank, - std::string esolver_type, - int rank_in_stogroup, - const int& is, + /// read volumetric data from .cube file into the parallel distributed grid. + bool read_vdata_palgrid( + const Parallel_Grid& pgrid, + const int my_rank, std::ofstream& ofs_running, - const int& nspin, const std::string& fn, - double* data, - const int& nx, - const int& ny, - const int& nz, - double& ef, - const UnitCell* ucell, - int& prenspin, - const bool& warning_flag = true); + double* const data, + const int nat); -void write_cube( -#ifdef __MPI - const int& bz, - const int& nbz, - const int& nplane, - const int& startz_current, -#endif - const double* data, - const int& is, - const int& nspin, - const int& iter, + /// write volumetric data on the parallized grid into a .cube file + void write_vdata_palgrid( + const Parallel_Grid& pgrid, + const double* const data, + const int is, + const int nspin, + const int iter, const std::string& fn, - const int& nx, - const int& ny, - const int& nz, - const double& ef, - const UnitCell* ucell, - const int& precision = 11, - const int& out_fermi = 1); // mohan add 2007-10-17 + const double ef, + const UnitCell*const ucell, + const int precision = 11, + const int out_fermi = 1); // mohan add 2007-10-17 + + /// read the full data from a cube file + bool read_cube(const std::string& file, + std::vector& comment, + int& natom, + std::vector& origin, + int& nx, + int& ny, + int& nz, + std::vector& dx, + std::vector& dy, + std::vector& dz, + std::vector& atom_type, + std::vector& atom_charge, + std::vector>& atom_pos, + std::vector& data); + + /// write a cube file + void write_cube(const std::string& file, + const std::vector& comment, + const int& natom, + const std::vector& origin, + const int& nx, + const int& ny, + const int& nz, + const std::vector& dx, + const std::vector& dy, + const std::vector& dz, + const std::vector& atom_type, + const std::vector& atom_charge, + const std::vector>& atom_pos, + const std::vector& data, + const int precision, + const int ndata_line = 6); /** * @brief The trilinear interpolation method @@ -69,28 +83,23 @@ void write_cube( * directions, divided by the grid spacing. Here, it is assumed that the grid spacing is equal and can be * omitted during computation. * - * @param ifs the ifstream used to read charge density + * @param data_in the input data of size nxyz_read * @param nx_read nx read from file * @param ny_read ny read from file * @param nz_read nz read from file * @param nx the dimension of grids along x * @param ny the dimension of grids along y * @param nz the dimension of grids along z - * @param data the interpolated results + * @param data_out the interpolated results of size nxyz */ - void trilinear_interpolate(std::ifstream& ifs, - const int& nx_read, - const int& ny_read, - const int& nz_read, - const int& nx, - const int& ny, - const int& nz, -#ifdef __MPI - double** data -#else - double* data -#endif - ); +void trilinear_interpolate(const double* const data_in, + const int& nx_read, + const int& ny_read, + const int& nz_read, + const int& nx, + const int& ny, + const int& nz, + double* data_out); } #endif diff --git a/source/module_io/get_pchg_lcao.cpp b/source/module_io/get_pchg_lcao.cpp index 3e8de3d5cf6..f4567a67da8 100644 --- a/source/module_io/get_pchg_lcao.cpp +++ b/source/module_io/get_pchg_lcao.cpp @@ -26,7 +26,7 @@ IState_Charge::~IState_Charge() { } -// for gamma only +// For gamma_only void IState_Charge::begin(Gint_Gamma& gg, double** rho, const ModuleBase::matrix& wg, @@ -41,13 +41,12 @@ void IState_Charge::begin(Gint_Gamma& gg, const int bigpw_nbz, const bool gamma_only_local, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int nspin, const int nlocal, const std::string& global_out_dir, - const int my_rank, std::ofstream& ofs_warning, const UnitCell* ucell_in, Grid_Driver* GridD_in, @@ -55,22 +54,22 @@ void IState_Charge::begin(Gint_Gamma& gg, { ModuleBase::TITLE("IState_Charge", "begin"); - std::cout << " Perform |psi(i)|^2 for selected bands (band-decomposed charge densities, gamma only)." << std::endl; + std::cout << " Calculate |psi(i)|^2 for selected bands (band-decomposed charge densities, gamma only)." + << std::endl; + // Determine the mode based on the input parameters int mode = 0; - if (nbands_istate > 0 && static_cast(out_band_kb.size()) == 0) + // mode = 1: select bands below and above the Fermi surface using parameter `nbands_istate` + if (nbands_istate > 0 && static_cast(out_pchg.size()) == 0) { mode = 1; } - else if (static_cast(out_band_kb.size()) > 0) + // mode = 2: select bands directly using parameter `out_pchg` + else if (static_cast(out_pchg.size()) > 0) { - // If out_band_kb (bands_to_print) is not empty, set mode to 2 + // If out_pchg is not empty, set mode to 2 mode = 2; - std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `bands_to_print`!" << std::endl; - } - else - { - mode = 3; + std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `out_pchg`!" << std::endl; } // if ucell is odd, it's correct, @@ -81,7 +80,7 @@ void IState_Charge::begin(Gint_Gamma& gg, std::cout << " number of occupied bands = " << fermi_band << std::endl; // Set this->bands_picked_ according to the mode - select_bands(nbands_istate, out_band_kb, nbands, nelec, mode, fermi_band); + select_bands(nbands_istate, out_pchg, nbands, nelec, mode, fermi_band); for (int ib = 0; ib < nbands; ++ib) { @@ -105,9 +104,9 @@ void IState_Charge::begin(Gint_Gamma& gg, DM.init_DMR(GridD_in, ucell_in); DM.cal_DMR(); - gg.initialize_pvpR(*ucell_in, GridD_in); + gg.initialize_pvpR(*ucell_in, GridD_in, PARAM.inp.nspin); gg.transfer_DM2DtoGrid(DM.get_DMR_vector()); - Gint_inout inout((double***)nullptr, rho, Gint_Tools::job_type::rho); + Gint_inout inout(rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); gg.cal_gint(&inout); // A solution to replace the original implementation of the following code: @@ -131,21 +130,12 @@ void IState_Charge::begin(Gint_Gamma& gg, // Use a const vector to store efermi for all spins, replace the original implementation: // const double ef_tmp = pelec->eferm.get_efval(is); double ef_spin = ef_all_spin[is]; - ModuleIO::write_cube( -#ifdef __MPI - bigpw_bz, - bigpw_nbz, - rhopw_nplane, - rhopw_startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, rho_save[is].data(), is, nspin, 0, ssc.str(), - rhopw_nx, - rhopw_ny, - rhopw_nz, ef_spin, ucell_in); } @@ -174,13 +164,12 @@ void IState_Charge::begin(Gint_k& gk, const int bigpw_nbz, const bool gamma_only_local, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int nspin, const int nlocal, const std::string& global_out_dir, - const int my_rank, std::ofstream& ofs_warning, UnitCell* ucell_in, Grid_Driver* GridD_in, @@ -191,18 +180,18 @@ void IState_Charge::begin(Gint_k& gk, { ModuleBase::TITLE("IState_Charge", "begin"); - std::cout << " Perform |psi(i)|^2 for selected bands (band-decomposed charge densities, multi-k)." << std::endl; + std::cout << " Calculate |psi(i)|^2 for selected bands (band-decomposed charge densities, multi-k)." << std::endl; int mode = 0; - if (nbands_istate > 0 && static_cast(out_band_kb.size()) == 0) + if (nbands_istate > 0 && static_cast(out_pchg.size()) == 0) { mode = 1; } - else if (static_cast(out_band_kb.size()) > 0) + else if (static_cast(out_pchg.size()) > 0) { - // If out_band_kb (bands_to_print) is not empty, set mode to 2 + // If out_pchg is not empty, set mode to 2 mode = 2; - std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `bands_to_print`!" << std::endl; + std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `out_pchg`!" << std::endl; } else { @@ -214,14 +203,15 @@ void IState_Charge::begin(Gint_k& gk, std::cout << " number of occupied bands = " << fermi_band << std::endl; // Set this->bands_picked_ according to the mode - select_bands(nbands_istate, out_band_kb, nbands, nelec, mode, fermi_band); + select_bands(nbands_istate, out_pchg, nbands, nelec, mode, fermi_band); for (int ib = 0; ib < nbands; ++ib) { if (bands_picked_[ib]) { // Using new density matrix inplementation (multi-k) - elecstate::DensityMatrix, double> DM(&kv, this->ParaV, nspin); + const int nspin_dm = std::map({ {1,1},{2,2},{4,1} })[nspin]; + elecstate::DensityMatrix, double> DM(this->ParaV, nspin_dm, kv.kvec_d, kv.get_nks() / nspin_dm); #ifdef __MPI this->idmatrix(ib, nspin, nelec, nlocal, wg, DM, kv, if_separate_k); @@ -244,9 +234,9 @@ void IState_Charge::begin(Gint_k& gk, DM.init_DMR(GridD_in, ucell_in); DM.cal_DMR(ik); - gk.initialize_pvpR(*ucell_in, GridD_in); + gk.initialize_pvpR(*ucell_in, GridD_in, PARAM.inp.nspin); gk.transfer_DM2DtoGrid(DM.get_DMR_vector()); - Gint_inout inout(rho, Gint_Tools::job_type::rho); + Gint_inout inout(rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); gk.cal_gint(&inout); // Using std::vector to replace the original double** rho_save @@ -266,21 +256,12 @@ void IState_Charge::begin(Gint_k& gk, ssc << global_out_dir << "BAND" << ib + 1 << "_K" << ik + 1 << "_SPIN" << is + 1 << "_CHG.cube"; double ef_spin = ef_all_spin[is]; - ModuleIO::write_cube( -#ifdef __MPI - bigpw_bz, - bigpw_nbz, - rhopw_nplane, - rhopw_startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, rho_save[is].data(), is, nspin, 0, ssc.str(), - rhopw_nx, - rhopw_ny, - rhopw_nz, ef_spin, ucell_in); } @@ -299,9 +280,9 @@ void IState_Charge::begin(Gint_k& gk, DM.init_DMR(GridD_in, ucell_in); DM.cal_DMR(); - gk.initialize_pvpR(*ucell_in, GridD_in); + gk.initialize_pvpR(*ucell_in, GridD_in, PARAM.inp.nspin); gk.transfer_DM2DtoGrid(DM.get_DMR_vector()); - Gint_inout inout(rho, Gint_Tools::job_type::rho); + Gint_inout inout(rho, Gint_Tools::job_type::rho, PARAM.inp.nspin); gk.cal_gint(&inout); // Using std::vector to replace the original double** rho_save @@ -322,13 +303,7 @@ void IState_Charge::begin(Gint_k& gk, { rho_save_pointers[i] = rho_save[i].data(); } - srho.begin(is, - rho_save_pointers.data(), - rhog, - ngmc, - nullptr, - rho_pw, - ucell_in->symm); + srho.begin(is, rho_save_pointers.data(), rhog, ngmc, nullptr, rho_pw, ucell_in->symm); } std::cout << " Writing cube files..."; @@ -340,21 +315,12 @@ void IState_Charge::begin(Gint_k& gk, ssc << global_out_dir << "BAND" << ib + 1 << "_SPIN" << is + 1 << "_CHG.cube"; double ef_spin = ef_all_spin[is]; - ModuleIO::write_cube( -#ifdef __MPI - bigpw_bz, - bigpw_nbz, - rhopw_nplane, - rhopw_startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, rho_save[is].data(), is, nspin, 0, ssc.str(), - rhopw_nx, - rhopw_ny, - rhopw_nz, ef_spin, ucell_in); } @@ -368,7 +334,7 @@ void IState_Charge::begin(Gint_k& gk, } void IState_Charge::select_bands(const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int mode, @@ -382,6 +348,7 @@ void IState_Charge::select_bands(const int nbands_istate, this->bands_picked_.resize(nbands); ModuleBase::GlobalFunc::ZEROS(bands_picked_.data(), nbands); + // mode = 1: select bands below and above the Fermi surface using parameter `nbands_istate` if (mode == 1) { bands_below = nbands_istate; @@ -404,33 +371,28 @@ void IState_Charge::select_bands(const int nbands_istate, } } } + // mode = 2: select bands directly using parameter `out_pchg` else if (mode == 2) { - // Check if length of out_band_kb is valid - if (static_cast(out_band_kb.size()) > nbands) + // Check if length of out_pchg is valid + if (static_cast(out_pchg.size()) > nbands) { - ModuleBase::WARNING_QUIT( - "IState_Charge::select_bands", - "The number of bands specified by `bands_to_print` in the INPUT file exceeds `nbands`!"); + ModuleBase::WARNING_QUIT("IState_Charge::select_bands", + "The number of bands specified by `out_pchg` in the INPUT file exceeds `nbands`!"); } - // Check if all elements in out_band_kb are 0 or 1 - for (int value: out_band_kb) + // Check if all elements in out_pchg are 0 or 1 + for (int value: out_pchg) { if (value != 0 && value != 1) { - ModuleBase::WARNING_QUIT( - "IState_Charge::select_bands", - "The elements of `bands_to_print` must be either 0 or 1. Invalid values found!"); + ModuleBase::WARNING_QUIT("IState_Charge::select_bands", + "The elements of `out_pchg` must be either 0 or 1. Invalid values found!"); } } - // Fill bands_picked_ with values from out_band_kb + // Fill bands_picked_ with values from out_pchg // Remaining bands are already set to 0 - const int length = std::min(static_cast(out_band_kb.size()), nbands); - for (int i = 0; i < length; ++i) - { - // out_band_kb rely on function parse_expression - bands_picked_[i] = out_band_kb[i]; - } + const int length = std::min(static_cast(out_pchg.size()), nbands); + std::copy(out_pchg.begin(), out_pchg.begin() + length, bands_picked_.begin()); // Check if there are selected bands below the Fermi surface bool has_below = false; @@ -485,7 +447,7 @@ void IState_Charge::select_bands(const int nbands_istate, } #ifdef __MPI -// for gamma only +// For gamma_only void IState_Charge::idmatrix(const int& ib, const int nspin, const double& nelec, diff --git a/source/module_io/get_pchg_lcao.h b/source/module_io/get_pchg_lcao.h index 26e15b2579b..a923397c32d 100644 --- a/source/module_io/get_pchg_lcao.h +++ b/source/module_io/get_pchg_lcao.h @@ -1,6 +1,7 @@ #ifndef ISTATE_CHARGE_H #define ISTATE_CHARGE_H #include "module_basis/module_pw/pw_basis.h" +#include "module_cell/klist.h" #include "module_elecstate/module_dm/density_matrix.h" #include "module_hamilt_lcao/module_gint/gint.h" #include "module_hamilt_lcao/module_gint/gint_gamma.h" @@ -28,7 +29,7 @@ class IState_Charge ~IState_Charge(); - // for gamma only + // For gamma_only void begin(Gint_Gamma& gg, double** rho, const ModuleBase::matrix& wg, @@ -43,13 +44,12 @@ class IState_Charge const int bigpw_nbz, const bool gamma_only_local, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int nspin, const int nlocal, const std::string& global_out_dir, - const int my_rank, std::ofstream& ofs_warning, const UnitCell* ucell_in, Grid_Driver* GridD_in, @@ -72,13 +72,12 @@ class IState_Charge const int bigpw_nbz, const bool gamma_only_local, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int nspin, const int nlocal, const std::string& global_out_dir, - const int my_rank, std::ofstream& ofs_warning, UnitCell* ucell_in, Grid_Driver* GridD_in, @@ -92,14 +91,14 @@ class IState_Charge * @brief Set this->bands_picked_ according to the mode, and process an error if the mode is not recognized. * * @param nbands_istate INPUT parameter nbands_istate. - * @param out_band_kb Calculated from INPUT parameter bands_to_print, vector. + * @param out_pchg INPUT parameter out_pchg, vector. * @param nbands INPUT parameter nbands. * @param nelec Total number of electrons. * @param mode Selected mode. * @param fermi_band Calculated Fermi band. */ void select_bands(const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_pchg, const int nbands, const double nelec, const int mode, diff --git a/source/module_io/get_pchg_pw.h b/source/module_io/get_pchg_pw.h index 1dfc797b324..e7ba789ede0 100644 --- a/source/module_io/get_pchg_pw.h +++ b/source/module_io/get_pchg_pw.h @@ -118,21 +118,12 @@ void get_pchg_pw(const std::vector& bands_to_print, ssc << global_out_dir << "BAND" << ib + 1 << "_K" << ik % (nks / nspin) + 1 << "_SPIN" << spin_index + 1 << "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - pw_big_bz, - pw_big_nbz, - pw_rhod->nplane, - pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, rho_band[spin_index].data(), spin_index, nspin, 0, ssc.str(), - nx, - ny, - nz, 0.0, ucell); @@ -195,21 +186,12 @@ void get_pchg_pw(const std::vector& bands_to_print, std::stringstream ssc; ssc << global_out_dir << "BAND" << ib + 1 << "_SPIN" << is + 1 << "_CHG.cube"; - ModuleIO::write_cube( -#ifdef __MPI - pw_big_bz, - pw_big_nbz, - pw_rhod->nplane, - pw_rhod->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, rho_band[is].data(), is, nspin, 0, ssc.str(), - nx, - ny, - nz, 0.0, ucell); } diff --git a/source/module_io/get_wf_lcao.cpp b/source/module_io/get_wf_lcao.cpp index 6792c4a64a2..d1257de1bb7 100644 --- a/source/module_io/get_wf_lcao.cpp +++ b/source/module_io/get_wf_lcao.cpp @@ -1,5 +1,6 @@ #include "get_wf_lcao.h" +#include "module_parameter/parameter.h" #include "module_base/global_function.h" #include "module_base/global_variable.h" #include "module_base/memory.h" @@ -17,10 +18,11 @@ IState_Envelope::~IState_Envelope() { } +// For gamma_only void IState_Envelope::begin(const psi::Psi* psid, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_Gamma& gg, const int& out_wfc_pw, @@ -28,7 +30,8 @@ void IState_Envelope::begin(const psi::Psi* psid, const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -36,150 +39,125 @@ void IState_Envelope::begin(const psi::Psi* psid, { ModuleBase::TITLE("IState_Envelope", "begin"); - std::cout << " Perform |psi(band, r)| for selected bands." << std::endl; + std::cout << " Calculate |psi(i, r)|, Re[psi(i, r)], Im[psi(i, r)] for selected bands (gamma only)." << std::endl; - int mode = 0; - if (nbands_istate > 0 && static_cast(out_band_kb.size()) == 0) - { - mode = 1; - } - else if (static_cast(out_band_kb.size()) > 0) - { - // If out_band_kb (bands_to_print) is not empty, set mode to 2 - mode = 2; - std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `bands_to_print`!" << std::endl; - } - - int fermi_band = 0; - int bands_below = 0; - int bands_above = 0; - - this->bands_picked_.resize(nbands); - ModuleBase::GlobalFunc::ZEROS(bands_picked_.data(), nbands); - - // (1) - // mohan update 2011-03-21 // if ucell is odd, it's correct, // if ucell is even, it's also correct. // +1.0e-8 in case like (2.999999999+1)/2 + const int fermi_band = static_cast((nelec + 1) / 2 + 1.0e-8); std::cout << " number of electrons = " << nelec << std::endl; - fermi_band = static_cast((nelec + 1) / 2 + 1.0e-8); std::cout << " number of occupied bands = " << fermi_band << std::endl; - if (mode == 1) + // allocate grid wave functions for gamma_only + std::vector wfc_gamma_grid(nspin); + for (int is = 0; is < nspin; ++is) { - bands_below = nbands_istate; - bands_above = nbands_istate; - - std::cout << " Plot band decomposed charge density below Fermi surface with " << bands_below << " bands." - << std::endl; - - std::cout << " Plot band decomposed charge density above Fermi surface with " << bands_above << " bands." - << std::endl; - - for (int ib = 0; ib < nbands; ib++) + wfc_gamma_grid[is] = new double*[nbands]; + for (int ib = 0; ib < nbands; ++ib) { - if (ib >= fermi_band - bands_below) - { - if (ib < fermi_band + bands_above) - { - bands_picked_[ib] = 1; - } - } + wfc_gamma_grid[is][ib] = new double[gg.gridt->lgd]; } } - else if (mode == 2) + + // for pw_wfc in G space + psi::Psi> psi_g; + if (out_wfc_pw || out_wfc_r) { - // Check if length of out_band_kb is valid - if (static_cast(out_band_kb.size()) > nbands) - { - ModuleBase::WARNING_QUIT( - "IState_Envelope::begin", - "The number of bands specified by `bands_to_print` in the INPUT file exceeds `nbands`!"); - } - // Check if all elements in bands_picked_ are 0 or 1 - for (int value: out_band_kb) - { - if (value != 0 && value != 1) - { - ModuleBase::WARNING_QUIT( - "IState_Envelope::begin", - "The elements of `bands_to_print` must be either 0 or 1. Invalid values found!"); - } - } - // Fill bands_picked_ with values from out_band_kb - // Remaining bands are already set to 0 - int length = std::min(static_cast(out_band_kb.size()), nbands); - for (int i = 0; i < length; ++i) - { - // out_band_kb rely on function parse_expression - bands_picked_[i] = out_band_kb[i]; - } + psi_g.resize(nspin, nbands, kv.ngk[0]); + } - std::cout << " Plot band decomposed charge density below the Fermi surface: band "; - for (int i = 0; i + 1 <= fermi_band; ++i) - { - if (bands_picked_[i] == 1) - { - std::cout << i + 1 << " "; - } - } - std::cout << std::endl; - std::cout << " Plot band decomposed charge density above the Fermi surface: band "; - for (int i = fermi_band; i < nbands; ++i) - { - if (bands_picked_[i] == 1) - { - std::cout << i + 1 << " "; - } - } - std::cout << std::endl; + const double mem_size = sizeof(double) * double(gg.gridt->lgd) * double(nbands) * double(nspin) / 1024.0 / 1024.0; + ModuleBase::Memory::record("IState_Envelope::begin::wfc_gamma_grid", mem_size); + printf(" Estimated on-the-fly memory consuming by IState_Envelope::begin::wfc_gamma_grid: %f MB\n", mem_size); + + int mode_norm = 0; + if (nbands_istate > 0 && static_cast(out_wfc_norm.size()) == 0) + { + mode_norm = 1; } - else + else if (static_cast(out_wfc_norm.size()) > 0) { - ModuleBase::WARNING_QUIT("IState_Envelope::begin", "Invalid mode! Please check the code."); + // If out_wfc_norm is not empty, set mode to 2 + mode_norm = 2; + std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `out_wfc_norm`!" << std::endl; } - // (2) cicle: + // Set this->bands_picked_ according to the mode + select_bands(nbands_istate, out_wfc_norm, nbands, nelec, mode_norm, fermi_band); - // (2.1) calculate the selected density matrix - // from wave functions. + // Calculate out_wfc_norm + for (int ib = 0; ib < nbands; ++ib) + { + if (bands_picked_[ib]) + { + std::cout << " Performing grid integral over real space grid for band " << ib + 1 << "..." << std::endl; - // (2.2) carry out the grid integration to - // get the charge density. + for (int is = 0; is < nspin; ++is) + { + ModuleBase::GlobalFunc::ZEROS(pes_->charge->rho[is], pw_wfc->nrxx); - // (2.3) output the charge density in .cub format. + psid->fix_k(is); +#ifdef __MPI + wfc_2d_to_grid(psid->get_pointer(), para_orb, wfc_gamma_grid[is], gg.gridt->trace_lo); +#else + // if not MPI enabled, it is the case psid holds a global matrix. use fix_k to switch between different + // spin channels (actually kpoints, because now the same kpoint in different spin channels are treated + // as distinct kpoints) - // allocate grid wavefunction for gamma_only - std::vector wfc_gamma_grid(nspin); - for (int is = 0; is < nspin; ++is) - { - wfc_gamma_grid[is] = new double*[nbands]; - for (int ib = 0; ib < nbands; ++ib) { - wfc_gamma_grid[is][ib] = new double[gg.gridt->lgd]; -} - } + for (int i = 0; i < nbands; ++i) + { + for (int j = 0; j < nlocal; ++j) + { + wfc_gamma_grid[is][i][j] = psid[0](i, j); + } + } +#endif - const double mem_size = sizeof(double) * double(gg.gridt->lgd) * double(nbands) * double(nspin) / 1024.0 / 1024.0; - ModuleBase::Memory::record("IState_Envelope::begin::wfc_gamma_grid", mem_size); - printf(" Estimated on-the-fly memory consuming by IState_Envelope::begin::wfc_gamma_grid: %f MB\n", mem_size); + gg.cal_env(wfc_gamma_grid[is][ib], pes_->charge->rho[is], GlobalC::ucell); - // for pw-wfc in G space - psi::Psi> pw_wfc_g; + pes_->charge->save_rho_before_sum_band(); - if (out_wfc_pw || out_wfc_r) + std::stringstream ss; + ss << global_out_dir << "BAND" << ib + 1 << "_GAMMA" << "_SPIN" << is + 1 << "_ENV.cube"; + + const double ef_tmp = this->pes_->eferm.get_efval(is); + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + pes_->charge->rho_save[is], + is, + nspin, + 0, + ss.str(), + ef_tmp, + &(GlobalC::ucell)); + } + } + } + + int mode_re_im = 0; + if (nbands_istate > 0 && static_cast(out_wfc_re_im.size()) == 0) + { + mode_re_im = 1; + } + else if (static_cast(out_wfc_re_im.size()) > 0) { - pw_wfc_g.resize(1, nbands, kv.ngk[0]); + // If out_wfc_re_im is not empty, set mode to 2 + mode_re_im = 2; + std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `out_wfc_re_im`!" << std::endl; } - for (int ib = 0; ib < nbands; ib++) + // Set this->bands_picked_ according to the mode + select_bands(nbands_istate, out_wfc_re_im, nbands, nelec, mode_re_im, fermi_band); + + // Calculate out_wfc_re_im + for (int ib = 0; ib < nbands; ++ib) { if (bands_picked_[ib]) { - for (int is = 0; is < nspin; ++is) // loop over spin + std::cout << " Performing grid integral over real space grid for band " << ib + 1 << "..." << std::endl; + + for (int is = 0; is < nspin; ++is) { - std::cout << " Perform envelope function for band " << ib + 1 << std::endl; - ModuleBase::GlobalFunc::ZEROS(pes_->charge->rho[is], wfcpw->nrxx); + ModuleBase::GlobalFunc::ZEROS(pes_->charge->rho[is], pw_wfc->nrxx); psid->fix_k(is); #ifdef __MPI @@ -192,38 +170,59 @@ void IState_Envelope::begin(const psi::Psi* psid, for (int i = 0; i < nbands; ++i) { for (int j = 0; j < nlocal; ++j) + { wfc_gamma_grid[is][i][j] = psid[0](i, j); + } } #endif + gg.cal_env(wfc_gamma_grid[is][ib], pes_->charge->rho[is], GlobalC::ucell); - pes_->charge->save_rho_before_sum_band(); // xiaohui add 2014-12-09 - std::stringstream ss; - ss << global_out_dir << "BAND" << ib + 1 << "_s_" << is + 1 << "_ENV.cube"; + pes_->charge->save_rho_before_sum_band(); + const double ef_tmp = this->pes_->eferm.get_efval(is); - ModuleIO::write_cube( -#ifdef __MPI - bigpw->bz, - bigpw->nbz, - rhopw->nplane, - rhopw->startz_current, -#endif - pes_->charge->rho_save[is], + + // only for gamma_only now + psi_g.fix_k(is); + this->set_pw_wfc(pw_wfc, is, ib, nspin, pes_->charge->rho, psi_g); + + // Calculate real-space wave functions + psi_g.fix_k(is); + std::vector> wfc_r(pw_wfc->nrxx); + pw_wfc->recip2real(&psi_g(ib, 0), wfc_r.data(), is); + + // Extract real and imaginary parts + std::vector wfc_real(pw_wfc->nrxx); + std::vector wfc_imag(pw_wfc->nrxx); + for (int ir = 0; ir < pw_wfc->nrxx; ++ir) + { + wfc_real[ir] = wfc_r[ir].real(); + wfc_imag[ir] = wfc_r[ir].imag(); + } + + // Output real part + std::stringstream ss_real; + ss_real << global_out_dir << "BAND" << ib + 1 << "_GAMMA" << "_SPIN" << is + 1 << "_REAL.cube"; + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + wfc_real.data(), is, nspin, 0, - ss.str(), - rhopw->nx, - rhopw->ny, - rhopw->nz, + ss_real.str(), ef_tmp, - &(GlobalC::ucell), - 3, - 1); + &(GlobalC::ucell)); - if (out_wfc_pw || out_wfc_r) { // only for gamma_only now - this->set_pw_wfc(wfcpw, 0, ib, nspin, pes_->charge->rho_save, pw_wfc_g); -} + // Output imaginary part + std::stringstream ss_imag; + ss_imag << global_out_dir << "BAND" << ib + 1 << "_GAMMA" << "_SPIN" << is + 1 << "_IMAG.cube"; + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + wfc_imag.data(), + is, + nspin, + 0, + ss_imag.str(), + ef_tmp, + &(GlobalC::ucell)); } } } @@ -232,29 +231,32 @@ void IState_Envelope::begin(const psi::Psi* psid, { std::stringstream ssw; ssw << global_out_dir << "WAVEFUNC"; - std::cout << " write G-space wavefunction into \"" << global_out_dir << "/" << ssw.str() << "\" files." + std::cout << " Write G-space wave functions into \"" << global_out_dir << "/" << ssw.str() << "\" files." << std::endl; - ModuleIO::write_wfc_pw(ssw.str(), pw_wfc_g, kv, wfcpw); + ModuleIO::write_wfc_pw(ssw.str(), psi_g, kv, pw_wfc); } + if (out_wfc_r) { - ModuleIO::write_psi_r_1(pw_wfc_g, wfcpw, "wfc_realspace", false, kv); + ModuleIO::write_psi_r_1(psi_g, pw_wfc, "wfc_realspace", false, kv); } for (int is = 0; is < nspin; ++is) { - for (int ib = 0; ib < nbands; ++ib) { + for (int ib = 0; ib < nbands; ++ib) + { delete[] wfc_gamma_grid[is][ib]; -} + } delete[] wfc_gamma_grid[is]; } return; } +// For multi-k void IState_Envelope::begin(const psi::Psi>* psi, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_k& gk, const int& out_wf, @@ -262,7 +264,8 @@ void IState_Envelope::begin(const psi::Psi>* psi, const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -270,123 +273,17 @@ void IState_Envelope::begin(const psi::Psi>* psi, { ModuleBase::TITLE("IState_Envelope", "begin"); - std::cout << " Perform |psi(band, r)| for selected bands." << std::endl; - - int mode = 0; - if (nbands_istate > 0 && static_cast(out_band_kb.size()) == 0) - { - mode = 1; - } - else if (static_cast(out_band_kb.size()) > 0) - { - // If out_band_kb (bands_to_print) is not empty, set mode to 2 - mode = 2; - std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `bands_to_print`!" << std::endl; - } + std::cout << " Calculate |psi(i, r)|, Re[psi(i, r)], Im[psi(i, r)] for selected bands (multi-k)." << std::endl; - int fermi_band = 0; - int bands_below = 0; - int bands_above = 0; - - this->bands_picked_.resize(nbands); - ModuleBase::GlobalFunc::ZEROS(bands_picked_.data(), nbands); - - // (1) - // mohan update 2011-03-21 // if ucell is odd, it's correct, // if ucell is even, it's also correct. // +1.0e-8 in case like (2.999999999+1)/2 // if NSPIN=4, each band only one electron, fermi_band should be nelec - + const int fermi_band = nspin < 4 ? static_cast((nelec + 1) / 2 + 1.0e-8) : nelec; std::cout << " number of electrons = " << nelec << std::endl; - fermi_band = nspin < 4 ? static_cast((nelec + 1) / 2 + 1.0e-8) : nelec; std::cout << " number of occupied bands = " << fermi_band << std::endl; - if (mode == 1) - { - bands_below = nbands_istate; - bands_above = nbands_istate; - - std::cout << " Plot band decomposed charge density below Fermi surface with " << bands_below << " bands." - << std::endl; - - std::cout << " Plot band decomposed charge density above Fermi surface with " << bands_above << " bands." - << std::endl; - - for (int ib = 0; ib < nbands; ib++) - { - if (ib >= fermi_band - bands_below) - { - if (ib < fermi_band + bands_above) - { - bands_picked_[ib] = 1; - } - } - } - } - else if (mode == 2) - { - // Check if length of out_band_kb is valid - if (static_cast(out_band_kb.size()) > nbands) - { - ModuleBase::WARNING_QUIT( - "IState_Envelope::begin", - "The number of bands specified by `bands_to_print` in the INPUT file exceeds `nbands`!"); - } - // Check if all elements in bands_picked_ are 0 or 1 - for (int value: out_band_kb) - { - if (value != 0 && value != 1) - { - ModuleBase::WARNING_QUIT( - "IState_Envelope::begin", - "The elements of `bands_to_print` must be either 0 or 1. Invalid values found!"); - } - } - // Fill bands_picked_ with values from out_band_kb - // Remaining bands are already set to 0 - int length = std::min(static_cast(out_band_kb.size()), nbands); - for (int i = 0; i < length; ++i) - { - // out_band_kb rely on function parse_expression - bands_picked_[i] = out_band_kb[i]; - } - - std::cout << " Plot band decomposed charge density below the Fermi surface: band "; - for (int i = 0; i + 1 <= fermi_band; ++i) - { - if (bands_picked_[i] == 1) - { - std::cout << i + 1 << " "; - } - } - std::cout << std::endl; - std::cout << " Plot band decomposed charge density above the Fermi surface: band "; - for (int i = fermi_band; i < nbands; ++i) - { - if (bands_picked_[i] == 1) - { - std::cout << i + 1 << " "; - } - } - std::cout << std::endl; - } - else - { - ModuleBase::WARNING_QUIT("IState_Envelope::begin", "Invalid mode! Please check the code."); - } - - // (2) cicle: - - // (2.1) calculate the selected density matrix - // from wave functions. - - // (2.2) carry out the grid integration to - // get the charge density. - - // (2.3) output the charge density in .cub format. - - // allocate grid wavefunction for gamma_only + // allocate grid wave functions for multi-k const int nks = kv.get_nks(); std::vector**> wfc_k_grid(nks); for (int ik = 0; ik < nks; ++ik) @@ -397,30 +294,48 @@ void IState_Envelope::begin(const psi::Psi>* psi, wfc_k_grid[ik][ib] = new std::complex[gk.gridt->lgd]; } } + const double mem_size = sizeof(std::complex) * double(gk.gridt->lgd) * double(nbands) * double(nks) / 1024.0 / 1024.0; ModuleBase::Memory::record("IState_Envelope::begin::wfc_k_grid", mem_size); printf(" Estimated on-the-fly memory consuming by IState_Envelope::begin::wfc_k_grid: %f MB\n", mem_size); - // for pw-wfc in G space - psi::Psi> pw_wfc_g(kv.ngk.data()); - + // for pw_wfc in G space + psi::Psi> psi_g(kv.ngk.data()); if (out_wf || out_wf_r) { - pw_wfc_g.resize(nks, nbands, wfcpw->npwk_max); + psi_g.resize(nks, nbands, pw_wfc->npwk_max); + } + + int mode_norm = 0; + if (nbands_istate > 0 && static_cast(out_wfc_norm.size()) == 0) + { + mode_norm = 1; + } + else if (static_cast(out_wfc_norm.size()) > 0) + { + // If out_wfc_norm is not empty, set mode to 2 + mode_norm = 2; + std::cout << " Notice: INPUT parameter `nbands_istate` overwritten by `out_wfc_norm`!" << std::endl; } - for (int ib = 0; ib < nbands; ib++) + // Set this->bands_picked_ according to the mode + select_bands(nbands_istate, out_wfc_norm, nbands, nelec, mode_norm, fermi_band); + + // Calculate out_wfc_norm + for (int ib = 0; ib < nbands; ++ib) { if (bands_picked_[ib]) { + std::cout << " Performing grid integral over real space grid for band " << ib + 1 << "..." << std::endl; + const int nspin0 = (nspin == 2) ? 2 : 1; for (int ik = 0; ik < nks; ++ik) // the loop of nspin0 is included { const int ispin = kv.isk[ik]; ModuleBase::GlobalFunc::ZEROS(pes_->charge->rho[ispin], - wfcpw->nrxx); // terrible, you make changes on another instance's data??? - std::cout << " Perform envelope function for kpoint " << ik << ", band" << ib + 1 << std::endl; + pw_wfc->nrxx); // terrible, you make changes on another instance's data??? + std::cout << " Calculate envelope function for kpoint " << ik + 1 << ", band" << ib + 1 << std::endl; // 2d-to-grid conversion is unified into `wfc_2d_to_grid`. psi->fix_k(ik); #ifdef __MPI // need to deal with NSPIN=4 !!!! @@ -436,34 +351,24 @@ void IState_Envelope::begin(const psi::Psi>* psi, gk.cal_env_k(ik, wfc_k_grid[ik][ib], pes_->charge->rho[ispin], kv.kvec_c, kv.kvec_d, GlobalC::ucell); std::stringstream ss; - ss << global_out_dir << "BAND" << ib + 1 << "_k_" << ik / nspin0 + 1 << "_s_" << ispin + 1 - << "_ENV.cube"; + ss << global_out_dir << "BAND" << ib + 1 << "_k_" << ik + 1 << "_s_" << ispin + 1 << "_ENV.cube"; const double ef_tmp = this->pes_->eferm.get_efval(ispin); - ModuleIO::write_cube( -#ifdef __MPI - bigpw->bz, - bigpw->nbz, - rhopw->nplane, - rhopw->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, pes_->charge->rho[ispin], ispin, nspin, 0, ss.str(), - rhopw->nx, - rhopw->ny, - rhopw->nz, ef_tmp, &(GlobalC::ucell), 3, 1); - if (out_wf || out_wf_r) // only for gamma_only now + if (out_wf || out_wf_r) { - pw_wfc_g.fix_k(ik); - this->set_pw_wfc(wfcpw, ik, ib, nspin, pes_->charge->rho, pw_wfc_g); + psi_g.fix_k(ik); + this->set_pw_wfc(pw_wfc, ik, ib, nspin, pes_->charge->rho, psi_g); } } } @@ -475,50 +380,226 @@ void IState_Envelope::begin(const psi::Psi>* psi, { std::stringstream ssw; ssw << global_out_dir << "WAVEFUNC"; - std::cout << " write G-space wavefunction into \"" << global_out_dir << "/" << ssw.str() << "\" files." + std::cout << " write G-space wave functions into \"" << global_out_dir << "/" << ssw.str() << "\" files." << std::endl; - ModuleIO::write_wfc_pw(ssw.str(), pw_wfc_g, kv, wfcpw); + ModuleIO::write_wfc_pw(ssw.str(), psi_g, kv, pw_wfc); } if (out_wf_r) { - ModuleIO::write_psi_r_1(pw_wfc_g, wfcpw, "wfc_realspace", false, kv); + ModuleIO::write_psi_r_1(psi_g, pw_wfc, "wfc_realspace", false, kv); + } + + std::cout << " Outputting real-space wave functions in cube format..." << std::endl; + + for (int ib = 0; ib < nbands; ++ib) + { + if (bands_picked_[ib]) + { + const int nspin0 = (nspin == 2) ? 2 : 1; + for (int ik = 0; ik < nks; ++ik) + { + const int ispin = kv.isk[ik]; + std::cout << " Processing band " << ib + 1 << ", k-point " << ik << ", spin " << ispin + 1 + << std::endl; + + psi_g.fix_k(ik); + + // Calculate real-space wave functions + std::vector> wfc_r(pw_wfc->nrxx); + pw_wfc->recip2real(&psi_g(ib, 0), wfc_r.data(), ik); + + // Extract real and imaginary parts + std::vector wfc_real(pw_wfc->nrxx); + std::vector wfc_imag(pw_wfc->nrxx); + for (int ir = 0; ir < pw_wfc->nrxx; ++ir) + { + wfc_real[ir] = wfc_r[ir].real(); + wfc_imag[ir] = wfc_r[ir].imag(); + } + + // Output real part + std::stringstream ss_real; + ss_real << global_out_dir << "BAND" << ib + 1 << "_k_" << ik + 1 << "_s_" << ispin + 1 + << "_REAL.cube"; + const double ef_tmp = this->pes_->eferm.get_efval(ispin); + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + wfc_real.data(), + ispin, + nspin, + 0, + ss_real.str(), + ef_tmp, + &(GlobalC::ucell)); + + // Output imaginary part + std::stringstream ss_imag; + ss_imag << global_out_dir << "BAND" << ib + 1 << "_k_" << ik + 1 << "_s_" << ispin + 1 + << "_IMAG.cube"; + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + wfc_imag.data(), + ispin, + nspin, + 0, + ss_imag.str(), + ef_tmp, + &(GlobalC::ucell)); + } + } } } for (int ik = 0; ik < nks; ++ik) { - for (int ib = 0; ib < nbands; ++ib) { + for (int ib = 0; ib < nbands; ++ib) + { delete[] wfc_k_grid[ik][ib]; -} + } delete[] wfc_k_grid[ik]; } return; } +void IState_Envelope::select_bands(const int nbands_istate, + const std::vector& out_wfc_kb, + const int nbands, + const double nelec, + const int mode, + const int fermi_band) +{ + ModuleBase::TITLE("IState_Envelope", "select_bands"); + + int bands_below = 0; + int bands_above = 0; + + this->bands_picked_.resize(nbands); + ModuleBase::GlobalFunc::ZEROS(bands_picked_.data(), nbands); + + // mode = 1: select bands below and above the Fermi surface using parameter `nbands_istate` + if (mode == 1) + { + bands_below = nbands_istate; + bands_above = nbands_istate; + + std::cout << " Plot wave functions below the Fermi surface with " << bands_below << " bands." << std::endl; + + std::cout << " Plot wave functions above the Fermi surface with " << bands_above << " bands." << std::endl; + + for (int ib = 0; ib < nbands; ++ib) + { + if (ib >= fermi_band - bands_below) + { + if (ib < fermi_band + bands_above) + { + bands_picked_[ib] = 1; + } + } + } + } + // mode = 2: select bands directly using parameter `out_wfc_norm` or `out_wfc_re_im` + else if (mode == 2) + { + // Check if length of out_wfc_kb is valid + if (static_cast(out_wfc_kb.size()) > nbands) + { + ModuleBase::WARNING_QUIT("IState_Envelope::select_bands", + "The number of bands specified by `out_wfc_norm` or `out_wfc_re_im` in the INPUT " + "file exceeds `nbands`!"); + } + // Check if all elements in out_wfc_kb are 0 or 1 + for (int value: out_wfc_kb) + { + if (value != 0 && value != 1) + { + ModuleBase::WARNING_QUIT( + "IState_Envelope::select_bands", + "The elements of `out_wfc_norm` or `out_wfc_re_im` must be either 0 or 1. Invalid values found!"); + } + } + // Fill bands_picked_ with values from out_wfc_kb + // Remaining bands are already set to 0 + const int length = std::min(static_cast(out_wfc_kb.size()), nbands); + std::copy(out_wfc_kb.begin(), out_wfc_kb.begin() + length, bands_picked_.begin()); + + // Check if there are selected bands below the Fermi surface + bool has_below = false; + for (int i = 0; i + 1 <= fermi_band; ++i) + { + if (bands_picked_[i] == 1) + { + has_below = true; + break; + } + } + if (has_below) + { + std::cout << " Plot wave functions below the Fermi surface: band "; + for (int i = 0; i + 1 <= fermi_band; ++i) + { + if (bands_picked_[i] == 1) + { + std::cout << i + 1 << " "; + } + } + std::cout << std::endl; + } + + // Check if there are selected bands above the Fermi surface + bool has_above = false; + for (int i = fermi_band; i < nbands; ++i) + { + if (bands_picked_[i] == 1) + { + has_above = true; + break; + } + } + if (has_above) + { + std::cout << " Plot wave functions above the Fermi surface: band "; + for (int i = fermi_band; i < nbands; ++i) + { + if (bands_picked_[i] == 1) + { + std::cout << i + 1 << " "; + } + } + std::cout << std::endl; + } + } + else + { + ModuleBase::WARNING_QUIT("IState_Envelope::select_bands", "Invalid mode! Please check the code."); + } +} + // for each band -void IState_Envelope::set_pw_wfc(const ModulePW::PW_Basis_K* wfcpw, +void IState_Envelope::set_pw_wfc(const ModulePW::PW_Basis_K* pw_wfc, const int& ik, const int& ib, const int& nspin, const double* const* const rho, psi::Psi>& wfc_g) { - if (ib == 0) { // once is enough + if (ib == 0) + { + // once is enough ModuleBase::TITLE("IState_Envelope", "set_pw_wfc"); -} + } - std::vector> Porter(wfcpw->nrxx); + std::vector> Porter(pw_wfc->nrxx); // here I refer to v_hartree, but I don't know how to deal with NSPIN=4 const int nspin0 = (nspin == 2) ? 2 : 1; - for (int is = 0; is < nspin0; is++) { - for (int ir = 0; ir < wfcpw->nrxx; ir++) { + for (int is = 0; is < nspin0; ++is) + { + for (int ir = 0; ir < pw_wfc->nrxx; ++ir) + { Porter[ir] += std::complex(rho[is][ir], 0.0); -} -} + } + } // call FFT - wfcpw->real2recip(Porter.data(), &wfc_g(ib, 0), ik); + pw_wfc->real2recip(Porter.data(), &wfc_g(ib, 0), ik); } #ifdef __MPI @@ -541,7 +622,7 @@ int IState_Envelope::set_wfc_grid(const int naroc[2], for (int j = 0; j < naroc[1]; ++j) { int igcol = globalIndex(j, nb, dim1, ipcol); - if (igcol >= GlobalV::NBANDS) + if (igcol >= PARAM.inp.nbands) { continue; } diff --git a/source/module_io/get_wf_lcao.h b/source/module_io/get_wf_lcao.h index 0b075b8462d..b4c8c11d56c 100644 --- a/source/module_io/get_wf_lcao.h +++ b/source/module_io/get_wf_lcao.h @@ -16,11 +16,11 @@ class IState_Envelope IState_Envelope(const elecstate::ElecState* pes); ~IState_Envelope(); - /// for gamma_only + /// For gamma_only void begin(const psi::Psi* psid, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_Gamma& gg, const int& out_wfc_pw, @@ -28,7 +28,8 @@ class IState_Envelope const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -36,9 +37,9 @@ class IState_Envelope /// tmp, delete after Gint is refactored. void begin(const psi::Psi* psid, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_k& gg, const int& out_wfc_pw, @@ -46,7 +47,8 @@ class IState_Envelope const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -54,11 +56,12 @@ class IState_Envelope { throw std::logic_error("gint_k should use with complex psi."); }; - /// for multi-k + + /// For multi-k void begin(const psi::Psi>* psi, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_k& gk, const int& out_wfc_pw, @@ -66,7 +69,8 @@ class IState_Envelope const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -74,9 +78,9 @@ class IState_Envelope /// tmp, delete after Gint is refactored. void begin(const psi::Psi>* psi, - const ModulePW::PW_Basis* rhopw, - const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_Big* bigpw, + const ModulePW::PW_Basis* pw_rhod, + const ModulePW::PW_Basis_K* pw_wfc, + const ModulePW::PW_Basis_Big* pw_big, const Parallel_Orbitals& para_orb, Gint_Gamma& gk, const int& out_wfc_pw, @@ -84,7 +88,8 @@ class IState_Envelope const K_Vectors& kv, const double nelec, const int nbands_istate, - const std::vector& out_band_kb, + const std::vector& out_wfc_norm, + const std::vector& out_wfc_re_im, const int nbands, const int nspin, const int nlocal, @@ -94,16 +99,22 @@ class IState_Envelope }; private: - std::vector bands_picked_; - const elecstate::ElecState* pes_ = nullptr; + void select_bands(const int nbands_istate, + const std::vector& out_wfc_kb, + const int nbands, + const double nelec, + const int mode, + const int fermi_band); - void set_pw_wfc(const ModulePW::PW_Basis_K* wfcpw, + void set_pw_wfc(const ModulePW::PW_Basis_K* pw_wfc, const int& ik, const int& ib, const int& nspin, const double* const* const rho, psi::Psi>& wfc_g); + int globalIndex(int localindex, int nblk, int nprocs, int myproc); + int localIndex(int globalindex, int nblk, int nprocs, int& myproc); #ifdef __MPI @@ -120,5 +131,8 @@ class IState_Envelope template void wfc_2d_to_grid(const T* wfc_2d, const Parallel_Orbitals& pv, T** wfc_grid, const std::vector& trace_lo); #endif + + std::vector bands_picked_; + const elecstate::ElecState* pes_ = nullptr; }; #endif diff --git a/source/module_io/input_conv.cpp b/source/module_io/input_conv.cpp index 41a9f8542a5..17391e8b9d3 100644 --- a/source/module_io/input_conv.cpp +++ b/source/module_io/input_conv.cpp @@ -166,19 +166,6 @@ void Input_Conv::Convert() //---------------------------------------------------------- // main parameters / electrons / spin ( 10/16 ) //---------------------------------------------------------- - // suffix - if (PARAM.inp.calculation == "md" && PARAM.mdp.md_restart) // md restart liuyu add 2023-04-12 - { - int istep = 0; - double temperature = 0.0; - MD_func::current_md_info(GlobalV::MY_RANK, PARAM.globalv.global_readin_dir, istep, temperature); - if (PARAM.inp.read_file_dir == "auto") - { - GlobalV::stru_file = PARAM.globalv.global_stru_dir + "STRU_MD_" + std::to_string(istep); - } - } else if (PARAM.inp.stru_file != "") { - GlobalV::stru_file = PARAM.inp.stru_file; - } ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "pseudo_dir", PARAM.inp.pseudo_dir); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "orbital_dir", PARAM.inp.orbital_dir); @@ -194,13 +181,7 @@ void Input_Conv::Convert() } - GlobalV::NBANDS = PARAM.inp.nbands; - - GlobalV::device_flag = base_device::information::get_device_flag(PARAM.inp.device, - PARAM.inp.ks_solver, - PARAM.inp.basis_type); - - if (GlobalV::device_flag == "gpu" && PARAM.inp.basis_type == "pw") + if (PARAM.inp.device == "gpu" && PARAM.inp.basis_type == "pw") { GlobalV::KPAR = base_device::information::get_device_kpar(PARAM.inp.kpar); } @@ -216,7 +197,7 @@ void Input_Conv::Convert() { GlobalV::KPAR = PARAM.inp.kpar; } - if (GlobalV::device_flag == "cpu" and PARAM.inp.precision == "single") + if (PARAM.inp.device == "cpu" and PARAM.inp.precision == "single") { // cpu single precision is not supported while float_fftw lib is not available #ifndef __ENABLE_FLOAT_FFTW @@ -290,11 +271,6 @@ void Input_Conv::Convert() //---------------------------------------------------------- // Yu Liu add 2022-09-13 //---------------------------------------------------------- - GlobalV::nelec = PARAM.inp.nelec; - if (PARAM.globalv.two_fermi) - { - GlobalV::nupdown = PARAM.inp.nupdown; - } elecstate::Gatefield::zgate = PARAM.inp.zgate; elecstate::Gatefield::relax = PARAM.inp.relax; elecstate::Gatefield::block = PARAM.inp.block; @@ -337,10 +313,11 @@ void Input_Conv::Convert() tolower); GlobalC::restart.folder = PARAM.globalv.global_readin_dir + "restart/"; ModuleBase::GlobalFunc::MAKE_DIR(GlobalC::restart.folder); - if (dft_functional_lower == "hf" || dft_functional_lower == "pbe0" - || dft_functional_lower == "hse" - || dft_functional_lower == "opt_orb" - || dft_functional_lower == "scan0") { + if (dft_functional_lower == "hf" || dft_functional_lower == "pbe0" || dft_functional_lower == "hse" + || dft_functional_lower == "opt_orb" || dft_functional_lower == "scan0"|| dft_functional_lower == "lc_pbe" + || dft_functional_lower == "lc_wpbe" || dft_functional_lower == "lrc_wpbe"|| dft_functional_lower == "lrc_wpbeh" + || dft_functional_lower == "cam_pbeh") + { GlobalC::restart.info_save.save_charge = true; GlobalC::restart.info_save.save_H = true; } else { @@ -358,7 +335,12 @@ void Input_Conv::Convert() if (dft_functional_lower == "hf" || dft_functional_lower == "pbe0" || dft_functional_lower == "hse" || dft_functional_lower == "opt_orb" - || dft_functional_lower == "scan0") { + || dft_functional_lower == "scan0" + || dft_functional_lower == "lc_pbe" + || dft_functional_lower == "lc_wpbe" + || dft_functional_lower == "lrc_wpbe" + || dft_functional_lower == "lrc_wpbeh" + || dft_functional_lower == "cam_pbeh") { GlobalC::restart.info_load.load_charge = true; GlobalC::restart.info_load.load_H = true; } else { @@ -380,16 +362,46 @@ void Input_Conv::Convert() if (dft_functional_lower == "hf" || dft_functional_lower == "pbe0" || dft_functional_lower == "scan0") { GlobalC::exx_info.info_global.cal_exx = true; - GlobalC::exx_info.info_global.ccp_type - = Conv_Coulomb_Pot_K::Ccp_Type::Hf; - } else if (dft_functional_lower == "hse") { + if (PARAM.inp.exx_use_ewald) + { + GlobalC::exx_info.info_global.cam_alpha = std::stod(PARAM.inp.exx_cam_alpha); + GlobalC::exx_info.info_global.cam_beta = std::stod(PARAM.inp.exx_cam_beta); + GlobalC::exx_info.info_global.use_ewald = true; + GlobalC::exx_info.info_ewald.fq_type = Singular_Value::Fq_type(PARAM.inp.exx_fq_type); + GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Ccp; + } + else + GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; + } + else if (dft_functional_lower == "hse") + { GlobalC::exx_info.info_global.cal_exx = true; GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hse; } else if (dft_functional_lower == "opt_orb") { GlobalC::exx_info.info_global.cal_exx = false; Exx_Abfs::Jle::generate_matrix = true; - } else { + } + else if (dft_functional_lower == "lc_pbe" + || dft_functional_lower == "lc_wpbe" + || dft_functional_lower == "lrc_wpbe" + || dft_functional_lower == "lrc_wpbeh" + || dft_functional_lower == "cam_pbeh") + { + GlobalC::exx_info.info_global.cal_exx = true; + GlobalC::exx_info.info_global.cam_alpha = std::stod(PARAM.inp.exx_cam_alpha); + GlobalC::exx_info.info_global.cam_beta = std::stod(PARAM.inp.exx_cam_beta); + if (PARAM.inp.exx_use_ewald) + { + GlobalC::exx_info.info_global.use_ewald = true; + GlobalC::exx_info.info_ewald.fq_type = Singular_Value::Fq_type(PARAM.inp.exx_fq_type); + GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Ccp; + } + else + GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Cam; + } + else + { GlobalC::exx_info.info_global.cal_exx = false; } @@ -398,12 +410,13 @@ void Input_Conv::Convert() // EXX case, convert all EXX related variables // GlobalC::exx_info.info_global.cal_exx = true; GlobalC::exx_info.info_global.hybrid_alpha = std::stod(PARAM.inp.exx_hybrid_alpha); - XC_Functional::get_hybrid_alpha(std::stod(PARAM.inp.exx_hybrid_alpha)); - GlobalC::exx_info.info_global.hse_omega = PARAM.inp.exx_hse_omega; + XC_Functional::set_hybrid_alpha(std::stod(PARAM.inp.exx_hybrid_alpha), + std::stod(PARAM.inp.exx_cam_alpha), + std::stod(PARAM.inp.exx_cam_beta)); + GlobalC::exx_info.info_global.hse_omega = std::stod(PARAM.inp.exx_hse_omega); GlobalC::exx_info.info_global.separate_loop = PARAM.inp.exx_separate_loop; GlobalC::exx_info.info_global.hybrid_step = PARAM.inp.exx_hybrid_step; GlobalC::exx_info.info_global.mixing_beta_for_loop1 = PARAM.inp.exx_mixing_beta; - GlobalC::exx_info.info_global.exx_symmetry_realspace = PARAM.inp.exx_symmetry_realspace; GlobalC::exx_info.info_lip.lambda = PARAM.inp.exx_lambda; GlobalC::exx_info.info_ri.real_number = std::stoi(PARAM.inp.exx_real_number); @@ -419,6 +432,7 @@ void Input_Conv::Convert() GlobalC::exx_info.info_ri.cauchy_force_threshold = PARAM.inp.exx_cauchy_force_threshold; GlobalC::exx_info.info_ri.cauchy_stress_threshold = PARAM.inp.exx_cauchy_stress_threshold; GlobalC::exx_info.info_ri.ccp_rmesh_times = std::stod(PARAM.inp.exx_ccp_rmesh_times); + GlobalC::exx_info.info_ewald.ewald_qdiv = PARAM.inp.exx_ewald_qdiv; Exx_Abfs::Jle::Lmax = PARAM.inp.exx_opt_orb_lmax; Exx_Abfs::Jle::Ecut_exx = PARAM.inp.exx_opt_orb_ecut; @@ -470,7 +484,6 @@ void Input_Conv::Convert() //---------------------------------------------------------- // wavefunction / charge / potential / (2/4) //---------------------------------------------------------- - GlobalV::nelec = PARAM.inp.nelec; #ifdef __LCAO diff --git a/source/module_io/json_output/general_info.cpp b/source/module_io/json_output/general_info.cpp index ac5146e9a26..6190e880df7 100644 --- a/source/module_io/json_output/general_info.cpp +++ b/source/module_io/json_output/general_info.cpp @@ -50,7 +50,7 @@ void gen_general_info(const Parameter& param) AbacusJson::add_json({"general_info", "omp_num"}, omp_num, false); AbacusJson::add_json({"general_info", "pseudo_dir"}, param.inp.pseudo_dir, false); AbacusJson::add_json({"general_info", "orbital_dir"}, param.inp.orbital_dir, false); - AbacusJson::add_json({"general_info", "stru_file"}, param.inp.stru_file, false); + AbacusJson::add_json({"general_info", "stru_file"}, param.globalv.global_in_stru, false); AbacusJson::add_json({"general_info", "kpt_file"}, param.inp.kpoint_file, false); AbacusJson::add_json({"general_info", "start_time"}, start_time_str, false); AbacusJson::add_json({"general_info", "end_time"}, end_time_str, false); diff --git a/source/module_io/json_output/init_info.cpp b/source/module_io/json_output/init_info.cpp index 5905bdfed34..657d37fe2d0 100644 --- a/source/module_io/json_output/init_info.cpp +++ b/source/module_io/json_output/init_info.cpp @@ -1,5 +1,6 @@ #include "init_info.h" +#include "module_parameter/parameter.h" #include "../para_json.h" #include "abacusjson.h" @@ -21,10 +22,10 @@ void gen_init(UnitCell* ucell) int numAtoms = ucell->nat; AbacusJson::add_json({"init", "natom"}, numAtoms, false); - AbacusJson::add_json({"init", "nband"}, GlobalV::NBANDS, false); + AbacusJson::add_json({"init", "nband"}, PARAM.inp.nbands, false); // Json::AbacusJson::add_Json(numAtoms,false,"init", "natom"); - // Json::AbacusJson::add_Json(GlobalV::NBANDS,false,"init", "nband"); + // Json::AbacusJson::add_Json(PARAM.inp.nbands,false,"init", "nband"); int ntype = ucell->ntype, nelec_total = 0; for (int it = 0; it < ntype; it++) diff --git a/source/module_io/json_output/test/para_json_test.cpp b/source/module_io/json_output/test/para_json_test.cpp index fef6aae0521..9ac40256b0c 100644 --- a/source/module_io/json_output/test/para_json_test.cpp +++ b/source/module_io/json_output/test/para_json_test.cpp @@ -214,7 +214,7 @@ TEST(AbacusJsonTest, GeneralInfo) PARAM.input.device = "cpu"; PARAM.input.pseudo_dir = "./abacus/test/pseudo_dir"; PARAM.input.orbital_dir = "./abacus/test/orbital_dir"; - PARAM.input.stru_file = "./abacus/test/stru_file"; + PARAM.sys.global_in_stru = "./abacus/test/stru_file"; PARAM.input.kpoint_file = "./abacus/test/kpoint_file"; // output the json file Json::AbacusJson::doc.Parse("{}"); @@ -272,7 +272,7 @@ TEST(AbacusJsonTest, InitInfo) ucell.symm.spgname = "O_h"; ucell.atoms = atomlist; ucell.ntype = 3; - GlobalV::NBANDS = 10; + PARAM.input.nbands = 10; ucell.atoms[0].label = "Si"; ucell.atoms[0].ncpp.zv = 3; diff --git a/source/module_io/nscf_fermi_surf.cpp b/source/module_io/nscf_fermi_surf.cpp index 1d62f429406..a6fb9c645fb 100644 --- a/source/module_io/nscf_fermi_surf.cpp +++ b/source/module_io/nscf_fermi_surf.cpp @@ -1,5 +1,6 @@ #include "nscf_fermi_surf.h" #include "module_base/global_function.h" +#include "module_parameter/parameter.h" #include "module_base/global_variable.h" #include "module_base/timer.h" @@ -16,7 +17,7 @@ void ModuleIO::nscf_fermi_surface(const std::string &out_band_dir, #ifdef __MPI int start = 1; - int end = GlobalV::NBANDS; + int end = PARAM.inp.nbands; std::ofstream ofs; if(GlobalV::MY_RANK==0) diff --git a/source/module_io/numerical_basis.cpp b/source/module_io/numerical_basis.cpp index 4e562f91b88..65e43102e8f 100644 --- a/source/module_io/numerical_basis.cpp +++ b/source/module_io/numerical_basis.cpp @@ -112,8 +112,8 @@ void Numerical_Basis::output_overlap(const psi::Psi>& psi, std::vector overlap_Sq(kv.get_nks()); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of k points", kv.get_nks()); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of bands", GlobalV::NBANDS); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of local orbitals", GlobalV::NLOCAL); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of bands", PARAM.inp.nbands); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of local orbitals", PARAM.globalv.nlocal); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "number of eigenvalues of Jl(x)", this->bessel_basis.get_ecut_number()); @@ -232,7 +232,7 @@ ModuleBase::ComplexArray Numerical_Basis::cal_overlap_Q(const int& ik, const int << std::endl; GlobalV::ofs_running << " Q = < J_mu, q | Psi_n, k > " << std::endl; - ModuleBase::ComplexArray overlap_Q(GlobalV::NBANDS, GlobalV::NLOCAL, this->bessel_basis.get_ecut_number()); + ModuleBase::ComplexArray overlap_Q(PARAM.inp.nbands, PARAM.globalv.nlocal, this->bessel_basis.get_ecut_number()); overlap_Q.zero_out(); const double normalization = (4 * ModuleBase::PI) / sqrt(ucell.omega); // Peize Lin add normalization 2015-12-29 @@ -273,7 +273,7 @@ ModuleBase::ComplexArray Numerical_Basis::cal_overlap_Q(const int& ik, const int for (int m = 0; m < 2 * L + 1; m++) { const int lm = L * L + m; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { std::complex overlap_tmp = ModuleBase::ZERO; for (int ig = 0; ig < np; ig++) @@ -309,7 +309,7 @@ ModuleBase::ComplexArray Numerical_Basis::cal_overlap_Sq(const int& ik, const in GlobalV::ofs_running << " S = < J_mu,q1 | J_nu,q2 >" << std::endl; const int enumber = this->bessel_basis.get_ecut_number(); - ModuleBase::ComplexArray overlap_Sq(GlobalV::NLOCAL, GlobalV::NLOCAL, enumber, enumber); + ModuleBase::ComplexArray overlap_Sq(PARAM.globalv.nlocal, PARAM.globalv.nlocal, enumber, enumber); overlap_Sq.zero_out(); const double normalization @@ -424,7 +424,7 @@ ModuleBase::matrix Numerical_Basis::cal_overlap_V(const ModulePW::PW_Basis_K* wf const double derivative_order, const K_Vectors& kv, const double tpiba) { - ModuleBase::matrix overlap_V(kv.get_nks(), GlobalV::NBANDS); + ModuleBase::matrix overlap_V(kv.get_nks(), PARAM.inp.nbands); for (int ik = 0; ik < kv.get_nks(); ++ik) { std::vector> gk(kv.ngk[ik]); @@ -434,7 +434,7 @@ ModuleBase::matrix Numerical_Basis::cal_overlap_V(const ModulePW::PW_Basis_K* wf const std::vector gpow = Numerical_Basis::cal_gpow(gk, derivative_order); - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) { + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { for (int ig = 0; ig < kv.ngk[ik]; ++ig) { overlap_V(ik, ib) += norm(psi(ik, ib, ig)) * gpow[ig]; } @@ -629,8 +629,8 @@ void Numerical_Basis::output_info(std::ofstream& ofs, const Bessel_Basis& bessel if (GlobalV::MY_RANK == 0) { ofs << kv.get_nkstot() << " nks" << std::endl; - ofs << GlobalV::NBANDS << " nbands" << std::endl; - ofs << GlobalV::NLOCAL << " nwfc" << std::endl; + ofs << PARAM.inp.nbands << " nbands" << std::endl; + ofs << PARAM.globalv.nlocal << " nwfc" << std::endl; ofs << bessel_basis.get_ecut_number() << " ne " << std::endl; } } diff --git a/source/module_io/numerical_descriptor.cpp b/source/module_io/numerical_descriptor.cpp index 1300ab89f48..aea1840e110 100644 --- a/source/module_io/numerical_descriptor.cpp +++ b/source/module_io/numerical_descriptor.cpp @@ -1,5 +1,6 @@ #include "numerical_descriptor.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_parameter/parameter.h" #include "module_cell/module_symmetry/symmetry.h" #include "winput.h" #include "module_base/math_ylmreal.h" @@ -85,8 +86,8 @@ void Numerical_Descriptor::output_descriptor(const psi::Psi // 3. Initialize overlap_Q1 and Q2 //------------------------------------- // OVERLAP : < J_mu | Psi > - ModuleBase::realArray overlap_Q1(nks, GlobalV::NBANDS, this->nlocal ); - ModuleBase::realArray overlap_Q2(nks, GlobalV::NBANDS, this->nlocal ); + ModuleBase::realArray overlap_Q1(nks, PARAM.inp.nbands, this->nlocal ); + ModuleBase::realArray overlap_Q2(nks, PARAM.inp.nbands, this->nlocal ); ModuleBase::GlobalFunc::ZEROS(overlap_Q1.ptr, overlap_Q1.getSize() ); ModuleBase::GlobalFunc::ZEROS(overlap_Q2.ptr, overlap_Q2.getSize() ); @@ -310,7 +311,7 @@ normalization 2015-12-29 for (int ie=0; ie < nmax; ie++) for (int m=0; m<2*L+1; m++) { const int lm = L*L+m; - for (int ib=0; ib overlap_tmp = ModuleBase::ZERO; for (int ig=0; ig& nzeta, + std::vector>& radials, + const int rank) +{ + nr = 0; // number of grid points + dr = 0; // grid spacing + int lmax = 0, nchi = 0; // number of radial functions + std::vector> radial_map_; // build a map from [l][izeta] to 1-d array index + std::string tmp; + // first read the header + if (rank == 0) + { + if (!ifs.is_open()) + { + ModuleBase::WARNING_QUIT("AtomicRadials::read_abacus_orb", "Couldn't open orbital file."); + } + while (ifs >> tmp) + { + if (tmp == "Element") + { + ifs >> elem; + } + else if (tmp == "Cutoff(Ry)") + { + ifs >> ecut; + } + else if (tmp == "Lmax") + { + ifs >> lmax; + nzeta.resize(lmax + 1); + for (int l = 0; l <= lmax; ++l) + { + ifs >> tmp >> tmp >> tmp >> nzeta[l]; + } + } + else if (tmp == "Mesh") + { + ifs >> nr; + continue; + } + else if (tmp == "dr") + { + ifs >> dr; + break; + } + } + radial_map_.resize(lmax + 1); + for (int l = 0; l <= lmax; ++l) + { + radial_map_[l].resize(nzeta[l]); + } + int ichi = 0; + for (int l = 0; l <= lmax; ++l) + { + for (int iz = 0; iz < nzeta[l]; ++iz) + { + radial_map_[l][iz] = ichi++; // return the value of ichi, then increment + } + } + nchi = ichi; // total number of radial functions + radials.resize(nchi); + std::for_each(radials.begin(), radials.end(), [nr](std::vector& v) { v.resize(nr); }); + } + + // broadcast the header information +#ifdef __MPI + Parallel_Common::bcast_string(elem); + Parallel_Common::bcast_double(ecut); + Parallel_Common::bcast_int(lmax); + Parallel_Common::bcast_int(nchi); + Parallel_Common::bcast_int(nr); + Parallel_Common::bcast_double(dr); +#endif + + // then adjust the size of the vectors + if (rank != 0) + { + nzeta.resize(lmax + 1); + radials.resize(nchi); + std::for_each(radials.begin(), radials.end(), [nr](std::vector& v) { v.resize(nr); }); + } + // broadcast the number of zeta functions for each angular momentum +#ifdef __MPI + Parallel_Common::bcast_int(nzeta.data(), lmax + 1); +#endif + + // read the radial functions by rank0 + int ichi = 0; + for (int i = 0; i != nchi; ++i) + { + if (rank == 0) + { + int l, izeta; + ifs >> tmp >> tmp >> tmp; + ifs >> tmp >> l >> izeta; + ichi = radial_map_[l][izeta]; + for (int ir = 0; ir != nr; ++ir) + { + ifs >> radials[ichi][ir]; + } + } + // broadcast the radial functions +#ifdef __MPI + Parallel_Common::bcast_int(ichi); // let other ranks know where to store the radial function + Parallel_Common::bcast_double(radials[ichi].data(), nr); +#endif + } +} + +void ModuleIO::write_abacus_orb(std::ofstream& ofs, + const std::string& elem, + const double& ecut, + const int nr, + const double dr, + const std::vector& nzeta, + const std::vector>& radials, + const int rank) +{ + const std::vector spec = {"S", "P", "D", "F", "G", "H", "I", "J", "K"}; + + if (rank == 0) + { + if (!ofs.is_open()) + { + ModuleBase::WARNING_QUIT("AtomicRadials::write_abacus_orb", "Couldn't open orbital file."); + } + const int lmax = nzeta.size() - 1; + + for (int i = 0; i < 75; ++i) + { + ofs << "-"; + } + ofs << std::endl; + // left aligned + ofs << std::left << std::setw(28) << "Element" << elem << std::endl; + ofs << std::left << std::setw(28) << "Energy Cutoff(Ry)" << ecut << std::endl; + // rcut .1f, not scientific + ofs << std::left << std::setw(28) << "Radius Cutoff(a.u.)" + << std::fixed << std::setprecision(1) << dr * (nr - 1) << std::endl; + ofs << std::left << std::setw(28) << "Lmax" << lmax << std::endl; + for (int l = 0; l != nzeta.size(); ++l) + { + std::string title = "Number of " + spec[l] + "orbital-->"; + ofs << std::left << std::setw(28) << title << nzeta[l] << std::endl; + } + for (int i = 0; i < 75; ++i) + { + ofs << "-"; + } + ofs << std::endl; + ofs << "SUMMARY END\n\n"; + ofs << std::left << std::setw(28) << "Mesh" << nr << std::endl; + ofs << std::left << std::setw(28) << "dr" << std::fixed << std::setprecision(2) << dr << std::endl; + + int ichi = 0; + for (int l = 0; l <= lmax; l++) + { + for (int izeta = 0; izeta < nzeta[l]; izeta++) + { + ofs << std::right << std::setw(20) << "Type" + << std::right << std::setw(20) << "L" + << std::right << std::setw(20) << "N" << std::endl; + ofs << std::right << std::setw(20) << 0 + << std::right << std::setw(20) << l + << std::right << std::setw(20) << izeta; + for (int i = 0; i < nr; i++) + { + if (i % 4 == 0) + { + ofs << std::endl; + } + ofs << std::left << std::setw(22) << std::setprecision(14) + << std::scientific << radials[ichi][i]; + } + ofs << std::endl; + ichi++; + } + } + } + // ofs.close(); // like read_abacus_orb, who opens it, who closes it +} diff --git a/source/module_io/orb_io.h b/source/module_io/orb_io.h new file mode 100644 index 00000000000..bdd0043fc2c --- /dev/null +++ b/source/module_io/orb_io.h @@ -0,0 +1,37 @@ +#include +#include +#include + +namespace ModuleIO +{ + /** + * @brief static version of read_abacus_orb. A delete-new operation may cause the memory leak, + * it is better to use std::vector to replace the raw pointer. + * + * @param ifs [in] ifstream from the orbital file, via `std::ifstream ifs(forb);` + * @param elem [out] element symbol + * @param ecut [out] planewave energy cutoff + * @param nr [out] number of radial grid points + * @param dr [out] radial grid spacing + * @param nzeta [out] number of zeta functions for each angular momentum + * @param radials [out] radial orbitals + * @param rank [in] MPI rank + */ + void read_abacus_orb(std::ifstream& ifs, + std::string& elem, + double& ecut, + int& nr, + double& dr, + std::vector& nzeta, + std::vector>& radials, + const int rank = 0); + + void write_abacus_orb(std::ofstream& ofs, + const std::string& elem, + const double& ecut, + const int nr, + const double dr, + const std::vector& nzeta, + const std::vector>& radials, + const int rank = 0); +} \ No newline at end of file diff --git a/source/module_io/output_log.cpp b/source/module_io/output_log.cpp index a940422ea4c..191dc413a2d 100644 --- a/source/module_io/output_log.cpp +++ b/source/module_io/output_log.cpp @@ -21,6 +21,28 @@ void output_convergence_after_scf(bool& convergence, double& energy, std::ofstre } } +void output_after_relax(bool conv_ion, bool conv_esolver, std::ofstream& ofs_running) +{ + if (conv_ion && !conv_esolver) + { + std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + std::cout << " Relaxation is converged, but the SCF is unconverged! The results are unreliable. " << std::endl; + std::cout << " It is suggested to increase the maximum SCF step and/or perform the relaxation again." + << std::endl; + std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + ofs_running << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + ofs_running << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + ofs_running << "\n Relaxation is converged, but the SCF is unconverged! The results are unreliable.. " + << std::endl; + ofs_running << "\n It is suggested to increase the maximum SCF step and/or perform the relaxation again. " + << std::endl; + ofs_running << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + ofs_running << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; + } +} + void output_efermi(bool& convergence, double& efermi, std::ofstream& ofs_running) { if (convergence && PARAM.inp.out_level != "m") @@ -224,7 +246,8 @@ void print_force(std::ofstream& ofs_running, fmt << atom_label << force_x << force_y << force_z; table = fmt.str(); ofs_running << table << std::endl; - if (PARAM.inp.test_force) std::cout << table << std::endl; + if (PARAM.inp.test_force) { std::cout << table << std::endl; +} } void print_stress(const std::string& name, const ModuleBase::matrix& scs, const bool screen, const bool ry) { @@ -282,4 +305,10 @@ void print_stress(const std::string& name, const ModuleBase::matrix& scs, const return; } +void write_head(std::ofstream& ofs_running, const int& istep, const int& iter, const std::string& basisname) +{ + ofs_running << "\n " << basisname << " ALGORITHM --------------- ION=" << std::setw(4) << istep + 1 + << " ELEC=" << std::setw(4) << iter << "--------------------------------\n"; +} + }// namespace ModuleIO \ No newline at end of file diff --git a/source/module_io/output_log.h b/source/module_io/output_log.h index 76bb6d293dd..68c93ade9da 100644 --- a/source/module_io/output_log.h +++ b/source/module_io/output_log.h @@ -16,6 +16,12 @@ namespace ModuleIO /// @param ofs_running the output stream void output_convergence_after_scf(bool& convergence, double& energy, std::ofstream& ofs_running = GlobalV::ofs_running); +/// @brief output after relaxation +/// @param conv_ion if is convergence for ions +/// @param conv_esolver if is convergence for electrons +/// @param ofs_running the output stream +void output_after_relax(bool conv_ion, bool conv_esolver, std::ofstream& ofs_running = GlobalV::ofs_running); + /// @brief output the fermi energy /// @param convergence if is convergence /// @param efermi @@ -60,6 +66,13 @@ void print_force(std::ofstream& ofs_running, /// @param ry true if the unit of force is a.u. void print_stress(const std::string& name, const ModuleBase::matrix& scs, const bool screen, const bool ry); +/// @brief write head for scf iteration +/// @param ofs_running output stream +/// @param istep the ion step +/// @param iter the scf iteration step +/// @param basisname basis set name +void write_head(std::ofstream& ofs_running, const int& istep, const int& iter, const std::string& basisname); + } // namespace ModuleIO #endif \ No newline at end of file diff --git a/source/module_io/print_info.cpp b/source/module_io/print_info.cpp index 5976cb11ad7..61a5cc3b23a 100644 --- a/source/module_io/print_info.cpp +++ b/source/module_io/print_info.cpp @@ -3,14 +3,13 @@ #include "module_base/global_variable.h" #include "module_parameter/parameter.h" -Print_Info::Print_Info(){} - -Print_Info::~Print_Info(){} +namespace ModuleIO +{ -void Print_Info::setup_parameters(UnitCell &ucell, K_Vectors &kv) +void setup_parameters(UnitCell& ucell, K_Vectors& kv) { - ModuleBase::TITLE("Print_Info","setup_parameters"); + ModuleBase::TITLE("ModuleIO", "setup_parameters"); if(PARAM.inp.calculation=="scf" || PARAM.inp.calculation=="relax" || PARAM.inp.calculation=="cell-relax" || PARAM.inp.calculation=="nscf" || PARAM.inp.calculation=="get_pchg" || PARAM.inp.calculation=="get_wf" || PARAM.inp.calculation=="md") @@ -72,7 +71,8 @@ void Print_Info::setup_parameters(UnitCell &ucell, K_Vectors &kv) std::cout << " " << std::setw(8) << "SPIN" << std::setw(16) << "KPOINTS" - << std::setw(12) << "PROCESSORS"; + << std::setw(12) << "PROCESSORS" + << std::setw(12) << "THREADS"; const bool orbinfo = (PARAM.inp.basis_type=="lcao" || PARAM.inp.basis_type=="lcao_in_pw" || (PARAM.inp.basis_type=="pw" && PARAM.inp.init_wfc.substr(0, 3) == "nao")); @@ -90,8 +90,9 @@ void Print_Info::setup_parameters(UnitCell &ucell, K_Vectors &kv) std::cout << std::setw(16) << kv.get_nkstot(); } - std::cout << std::setw(12) << GlobalV::NPROC; - if (orbinfo) { std::cout << std::setw(12) << GlobalV::NLOCAL; } + std::cout << std::setw(12) << GlobalV::NPROC + << std::setw(12) << PARAM.globalv.nthread_per_proc * GlobalV::NPROC; + if (orbinfo) { std::cout << std::setw(12) << PARAM.globalv.nlocal; } std::cout << std::endl; @@ -168,7 +169,7 @@ void Print_Info::setup_parameters(UnitCell &ucell, K_Vectors &kv) return; } -void Print_Info::print_time(time_t &time_start, time_t &time_finish) +void print_time(time_t& time_start, time_t& time_finish) { // print out information before ABACUS ends std::cout << "\n START Time : " << ctime(&time_start); @@ -188,38 +189,197 @@ void Print_Info::print_time(time_t &time_start, time_t &time_finish) << unsigned(secs) << " secs "<< std::endl; } -/* -void Print_Info::print_scf(const int &istep, const int &iter) +void print_rhofft(ModulePW::PW_Basis* pw_rhod, + ModulePW::PW_Basis* pw_rho, + ModulePW::PW_Basis_Big* pw_big, + std::ofstream& ofs) { - if(PARAM.inp.basis_type=="pw") + std::cout << " UNIFORM GRID DIM : " << pw_rho->nx << " * " << pw_rho->ny << " * " << pw_rho->nz << std::endl; + std::cout << " UNIFORM GRID DIM(BIG) : " << pw_big->nbx << " * " << pw_big->nby << " * " << pw_big->nbz + << std::endl; + if (PARAM.globalv.double_grid) { - GlobalV::ofs_running << "\n PW ALGORITHM ------------- "; + std::cout << " UNIFORM GRID DIM(DENSE) : " << pw_rhod->nx << " * " << pw_rhod->ny << " * " << pw_rhod->nz + << std::endl; } - else + + ofs << "\n\n\n\n"; + ofs << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ">>>>" + << std::endl; + ofs << " | " + " |" + << std::endl; + ofs << " | Setup plane waves of charge/potential: " + " |" + << std::endl; + ofs << " | Use the energy cutoff and the lattice vectors to generate the " + " |" + << std::endl; + ofs << " | dimensions of FFT grid. The number of FFT grid on each " + "processor |" + << std::endl; + ofs << " | is 'nrxx'. The number of plane wave basis in reciprocal space " + "is |" + << std::endl; + ofs << " | different for charege/potential and wave functions. We also set " + " |" + << std::endl; + ofs << " | the 'sticks' for the parallel of FFT. The number of plane waves " + " |" + << std::endl; + ofs << " | is 'npw' in each processor. " + " |" + << std::endl; + ofs << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" + "<<<<" + << std::endl; + ofs << "\n\n\n\n"; + ofs << "\n SETUP THE PLANE WAVE BASIS" << std::endl; + + double ecut = 4 * PARAM.inp.ecutwfc; + if (PARAM.inp.nx * PARAM.inp.ny * PARAM.inp.nz > 0) { - GlobalV::ofs_running << "\n LCAO ALGORITHM ------------- "; + ecut = pw_rho->gridecut_lat * pw_rho->tpiba2; + ofs << "use input fft dimensions for wave functions." << std::endl; + ofs << "calculate energy cutoff from nx, ny, nz:" << std::endl; } - if(PARAM.inp.calculation=="scf") + ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for charge/potential (unit:Ry)", ecut); + + ModuleBase::GlobalFunc::OUT(ofs, "fft grid for charge/potential", pw_rho->nx, pw_rho->ny, pw_rho->nz); + ModuleBase::GlobalFunc::OUT(ofs, "fft grid division", pw_big->bx, pw_big->by, pw_big->bz); + ModuleBase::GlobalFunc::OUT(ofs, "big fft grid for charge/potential", pw_big->nbx, pw_big->nby, pw_big->nbz); + ModuleBase::GlobalFunc::OUT(ofs, "nbxx", pw_big->nbxx); + ModuleBase::GlobalFunc::OUT(ofs, "nrxx", pw_rho->nrxx); + + ofs << "\n SETUP PLANE WAVES FOR CHARGE/POTENTIAL" << std::endl; + ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", pw_rho->npwtot); + ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", pw_rho->nstot); + + ofs << "\n PARALLEL PW FOR CHARGE/POTENTIAL" << std::endl; + ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; + + for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) { - GlobalV::ofs_running << "ELEC = " << std::setw(4) << unsigned(iter); + ofs << " " << std::setw(8) << i + 1 << std::setw(15) << pw_rho->nst_per[i] << std::setw(15) + << pw_rho->npw_per[i] << std::endl; } - else if(PARAM.inp.calculation=="relax" || PARAM.inp.calculation=="cell-relax") - { - GlobalV::ofs_running << "ION = " << std::setw(4) << unsigned(istep+1) - << " ELEC = " << std::setw(4) << unsigned(iter); - } - else if(PARAM.inp.calculation=="md") - { - GlobalV::ofs_running << "MD = " << std::setw(4) << unsigned(istep+1) - << " ELEC = " << std::setw(4) << unsigned(iter); - } + ofs << " --------------- sum -------------------" << std::endl; + ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << pw_rho->nstot << std::setw(15) + << pw_rho->npwtot << std::endl; + + ModuleBase::GlobalFunc::OUT(ofs, "number of |g|", pw_rho->ngg); + ModuleBase::GlobalFunc::OUT(ofs, "max |g|", pw_rho->gg_uniq[pw_rho->ngg - 1]); + ModuleBase::GlobalFunc::OUT(ofs, "min |g|", pw_rho->gg_uniq[0]); + + if (PARAM.globalv.double_grid) + { + ofs << std::endl; + ofs << std::endl; + ofs << std::endl; + double ecut = PARAM.inp.ecutrho; + if (PARAM.inp.ndx * PARAM.inp.ndy * PARAM.inp.ndz > 0) + { + ecut = pw_rhod->gridecut_lat * pw_rhod->tpiba2; + ofs << "use input fft dimensions for the dense part of charge " + "density." + << std::endl; + ofs << "calculate energy cutoff from ndx, ndy, ndz:" << std::endl; + } + ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for dense charge/potential (unit:Ry)", ecut); + + ModuleBase::GlobalFunc::OUT(ofs, "fft grid for dense charge/potential", pw_rhod->nx, pw_rhod->ny, pw_rhod->nz); - GlobalV::ofs_running << " --------------------------------\n"; + ModuleBase::GlobalFunc::OUT(ofs, "nrxx", pw_rhod->nrxx); + + ofs << "\n SETUP PLANE WAVES FOR dense CHARGE/POTENTIAL" << std::endl; + ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", pw_rhod->npwtot); + ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", pw_rhod->nstot); + + ofs << "\n PARALLEL PW FOR dense CHARGE/POTENTIAL" << std::endl; + ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; + + for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) + { + ofs << " " << std::setw(8) << i + 1 << std::setw(15) << pw_rhod->nst_per[i] << std::setw(15) + << pw_rhod->npw_per[i] << std::endl; + } + ofs << " --------------- sum -------------------" << std::endl; + ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << pw_rhod->nstot << std::setw(15) + << pw_rhod->npwtot << std::endl; + + ModuleBase::GlobalFunc::OUT(ofs, "number of |g|", pw_rhod->ngg); + ModuleBase::GlobalFunc::OUT(ofs, "max |g|", pw_rhod->gg_uniq[pw_rhod->ngg - 1]); + ModuleBase::GlobalFunc::OUT(ofs, "min |g|", pw_rhod->gg_uniq[0]); + } +} + +void print_wfcfft(const Input_para& inp, ModulePW::PW_Basis_K& pw_wfc, std::ofstream& ofs) +{ + ofs << "\n\n\n\n"; + ofs << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ">>>>" + << std::endl; + ofs << " | " + " |" + << std::endl; + ofs << " | Setup plane waves of wave functions: " + " |" + << std::endl; + ofs << " | Use the energy cutoff and the lattice vectors to generate the " + " |" + << std::endl; + ofs << " | dimensions of FFT grid. The number of FFT grid on each " + "processor |" + << std::endl; + ofs << " | is 'nrxx'. The number of plane wave basis in reciprocal space " + "is |" + << std::endl; + ofs << " | different for charege/potential and wave functions. We also set " + " |" + << std::endl; + ofs << " | the 'sticks' for the parallel of FFT. The number of plane wave " + "of |" + << std::endl; + ofs << " | each k-point is 'npwk[ik]' in each processor " + " |" + << std::endl; + ofs << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" + "<<<<" + << std::endl; + ofs << "\n\n\n\n"; + ofs << "\n SETUP PLANE WAVES FOR WAVE FUNCTIONS" << std::endl; + + double ecut = inp.ecutwfc; + if (std::abs(ecut - pw_wfc.gk_ecut * pw_wfc.tpiba2) > 1e-6) + { + ecut = pw_wfc.gk_ecut * pw_wfc.tpiba2; + ofs << "Energy cutoff for wavefunc is incompatible with nx, ny, nz and " + "it will be reduced!" + << std::endl; + } + ModuleBase::GlobalFunc::OUT(ofs, "energy cutoff for wavefunc (unit:Ry)", ecut); + ModuleBase::GlobalFunc::OUT(ofs, "fft grid for wave functions", pw_wfc.nx, pw_wfc.ny, pw_wfc.nz); + ModuleBase::GlobalFunc::OUT(ofs, "number of plane waves", pw_wfc.npwtot); + ModuleBase::GlobalFunc::OUT(ofs, "number of sticks", pw_wfc.nstot); + + ofs << "\n PARALLEL PW FOR WAVE FUNCTIONS" << std::endl; + ofs << " " << std::setw(8) << "PROC" << std::setw(15) << "COLUMNS(POT)" << std::setw(15) << "PW" << std::endl; + + for (int i = 0; i < GlobalV::NPROC_IN_POOL; ++i) + { + ofs << " " << std::setw(8) << i + 1 << std::setw(15) << pw_wfc.nst_per[i] << std::setw(15) << pw_wfc.npw_per[i] + << std::endl; + } + + ofs << " --------------- sum -------------------" << std::endl; + ofs << " " << std::setw(8) << GlobalV::NPROC_IN_POOL << std::setw(15) << pw_wfc.nstot << std::setw(15) + << pw_wfc.npwtot << std::endl; + ModuleBase::GlobalFunc::DONE(ofs, "INIT PLANEWAVE"); } -*/ -void Print_Info::print_screen(const int &stress_step, const int &force_step, const int &istep) +void print_screen(const int& stress_step, const int& force_step, const int& istep) { std::cout << " -------------------------------------------" << std::endl; GlobalV::ofs_running << "\n -------------------------------------------" << std::endl; @@ -263,3 +423,5 @@ void Print_Info::print_screen(const int &stress_step, const int &force_step, con std::cout << " -------------------------------------------" << std::endl; GlobalV::ofs_running << " -------------------------------------------" << std::endl; } + +} // namespace ModuleIO \ No newline at end of file diff --git a/source/module_io/print_info.h b/source/module_io/print_info.h index e037e3533e0..a7bcb2a0cf5 100644 --- a/source/module_io/print_info.h +++ b/source/module_io/print_info.h @@ -2,28 +2,29 @@ // AUTHOR : mohan // DATE : 2021-01-30 //========================================================== -#ifndef PRINT_INFO_H -#define PRINT_INFO_H +#ifndef PRINT_INFO +#define PRINT_INFO #include "module_base/timer.h" -#include "module_cell/unitcell.h" +#include "module_basis/module_pw/pw_basis_k.h" #include "module_cell/klist.h" -//#include "../module_cell/klist.h" +#include "module_cell/unitcell.h" +#include "module_parameter/input_parameter.h" -class Print_Info +namespace ModuleIO { - public: - - Print_Info(); - ~Print_Info(); - - // print out to screen about the readin parameters - static void setup_parameters(UnitCell &ucell, K_Vectors &kv); - static void print_time(time_t &time_start, time_t &time_finish); - static void print_scf(const int &istep, const int &iter); - static void print_screen(const int &stress_step, const int &force_step, const int &istep); +// print out to screen about the readin parameters +void setup_parameters(UnitCell& ucell, K_Vectors& kv); +void print_time(time_t& time_start, time_t& time_finish); +void print_screen(const int& stress_step, const int& force_step, const int& istep); +//! Print charge density using FFT +void print_rhofft(ModulePW::PW_Basis* pw_rhod, + ModulePW::PW_Basis* pw_rho, + ModulePW::PW_Basis_Big* pw_big, + std::ofstream& ofs); +void print_wfcfft(const Input_para& inp, ModulePW::PW_Basis_K& pw_wfc, std::ofstream& ofs); -}; +} // namespace ModuleIO #endif diff --git a/source/module_io/read_cube.cpp b/source/module_io/read_cube.cpp index 286a5e7f2d5..f34c1f4680d 100644 --- a/source/module_io/read_cube.cpp +++ b/source/module_io/read_cube.cpp @@ -1,214 +1,87 @@ #include "module_io/cube_io.h" +#include +#include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" // #include "module_base/global_variable.h" // GlobalV reference removed -bool ModuleIO::read_cube( -#ifdef __MPI - Parallel_Grid* Pgrid, -#endif - int my_rank, - std::string esolver_type, - int rank_in_stogroup, - const int& is, +bool ModuleIO::read_vdata_palgrid( + const Parallel_Grid& pgrid, + const int my_rank, std::ofstream& ofs_running, - const int& nspin, const std::string& fn, - double* data, - const int& nx, - const int& ny, - const int& nz, - double& ef, - const UnitCell* ucell, - int& prenspin, - const bool& warning_flag) + double* const data, + const int natom) { - ModuleBase::TITLE("ModuleIO","read_cube"); - std::ifstream ifs(fn.c_str()); - if (!ifs) - { - std::string tmp_warning_info = "!!! Couldn't find the charge file of "; - tmp_warning_info += fn; - ofs_running << tmp_warning_info << std::endl; - return false; - } - else - { - ofs_running << " Find the file, try to read charge from file." << std::endl; - } + ModuleBase::TITLE("ModuleIO", "read_vdata_palgrid"); - bool quit=false; - - ifs.ignore(300, '\n'); // skip the header - - if(nspin != 4) - { - int v_in; - ifs >> v_in; - if (v_in != nspin) - { - std::cout << " WARNING: nspin mismatch: " << nspin << " in INPUT parameters but " << v_in << " in " << fn << std::endl; - return false; - } - } - else - { - ifs >> prenspin; - } - ifs.ignore(150, ')'); - - ifs >> ef; - ofs_running << " read in fermi energy = " << ef << std::endl; - - ifs.ignore(150, '\n'); - - ModuleBase::CHECK_INT(ifs, ucell->nat); - ifs.ignore(150, '\n'); - - int nx_read = 0; - int ny_read = 0; - int nz_read = 0; - double fac = ucell->lat0; - std::string temp; - if (warning_flag) + // check if the file exists + std::ifstream ifs(fn.c_str()); + if (!ifs) { - ifs >> nx_read; - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e11 / double(nx), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e12 / double(nx), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e13 / double(nx), quit); - ifs >> ny_read; - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e21 / double(ny), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e22 / double(ny), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e23 / double(ny), quit); - ifs >> nz_read; - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e31 / double(nz), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e32 / double(nz), quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->latvec.e33 / double(nz), quit); + std::string tmp_warning_info = "!!! Couldn't find the file: " + fn; + ofs_running << tmp_warning_info << std::endl; + return false; } else { - ifs >> nx_read; - ifs >> temp >> temp >> temp; - ifs >> ny_read; - ifs >> temp >> temp >> temp; - ifs >> nz_read; - ifs >> temp >> temp >> temp; + ofs_running << " Find the file " << fn << " , try to read it." << std::endl; } - const bool same = (nx == nx_read && ny == ny_read && nz == nz_read) ? true : false; - - for (int it = 0; it < ucell->ntype; it++) + // read the full grid data + const int& nx = pgrid.nx; + const int& ny = pgrid.ny; + const int& nz = pgrid.nz; + const int& nxyz = nx * ny * nz; + std::vector data_xyz_full(nxyz, 0.0); + if (my_rank == 0) { - for (int ia = 0; ia < ucell->atoms[it].na; ia++) + std::vector comment; + int natom = 0; + std::vector origin; + std::vector nvoxel; + int nx_read = 0; + int ny_read = 0; + int nz_read = 0; + std::vector dx(3); + std::vector dy(3); + std::vector dz(3); + std::vector> axis_vecs; + std::vector atom_type; + std::vector atom_charge; + std::vector> atom_pos; + std::vector data_read; + + // we've already checked the file existence, so we don't need the returned value here + ModuleIO::read_cube(fn, comment, natom, origin, nx_read, ny_read, nz_read, dx, dy, dz, atom_type, atom_charge, atom_pos, data_read); + + // if mismatch, trilinear interpolate + if (nx == nx_read && ny == ny_read && nz == nz_read) { - ifs >> temp; // skip atomic number - ifs >> temp; // skip Z valance - if (warning_flag) - { - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->atoms[it].tau[ia].x, quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->atoms[it].tau[ia].y, quit); - ModuleBase::CHECK_DOUBLE(ifs, fac * ucell->atoms[it].tau[ia].z, quit); - } - else - { - ifs >> temp >> temp >> temp; - } - } - } - -#ifdef __MPI - const int nxy = nx * ny; - double* zpiece = nullptr; - double** read_rho = nullptr; - if (my_rank == 0 || (esolver_type == "sdft" && rank_in_stogroup == 0)) - { - read_rho = new double*[nz]; - for (int iz = 0; iz < nz; iz++) - { - read_rho[iz] = new double[nxy]; - } - if (same) - { - for (int ix = 0; ix < nx; ix++) - { - for (int iy = 0; iy < ny; iy++) - { - for (int iz = 0; iz < nz; iz++) - { - ifs >> read_rho[iz][ix * ny + iy]; - } - } - } + std::memcpy(data_xyz_full.data(), data_read.data(), nxyz * sizeof(double)); } else { - ModuleIO::trilinear_interpolate(ifs, nx_read, ny_read, nz_read, nx, ny, nz, read_rho); + trilinear_interpolate(data_read.data(), nx_read, ny_read, nz_read, nx, ny, nz, data_xyz_full.data()); } } - else - { - zpiece = new double[nxy]; - ModuleBase::GlobalFunc::ZEROS(zpiece, nxy); - } - for (int iz = 0; iz < nz; iz++) - { - if (my_rank == 0 || (esolver_type == "sdft" && rank_in_stogroup == 0)) - { - zpiece = read_rho[iz]; - } - Pgrid->zpiece_to_all(zpiece, iz, data); - } // iz - - if (my_rank == 0 || (esolver_type == "sdft" && rank_in_stogroup == 0)) - { - for (int iz = 0; iz < nz; iz++) - { - delete[] read_rho[iz]; - } - delete[] read_rho; - } - else - { - delete[] zpiece; - } + // distribute +#ifdef __MPI + pgrid.bcast(data_xyz_full.data(), data, my_rank); #else - ofs_running << " Read SPIN = " << is + 1 << " charge now." << std::endl; - if (same) - { - for (int i = 0; i < nx; i++) - { - for (int j = 0; j < ny; j++) - { - for (int k = 0; k < nz; k++) - { - ifs >> data[k * nx * ny + i * ny + j]; - } - } - } - } - else - { - ModuleIO::trilinear_interpolate(ifs, nx_read, ny_read, nz_read, nx, ny, nz, data); - } + std::memcpy(data, data_xyz_full.data(), nxyz * sizeof(double)); #endif - - if (my_rank == 0 || (esolver_type == "sdft" && rank_in_stogroup == 0)) - ifs.close(); return true; } -void ModuleIO::trilinear_interpolate(std::ifstream& ifs, - const int& nx_read, - const int& ny_read, - const int& nz_read, - const int& nx, - const int& ny, - const int& nz, -#ifdef __MPI - double** data -#else - double* data -#endif -) +void ModuleIO::trilinear_interpolate( + const double* const data_in, + const int& nx_read, + const int& ny_read, + const int& nz_read, + const int& nx, + const int& ny, + const int& nz, + double* data_out) { ModuleBase::TITLE("ModuleIO", "trilinear_interpolate"); @@ -223,7 +96,7 @@ void ModuleIO::trilinear_interpolate(std::ifstream& ifs, { for (int iz = 0; iz < nz_read; iz++) { - ifs >> read_rho[iz][ix * ny_read + iy]; + read_rho[iz][ix * ny_read + iy] = data_in[(ix * ny_read + iy) * nz_read + iz]; } } } @@ -259,11 +132,7 @@ void ModuleIO::trilinear_interpolate(std::ifstream& ifs, + read_rho[highz][lowx * ny_read + highy] * (1 - dx) * dy * dz + read_rho[highz][highx * ny_read + highy] * dx * dy * dz; -#ifdef __MPI - data[iz][ix * ny + iy] = result; -#else - data[iz * nx * ny + ix * ny + iy] = result; -#endif + data_out[(ix * ny + iy) * nz + iz] = result; // x > y > z order, consistent with the cube file } } } @@ -273,4 +142,53 @@ void ModuleIO::trilinear_interpolate(std::ifstream& ifs, delete[] read_rho[iz]; } delete[] read_rho; +} + +bool ModuleIO::read_cube(const std::string& file, + std::vector& comment, + int& natom, + std::vector& origin, + int& nx, + int& ny, + int& nz, + std::vector& dx, + std::vector& dy, + std::vector& dz, + std::vector& atom_type, + std::vector& atom_charge, + std::vector>& atom_pos, + std::vector& data) +{ + std::ifstream ifs(file); + + if (!ifs) { return false; } + + comment.resize(2); + for (auto& c : comment) { std::getline(ifs, c); } + + ifs >> natom; + origin.resize(3); + for (auto& cp : origin) { ifs >> cp; } + + dx.resize(3); + dy.resize(3); + dz.resize(3); + ifs >> nx >> dx[0] >> dx[1] >> dx[2]; + ifs >> ny >> dy[0] >> dy[1] >> dy[2]; + ifs >> nz >> dz[0] >> dz[1] >> dz[2]; + + atom_type.resize(natom); + atom_charge.resize(natom); + atom_pos.resize(natom, std::vector(3)); + for (int i = 0;i < natom;++i) + { + ifs >> atom_type[i] >> atom_charge[i] >> atom_pos[i][0] >> atom_pos[i][1] >> atom_pos[i][2]; + } + + const int nxyz = nx * ny * nz; + data.resize(nxyz); + for (int i = 0;i < nxyz;++i) { ifs >> data[i]; } + + ifs.close(); + return true; } \ No newline at end of file diff --git a/source/module_io/read_input.cpp b/source/module_io/read_input.cpp index 0026b44d42d..f693af76aa5 100644 --- a/source/module_io/read_input.cpp +++ b/source/module_io/read_input.cpp @@ -304,12 +304,7 @@ void ReadInput::read_txt_input(Parameter& param, const std::string& filename) readvalue_item->read_value(*readvalue_item, param); } - // 2) count the number of atom types from STRU file - if (this->check_ntype_flag) { - check_ntype(param.input.stru_file, param.input.ntype); -} - - // 3) reset this value when some conditions are met + // 2) reset this value when some conditions are met // e.g. if (calulation_type == "nscf") then set "init_chg" to "file". for (auto& input_item: this->input_lists) { @@ -320,6 +315,12 @@ void ReadInput::read_txt_input(Parameter& param, const std::string& filename) } this->set_globalv(param); + // 3) count the number of atom types from STRU file + if (this->check_ntype_flag) + { + check_ntype(param.globalv.global_in_stru, param.input.ntype); + } + // 4) check the value of the parameters for (auto& input_item: this->input_lists) { @@ -397,7 +398,7 @@ void ReadInput::write_txt_input(const Parameter& param, const std::string& filen { ofs << "\n#Parameters (14.vdW Correction)" << std::endl; } - else if (p_item->label == "exx_hybrid_alpha") + else if (p_item->label == "exx_hybrid_alpha" || p_item->label == "exx_use_ewald") { ofs << "\n#Parameters (15.exx)" << std::endl; } @@ -432,7 +433,7 @@ void ReadInput::check_ntype(const std::string& fn, int& param_ntype) if (!ifa) { GlobalV::ofs_warning << fn; - ModuleBase::WARNING_QUIT("ReadInput::check_ntype", "Can not find the file containing atom positions.!"); + ModuleBase::WARNING_QUIT("ReadInput::check_ntype", "Can not find the file: " + fn); } int ntype_stru = 0; @@ -476,6 +477,24 @@ void ReadInput::check_ntype(const std::string& fn, int& param_ntype) } } +int ReadInput::current_md_step(const std::string& file_dir) +{ + std::stringstream ssc; + ssc << file_dir << "Restart_md.dat"; + std::ifstream file(ssc.str().c_str()); + + if (!file) + { + ModuleBase::WARNING_QUIT("current_md_step", "no Restart_md.dat"); + } + + int md_step; + file >> md_step; + file.close(); + + return md_step; +} + void ReadInput::add_item(const Input_Item& item) { // only rank 0 read the input file diff --git a/source/module_io/read_input.h b/source/module_io/read_input.h index 1120b1ad666..0bd8745ad70 100644 --- a/source/module_io/read_input.h +++ b/source/module_io/read_input.h @@ -65,6 +65,13 @@ class ReadInput * @param filename output file name */ void write_txt_input(const Parameter& param, const std::string& filename); + /** + * @brief determine the md step in restart case + * + * @param file_dir directory of Restart_md.dat + * @return md step + */ + int current_md_step(const std::string& file_dir); /** * @brief count_nype from STRU file * diff --git a/source/module_io/read_input_item_elec_stru.cpp b/source/module_io/read_input_item_elec_stru.cpp index 4e7795a8538..e039b7f0430 100644 --- a/source/module_io/read_input_item_elec_stru.cpp +++ b/source/module_io/read_input_item_elec_stru.cpp @@ -69,6 +69,7 @@ void ReadInput::item_elec_stru() "lapack", "scalapack_gvx", "cusolver", + "cusolvermp", "pexsi", "cg_in_lcao", }; @@ -234,7 +235,18 @@ void ReadInput::item_elec_stru() para.input.nupdown = doublevalue; para.sys.two_fermi = true; }; - + item.reset_value = [](const Input_Item&, Parameter& para) { + if (para.input.nspin == 1) + { + para.sys.two_fermi = false; + } + }; + item.check_value = [](const Input_Item&, const Parameter& para) { + if (para.input.nspin == 1 && para.input.nupdown != 0.0) + { + ModuleBase::WARNING_QUIT("ReadInput", "nupdown mustn't have a non-zero value for spin-unpolarized calculations."); + } + }; sync_double(input.nupdown); this->add_item(item); } @@ -457,8 +469,7 @@ void ReadInput::item_elec_stru() GlobalV::ofs_warning << " WARNING : gamma_only has not been implemented for pw yet" << std::endl; GlobalV::ofs_warning << "gamma_only is not supported in the pw model" << std::endl; GlobalV::ofs_warning << " the INPUT parameter gamma_only has been reset to 0" << std::endl; - GlobalV::ofs_warning << " and a new KPT is generated with " - "gamma point as the only k point"<< std::endl; + GlobalV::ofs_warning << " and a new KPT is generated with gamma point as the only k point"<< std::endl; GlobalV::ofs_warning << " Auto generating k-points file: " << para.input.kpoint_file << std::endl; std::ofstream ofs(para.input.kpoint_file.c_str()); ofs << "K_POINTS" << std::endl; @@ -467,6 +478,13 @@ void ReadInput::item_elec_stru() ofs << "1 1 1 0 0 0" << std::endl; ofs.close(); } + if (para.input.basis_type == "lcao" && para.input.gamma_only) + { + if (para.input.nspin == 4) + { + ModuleBase::WARNING_QUIT("NOTICE", "nspin=4(soc or noncollinear-spin) does not support gamma only calculation"); + } + } }; this->add_item(item); } @@ -510,6 +528,36 @@ void ReadInput::item_elec_stru() read_sync_double(input.scf_ene_thr); this->add_item(item); } + { + Input_Item item("scf_os_stop"); + item.annotation = "whether to stop scf when oscillation is detected"; + read_sync_bool(input.scf_os_stop); + this->add_item(item); + } + { + Input_Item item("scf_os_thr"); + item.annotation = "charge density threshold for oscillation"; + read_sync_double(input.scf_os_thr); + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.scf_os_thr >= 0) + { + ModuleBase::WARNING_QUIT("ReadInput", "scf_os_thr should be negative"); + } + }; + this->add_item(item); + } + { + Input_Item item("scf_os_ndim"); + item.annotation = "number of old iterations used for oscillation detection"; + read_sync_int(input.scf_os_ndim); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (para.input.scf_os_ndim <= 0) // default value + { + para.input.scf_os_ndim = para.input.mixing_ndim; + } + }; + this->add_item(item); + } { Input_Item item("scf_thr_type"); item.annotation = "type of the criterion of scf_thr, 1: reci drho for " diff --git a/source/module_io/read_input_item_exx_dftu.cpp b/source/module_io/read_input_item_exx_dftu.cpp index 98c78243907..59c3e939463 100644 --- a/source/module_io/read_input_item_exx_dftu.cpp +++ b/source/module_io/read_input_item_exx_dftu.cpp @@ -42,10 +42,132 @@ void ReadInput::item_exx() }; this->add_item(item); } + { + Input_Item item("exx_fq_type"); + item.annotation = "auxiliary-function fq used in correction to V(q) at q->0"; + read_sync_int(input.exx_fq_type); + this->add_item(item); + } + { + Input_Item item("exx_ewald_qdiv"); + item.annotation = "the order of q-divergence in auxiliary function"; + read_sync_double(input.exx_ewald_qdiv); + this->add_item(item); + } + { + Input_Item item("exx_use_ewald"); + item.annotation = "if 1, use Ewald method to construct V matrix"; + read_sync_bool(input.exx_use_ewald); + this->add_item(item); + } + { + Input_Item item("exx_cam_alpha"); + item.annotation = "fraction of the full-range parts of Fock exchange in range-separated hybrid funtionals"; + read_sync_string(input.exx_cam_alpha); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (para.input.exx_cam_alpha == "default") + { + std::string& dft_functional = para.input.dft_functional; + std::string dft_functional_lower = dft_functional; + std::transform(dft_functional.begin(), dft_functional.end(), dft_functional_lower.begin(), tolower); + if (dft_functional_lower == "hf" || + dft_functional_lower == "lc_pbe" || dft_functional_lower == "lc_wpbe" || + dft_functional_lower == "lrc_wpbe" || dft_functional_lower == "lrc_wpbeh") + { + para.input.exx_cam_alpha = "1"; + } + else if (dft_functional_lower == "cam_pbeh") + { + para.input.exx_cam_alpha = "0.2"; + } + else if (dft_functional_lower == "pbe0" + || dft_functional_lower == "scan0") + { + para.input.exx_cam_alpha = "0.25"; + } + else + { + para.input.exx_cam_alpha = "0"; + } + } + }; + this->add_item(item); + } + { + Input_Item item("exx_cam_beta"); + item.annotation = "fraction of the short-range parts of Fock exchange in range-separated hybrid funtionals"; + read_sync_string(input.exx_cam_beta); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (para.input.exx_cam_beta == "default") + { + std::string& dft_functional = para.input.dft_functional; + std::string dft_functional_lower = dft_functional; + std::transform(dft_functional.begin(), dft_functional.end(), dft_functional_lower.begin(), tolower); + if (dft_functional_lower == "lc_pbe" || dft_functional_lower == "lc_wpbe" || + dft_functional_lower == "lrc_wpbe") + { + para.input.exx_cam_beta = "-1"; + } + else if (dft_functional_lower == "lrc_wpbeh") + { + para.input.exx_cam_beta = "-0.8"; + } + else if (dft_functional_lower == "cam_pbeh") + { + para.input.exx_cam_beta = "0.8"; + } + else if (dft_functional_lower == "hse") + { + para.input.exx_cam_beta = "0.25"; + } + else + { + para.input.exx_cam_beta = "0"; + } + } + }; + this->add_item(item); + } { Input_Item item("exx_hse_omega"); - item.annotation = "range-separation parameter in HSE functional"; - read_sync_double(input.exx_hse_omega); + item.annotation = "range-separation parameter in HSE/CAM/LR functional"; + read_sync_string(input.exx_hse_omega); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (para.input.exx_hse_omega == "default") + { + std::string& dft_functional = para.input.dft_functional; + std::string dft_functional_lower = dft_functional; + std::transform(dft_functional.begin(), dft_functional.end(), dft_functional_lower.begin(), tolower); + if (dft_functional_lower == "lc_pbe") + { + para.input.exx_hse_omega = "0.11"; + } + else if (dft_functional_lower == "lc_wpbe") + { + para.input.exx_hse_omega = "0.4"; + } + else if (dft_functional_lower == "lrc_wpbe") + { + para.input.exx_hse_omega = "0.3"; + } + else if (dft_functional_lower == "lrc_wpbeh") + { + para.input.exx_hse_omega = "0.2"; + } + else if (dft_functional_lower == "cam_pbeh") + { + para.input.exx_hse_omega = "0.7"; + } + else if (dft_functional_lower == "hse") + { + para.input.exx_hse_omega = "0.11"; + } + else + { + para.input.exx_hse_omega = "0"; + } + } + }; this->add_item(item); } { @@ -88,7 +210,7 @@ void ReadInput::item_exx() read_sync_string(input.exx_real_number); item.reset_value = [](const Input_Item& item, Parameter& para) { if (para.input.exx_real_number == "default") - { + { // to run through here, the default value of para.input.exx_real_number should be "default" if (para.input.gamma_only) { para.input.exx_real_number = "1"; @@ -181,7 +303,7 @@ void ReadInput::item_exx() read_sync_string(input.exx_ccp_rmesh_times); item.reset_value = [](const Input_Item& item, Parameter& para) { if (para.input.exx_ccp_rmesh_times == "default") - { + { // to run through here, the default value of para.input.exx_ccp_rmesh_times should be "default" std::string& dft_functional = para.input.dft_functional; std::string dft_functional_lower = dft_functional; std::transform(dft_functional.begin(), dft_functional.end(), dft_functional_lower.begin(), tolower); diff --git a/source/module_io/read_input_item_model.cpp b/source/module_io/read_input_item_model.cpp index 964e0f2c52a..30549e5d6f8 100644 --- a/source/module_io/read_input_item_model.cpp +++ b/source/module_io/read_input_item_model.cpp @@ -147,10 +147,10 @@ void ReadInput::item_model() { para.input.vdw_s6 = "0.75"; } - else if (para.input.vdw_method == "d3_0" || para.input.vdw_method == "d3_bj") - { - para.input.vdw_s6 = "1.0"; - } + // else if (para.input.vdw_method == "d3_0" || para.input.vdw_method == "d3_bj") + // { + // para.input.vdw_s6 = "1.0"; + // } } }; read_sync_string(input.vdw_s6); @@ -160,17 +160,17 @@ void ReadInput::item_model() Input_Item item("vdw_s8"); item.annotation = "scale parameter of d3_0/d3_bj"; item.reset_value = [](const Input_Item& item, Parameter& para) { - if (para.input.vdw_s8 == "default") - { - if (para.input.vdw_method == "d3_0") - { - para.input.vdw_s8 = "0.722"; - } - else if (para.input.vdw_method == "d3_bj") - { - para.input.vdw_s8 = "0.7875"; - } - } + // if (para.input.vdw_s8 == "default") + // { + // if (para.input.vdw_method == "d3_0") + // { + // para.input.vdw_s8 = "0.722"; + // } + // else if (para.input.vdw_method == "d3_bj") + // { + // para.input.vdw_s8 = "0.7875"; + // } + // } }; read_sync_string(input.vdw_s8); this->add_item(item); @@ -179,17 +179,17 @@ void ReadInput::item_model() Input_Item item("vdw_a1"); item.annotation = "damping parameter of d3_0/d3_bj"; item.reset_value = [](const Input_Item& item, Parameter& para) { - if (para.input.vdw_a1 == "default") - { - if (para.input.vdw_method == "d3_0") - { - para.input.vdw_a1 = "1.217"; - } - else if (para.input.vdw_method == "d3_bj") - { - para.input.vdw_a1 = "0.4289"; - } - } + // if (para.input.vdw_a1 == "default") + // { + // if (para.input.vdw_method == "d3_0") + // { + // para.input.vdw_a1 = "1.217"; + // } + // else if (para.input.vdw_method == "d3_bj") + // { + // para.input.vdw_a1 = "0.4289"; + // } + // } }; read_sync_string(input.vdw_a1); this->add_item(item); @@ -198,17 +198,17 @@ void ReadInput::item_model() Input_Item item("vdw_a2"); item.annotation = "damping parameter of d3_bj"; item.reset_value = [](const Input_Item& item, Parameter& para) { - if (para.input.vdw_a2 == "default") - { - if (para.input.vdw_method == "d3_0") - { - para.input.vdw_a2 = "1.0"; - } - else if (para.input.vdw_method == "d3_bj") - { - para.input.vdw_a2 = "4.4407"; - } - } + // if (para.input.vdw_a2 == "default") + // { + // if (para.input.vdw_method == "d3_0") + // { + // para.input.vdw_a2 = "1.0"; + // } + // else if (para.input.vdw_method == "d3_bj") + // { + // para.input.vdw_a2 = "4.4407"; + // } + // } }; read_sync_string(input.vdw_a2); this->add_item(item); diff --git a/source/module_io/read_input_item_output.cpp b/source/module_io/read_input_item_output.cpp index d67f0af38aa..7709f602137 100644 --- a/source/module_io/read_input_item_output.cpp +++ b/source/module_io/read_input_item_output.cpp @@ -42,12 +42,16 @@ void ReadInput::item_output() item.read_value = [](const Input_Item& item, Parameter& para) { size_t count = item.get_size(); std::vector out_chg(count); // create a placeholder vector - std::transform(item.str_values.begin(), item.str_values.end(), out_chg.begin(), [](std::string s) { return std::stoi(s); }); + std::transform(item.str_values.begin(), item.str_values.end(), out_chg.begin(), [](std::string s) { + return std::stoi(s); + }); // assign non-negative values to para.input.out_chg std::copy(out_chg.begin(), out_chg.end(), para.input.out_chg.begin()); }; item.reset_value = [](const Input_Item& item, Parameter& para) { - para.input.out_chg[0] = (para.input.calculation == "get_wf" || para.input.calculation == "get_pchg") ? 1 : para.input.out_chg[0]; + para.input.out_chg[0] = (para.input.calculation == "get_wf" || para.input.calculation == "get_pchg") + ? 1 + : para.input.out_chg[0]; }; sync_intvec(input.out_chg, 2, 0); this->add_item(item); @@ -472,7 +476,7 @@ void ReadInput::item_output() } { Input_Item item("bands_to_print"); - item.annotation = "specify the bands to be calculated in get_wf and get_pchg calculation"; + item.annotation = "specify the bands to be calculated for the partial (band-decomposed) charge densities"; item.read_value = [](const Input_Item& item, Parameter& para) { parse_expression(item.str_values, para.input.bands_to_print); }; @@ -485,6 +489,51 @@ void ReadInput::item_output() add_intvec_bcast(input.bands_to_print, para.input.bands_to_print.size(), 0); this->add_item(item); } + { + Input_Item item("out_pchg"); + item.annotation = "specify the bands to be calculated for the partial (band-decomposed) charge densities"; + item.read_value = [](const Input_Item& item, Parameter& para) { + parse_expression(item.str_values, para.input.out_pchg); + }; + item.get_final_value = [](Input_Item& item, const Parameter& para) { + if (item.is_read()) + { + item.final_value.str(longstring(item.str_values)); + } + }; + add_intvec_bcast(input.out_pchg, para.input.out_pchg.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_wfc_norm"); + item.annotation = "specify the bands to be calculated for the norm of wavefunctions"; + item.read_value = [](const Input_Item& item, Parameter& para) { + parse_expression(item.str_values, para.input.out_wfc_norm); + }; + item.get_final_value = [](Input_Item& item, const Parameter& para) { + if (item.is_read()) + { + item.final_value.str(longstring(item.str_values)); + } + }; + add_intvec_bcast(input.out_wfc_norm, para.input.out_wfc_norm.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_wfc_re_im"); + item.annotation = "specify the bands to be calculated for the real and imaginary parts of wavefunctions"; + item.read_value = [](const Input_Item& item, Parameter& para) { + parse_expression(item.str_values, para.input.out_wfc_re_im); + }; + item.get_final_value = [](Input_Item& item, const Parameter& para) { + if (item.is_read()) + { + item.final_value.str(longstring(item.str_values)); + } + }; + add_intvec_bcast(input.out_wfc_re_im, para.input.out_wfc_re_im.size(), 0); + this->add_item(item); + } { Input_Item item("if_separate_k"); item.annotation = "specify whether to write the partial charge densities for all k-points to individual files " @@ -492,5 +541,25 @@ void ReadInput::item_output() read_sync_bool(input.if_separate_k); this->add_item(item); } + { + Input_Item item("out_elf"); + item.annotation = "> 0 output electron localization function (ELF) for selected electron steps" + ", second parameter controls the precision, default is 3."; + item.read_value = [](const Input_Item& item, Parameter& para) { + size_t count = item.get_size(); + std::vector out_elf(count); // create a placeholder vector + std::transform(item.str_values.begin(), item.str_values.end(), out_elf.begin(), [](std::string s) { return std::stoi(s); }); + // assign non-negative values to para.input.out_elf + std::copy(out_elf.begin(), out_elf.end(), para.input.out_elf.begin()); + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_elf[0] > 0 && para.input.esolver_type != "ksdft" && para.input.esolver_type != "ofdft") + { + ModuleBase::WARNING_QUIT("ReadInput", "ELF is only aviailable for ksdft and ofdft"); + } + }; + sync_intvec(input.out_elf, 2, 0); + this->add_item(item); + } } } // namespace ModuleIO diff --git a/source/module_io/read_input_item_postprocess.cpp b/source/module_io/read_input_item_postprocess.cpp index 411214fe6ce..1087e24d952 100644 --- a/source/module_io/read_input_item_postprocess.cpp +++ b/source/module_io/read_input_item_postprocess.cpp @@ -130,6 +130,10 @@ void ReadInput::item_postprocess() { ModuleBase::WARNING_QUIT("ReadInput", "calculate berry phase, please set gdir = 1 or 2 or 3"); } + if (para.input.symmetry != "-1") + { + ModuleBase::WARNING_QUIT("ReadInput", "calculate berry phase, please set symmetry = -1"); + } } }; this->add_item(item); diff --git a/source/module_io/read_input_item_system.cpp b/source/module_io/read_input_item_system.cpp index 32ff4bccef8..38287596741 100644 --- a/source/module_io/read_input_item_system.cpp +++ b/source/module_io/read_input_item_system.cpp @@ -2,6 +2,7 @@ #include "module_base/tool_quit.h" #include "read_input.h" #include "read_input_tool.h" +#include "module_base/module_device/device.h" #include #include @@ -155,6 +156,10 @@ void ReadInput::item_system() { para.input.symmetry = "-1"; // disable kpoint reduce } + if (para.input.berry_phase) + { + para.input.symmetry = "-1"; // disable kpoint reduce + } }; this->add_item(item); } @@ -257,6 +262,24 @@ void ReadInput::item_system() Input_Item item("ecutwfc"); item.annotation = "energy cutoff for wave functions"; read_sync_double(input.ecutwfc); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (para.input.ecutwfc == 0){ // 0 means no input value + if (para.input.basis_type == "lcao") + { + para.input.ecutwfc = 100; + } + else + { + para.input.ecutwfc = 50; + } + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.ecutwfc <= 0) + { + ModuleBase::WARNING_QUIT("ReadInput", "ecutwfc should be positive"); + } + }; this->add_item(item); } { @@ -442,20 +465,6 @@ void ReadInput::item_system() read_sync_int(input.fft_mode); this->add_item(item); } - { - Input_Item item("diago_full_acc"); - item.annotation = "all the empty states are diagonalized"; - /** - * @brief diago_full_acc - * If .TRUE. all the empty states are diagonalized at the same level of - * accuracy of the occupied ones. Otherwise the empty states are - * diagonalized using a larger threshold (this should not affect total - * energy, forces, and other ground-state properties). - * - */ - read_sync_bool(input.diago_full_acc); - this->add_item(item); - } { Input_Item item("init_wfc"); item.annotation = "start wave functions are from 'atomic', " @@ -645,10 +654,6 @@ void ReadInput::item_system() { para.input.read_file_dir = "OUT." + para.input.suffix; } - else - { - para.input.read_file_dir = para.input.read_file_dir; - } para.input.read_file_dir = to_dir(para.input.read_file_dir); }; this->add_item(item); @@ -756,6 +761,10 @@ void ReadInput::item_system() Input_Item item("device"); item.annotation = "the computing device for ABACUS"; read_sync_string(input.device); + item.reset_value = [](const Input_Item& item, Parameter& para) { + para.input.device=base_device::information::get_device_flag( + para.inp.device, para.inp.basis_type); + }; this->add_item(item); } { diff --git a/source/module_io/read_input_item_tddft.cpp b/source/module_io/read_input_item_tddft.cpp index 544fe00ebb7..ccd3190c543 100644 --- a/source/module_io/read_input_item_tddft.cpp +++ b/source/module_io/read_input_item_tddft.cpp @@ -327,6 +327,12 @@ void ReadInput::item_lr_tddft() read_sync_bool(input.out_wfc_lr); this->add_item(item); } + { + Input_Item item("lr_unrestricted"); + item.annotation = "Whether to use unrestricted construction for LR-TDDFT"; + read_sync_bool(input.lr_unrestricted); + this->add_item(item); + } { Input_Item item("abs_wavelen_range"); item.annotation = "the range of wavelength(nm) to output the absorption spectrum "; @@ -337,10 +343,6 @@ void ReadInput::item_lr_tddft() para.input.abs_wavelen_range.push_back(std::stod(item.str_values[i])); } }; - item.check_value = [](const Input_Item& item, const Parameter& para) { - auto& awr = para.input.abs_wavelen_range; - if (awr.size() < 2) { ModuleBase::WARNING_QUIT("ReadInput", "abs_wavelen_range must have two values"); } - }; sync_doublevec(input.abs_wavelen_range, 2, 0.0); this->add_item(item); } diff --git a/source/module_io/read_rho.cpp b/source/module_io/read_rho.cpp deleted file mode 100644 index e6d01f7086a..00000000000 --- a/source/module_io/read_rho.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "module_io/rho_io.h" -#include "module_io/cube_io.h" - - -bool ModuleIO::read_rho( -#ifdef __MPI - Parallel_Grid* Pgrid, -#endif - int my_rank, - std::string esolver_type, - int rank_in_stogroup, - const int& is, - std::ofstream& ofs_running, - const int &nspin, - const std::string &fn, - double* rho, - int& nx, - int& ny, - int& nz, - double& ef, - const UnitCell* ucell, - int &prenspin) -{ - return ModuleIO::read_cube( -#ifdef __MPI - Pgrid, -#endif - my_rank, - esolver_type, - rank_in_stogroup, - is, - ofs_running, - nspin, - fn, - rho, - nx, - ny, - nz, - ef, - ucell, - prenspin); -} diff --git a/source/module_io/read_set_globalv.cpp b/source/module_io/read_set_globalv.cpp index 9b0ac2af892..1eb115fd9fa 100644 --- a/source/module_io/read_set_globalv.cpp +++ b/source/module_io/read_set_globalv.cpp @@ -1,8 +1,9 @@ -#include "read_input.h" -#include "read_input_tool.h" -#include "module_parameter/parameter.h" #include "module_base/global_variable.h" #include "module_base/tool_quit.h" +#include "module_base/module_device/device.h" +#include "module_parameter/parameter.h" +#include "read_input.h" +#include "read_input_tool.h" namespace ModuleIO { void ReadInput::set_globalv(Parameter& para) @@ -20,17 +21,30 @@ void ReadInput::set_globalv(Parameter& para) /// get the global output directory para.sys.global_matrix_dir = para.globalv.global_out_dir + "matrix/"; para.sys.global_matrix_dir = to_dir(para.sys.global_matrix_dir); - + /// get the global readin directory - if (para.inp.read_file_dir == "auto") + para.sys.global_readin_dir = para.inp.read_file_dir + '/'; + para.sys.global_readin_dir = to_dir(para.sys.global_readin_dir); + + /// get the stru file for md restart case + if (para.inp.calculation == "md" && para.mdp.md_restart) { - para.sys.global_readin_dir = para.globalv.global_out_dir; + int istep = current_md_step(para.sys.global_readin_dir); + + if (para.inp.read_file_dir == to_dir("OUT." + para.input.suffix)) + { + para.sys.global_in_stru = para.sys.global_stru_dir + "STRU_MD_" + std::to_string(istep); + } + else + { + para.sys.global_in_stru = para.inp.read_file_dir + "STRU_MD_" + std::to_string(istep); + } } else { - para.sys.global_readin_dir = para.inp.read_file_dir + '/'; + para.sys.global_in_stru = para.inp.stru_file; } - para.sys.global_readin_dir = to_dir(para.sys.global_readin_dir); + /// caculate the gamma_only_pw and gamma_only_local if (para.input.gamma_only) { @@ -49,6 +63,7 @@ void ReadInput::set_globalv(Parameter& para) { para.sys.deepks_setorb = true; } + /// set the noncolin and lspinorb from nspin switch (para.input.nspin) { case 4: @@ -73,25 +88,6 @@ void ReadInput::set_globalv(Parameter& para) break; } - if (para.input.device == "cpu") - { - para.sys.device_flag = "cpu"; - } - else if (para.input.device == "gpu") - { - if (para.input.basis_type == "lcao_in_pw") - { - GlobalV::ofs_warning << "The GPU currently does not support the basis type \"lcao_in_pw\"!" << std::endl; - para.sys.device_flag = "cpu"; - } - para.sys.device_flag = "gpu"; - } - else - { - GlobalV::ofs_warning << "Parameter \"device\" can only be set to \"cpu\" or \"gpu\"!" << std::endl; - ModuleBase::WARNING_QUIT("device", "Parameter \"device\" can only be set to \"cpu\" or \"gpu\"!"); - } - para.sys.nqx=static_cast((sqrt(para.inp.ecutwfc) / para.sys.dq + 4.0) * para.inp.cell_factor); para.sys.nqxq=static_cast((sqrt(para.inp.ecutrho) / para.sys.dq + 4.0) * para.inp.cell_factor); } @@ -99,7 +95,9 @@ void ReadInput::set_globalv(Parameter& para) void ReadInput::set_globalv_bcast() { + // add_int_bcast(sys.myrank); add_bool_bcast(sys.two_fermi); + add_bool_bcast(sys.use_uspp); add_bool_bcast(sys.dos_setemin); add_bool_bcast(sys.dos_setemax); @@ -123,8 +121,6 @@ void ReadInput::set_globalv_bcast() add_bool_bcast(sys.domag); add_bool_bcast(sys.domag_z); add_int_bcast(sys.npol); - - add_string_bcast(sys.device_flag); add_bool_bcast(sys.double_grid); add_double_bcast(sys.uramping); diff --git a/source/module_io/read_wfc_pw.cpp b/source/module_io/read_wfc_pw.cpp index 3ed60c2d6b4..43977d0a3df 100644 --- a/source/module_io/read_wfc_pw.cpp +++ b/source/module_io/read_wfc_pw.cpp @@ -82,7 +82,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, ikstot = ik; #endif - npwtot *= PARAM.globalv.npol; + int npwtot_npol = npwtot * PARAM.globalv.npol; @@ -114,7 +114,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, MPI_Bcast(&tpiba_in, 1, MPI_DOUBLE, 0, POOL_WORLD); #endif - if (ikstot_in != ikstot + 1 || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != GlobalV::NBANDS) + if (ikstot_in != ikstot + 1 || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != PARAM.inp.nbands) { std::cout << "ikstot_in = " << ikstot_in << std::endl; std::cout << "ikstot = " << ikstot + 1 << std::endl; @@ -123,10 +123,10 @@ void ModuleIO::read_wfc_pw(const std::string& filename, std::cout << "npwtot_in = " << npwtot_in << std::endl; std::cout << "npwtot = " << npwtot << std::endl; std::cout << "nbands_in = " << nbands_in << std::endl; - std::cout << "nbands = " << GlobalV::NBANDS << std::endl; + std::cout << "nbands = " << PARAM.inp.nbands << std::endl; ModuleBase::WARNING_QUIT( "ModuleIO::read_wfc_pw", - "ikstot_in != ikstot || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != GlobalV::NBANDS"); + "ikstot_in != ikstot || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != PARAM.inp.nbands"); } if (kvec[0] != pw_wfc->kvec_c[ik].x || kvec[1] != pw_wfc->kvec_c[ik].y || kvec[2] != pw_wfc->kvec_c[ik].z) @@ -178,7 +178,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, } // read in miller index - ModuleBase::Vector3* miller = new ModuleBase::Vector3[npwtot_in]; + ModuleBase::Vector3* miller = new ModuleBase::Vector3[npwtot]; int* glo_order = nullptr; if (GlobalV::RANK_IN_POOL == 0) { @@ -188,7 +188,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, else if (filetype == "dat") { rfs >> size; - for (int i = 0; i < npwtot_in; ++i) + for (int i = 0; i < npwtot; ++i) { rfs >> miller[i].x >> miller[i].y >> miller[i].z; } @@ -201,7 +201,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, { glo_order[i] = -1; } - for (int i = 0; i < npwtot_in / PARAM.globalv.npol; ++i) + for (int i = 0; i < npwtot; ++i) { int index = (miller[i].x * ny + miller[i].y) * nz + miller[i].z; glo_order[index] = i; @@ -221,7 +221,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, } // read in wfc - std::complex* wfc_in = new std::complex[npwtot_in]; + std::complex* wfc_in = new std::complex[npwtot_npol]; for (int ib = 0; ib < nbands_in; ib++) { if (GlobalV::RANK_IN_POOL == 0) @@ -232,7 +232,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, else if (filetype == "dat") { rfs >> size; - for (int i = 0; i < npwtot_in; ++i) + for (int i = 0; i < npwtot_npol; ++i) { rfs >> wfc_in[i]; } @@ -285,7 +285,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, { for (int i = 0; i < size; i++) { - wfc_ip[i] = wfc_in[glo_order[ig_ip[i]] + npwtot_in / 2]; + wfc_ip[i] = wfc_in[glo_order[ig_ip[i]] + npwtot]; } MPI_Send(wfc_ip, size, MPI_DOUBLE_COMPLEX, ip, ip + 2 * GlobalV::NPROC_IN_POOL, POOL_WORLD); } @@ -305,7 +305,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, { for (int i = 0; i < pw_wfc->npwk[ik]; ++i) { - wfc(ib, i + npwk_max) = wfc_in[glo_order[l2g_pw[i]] + npwtot_in / 2]; + wfc(ib, i + npwk_max) = wfc_in[glo_order[l2g_pw[i]] + npwtot]; } } } @@ -321,7 +321,7 @@ void ModuleIO::read_wfc_pw(const std::string& filename, { for (int i = 0; i < pw_wfc->npwk[ik]; ++i) { - wfc(ib, i + npwk_max) = wfc_in[glo_order[l2g_pw[i]] + npwtot_in / 2]; + wfc(ib, i + npwk_max) = wfc_in[glo_order[l2g_pw[i]] + npwtot]; } } #endif diff --git a/source/module_io/read_wfc_to_rho.cpp b/source/module_io/read_wfc_to_rho.cpp index abd3a3c2b1a..bef1a874628 100644 --- a/source/module_io/read_wfc_to_rho.cpp +++ b/source/module_io/read_wfc_to_rho.cpp @@ -5,6 +5,7 @@ #include "module_hamilt_pw/hamilt_pwdft/global.h" #include "module_elecstate/module_charge/symmetry_rho.h" #include "module_parameter/parameter.h" +#include "module_elecstate/kernels/elecstate_op.h" void ModuleIO::read_wfc_to_rho(const ModulePW::PW_Basis_K* pw_wfc, ModuleSymmetry::Symmetry& symm, @@ -18,17 +19,17 @@ void ModuleIO::read_wfc_to_rho(const ModulePW::PW_Basis_K* pw_wfc, const int kpar = GlobalV::KPAR; const int my_pool = GlobalV::MY_POOL; const int my_rank = GlobalV::MY_RANK; - const int nbands = GlobalV::NBANDS; + const int nbands = PARAM.inp.nbands; const int nspin = PARAM.inp.nspin; - const int npwk_max = pw_wfc->npwk_max; + const int ng_npol = pw_wfc->npwk_max * PARAM.globalv.npol; const int nrxx = pw_wfc->nrxx; for (int is = 0; is < nspin; ++is) { ModuleBase::GlobalFunc::ZEROS(chg.rho[is], nrxx); } - ModuleBase::ComplexMatrix wfc_tmp(nbands, npwk_max); + ModuleBase::ComplexMatrix wfc_tmp(nbands, ng_npol); std::vector> rho_tmp(nrxx); // read occupation numbers @@ -78,21 +79,44 @@ void ModuleIO::read_wfc_to_rho(const ModulePW::PW_Basis_K* pw_wfc, std::stringstream filename; filename << PARAM.globalv.global_readin_dir << "WAVEFUNC" << ikstot + 1 << ".dat"; ModuleIO::read_wfc_pw(filename.str(), pw_wfc, ik, nkstot, wfc_tmp); - for (int ib = 0; ib < nbands; ++ib) + if (PARAM.inp.nspin == 4) { - const std::complex* wfc_ib = wfc_tmp.c + ib * npwk_max; - pw_wfc->recip2real(wfc_ib, rho_tmp.data(), ik); - - const double w1 = wg_tmp(ikstot, ib) / pw_wfc->omega; + std::vector> rho_tmp2(nrxx); + for (int ib = 0; ib < nbands; ++ib) + { + const std::complex* wfc_ib = wfc_tmp.c + ib * ng_npol; + const std::complex* wfc_ib2 = wfc_tmp.c + ib * ng_npol + ng_npol / 2; + pw_wfc->recip2real(wfc_ib, rho_tmp.data(), ik); + pw_wfc->recip2real(wfc_ib2, rho_tmp2.data(), ik); + const double w1 = wg_tmp(ikstot, ib) / pw_wfc->omega; - if (w1 != 0.0) + if (w1 != 0.0) + { + base_device::DEVICE_CPU* ctx = nullptr; + elecstate::elecstate_pw_op()(ctx, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + nrxx, + w1, + chg.rho, + rho_tmp.data(), + rho_tmp2.data()); + } + } + } + else + { + for (int ib = 0; ib < nbands; ++ib) { -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (int ir = 0; ir < nrxx; ir++) + const std::complex* wfc_ib = wfc_tmp.c + ib * ng_npol; + pw_wfc->recip2real(wfc_ib, rho_tmp.data(), ik); + + const double w1 = wg_tmp(ikstot, ib) / pw_wfc->omega; + + if (w1 != 0.0) { - chg.rho[is][ir] += w1 * std::norm(rho_tmp[ir]); + base_device::DEVICE_CPU* ctx = nullptr; + elecstate::elecstate_pw_op()(ctx, is, nrxx, w1, chg.rho, rho_tmp.data()); } } } diff --git a/source/module_io/rho_io.h b/source/module_io/rho_io.h deleted file mode 100644 index d23467ad966..00000000000 --- a/source/module_io/rho_io.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef RHO_IO_H -#define RHO_IO_H -#include -#include "module_cell/unitcell.h" -#ifdef __MPI -#include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" -#endif - -namespace ModuleIO -{ -bool read_rho( -#ifdef __MPI - Parallel_Grid* Pgrid, -#endif - int my_rank, - std::string esolver_type, - int rank_in_stogroup, - const int& is, - std::ofstream& ofs_running, - const int& nspin, - const std::string& fn, - double* rho, - int& nx, - int& ny, - int& nz, - double& ef, - const UnitCell* ucell, - int& prenspin); -} - -#endif diff --git a/source/module_io/single_R_io.cpp b/source/module_io/single_R_io.cpp index 8c81d8b3fb5..f0116b8fba3 100644 --- a/source/module_io/single_R_io.cpp +++ b/source/module_io/single_R_io.cpp @@ -24,7 +24,7 @@ void ModuleIO::output_single_R(std::ofstream& ofs, { T* line = nullptr; std::vector indptr; - indptr.reserve(GlobalV::NLOCAL + 1); + indptr.reserve(PARAM.globalv.nlocal + 1); indptr.push_back(0); std::stringstream tem1; @@ -44,10 +44,10 @@ void ModuleIO::output_single_R(std::ofstream& ofs, } } - line = new T[GlobalV::NLOCAL]; - for(int row = 0; row < GlobalV::NLOCAL; ++row) + line = new T[PARAM.globalv.nlocal]; + for(int row = 0; row < PARAM.globalv.nlocal; ++row) { - ModuleBase::GlobalFunc::ZEROS(line, GlobalV::NLOCAL); + ModuleBase::GlobalFunc::ZEROS(line, PARAM.globalv.nlocal); if (!reduce || pv.global2local_row(row) >= 0) { @@ -61,12 +61,13 @@ void ModuleIO::output_single_R(std::ofstream& ofs, } } - if (reduce)Parallel_Reduce::reduce_all(line, GlobalV::NLOCAL); + if (reduce) {Parallel_Reduce::reduce_all(line, PARAM.globalv.nlocal); +} if (!reduce || GlobalV::DRANK == 0) { int nonzeros_count = 0; - for (int col = 0; col < GlobalV::NLOCAL; ++col) + for (int col = 0; col < PARAM.globalv.nlocal; ++col) { if (std::abs(line[col]) > sparse_threshold) { diff --git a/source/module_io/td_current_io.cpp b/source/module_io/td_current_io.cpp index 0102d18e394..47a9c7a6b5b 100644 --- a/source/module_io/td_current_io.cpp +++ b/source/module_io/td_current_io.cpp @@ -1,6 +1,5 @@ #include "td_current_io.h" -#include "module_parameter/parameter.h" #include "module_base/global_function.h" #include "module_base/global_variable.h" #include "module_base/libm/libm.h" @@ -11,9 +10,10 @@ #include "module_elecstate/module_dm/cal_dm_psi.h" #include "module_elecstate/potentials/H_TDDFT_pw.h" #include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" -#include "module_hamilt_lcao/module_tddft/td_velocity.h" #include "module_hamilt_lcao/module_tddft/td_current.h" +#include "module_hamilt_lcao/module_tddft/td_velocity.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" +#include "module_parameter/parameter.h" #ifdef __LCAO @@ -28,7 +28,7 @@ void ModuleIO::cal_tmp_DM(elecstate::DensityMatrix, double> int ld_hk = DM_real.get_paraV_pointer()->nrow; int ld_hk2 = 2 * ld_hk; // tmp for is - int ik_begin = DM_real.get_DMK_nks() / nspin * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = DM_real.get_DMK_nks() / nspin * (is - 1); // jump nk for spin_down if nspin==2 hamilt::HContainer* tmp_DMR_real = DM_real.get_DMR_vector()[is - 1]; hamilt::HContainer* tmp_DMR_imag = DM_imag.get_DMR_vector()[is - 1]; @@ -156,7 +156,7 @@ void ModuleIO::write_current(const int istep, cal_current->calculate_grad_term(); for (int dir = 0; dir < 3; dir++) { - current_term[dir]=cal_current->get_current_term_pointer(dir); + current_term[dir] = cal_current->get_current_term_pointer(dir); } } else @@ -167,16 +167,16 @@ void ModuleIO::write_current(const int istep, } for (int dir = 0; dir < 3; dir++) { - current_term[dir]=TD_Velocity::td_vel_op->get_current_term_pointer(dir); + current_term[dir] = TD_Velocity::td_vel_op->get_current_term_pointer(dir); } } - // construct a DensityMatrix object // Since the function cal_dm_psi do not suport DMR in complex type, I replace it with two DMR in double type. Should // be refactored in the future. - elecstate::DensityMatrix, double> DM_real(&kv, pv, PARAM.inp.nspin); - elecstate::DensityMatrix, double> DM_imag(&kv, pv, PARAM.inp.nspin); + const int nspin_dm = std::map({ {1,1},{2,2},{4,1} })[PARAM.inp.nspin]; + elecstate::DensityMatrix, double> DM_real(pv, nspin_dm, kv.kvec_d, kv.get_nks() / nspin_dm); + elecstate::DensityMatrix, double> DM_imag(pv, nspin_dm, kv.kvec_d, kv.get_nks() / nspin_dm); // calculate DMK elecstate::cal_dm_psi(DM_real.get_paraV_pointer(), pelec->wg, psi[0], DM_real); @@ -241,12 +241,17 @@ void ModuleIO::write_current(const int istep, double Rz = ra.info[iat][cb][2]; //std::cout<< "iat1: " << iat1 << " iat2: " << iat2 << " Rx: " << Rx << " Ry: " << Ry << " Rz:" << Rz << std::endl; // get BaseMatrix - hamilt::BaseMatrix* tmp_matrix_real = DM_real.get_DMR_pointer(is)->find_matrix(iat1, iat2, Rx, Ry, Rz); - hamilt::BaseMatrix* tmp_matrix_imag = DM_imag.get_DMR_pointer(is)->find_matrix(iat1, iat2, Rx, Ry, Rz); + hamilt::BaseMatrix* tmp_matrix_real + = DM_real.get_DMR_pointer(is)->find_matrix(iat1, iat2, Rx, Ry, Rz); + hamilt::BaseMatrix* tmp_matrix_imag + = DM_imag.get_DMR_pointer(is)->find_matrix(iat1, iat2, Rx, Ry, Rz); // refactor - hamilt::BaseMatrix>* tmp_m_rvx = current_term[0]->find_matrix(iat1, iat2, Rx, Ry, Rz); - hamilt::BaseMatrix>* tmp_m_rvy = current_term[1]->find_matrix(iat1, iat2, Rx, Ry, Rz); - hamilt::BaseMatrix>* tmp_m_rvz = current_term[2]->find_matrix(iat1, iat2, Rx, Ry, Rz); + hamilt::BaseMatrix>* tmp_m_rvx + = current_term[0]->find_matrix(iat1, iat2, Rx, Ry, Rz); + hamilt::BaseMatrix>* tmp_m_rvy + = current_term[1]->find_matrix(iat1, iat2, Rx, Ry, Rz); + hamilt::BaseMatrix>* tmp_m_rvz + = current_term[2]->find_matrix(iat1, iat2, Rx, Ry, Rz); if (tmp_matrix_real == nullptr) { continue; @@ -277,13 +282,13 @@ void ModuleIO::write_current(const int istep, local_current_ik[0] -= dm2d1_real * rvx.real() - dm2d1_imag * rvx.imag(); local_current_ik[1] -= dm2d1_real * rvy.real() - dm2d1_imag * rvy.imag(); local_current_ik[2] -= dm2d1_real * rvz.real() - dm2d1_imag * rvz.imag(); - + ++local_total_irr; ++irr; } // end kk - } // end jj - } // end cb - } // end iat + } // end jj + } // end cb + } // end iat #ifdef _OPENMP #pragma omp critical(cal_current_k_reduce) { @@ -313,9 +318,8 @@ void ModuleIO::write_current(const int istep, fout.close(); } // write end - ModuleBase::timer::tick("ModuleIO", "write_current"); } // end nks - } // end is + } // end is if (GlobalV::MY_RANK == 0) { std::string filename = PARAM.globalv.global_out_dir + "current_total.dat"; @@ -326,10 +330,12 @@ void ModuleIO::write_current(const int istep, fout << istep << " " << current_total[0] << " " << current_total[1] << " " << current_total[2] << std::endl; fout.close(); } - if(!TD_Velocity::tddft_velocity) + if (!TD_Velocity::tddft_velocity) { delete cal_current; } + + ModuleBase::timer::tick("ModuleIO", "write_current"); return; } #endif //__LCAO diff --git a/source/module_io/test/CMakeLists.txt b/source/module_io/test/CMakeLists.txt index ad18e6fb139..543c4f363c2 100644 --- a/source/module_io/test/CMakeLists.txt +++ b/source/module_io/test/CMakeLists.txt @@ -155,6 +155,7 @@ AddTest( ../../module_cell/parallel_kpoints.cpp ../../module_cell/test/support/mock_unitcell.cpp ../../module_hamilt_lcao/hamilt_lcaodft/center2_orb.cpp + ../orb_io.cpp ) endif() @@ -185,7 +186,10 @@ add_test(NAME read_wfc_to_rho_parallel AddTest( TARGET numerical_basis_test LIBS parameter base ${math_libs} device numerical_atomic_orbitals container orb - SOURCES numerical_basis_test.cpp ../numerical_basis_jyjy.cpp ../../module_hamilt_lcao/hamilt_lcaodft/center2_orb.cpp + SOURCES numerical_basis_test.cpp + ../numerical_basis_jyjy.cpp + ../../module_hamilt_lcao/hamilt_lcaodft/center2_orb.cpp + ../orb_io.cpp ) @@ -196,6 +200,7 @@ AddTest( ../../module_cell/cell_index.cpp ../../module_basis/module_ao/parallel_2d.cpp ../../module_basis/module_ao/parallel_orbitals.cpp + ../orb_io.cpp ) if(ENABLE_LCAO) @@ -221,4 +226,15 @@ AddTest( add_test(NAME cif_io_test_parallel COMMAND mpirun -np 4 ./cif_io_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +AddTest( + TARGET orb_io_test + LIBS parameter base ${math_libs} device + SOURCES orb_io_test.cpp ../orb_io.cpp +) + +add_test(NAME orb_io_test_parallel + COMMAND mpirun -np 4 ./orb_io_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) \ No newline at end of file diff --git a/source/module_io/test/cif_io_test.cpp b/source/module_io/test/cif_io_test.cpp index c1e1e96ca45..3159142c833 100644 --- a/source/module_io/test/cif_io_test.cpp +++ b/source/module_io/test/cif_io_test.cpp @@ -167,11 +167,13 @@ TEST(CifParserTest, ReadSimpleTest) ofs.close(); #ifdef __MPI } + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is written #endif std::map> data; ModuleIO::CifParser::read("mp-2516584.cif", data); // delete the file #ifdef __MPI + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is already read if (rank == 0) { #endif @@ -241,11 +243,13 @@ TEST(CifParserTest, ReadMediumTest) ofs.close(); #ifdef __MPI } + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is written #endif std::map> data; ModuleIO::CifParser::read("cod-1000065.cif", data); // delete the file #ifdef __MPI + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is already read if (rank == 0) { #endif @@ -316,7 +320,6 @@ TEST(CifParserTest, WriteTest) MPI_Comm_rank(MPI_COMM_WORLD, &rank); #endif const std::string fcif = "test.cif"; - std::ofstream ofs(fcif); const std::vector abc_angles = {2.46637620, 2.46637620, 24.84784531, 90.0, 90.0, 120.0}; const int natom = 4; const std::vector atom_site_labels = {"C", "C", "C", "C"}; @@ -325,16 +328,21 @@ TEST(CifParserTest, WriteTest) 0.333333, 0.666667, 0.75, 0.666667, 0.333333, 0.25}; ModuleIO::CifParser::write(fcif, - abc_angles.data(), - natom, - atom_site_labels.data(), - atom_site_fract.data(), - "# Generated during unittest of function ModuleIO::CifParser::write", - "data_test"); + abc_angles.data(), + natom, + atom_site_labels.data(), + atom_site_fract.data(), + "# Generated during unittest of function ModuleIO::CifParser::write", + "data_test", + rank); +#ifdef __MPI + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is written +#endif std::map> data; - ModuleIO::CifParser::read(fcif, data); + ModuleIO::CifParser::read(fcif, data, rank); // delete the file #ifdef __MPI + MPI_Barrier(MPI_COMM_WORLD); // make sure the file is already read if (rank == 0) { #endif diff --git a/source/module_io/test/orb_io_test.cpp b/source/module_io/test/orb_io_test.cpp new file mode 100644 index 00000000000..a5c9e1df9f9 --- /dev/null +++ b/source/module_io/test/orb_io_test.cpp @@ -0,0 +1,162 @@ +#include +#include "module_io/orb_io.h" + +#ifdef __MPI +#include +#endif + +#include "module_base/constants.h" +#include "module_base/global_variable.h" + +class OrbIOTest : public testing::Test +{ + protected: + void SetUp(); + void TearDown(){}; + + const std::string file = "../../../../tests/PP_ORB/Ti_gga_10au_100Ry_4s2p2d1f.orb"; + const double tol = 1e-12; +}; + +void OrbIOTest::SetUp() +{ +#ifdef __MPI + MPI_Comm_rank(MPI_COMM_WORLD, &GlobalV::MY_RANK); +#endif +} + +TEST_F(OrbIOTest, ReadAbacusOrb) +{ + std::ifstream ifs; + std::string elem; + double ecut, dr; + int nr; + std::vector nzeta; + std::vector> radials; + if (GlobalV::MY_RANK == 0) + { + ifs.open(file); + } + ModuleIO::read_abacus_orb(ifs, elem, ecut, nr, dr, nzeta, radials, GlobalV::MY_RANK); + if (GlobalV::MY_RANK == 0) + { + ifs.close(); + } + EXPECT_EQ(elem, "Ti"); + EXPECT_DOUBLE_EQ(ecut, 100.0); + EXPECT_EQ(nr, 1001); + EXPECT_DOUBLE_EQ(dr, 0.01); + EXPECT_EQ(nzeta.size(), 4); // l from 0 to 3 + EXPECT_EQ(nzeta[0], 4); + EXPECT_EQ(nzeta[1], 2); + EXPECT_EQ(nzeta[2], 2); + EXPECT_EQ(nzeta[3], 1); + EXPECT_EQ(radials.size(), 9); // 4 + 2 + 2 + 1 + for(auto& radial: radials) + { + EXPECT_EQ(radial.size(), 1001); + } + EXPECT_EQ(radials[0][0], -1.581711853170e-01); + EXPECT_EQ(radials[0][4], -1.583907030513e-01); + EXPECT_EQ(radials[0][996], -4.183526380009e-05); + EXPECT_EQ(radials[0][1000], 0); + EXPECT_EQ(radials[3][0], -1.166292682541e+00); + EXPECT_EQ(radials[3][4], -1.164223359672e+00); + EXPECT_EQ(radials[3][996], -3.183325576529e-04); + EXPECT_EQ(radials[3][1000], 0); + EXPECT_EQ(radials[8][0], 0); + EXPECT_EQ(radials[8][4], 3.744878535962e-05); + EXPECT_EQ(radials[8][996], 7.495357740660e-05); + EXPECT_EQ(radials[8][1000], 0); +} + +TEST_F(OrbIOTest, WriteAbacusOrb) +{ + std::ifstream ifs; + std::string elem; + double ecut, dr; + int nr; + std::vector nzeta; + std::vector> radials; + if (GlobalV::MY_RANK == 0) + { + ifs.open(file); + } + ModuleIO::read_abacus_orb(ifs, elem, ecut, nr, dr, nzeta, radials, GlobalV::MY_RANK); + if (GlobalV::MY_RANK == 0) + { + ifs.close(); + } + + const std::string ftmp = "tmp.orb"; + std::ofstream ofs; + if (GlobalV::MY_RANK == 0) + { + ofs.open(ftmp); + } + ModuleIO::write_abacus_orb(ofs, elem, ecut, nr, dr, nzeta, radials, GlobalV::MY_RANK); + if (GlobalV::MY_RANK == 0) + { + ofs.close(); + } +#ifdef __MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + + std::ifstream ifs1; + + std::string elem1; + double ecut1, dr1; + int nr1; + std::vector nzeta1; + std::vector> radials1; + if (GlobalV::MY_RANK == 0) + { + ifs1.open(ftmp); + } + ModuleIO::read_abacus_orb(ifs1, elem1, ecut1, nr1, dr1, nzeta1, radials1, GlobalV::MY_RANK); + if (GlobalV::MY_RANK == 0) + { + ifs1.close(); + } + + EXPECT_EQ(elem, elem1); + EXPECT_DOUBLE_EQ(ecut, ecut1); + EXPECT_EQ(nr, nr1); + EXPECT_DOUBLE_EQ(dr, dr1); + EXPECT_EQ(nzeta.size(), nzeta1.size()); + for (int i = 0; i < nzeta.size(); ++i) + { + EXPECT_EQ(nzeta[i], nzeta1[i]); + } + EXPECT_EQ(radials.size(), radials1.size()); + for (int i = 0; i < radials.size(); ++i) + { + EXPECT_EQ(radials[i].size(), radials1[i].size()); + for (int j = 0; j < radials[i].size(); ++j) + { + EXPECT_NEAR(radials[i][j], radials1[i][j], tol); + } + } + if (GlobalV::MY_RANK == 0) + { + remove(ftmp.c_str()); + } +} + +int main(int argc, char** argv) +{ + +#ifdef __MPI + MPI_Init(&argc, &argv); +#endif + + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef __MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/source/module_io/test/outputlog_test.cpp b/source/module_io/test/outputlog_test.cpp index 1fd15a30ea4..4dbb02e73e4 100644 --- a/source/module_io/test/outputlog_test.cpp +++ b/source/module_io/test/outputlog_test.cpp @@ -86,6 +86,33 @@ TEST(OutputEfermiTest, TestConvergence) { std::remove("test_output_efermi.txt"); } +// Test the output_efermi function +TEST(OutputAfterRelaxTest, TestConvergence) +{ + bool conv_ion = true; + bool conv_esolver = false; + std::ofstream ofs_running("test_output_after_relax.txt"); + ModuleIO::output_after_relax(conv_ion, conv_esolver, ofs_running); + ofs_running.close(); + + std::ifstream ifs_running("test_output_after_relax.txt"); + std::stringstream ss; + ss << ifs_running.rdbuf(); + std::string file_content = ss.str(); + ifs_running.close(); + + std::string expected_content + = "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n Relaxation is converged, but the SCF is unconverged! The " + "results are unreliable.. \n\n It is suggested to increase the maximum SCF step and/or perform the " + "relaxation again. " + "\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; + + EXPECT_EQ(file_content, expected_content); + std::remove("test_output_after_relax.txt"); +} + TEST(OutputEfermiTest, TestNotConvergence) { bool convergence = false; double efermi = 1.0; diff --git a/source/module_io/test/prepare_unitcell.h b/source/module_io/test/prepare_unitcell.h index 5a831eea06a..d9deaf0ff3a 100644 --- a/source/module_io/test/prepare_unitcell.h +++ b/source/module_io/test/prepare_unitcell.h @@ -252,8 +252,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_io/test/print_info_test.cpp b/source/module_io/test/print_info_test.cpp index 7c2a255a8e9..f4e96f2e16a 100644 --- a/source/module_io/test/print_info_test.cpp +++ b/source/module_io/test/print_info_test.cpp @@ -60,11 +60,6 @@ class PrintInfoTest : public testing::Test } }; -TEST_F(PrintInfoTest, Constructor) -{ - EXPECT_NO_THROW(Print_Info pinfo); -} - TEST_F(PrintInfoTest, SetupParameters) { UcellTestPrepare utp = UcellTestLib["Si"]; @@ -83,8 +78,8 @@ TEST_F(PrintInfoTest, SetupParameters) PARAM.sys.gamma_only_local = false; PARAM.input.calculation = cal_type[i]; testing::internal::CaptureStdout(); - EXPECT_NO_THROW(Print_Info::setup_parameters(*ucell,*kv)); - output = testing::internal::GetCapturedStdout(); + EXPECT_NO_THROW(ModuleIO::setup_parameters(*ucell, *kv)); + output = testing::internal::GetCapturedStdout(); if(PARAM.input.calculation == "scf") { EXPECT_THAT(output,testing::HasSubstr("Self-consistent calculations")); @@ -106,7 +101,7 @@ TEST_F(PrintInfoTest, SetupParameters) { PARAM.input.mdp.md_type = md_types[j]; testing::internal::CaptureStdout(); - EXPECT_NO_THROW(Print_Info::setup_parameters(*ucell,*kv)); + EXPECT_NO_THROW(ModuleIO::setup_parameters(*ucell, *kv)); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("Molecular Dynamics simulations")); if (PARAM.mdp.md_type == "fire") @@ -141,8 +136,8 @@ TEST_F(PrintInfoTest, SetupParameters) { PARAM.input.basis_type = basis_type[i]; testing::internal::CaptureStdout(); - EXPECT_NO_THROW(Print_Info::setup_parameters(*ucell,*kv)); - output = testing::internal::GetCapturedStdout(); + EXPECT_NO_THROW(ModuleIO::setup_parameters(*ucell, *kv)); + output = testing::internal::GetCapturedStdout(); if(PARAM.input.basis_type == "lcao") { EXPECT_THAT(output,testing::HasSubstr("Use Systematically Improvable Atomic bases")); @@ -170,22 +165,22 @@ TEST_F(PrintInfoTest, PrintScreen) if(PARAM.input.calculation=="scf") { testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("SELF-CONSISTENT")); } else if(PARAM.input.calculation=="nscf") { testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("NONSELF-CONSISTENT")); } else if(PARAM.input.calculation=="md") { testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("STEP OF MOLECULAR DYNAMICS")); } else @@ -194,22 +189,22 @@ TEST_F(PrintInfoTest, PrintScreen) if(PARAM.input.calculation=="relax") { testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("STEP OF ION RELAXATION")); } else if(PARAM.input.calculation=="cell-relax") { testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("RELAX CELL")); EXPECT_THAT(output,testing::HasSubstr("RELAX IONS")); } PARAM.input.relax_new = true; testing::internal::CaptureStdout(); - Print_Info::print_screen(stress_step,force_step,istep); - output = testing::internal::GetCapturedStdout(); + ModuleIO::print_screen(stress_step, force_step, istep); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("STEP OF RELAXATION")); } } @@ -220,8 +215,8 @@ TEST_F(PrintInfoTest, PrintTime) time_t time_start = std::time(nullptr); time_t time_finish = std::time(nullptr); testing::internal::CaptureStdout(); - EXPECT_NO_THROW(Print_Info::print_time(time_start,time_finish)); - output = testing::internal::GetCapturedStdout(); + EXPECT_NO_THROW(ModuleIO::print_time(time_start, time_finish)); + output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output,testing::HasSubstr("START Time")); EXPECT_THAT(output,testing::HasSubstr("FINISH Time")); EXPECT_THAT(output,testing::HasSubstr("TOTAL Time")); diff --git a/source/module_io/test/read_input_ptest.cpp b/source/module_io/test/read_input_ptest.cpp index af8125696d0..9365c299ef4 100644 --- a/source/module_io/test/read_input_ptest.cpp +++ b/source/module_io/test/read_input_ptest.cpp @@ -51,6 +51,9 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.nbands_sto, 256); EXPECT_EQ(param.inp.nbands_istate, 5); EXPECT_EQ(param.inp.bands_to_print.size(), 0); + EXPECT_EQ(param.inp.out_pchg.size(), 0); + EXPECT_EQ(param.inp.out_wfc_norm.size(), 0); + EXPECT_EQ(param.inp.out_wfc_re_im.size(), 0); EXPECT_FALSE(param.inp.if_separate_k); EXPECT_EQ(param.inp.pw_seed, 1); EXPECT_EQ(param.inp.emin_sto, 0.0); @@ -161,7 +164,10 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(PARAM.inp.test_force, 0); EXPECT_EQ(param.inp.test_stress, 0); EXPECT_NEAR(param.inp.scf_thr, 1.0e-8, 1.0e-15); - EXPECT_NEAR(param.inp.scf_ene_thr, -1.0, 1.0e-15); + EXPECT_EQ(param.inp.scf_os_stop, 1); + EXPECT_NEAR(param.inp.scf_os_thr, -0.02, 1.0e-15); + EXPECT_EQ(param.inp.scf_os_ndim, 10); + EXPECT_NEAR(param.inp.scf_ene_thr, 1.0e-6, 1.0e-15); EXPECT_EQ(param.inp.scf_nmax, 50); EXPECT_EQ(param.inp.relax_nmax, 1); EXPECT_EQ(param.inp.out_stru, 0); @@ -180,6 +186,8 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.out_freq_ion, 0); EXPECT_EQ(param.inp.out_chg[0], 0); EXPECT_EQ(param.inp.out_chg[1], 3); + EXPECT_EQ(param.inp.out_elf[0], 0); + EXPECT_EQ(param.inp.out_elf[1], 3); EXPECT_EQ(param.inp.out_dm, 0); EXPECT_EQ(param.inp.out_dm1, 0); EXPECT_EQ(param.inp.deepks_out_labels, 0); @@ -258,6 +266,10 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.vdw_cutoff_period[1], 3); EXPECT_EQ(param.inp.vdw_cutoff_period[2], 3); EXPECT_EQ(std::stod(param.inp.exx_hybrid_alpha), 0.25); + EXPECT_EQ(std::stod(param.inp.exx_cam_alpha), 0.0); + EXPECT_EQ(std::stod(param.inp.exx_cam_beta), 0.0); + EXPECT_EQ(param.inp.exx_use_ewald, 0); + EXPECT_EQ(param.inp.exx_fq_type, 1); EXPECT_EQ(param.inp.exx_real_number, "1"); EXPECT_DOUBLE_EQ(param.inp.exx_hse_omega, 0.11); EXPECT_TRUE(param.inp.exx_separate_loop); @@ -414,6 +426,7 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.xc_kernel, "LDA"); EXPECT_EQ(param.inp.lr_solver, "dav"); EXPECT_DOUBLE_EQ(param.inp.lr_thr, 1e-2); + EXPECT_FALSE(param.inp.lr_unrestricted); EXPECT_FALSE(param.inp.out_wfc_lr); EXPECT_EQ(param.inp.abs_wavelen_range.size(), 2); EXPECT_DOUBLE_EQ(param.inp.abs_wavelen_range[0], 0.0); diff --git a/source/module_io/test/read_wfc_pw_test.cpp b/source/module_io/test/read_wfc_pw_test.cpp index 78867db78b5..0d717955de8 100644 --- a/source/module_io/test/read_wfc_pw_test.cpp +++ b/source/module_io/test/read_wfc_pw_test.cpp @@ -1,5 +1,8 @@ #include "module_io/read_wfc_pw.h" +#define private public +#include "module_parameter/parameter.h" +#undef private #include "gmock/gmock.h" #include "gtest/gtest.h" #ifdef __MPI @@ -49,9 +52,9 @@ TEST_F(ReadWfcPwTest, ReadWfcPw) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - GlobalV::NBANDS = 8; + PARAM.input.nbands = 8; const int nbasis = wfcpw->npwk[0]; - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, nbasis); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, nbasis); ModuleIO::read_wfc_pw(filename, wfcpw, 0, nkstot, wfcatom); if (GlobalV::NPROC_IN_POOL == 1) @@ -116,7 +119,7 @@ TEST_F(ReadWfcPwTest, NotFoundFile) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, wfcpw->npwk[0]); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, wfcpw->npwk[0]); if(GlobalV::RANK_IN_POOL == 0) { @@ -159,9 +162,9 @@ TEST_F(ReadWfcPwTest, InconsistentBands) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - GlobalV::NBANDS = 4; + PARAM.input.nbands = 4; const int nbasis = wfcpw->npwk[0]; - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, nbasis); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, nbasis); testing::internal::CaptureStdout(); EXPECT_EXIT(ModuleIO::read_wfc_pw(filename, wfcpw, 0, nkstot, wfcatom), ::testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); @@ -170,7 +173,7 @@ TEST_F(ReadWfcPwTest, InconsistentBands) EXPECT_THAT( output, testing::HasSubstr( - "ikstot_in != ikstot || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != GlobalV::NBANDS")); + "ikstot_in != ikstot || nkstot_in != nkstot || npwtot_in != npwtot || nbands_in != PARAM.inp.nbands")); } } @@ -191,9 +194,9 @@ TEST_F(ReadWfcPwTest, InconsistentKvec) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - GlobalV::NBANDS = 8; + PARAM.input.nbands = 8; const int nbasis = wfcpw->npwk[0]; - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, nbasis); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, nbasis); testing::internal::CaptureStdout(); EXPECT_EXIT(ModuleIO::read_wfc_pw(filename, wfcpw, 0, nkstot, wfcatom), ::testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); @@ -219,9 +222,9 @@ TEST_F(ReadWfcPwTest, InconsistentLat0) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - GlobalV::NBANDS = 8; + PARAM.input.nbands = 8; const int nbasis = wfcpw->npwk[0]; - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, nbasis); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, nbasis); testing::internal::CaptureStdout(); EXPECT_EXIT(ModuleIO::read_wfc_pw(filename, wfcpw, 0, nkstot, wfcatom), ::testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); @@ -247,9 +250,9 @@ TEST_F(ReadWfcPwTest, InconsistentG) wfcpw->setuptransform(); wfcpw->collect_local_pw(); - GlobalV::NBANDS = 8; + PARAM.input.nbands = 8; const int nbasis = wfcpw->npwk[0]; - ModuleBase::ComplexMatrix wfcatom(GlobalV::NBANDS, nbasis); + ModuleBase::ComplexMatrix wfcatom(PARAM.input.nbands, nbasis); testing::internal::CaptureStdout(); EXPECT_EXIT(ModuleIO::read_wfc_pw(filename, wfcpw, 0, nkstot, wfcatom), ::testing::ExitedWithCode(0), ""); std::string output = testing::internal::GetCapturedStdout(); diff --git a/source/module_io/test/read_wfc_to_rho_test.cpp b/source/module_io/test/read_wfc_to_rho_test.cpp index 0a1e42e09f3..ad11042b590 100644 --- a/source/module_io/test/read_wfc_to_rho_test.cpp +++ b/source/module_io/test/read_wfc_to_rho_test.cpp @@ -115,7 +115,7 @@ class ReadWfcRhoTest : public ::testing::Test wfcpw = new ModulePW::PW_Basis_K; rhopw = new ModulePW::PW_Basis; kv = new K_Vectors; - GlobalV::NBANDS = 4; + PARAM.input.nbands = 4; PARAM.input.nspin = 1; PARAM.input.out_wfc_pw = 2; } @@ -132,7 +132,7 @@ TEST_F(ReadWfcRhoTest, ReadWfcRho) { // Init K_Vectors const int my_pool = GlobalV::MY_POOL; - const int nbands = GlobalV::NBANDS; + const int nbands = PARAM.input.nbands; const int nks = 2; const int nkstot = GlobalV::KPAR * nks; kv->set_nkstot(nkstot); diff --git a/source/module_io/test/single_R_io_test.cpp b/source/module_io/test/single_R_io_test.cpp index 779e36626f8..7b142fa25f8 100644 --- a/source/module_io/test/single_R_io_test.cpp +++ b/source/module_io/test/single_R_io_test.cpp @@ -1,5 +1,8 @@ #include "gtest/gtest.h" #include "gmock/gmock.h" +#define private public +#include "module_parameter/parameter.h" +#undef private #include "module_io/single_R_io.h" #include "module_base/global_variable.h" #include "module_basis/module_ao/parallel_orbitals.h" @@ -41,8 +44,8 @@ TEST(ModuleIOTest, OutputSingleR) const double sparse_threshold = 1e-8; const bool binary = false; Parallel_Orbitals pv; - GlobalV::NLOCAL = 5; - pv.set_serial(GlobalV::NLOCAL, GlobalV::NLOCAL); + PARAM.sys.nlocal = 5; + pv.set_serial(PARAM.sys.nlocal, PARAM.sys.nlocal); std::map> XR = { {0, {{1, 0.5}, {3, 0.3}}}, {1, {{0, 0.2}, {2, 0.4}}}, diff --git a/source/module_io/test/support/INPUT b/source/module_io/test/support/INPUT index 95a987e8e71..a088c274540 100644 --- a/source/module_io/test/support/INPUT +++ b/source/module_io/test/support/INPUT @@ -51,6 +51,10 @@ erf_sigma 4 #the width of the energy step for reciprocal ve fft_mode 0 #mode of FFTW pw_diag_thr 0.01 #threshold for eigenvalues is cg electron iterations scf_thr 1e-08 #charge density error +scf_ene_thr 1e-06 #total energy error threshold +scf_os_stop 1 #whether to stop scf when oscillation is detected +scf_os_thr -0.02 #charge density threshold for oscillation +scf_os_ndim 10 #number of old iterations used for oscillation detection scf_thr_type 2 #type of the criterion of scf_thr, 1: reci drho for pw, 2: real drho for lcao init_wfc atomic #start wave functions are from 'atomic', 'atomic+random', 'random' or 'file' init_chg atomic #start charge is from 'atomic' or file @@ -269,8 +273,12 @@ vdw_cutoff_period 3 3 3 #periods of periodic structure #Parameters (14.exx) exx_hybrid_alpha default # -exx_hse_omega 0.11 # +exx_cam_alpha default # +exx_cam_beta default # +exx_hse_omega default # exx_separate_loop 1 #0 or 1 +exx_use_ewald 0 +exx_fq_type 1 exx_hybrid_step 100 # exx_mixing_beta 1.0 # exx_lambda 0.3 # diff --git a/source/module_io/test/to_qo_test.cpp b/source/module_io/test/to_qo_test.cpp index 07c57e25dfa..8f03609b74d 100644 --- a/source/module_io/test/to_qo_test.cpp +++ b/source/module_io/test/to_qo_test.cpp @@ -110,12 +110,16 @@ class toQOTest : public testing::Test protected: void SetUp() override { + #ifdef __MPI + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + #endif } void TearDown() override { } UnitCell ucell; + int myrank = 0; }; TEST_F(toQOTest, Constructor) @@ -1500,6 +1504,50 @@ TEST_F(toQOTest, CalculateHydrogenlike) } } +TEST_F(toQOTest, BcastStdvectorOfVector3Int) +{ + #ifdef __MPI + std::vector> vec; + if (this->myrank == 0) + { + vec.push_back(ModuleBase::Vector3(1, 2, 3)); + vec.push_back(ModuleBase::Vector3(4, 5, 6)); + vec.push_back(ModuleBase::Vector3(7, 8, 9)); + } + toQO::bcast_stdvector_ofvector3int(vec, myrank); + if (this->myrank != 0) + { + EXPECT_EQ(vec[0], ModuleBase::Vector3(1, 2, 3)); + EXPECT_EQ(vec[1], ModuleBase::Vector3(4, 5, 6)); + EXPECT_EQ(vec[2], ModuleBase::Vector3(7, 8, 9)); + } + #else + GTEST_SKIP(); + #endif +} + +TEST_F(toQOTest, BcastStdvectorOfVector3Double) +{ + #ifdef __MPI + std::vector> vec; + if (this->myrank == 0) + { + vec.push_back(ModuleBase::Vector3(1.0, 2.0, 3.0)); + vec.push_back(ModuleBase::Vector3(4.0, 5.0, 6.0)); + vec.push_back(ModuleBase::Vector3(7.0, 8.0, 9.0)); + } + toQO::bcast_stdvector_ofvector3double(vec, myrank); + if (this->myrank != 0) + { + EXPECT_EQ(vec[0], ModuleBase::Vector3(1.0, 2.0, 3.0)); + EXPECT_EQ(vec[1], ModuleBase::Vector3(4.0, 5.0, 6.0)); + EXPECT_EQ(vec[2], ModuleBase::Vector3(7.0, 8.0, 9.0)); + } + #else + GTEST_SKIP(); + #endif +} + /**/ int main(int argc, char** argv) { diff --git a/source/module_io/test/write_dos_pw_test.cpp b/source/module_io/test/write_dos_pw_test.cpp index 18448958a38..6415827d568 100644 --- a/source/module_io/test/write_dos_pw_test.cpp +++ b/source/module_io/test/write_dos_pw_test.cpp @@ -62,7 +62,7 @@ TEST_F(DosPWTest,Dos1) kv->isk[ik] = dosp.isk[ik]; kv->wk[ik] = dosp.wk[ik]; } - GlobalV::NBANDS = dosp.nbands; + PARAM.input.nbands = dosp.nbands; ModuleIO::write_dos_pw(dosp.ekb, dosp.wg, *kv, @@ -112,7 +112,7 @@ TEST_F(DosPWTest,Dos2) kv->isk[ik] = dosp.isk[ik]; kv->wk[ik] = dosp.wk[ik]; } - GlobalV::NBANDS = dosp.nbands; + PARAM.input.nbands = dosp.nbands; ModuleIO::write_dos_pw(dosp.ekb, dosp.wg, *kv, diff --git a/source/module_io/test/write_istate_info_test.cpp b/source/module_io/test/write_istate_info_test.cpp index 43fc87f2b30..9be9c28532c 100644 --- a/source/module_io/test/write_istate_info_test.cpp +++ b/source/module_io/test/write_istate_info_test.cpp @@ -48,7 +48,7 @@ TEST_F(IstateInfoTest, OutIstateInfoS1) { // preconditions GlobalV::KPAR = 1; - GlobalV::NBANDS = 4; + PARAM.input.nbands = 4; PARAM.input.nspin = 1; PARAM.sys.global_out_dir = "./"; // mpi setting @@ -71,8 +71,8 @@ TEST_F(IstateInfoTest, OutIstateInfoS1) // std::cout<<"MY_POOL "<set_nks(Pkpoints->nks_pool[GlobalV::MY_POOL]); // std::cout<<"nks "<get_nks()<get_nks(), GlobalV::NBANDS); - wg.create(kv->get_nks(), GlobalV::NBANDS); + ekb.create(kv->get_nks(), PARAM.input.nbands); + wg.create(kv->get_nks(), PARAM.input.nbands); ekb.fill_out(0.15); wg.fill_out(0.0); kv->kvec_d.resize(kv->get_nkstot()); @@ -99,7 +99,7 @@ TEST_F(IstateInfoTest, OutIstateInfoS2) { // preconditions GlobalV::KPAR = 1; - GlobalV::NBANDS = 4; + PARAM.input.nbands = 4; PARAM.input.nspin = 2; PARAM.sys.global_out_dir = "./"; // mpi setting @@ -122,8 +122,8 @@ TEST_F(IstateInfoTest, OutIstateInfoS2) // std::cout<<"MY_POOL "<set_nks(Pkpoints->nks_pool[GlobalV::MY_POOL]); // std::cout<<"nks "<get_nks()<get_nks(), GlobalV::NBANDS); - wg.create(kv->get_nks(), GlobalV::NBANDS); + ekb.create(kv->get_nks(), PARAM.input.nbands); + wg.create(kv->get_nks(), PARAM.input.nbands); ekb.fill_out(0.15); wg.fill_out(0.0); kv->kvec_d.resize(kv->get_nkstot()); diff --git a/source/module_io/test/write_orb_info_test.cpp b/source/module_io/test/write_orb_info_test.cpp index 7da84e439f7..9c4fae341b2 100644 --- a/source/module_io/test/write_orb_info_test.cpp +++ b/source/module_io/test/write_orb_info_test.cpp @@ -49,6 +49,7 @@ TEST(OrbInfo,WriteOrbInfo) PARAM.input.nspin = 1; PARAM.input.basis_type = "pw"; PARAM.input.dft_functional = "default"; + PARAM.sys.nlocal = 18; ucell->read_cell_pseudopots(pp_dir,ofs); ucell->cal_nwfc(ofs); ModuleIO::write_orb_info(ucell); diff --git a/source/module_io/test/write_wfc_nao_test.cpp b/source/module_io/test/write_wfc_nao_test.cpp index 64ebcf0959d..f0503ad80c3 100644 --- a/source/module_io/test/write_wfc_nao_test.cpp +++ b/source/module_io/test/write_wfc_nao_test.cpp @@ -229,8 +229,8 @@ TEST(ModuleIOTest, WriteWfcNao) { // Set up GlobalV GlobalV::DRANK = 0; - GlobalV::NBANDS = 2; - GlobalV::NLOCAL = 2; + PARAM.input.nbands = 2; + PARAM.sys.nlocal = 2; PARAM.input.out_app_flag = true; // Set up test data @@ -248,7 +248,7 @@ TEST(ModuleIOTest, WriteWfcNao) wg(1, 1) = 1.2; // Call the function to be tested - ModuleIO::wfc_nao_write2file(filename, ctot.data(), GlobalV::NLOCAL, 0, ekb, wg, false); + ModuleIO::wfc_nao_write2file(filename, ctot.data(), PARAM.sys.nlocal, 0, ekb, wg, false); // Check the output file std::ifstream ifs(filename); @@ -276,8 +276,8 @@ TEST(ModuleIOTest, WriteWfcNaoBinary) { // Set up GlobalV GlobalV::DRANK = 0; - GlobalV::NBANDS = 2; - GlobalV::NLOCAL = 2; + PARAM.input.nbands = 2; + PARAM.sys.nlocal = 2; PARAM.input.out_app_flag = true; // Set up test data @@ -295,7 +295,7 @@ TEST(ModuleIOTest, WriteWfcNaoBinary) wg(1, 1) = 1.2; // Call the function to be tested - ModuleIO::wfc_nao_write2file(filename, ctot.data(), GlobalV::NLOCAL, 0, ekb, wg, true); + ModuleIO::wfc_nao_write2file(filename, ctot.data(), PARAM.sys.nlocal, 0, ekb, wg, true); // Check the output file Binstream wfc(filename, "r"); @@ -333,8 +333,8 @@ TEST(ModuleIOTest, WriteWfcNaoComplex) if (GlobalV::MY_RANK == 0) { // Set up GlobalV - GlobalV::NBANDS = 2; - GlobalV::NLOCAL = 3; + PARAM.input.nbands = 2; + PARAM.sys.nlocal = 3; PARAM.input.out_app_flag = true; // set up test data std::string name = "test_wfc_nao_complex.txt"; @@ -354,7 +354,7 @@ TEST(ModuleIOTest, WriteWfcNaoComplex) std::complex(0.0, 3.0)}; // Call the function - ModuleIO::wfc_nao_write2file_complex(name, ctot.data(), GlobalV::NLOCAL, ik, kvec_c, ekb, wg); + ModuleIO::wfc_nao_write2file_complex(name, ctot.data(), PARAM.sys.nlocal, ik, kvec_c, ekb, wg); // Check the output file std::ifstream ifs(name); std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -377,8 +377,8 @@ TEST(ModuleIOTest, WriteWfcNaoComplexBinary) if (GlobalV::MY_RANK == 0) { // Set up GlobalV - GlobalV::NBANDS = 2; - GlobalV::NLOCAL = 3; + PARAM.input.nbands = 2; + PARAM.sys.nlocal = 3; PARAM.input.out_app_flag = true; // set up test data std::string name = "test_wfc_nao_complex.dat"; @@ -398,7 +398,7 @@ TEST(ModuleIOTest, WriteWfcNaoComplexBinary) std::complex(6.0, 8.0)}; // Call the function - ModuleIO::wfc_nao_write2file_complex(name, ctot.data(), GlobalV::NLOCAL, ik, kvec_c, ekb, wg, true); + ModuleIO::wfc_nao_write2file_complex(name, ctot.data(), PARAM.sys.nlocal, ik, kvec_c, ekb, wg, true); // Check the output file Binstream wfc(name, "r"); diff --git a/source/module_io/test_serial/CMakeLists.txt b/source/module_io/test_serial/CMakeLists.txt index e6a7f3b80da..ce3993fb8e4 100644 --- a/source/module_io/test_serial/CMakeLists.txt +++ b/source/module_io/test_serial/CMakeLists.txt @@ -27,7 +27,9 @@ install(DIRECTORY support DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) AddTest( TARGET io_read_input_serial LIBS parameter ${math_libs} io_input_serial - SOURCES read_input_test.cpp ../../module_base/test/tool_quit_no_exit.cpp + SOURCES read_input_test.cpp + ../../module_base/test/tool_quit_no_exit.cpp + ../../module_base/module_device/device.cpp ) AddTest( @@ -44,7 +46,7 @@ AddTest( AddTest( TARGET io_rho_io LIBS parameter ${math_libs} base device cell_info - SOURCES rho_io_test.cpp ../read_cube.cpp ../write_cube.cpp ../read_rho.cpp ../output.cpp + SOURCES rho_io_test.cpp ../read_cube.cpp ../write_cube.cpp ../output.cpp ) AddTest( diff --git a/source/module_io/test_serial/prepare_unitcell.h b/source/module_io/test_serial/prepare_unitcell.h index 5f217aadf2a..a92f15842fc 100644 --- a/source/module_io/test_serial/prepare_unitcell.h +++ b/source/module_io/test_serial/prepare_unitcell.h @@ -252,8 +252,8 @@ UcellTestPrepare::UcellTestPrepare(std::string latname_in, coor_type(coor_type_in), coordinates(coordinates_in) { - mbl = {0}; - velocity = {0}; + mbl = std::valarray(0.0, coordinates_in.size()); + velocity = std::valarray(0.0, coordinates_in.size()); } UcellTestPrepare::UcellTestPrepare(std::string latname_in, diff --git a/source/module_io/test_serial/read_input_item_test.cpp b/source/module_io/test_serial/read_input_item_test.cpp index 9f7c6abe89e..d7c8955e599 100644 --- a/source/module_io/test_serial/read_input_item_test.cpp +++ b/source/module_io/test_serial/read_input_item_test.cpp @@ -151,6 +151,11 @@ TEST_F(InputTest, Item_test) param.input.qo_switch = true; it->second.reset_value(it->second, param); EXPECT_EQ(param.input.symmetry, "-1"); + + param.input.symmetry = "default"; + param.input.berry_phase = true; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.symmetry, "-1"); } { // nelec auto it = find_label("nelec", readinput.input_lists); @@ -820,6 +825,14 @@ TEST_F(InputTest, Item_test) ifs.close(); EXPECT_EQ(line, "K_POINTS"); + param.input.basis_type = "lcao"; + param.input.gamma_only = true; + param.input.nspin = 4; + testing::internal::CaptureStdout(); + EXPECT_EXIT(it->second.reset_value(it->second, param), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("NOTICE")); + } { // out_mat_r auto it = find_label("out_mat_r", readinput.input_lists); @@ -1036,46 +1049,54 @@ TEST_F(InputTest, Item_test2) it->second.reset_value(it->second, param); EXPECT_EQ(param.input.vdw_s6, "0.75"); + // dftd3 parameter will not get its value here param.input.vdw_s6 = "default"; param.input.vdw_method = "d3_0"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_s6, "1.0"); + // EXPECT_EQ(param.input.vdw_s6, "1.0"); + EXPECT_EQ(param.input.vdw_s6, "default"); } { // vdw_s8 auto it = find_label("vdw_s8", readinput.input_lists); param.input.vdw_s8 = "default"; param.input.vdw_method = "d3_0"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_s8, "0.722"); + // EXPECT_EQ(param.input.vdw_s8, "0.722"); + EXPECT_EQ(param.input.vdw_s8, "default"); param.input.vdw_s8 = "default"; param.input.vdw_method = "d3_bj"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_s8, "0.7875"); + // EXPECT_EQ(param.input.vdw_s8, "0.7875"); + EXPECT_EQ(param.input.vdw_s8, "default"); } { // vdw_a1 auto it = find_label("vdw_a1", readinput.input_lists); param.input.vdw_a1 = "default"; param.input.vdw_method = "d3_0"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_a1, "1.217"); + // EXPECT_EQ(param.input.vdw_a1, "1.217"); + EXPECT_EQ(param.input.vdw_a1, "default"); param.input.vdw_a1 = "default"; param.input.vdw_method = "d3_bj"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_a1, "0.4289"); + // EXPECT_EQ(param.input.vdw_a1, "0.4289"); + EXPECT_EQ(param.input.vdw_a1, "default"); } { // vdw_a2 auto it = find_label("vdw_a2", readinput.input_lists); param.input.vdw_a2 = "default"; param.input.vdw_method = "d3_0"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_a2, "1.0"); + // EXPECT_EQ(param.input.vdw_a2, "1.0"); + EXPECT_EQ(param.input.vdw_a2, "default"); param.input.vdw_a2 = "default"; param.input.vdw_method = "d3_bj"; it->second.reset_value(it->second, param); - EXPECT_EQ(param.input.vdw_a2, "4.4407"); + // EXPECT_EQ(param.input.vdw_a2, "4.4407"); + EXPECT_EQ(param.input.vdw_a2, "default"); } { // vdw_c6_unit auto it = find_label("vdw_c6_unit", readinput.input_lists); @@ -1207,6 +1228,140 @@ TEST_F(InputTest, Item_test2) output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("NOTICE")); } + { // exx_cam_alpha + auto it = find_label("exx_cam_alpha", readinput.input_lists); + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "HF"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "1"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "PBE0"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "0.25"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "SCAN0"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "0.25"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "lc_pbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "1"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "lc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "1"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "lrc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "1"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "lrc_wpbeh"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "1"); + + param.input.exx_cam_alpha = "default"; + param.input.dft_functional = "none"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_alpha, "0"); + + param.input.exx_cam_alpha = "-1"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("NOTICE")); + } + { // exx_cam_beta + auto it = find_label("exx_cam_beta", readinput.input_lists); + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "lc_pbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "-1"); + + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "lc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "-1"); + + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "lrc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "-1"); + + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "lrc_wpbeh"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "-0.8"); + + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "cam_pbeh"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "0.8"); + + param.input.exx_cam_beta = "default"; + param.input.dft_functional = "hse"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "0.25"); + + param.input.exx_cam_beta= "default"; + param.input.dft_functional = "none"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_cam_beta, "0"); + + param.input.exx_cam_beta = "-1"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("NOTICE")); + } + { // exx_hse_omega + auto it = find_label("exx_hse_omega", readinput.input_lists); + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "lc_pbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.11"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "lc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.4"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "lrc_wpbe"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.3"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "lrc_wpbeh"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.2"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "cam_pbeh"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.7"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "hse"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0.11"); + + param.input.exx_hse_omega = "default"; + param.input.dft_functional = "none"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_hse_omega, "0"); + + param.input.exx_hse_omega = "-1"; + testing::internal::CaptureStdout(); + EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(0), ""); + output = testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, testing::HasSubstr("NOTICE")); + } { // exx_hybrid_step auto it = find_label("exx_hybrid_step", readinput.input_lists); param.input.exx_hybrid_step = -1; diff --git a/source/module_io/test_serial/rho_io_test.cpp b/source/module_io/test_serial/rho_io_test.cpp index 20c456ea1e0..cf13dea9a5b 100644 --- a/source/module_io/test_serial/rho_io_test.cpp +++ b/source/module_io/test_serial/rho_io_test.cpp @@ -1,10 +1,11 @@ -#include "module_io/rho_io.h" +#include "module_io/cube_io.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "module_base/global_variable.h" #include "module_io/cube_io.h" #include "prepare_unitcell.h" +#include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" #ifdef __LCAO InfoNonlocal::InfoNonlocal() @@ -30,6 +31,7 @@ Magnetism::~Magnetism() { delete[] this->start_magnetization; } +Parallel_Grid::~Parallel_Grid() {} #define private public #include "module_parameter/parameter.h" @@ -59,8 +61,6 @@ class RhoIOTest : public ::testing::Test UnitCell* ucell; int my_rank = 0; - std::string esolver_type = "ksdft"; - int rank_in_stogroup = 0; std::ofstream ofs_running = std::ofstream("unittest.log"); void SetUp() @@ -93,15 +93,33 @@ TEST_F(RhoIOTest, Read) double ef; UcellTestPrepare utp = UcellTestLib["Si"]; ucell = utp.SetUcellInfo(); - ModuleIO::read_rho(my_rank, esolver_type, rank_in_stogroup, is, ofs_running, nspin, fn, rho[is], nx, ny, nz, ef, ucell, prenspin); - EXPECT_DOUBLE_EQ(ef, 0.461002); + Parallel_Grid pgrid(nx, ny, nz, nz, nrxx, nz, 1); + ModuleIO::read_vdata_palgrid(pgrid, my_rank, ofs_running, fn, rho[is], ucell->nat); EXPECT_DOUBLE_EQ(rho[0][0], 1.27020863940e-03); EXPECT_DOUBLE_EQ(rho[0][46655], 1.33581335706e-02); } +TEST_F(RhoIOTest, Write) +{ + int nx = 36; + int ny = 36; + int nz = 36; + UcellTestPrepare utp = UcellTestLib["Si"]; + ucell = utp.SetUcellInfo(); + ucell->lat0 = 10.2; + ucell->latvec = { -0.5,0,0.5,0,0.5,0.5,-0.5,0.5,0 }; + ucell->atoms[0].tau[0] = ModuleBase::Vector3(0.0, 0.0, 0.0); + ucell->atoms[0].tau[1] = ModuleBase::Vector3(-0.75, 0.75, 0.75); + ucell->atoms[0].ncpp.zv = 4; + ucell->atoms[1].ncpp.zv = 4; + Parallel_Grid pgrid(nx, ny, nz, nz, nrxx, nz, 1); + ModuleIO::read_vdata_palgrid(pgrid, my_rank, ofs_running, "support/SPIN1_CHG.cube", rho[0], ucell->nat); + ModuleIO::write_vdata_palgrid(pgrid, rho[0], 0, nspin, 0, "test_write_vdata_palgrid.cube", 0.461002, ucell, 11, 1); + EXPECT_EQ(system("diff -q test_write_vdata_palgrid.cube support/SPIN1_CHG.cube"), 0); +} + TEST_F(RhoIOTest, TrilinearInterpolate) { - double data[36 * 40 * 44]; int nx = 36; int ny = 40; int nz = 44; @@ -113,8 +131,92 @@ TEST_F(RhoIOTest, TrilinearInterpolate) { ifs.ignore(300, '\n'); } - ModuleIO::trilinear_interpolate(ifs, nx_read, ny_read, nz_read, nx, ny, nz, data); + std::vector data_read(nx_read * ny_read * nz_read); + for (int ix = 0; ix < nx_read; ix++) + { + for (int iy = 0; iy < ny_read; iy++) + { + for (int iz = 0; iz < nz_read; iz++) + { + ifs >> data_read[(ix * ny_read + iy) * nz_read + iz]; + } + } + } + + // The old implementation is inconsistent: ifdef MPI, [x][y][z]; else, [z][x][y]. + // Now we use [x][y][z] for both MPI and non-MPI, so here we need to chage the index order. + auto permute_xyz2zxy = [&](const double* const xyz, double* const zxy) -> void + { + for (int ix = 0; ix < nx; ix++) + { + for (int iy = 0; iy < ny; iy++) + { + for (int iz = 0; iz < nz; iz++) + { + zxy[(iz * nx + ix) * ny + iy] = xyz[(ix * ny + iy) * nz + iz]; + } + } + } + }; + const int nxyz = nx * ny * nz; + std::vector data_xyz(nxyz); + std::vector data(nxyz); // z > x > y + ModuleIO::trilinear_interpolate(data_read.data(), nx_read, ny_read, nz_read, nx, ny, nz, data_xyz.data()); + permute_xyz2zxy(data_xyz.data(), data.data()); EXPECT_DOUBLE_EQ(data[0], 0.0010824725010374092); EXPECT_DOUBLE_EQ(data[10], 0.058649850374240906); EXPECT_DOUBLE_EQ(data[100], 0.018931708073604996); +} + +struct CubeIOTest : public ::testing::Test +{ + std::vector comment; + int natom = 0; + std::vector origin; + std::vector nvoxel; + int nx_read = 0; + int ny_read = 0; + int nz_read = 0; + std::vector dx; + std::vector dy; + std::vector dz; + std::vector> axis_vecs; + std::vector atom_type; + std::vector atom_charge; + std::vector> atom_pos; + std::vector data_read; + const std::string fn = "./support/SPIN1_CHG.cube"; +}; + + +TEST_F(CubeIOTest, ReadCube) +{ + ModuleIO::read_cube(fn, comment, natom, origin, nx_read, ny_read, nz_read, dx, dy, dz, atom_type, atom_charge, atom_pos, data_read); + EXPECT_EQ(comment[0], "STEP: 0 Cubefile created from ABACUS. Inner loop is z, followed by y and x"); + EXPECT_EQ(comment[1], "1 (nspin) 0.461002 (fermi energy, in Ry)"); + EXPECT_EQ(natom, 2); + for (auto& o : origin) { EXPECT_EQ(o, 0.0); } + EXPECT_EQ(nx_read, 36); + EXPECT_EQ(ny_read, 36); + EXPECT_EQ(nz_read, 36); + EXPECT_DOUBLE_EQ(dx[0], -0.141667); + EXPECT_DOUBLE_EQ(dy[2], 0.141667); + EXPECT_DOUBLE_EQ(dz[1], 0.141667); + EXPECT_EQ(atom_type.size(), natom); + EXPECT_EQ(atom_charge.size(), natom); + EXPECT_EQ(atom_pos.size(), natom); + for (auto& t : atom_type) { EXPECT_EQ(t, 14); } + for (auto& c : atom_charge) { EXPECT_DOUBLE_EQ(c, 4.0); } + EXPECT_DOUBLE_EQ(atom_pos[1][1], 7.65); + const int nxyz = nx_read * ny_read * nz_read; + EXPECT_EQ(data_read.size(), nxyz); + EXPECT_EQ(data_read[1], 2.64004483879e-03); + EXPECT_EQ(data_read[nxyz - 1], 1.33581335706e-02); +} + +TEST_F(CubeIOTest, WriteCube) +{ + ModuleIO::read_cube(fn, comment, natom, origin, nx_read, ny_read, nz_read, dx, dy, dz, atom_type, atom_charge, atom_pos, data_read); + ModuleIO::write_cube("test_write.cube", comment, natom, origin, nx_read, ny_read, nz_read, dx, dy, dz, atom_type, atom_charge, atom_pos, data_read, 11); + EXPECT_EQ(system("diff -q test_write.cube ./support/SPIN1_CHG.cube"), 0); } \ No newline at end of file diff --git a/source/module_io/test_serial/support/SPIN1_CHG.cube b/source/module_io/test_serial/support/SPIN1_CHG.cube index 4f0d2e8afc6..6aa8d9205cf 100644 --- a/source/module_io/test_serial/support/SPIN1_CHG.cube +++ b/source/module_io/test_serial/support/SPIN1_CHG.cube @@ -1,11 +1,11 @@ STEP: 0 Cubefile created from ABACUS. Inner loop is z, followed by y and x 1 (nspin) 0.461002 (fermi energy, in Ry) 2 0.0 0.0 0.0 -36 -0.141667 0 0.141667 -36 0 0.141667 0.141667 -36 -0.141667 0.141667 0 - 14 4 0 0 0 - 14 4 -7.65 7.65 7.65 +36 -0.141667 0.000000 0.141667 +36 0.000000 0.141667 0.141667 +36 -0.141667 0.141667 0.000000 + 14 4.000000 0.000000 0.000000 0.000000 + 14 4.000000 -7.650000 7.650000 7.650000 1.27020863940e-03 2.64004483879e-03 7.45857574908e-03 1.69819929531e-02 3.09103717113e-02 4.60013609401e-02 5.75824043038e-02 6.28259810566e-02 6.21334821617e-02 5.77319585491e-02 5.18034033720e-02 4.57409612273e-02 4.02453701311e-02 3.55932306397e-02 3.18414068716e-02 2.89647599965e-02 2.69304328597e-02 2.57176061925e-02 diff --git a/source/module_io/to_qo.h b/source/module_io/to_qo.h index 832c0daba9a..ecbcf5b287b 100644 --- a/source/module_io/to_qo.h +++ b/source/module_io/to_qo.h @@ -145,8 +145,10 @@ class toQO void append_ovlpR_eiRk(int ik, int iR); //< append S(R) to S(k), memory saving // MPI related - void bcast_stdvector_ofvector3int(std::vector>& vec); - void bcast_stdvector_ofvector3double(std::vector>& vec); + static void bcast_stdvector_ofvector3int(std::vector>& vec, + const int rank); + static void bcast_stdvector_ofvector3double(std::vector>& vec, + const int rank); // Neighboring list /// @brief get all possible (n1n2n3) defining supercell and scatter if MPI enabled diff --git a/source/module_io/to_qo_mpi.cpp b/source/module_io/to_qo_mpi.cpp index cc30dcb92db..52c198ba923 100644 --- a/source/module_io/to_qo_mpi.cpp +++ b/source/module_io/to_qo_mpi.cpp @@ -3,12 +3,13 @@ #include "../module_base/parallel_common.h" #endif -void toQO::bcast_stdvector_ofvector3int(std::vector>& vec) +void toQO::bcast_stdvector_ofvector3int(std::vector>& vec, + const int rank) { #ifdef __MPI int dim; std::vector vec_1d; - if(iproc_ == 0) + if(rank == 0) { dim = vec.size(); for(int i = 0; i < dim; i++) @@ -19,9 +20,9 @@ void toQO::bcast_stdvector_ofvector3int(std::vector>& v } } Parallel_Common::bcast_int(dim); - if(iproc_ != 0) vec_1d.resize(dim * 3); + if(rank != 0) { vec_1d.resize(dim * 3); } Parallel_Common::bcast_int(vec_1d.data(), dim * 3); - if(iproc_ != 0) + if(rank != 0) { vec.clear(); vec.resize(dim); for(int i = 0; i < dim; i++) @@ -32,12 +33,13 @@ void toQO::bcast_stdvector_ofvector3int(std::vector>& v #endif } -void toQO::bcast_stdvector_ofvector3double(std::vector>& vec) +void toQO::bcast_stdvector_ofvector3double(std::vector>& vec, + const int rank) { #ifdef __MPI int dim; std::vector vec_1d; - if(iproc_ == 0) + if(rank == 0) { dim = vec.size(); for(int i = 0; i < dim; i++) @@ -48,9 +50,9 @@ void toQO::bcast_stdvector_ofvector3double(std::vector> nR_divided(nranks); // indiced by iproc, then list of indices of supercells_ if(rank == 0) diff --git a/source/module_io/to_wannier90.cpp b/source/module_io/to_wannier90.cpp index 207fa4d1502..aa54f6738d2 100644 --- a/source/module_io/to_wannier90.cpp +++ b/source/module_io/to_wannier90.cpp @@ -479,31 +479,31 @@ bool toWannier90::try_read_nnkp(const K_Vectors& kv) nnkp_read.close(); - if (GlobalV::NBANDS <= num_exclude_bands) + if (PARAM.inp.nbands <= num_exclude_bands) { ModuleBase::WARNING_QUIT("toWannier90::read_nnkp", "you set the band numer is not enough, please add bands number."); } - // tag_cal_band = new bool[GlobalV::NBANDS]; - // for (int ib = 0; ib < GlobalV::NBANDS; ib++) tag_cal_band[ib] = true; + // tag_cal_band = new bool[PARAM.inp.nbands]; + // for (int ib = 0; ib < PARAM.inp.nbands; ib++) tag_cal_band[ib] = true; // for (int ib = 0; ib < num_exclude_bands; ib++) tag_cal_band[ib] = false; if (num_exclude_bands == 0) { - num_bands = GlobalV::NBANDS; + num_bands = PARAM.inp.nbands; cal_band_index = new int[num_bands]; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { cal_band_index[ib] = ib; } } else { - num_bands = GlobalV::NBANDS - num_exclude_bands; + num_bands = PARAM.inp.nbands - num_exclude_bands; cal_band_index = new int[num_bands]; int count = 0; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (exclude_bands.count(ib) != 1) { diff --git a/source/module_io/to_wannier90_lcao.cpp b/source/module_io/to_wannier90_lcao.cpp index 3ff2c6ad3f3..a886c29f507 100644 --- a/source/module_io/to_wannier90_lcao.cpp +++ b/source/module_io/to_wannier90_lcao.cpp @@ -65,12 +65,12 @@ void toWannier90_LCAO::calculate(const ModuleBase::matrix& ekb, if (out_wannier_mmn || out_wannier_amn) { - iw2it.resize(GlobalV::NLOCAL); - iw2ia.resize(GlobalV::NLOCAL); - iw2iL.resize(GlobalV::NLOCAL); - iw2iN.resize(GlobalV::NLOCAL); - iw2im.resize(GlobalV::NLOCAL); - iw2iorb.resize(GlobalV::NLOCAL); + iw2it.resize(PARAM.globalv.nlocal); + iw2ia.resize(PARAM.globalv.nlocal); + iw2iL.resize(PARAM.globalv.nlocal); + iw2iN.resize(PARAM.globalv.nlocal); + iw2im.resize(PARAM.globalv.nlocal); + iw2iorb.resize(PARAM.globalv.nlocal); std::map>> temp_orb_index; int count = 0; @@ -421,8 +421,8 @@ void toWannier90_LCAO::unkdotkb(const K_Vectors& kv, char transa = 'C'; char transb = 'N'; - int Bands = GlobalV::NBANDS; - int nlocal = GlobalV::NLOCAL; + int Bands = PARAM.inp.nbands; + int nlocal = PARAM.globalv.nlocal; std::complex alpha = {1.0, 0.0}, beta = {0.0, 0.0}; int one = 1; @@ -474,7 +474,7 @@ void toWannier90_LCAO::unkdotkb(const K_Vectors& kv, #endif int count_m = -1; - for (int m = 0; m < GlobalV::NBANDS; m++) + for (int m = 0; m < PARAM.inp.nbands; m++) { if (exclude_bands.count(m)) { continue; @@ -485,7 +485,7 @@ void toWannier90_LCAO::unkdotkb(const K_Vectors& kv, if (ir >= 0) { int count_n = -1; - for (int n = 0; n < GlobalV::NBANDS; n++) + for (int n = 0; n < PARAM.inp.nbands; n++) { if (exclude_bands.count(n)) { continue; @@ -1138,7 +1138,7 @@ void toWannier90_LCAO::unkdotA(const K_Vectors& kv, int R_num = R_coor_car.size(); if (PARAM.inp.nspin != 4) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (exclude_bands.count(ib)) { continue; @@ -1170,7 +1170,7 @@ void toWannier90_LCAO::unkdotA(const K_Vectors& kv, } else { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (exclude_bands.count(ib)) { continue; diff --git a/source/module_io/to_wannier90_lcao_in_pw.cpp b/source/module_io/to_wannier90_lcao_in_pw.cpp index cd962f9678d..0419009d170 100644 --- a/source/module_io/to_wannier90_lcao_in_pw.cpp +++ b/source/module_io/to_wannier90_lcao_in_pw.cpp @@ -123,7 +123,7 @@ psi::Psi>* toWannier90_LCAO_IN_PW::get_unk_from_lcao( for (int ik = 0; ik < num_kpts; ik++) { int npw = kv.ngk[ik]; - ModuleBase::ComplexMatrix orbital_in_G(GlobalV::NLOCAL, npwx*PARAM.globalv.npol); + ModuleBase::ComplexMatrix orbital_in_G(PARAM.globalv.nlocal, npwx*PARAM.globalv.npol); // Wavefunc_in_pw::produce_local_basis_in_pw(ik, wfcpw, sf, orbital_in_G, table_local); //produce_local_basis_in_pw(ik, wfcpw, sf, orbital_in_G, table_local); nao_G_expansion(ik, wfcpw, orbital_in_G); @@ -137,7 +137,7 @@ psi::Psi>* toWannier90_LCAO_IN_PW::get_unk_from_lcao( { for (int ig = 0; ig < npw; ig++) { - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { unk_inLcao[0](ik, ib, ig) += lcao_wfc_global(ib, iw) * orbital_in_G(iw, ig); } @@ -165,7 +165,7 @@ psi::Psi>* toWannier90_LCAO_IN_PW::get_unk_from_lcao( { // for (int ig = 0; ig < npwx*PARAM.globalv.npol; ig++) // { - // for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + // for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) // { // unk_inLcao[0](ik, ib, ig) += lcao_wfc_global(ib, iw) * orbital_in_G(iw, ig); // } @@ -173,7 +173,7 @@ psi::Psi>* toWannier90_LCAO_IN_PW::get_unk_from_lcao( for (int ig = 0; ig < npw; ig++) { - int basis_num = GlobalV::NLOCAL / 2; + int basis_num = PARAM.globalv.nlocal / 2; for (int iw = 0; iw < basis_num; iw++) { unk_inLcao[0](ik, ib, ig) += lcao_wfc_global(ib, 2*iw) * orbital_in_G(iw, ig); @@ -219,7 +219,7 @@ void toWannier90_LCAO_IN_PW::nao_G_expansion( std::weak_ptr>> psig = this->psi_init_->share_psig(); if(psig.expired()) { ModuleBase::WARNING_QUIT("toWannier90_LCAO_IN_PW::nao_G_expansion", "psig is expired"); } - int nbands = GlobalV::NLOCAL; + int nbands = PARAM.globalv.nlocal; int nbasis = npwx*PARAM.globalv.npol; for (int ib = 0; ib < nbands; ib++) { @@ -236,12 +236,12 @@ void toWannier90_LCAO_IN_PW::get_lcao_wfc_global_ik( ModuleBase::ComplexMatrix &lcao_wfc_global ) { - lcao_wfc_global.create(num_bands, GlobalV::NLOCAL); + lcao_wfc_global.create(num_bands, PARAM.globalv.nlocal); int count_b = -1; int row = this->ParaV->get_row_size(); int global_row_index = 0; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (exclude_bands.count(ib)) { continue; } diff --git a/source/module_io/unk_overlap_lcao.cpp b/source/module_io/unk_overlap_lcao.cpp index cf31cbfdbeb..b8ca83ebf26 100644 --- a/source/module_io/unk_overlap_lcao.cpp +++ b/source/module_io/unk_overlap_lcao.cpp @@ -15,7 +15,7 @@ unkOverlap_lcao::~unkOverlap_lcao() { if (allocate_flag) { - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { delete [] cal_tag[iw]; } @@ -88,11 +88,11 @@ void unkOverlap_lcao::init(const Grid_Technique& gt, const int nkstot, const LCA this->kpoints_number = nkstot; if (allocate_flag) { - cal_tag = new int*[GlobalV::NLOCAL]; - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + cal_tag = new int*[PARAM.globalv.nlocal]; + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { - cal_tag[iw] = new int[GlobalV::NLOCAL]; - ModuleBase::GlobalFunc::ZEROS(cal_tag[iw], GlobalV::NLOCAL); + cal_tag[iw] = new int[PARAM.globalv.nlocal]; + ModuleBase::GlobalFunc::ZEROS(cal_tag[iw], PARAM.globalv.nlocal); } } @@ -101,7 +101,7 @@ void unkOverlap_lcao::init(const Grid_Technique& gt, const int nkstot, const LCA int nproc, myrank; MPI_Comm_size(MPI_COMM_WORLD, &nproc); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - const int total_term = GlobalV::NLOCAL * GlobalV::NLOCAL; + const int total_term = PARAM.globalv.nlocal * PARAM.globalv.nlocal; const int remain = total_term % nproc; int local_term = total_term / nproc; if (myrank < remain) @@ -125,12 +125,12 @@ void unkOverlap_lcao::init(const Grid_Technique& gt, const int nkstot, const LCA } #else int start = 0; - int local_term = GlobalV::NLOCAL * GlobalV::NLOCAL; + int local_term = PARAM.globalv.nlocal * PARAM.globalv.nlocal; #endif int count = -1; - for (int iw1 = 0; iw1 < GlobalV::NLOCAL; iw1++) + for (int iw1 = 0; iw1 < PARAM.globalv.nlocal; iw1++) { - for (int iw2 = 0; iw2 < GlobalV::NLOCAL; iw2++) + for (int iw2 = 0; iw2 < PARAM.globalv.nlocal; iw2++) { count++; if (count >= start && count < (start + local_term)) @@ -361,10 +361,10 @@ void unkOverlap_lcao::cal_R_number() { // The number of overlaps between atomic orbitals 1 and atomic orbitals 2, // or the number of R, is empty when there is no overlap - orb1_orb2_R.resize(GlobalV::NLOCAL); - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + orb1_orb2_R.resize(PARAM.globalv.nlocal); + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { - orb1_orb2_R[iw].resize(GlobalV::NLOCAL); + orb1_orb2_R[iw].resize(PARAM.globalv.nlocal); } ModuleBase::Vector3 tau1, tau2, dtau; @@ -419,19 +419,19 @@ void unkOverlap_lcao::cal_R_number() void unkOverlap_lcao::cal_orb_overlap() { // std::cout << "the cal_orb_overlap is start" << std::endl; - psi_psi.resize(GlobalV::NLOCAL); - psi_r_psi.resize(GlobalV::NLOCAL); - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + psi_psi.resize(PARAM.globalv.nlocal); + psi_r_psi.resize(PARAM.globalv.nlocal); + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { - psi_psi[iw].resize(GlobalV::NLOCAL); - psi_r_psi[iw].resize(GlobalV::NLOCAL); + psi_psi[iw].resize(PARAM.globalv.nlocal); + psi_r_psi[iw].resize(PARAM.globalv.nlocal); } ModuleBase::Vector3 origin_point(0.0, 0.0, 0.0); - for (int iw1 = 0; iw1 < GlobalV::NLOCAL; iw1++) + for (int iw1 = 0; iw1 < PARAM.globalv.nlocal; iw1++) { - for (int iw2 = 0; iw2 < GlobalV::NLOCAL; iw2++) + for (int iw2 = 0; iw2 < PARAM.globalv.nlocal; iw2++) { // if ( !pv.in_this_processor(iw1,iw2) ) continue; @@ -501,9 +501,9 @@ void unkOverlap_lcao::prepare_midmatrix_pblas(const int ik_L, // ModuleBase::Vector3 dk = kv.kvec_c[ik_R] - kv.kvec_c[ik_L]; midmatrix = new std::complex[pv.nloc]; ModuleBase::GlobalFunc::ZEROS(midmatrix, pv.nloc); - for (int iw_row = 0; iw_row < GlobalV::NLOCAL; iw_row++) // global + for (int iw_row = 0; iw_row < PARAM.globalv.nlocal; iw_row++) // global { - for (int iw_col = 0; iw_col < GlobalV::NLOCAL; iw_col++) // global + for (int iw_col = 0; iw_col < PARAM.globalv.nlocal; iw_col++) // global { int ir = pv.global2local_row(iw_row); // local int ic = pv.global2local_col(iw_col); // local @@ -546,7 +546,7 @@ std::complex unkOverlap_lcao::det_berryphase(const int ik_L, char transa = 'C'; char transb = 'N'; int occBands = occ_bands; - int nlocal = GlobalV::NLOCAL; + int nlocal = PARAM.globalv.nlocal; std::complex alpha = {1.0, 0.0}, beta = {0.0, 0.0}; int one = 1; #ifdef __MPI diff --git a/source/module_io/winput.cpp b/source/module_io/winput.cpp index 4927a926686..1df64a3cb7b 100644 --- a/source/module_io/winput.cpp +++ b/source/module_io/winput.cpp @@ -703,9 +703,9 @@ void winput::Check() // { // ModuleBase::WARNING_QUIT("winput::Check","Please check your bloch_end"); // } - // if(bloch_end > GlobalV::NBANDS) + // if(bloch_end > PARAM.inp.nbands) // { - // ModuleBase::WARNING_QUIT("winput::Check","Bloch_end > GlobalV::NBANDS, reset either of them"); + // ModuleBase::WARNING_QUIT("winput::Check","Bloch_end > PARAM.inp.nbands, reset either of them"); // } // } // }// end after_iter diff --git a/source/module_io/write_HS.hpp b/source/module_io/write_HS.hpp index ae4d2d880fc..a328f746d06 100644 --- a/source/module_io/write_HS.hpp +++ b/source/module_io/write_HS.hpp @@ -33,9 +33,9 @@ void ModuleIO::save_HS_ccf(const int &iter, const int &Hnnz, const int *colptr_H FILE *g1 = fopen(ssh.str().c_str(),"wb"); FILE *g2 = fopen(sss.str().c_str(),"wb"); - fwrite(&GlobalV::NLOCAL,sizeof(int),1,g1); + fwrite(&PARAM.globalv.nlocal,sizeof(int),1,g1); fwrite(&Hnnz,sizeof(int),1,g1); - fwrite(&GlobalV::NLOCAL,sizeof(int),1,g2); + fwrite(&PARAM.globalv.nlocal,sizeof(int),1,g2); fwrite(&Hnnz,sizeof(int),1,g2); fclose(g1); @@ -48,10 +48,10 @@ void ModuleIO::save_HS_ccf(const int &iter, const int &Hnnz, const int *colptr_H std::ofstream g1(ssh.str().c_str()); std::ofstream g2(sss.str().c_str()); - g1 << GlobalV::NLOCAL << " " << Hnnz << std::endl; - g2 << GlobalV::NLOCAL << " " << Hnnz << std::endl; + g1 << PARAM.globalv.nlocal << " " << Hnnz << std::endl; + g2 << PARAM.globalv.nlocal << " " << Hnnz << std::endl; - for(int i=0; i(&step), sizeof(int)); - g1[ispin].write(reinterpret_cast(&GlobalV::NLOCAL), + g1[ispin].write(reinterpret_cast(&nlocal), sizeof(int)); g1[ispin].write(reinterpret_cast(&output_R_number), sizeof(int)); @@ -153,7 +154,7 @@ void ModuleIO::save_HSR_sparse(const int& istep, g2.open(sss.str().c_str(), std::ios::binary); } g2.write(reinterpret_cast(&step), sizeof(int)); - g2.write(reinterpret_cast(&GlobalV::NLOCAL), sizeof(int)); + g2.write(reinterpret_cast(&nlocal), sizeof(int)); g2.write(reinterpret_cast(&output_R_number), sizeof(int)); } else { for (int ispin = 0; ispin < spin_loop; ++ispin) { @@ -164,7 +165,7 @@ void ModuleIO::save_HSR_sparse(const int& istep, g1[ispin].open(ssh[ispin].str().c_str()); } g1[ispin] << "STEP: " << step << std::endl; - g1[ispin] << "Matrix Dimension of H(R): " << GlobalV::NLOCAL + g1[ispin] << "Matrix Dimension of H(R): " << PARAM.globalv.nlocal << std::endl; g1[ispin] << "Matrix number of H(R): " << output_R_number << std::endl; @@ -176,7 +177,7 @@ void ModuleIO::save_HSR_sparse(const int& istep, g2.open(sss.str().c_str()); } g2 << "STEP: " << step << std::endl; - g2 << "Matrix Dimension of S(R): " << GlobalV::NLOCAL << std::endl; + g2 << "Matrix Dimension of S(R): " << PARAM.globalv.nlocal << std::endl; g2 << "Matrix number of S(R): " << output_R_number << std::endl; } } @@ -238,7 +239,7 @@ void ModuleIO::save_HSR_sparse(const int& istep, // { // g1[ispin] << std::endl; // g1[ispin] << std::endl; - // for (int index = 0; index < GlobalV::NLOCAL+1; + // for (int index = 0; index < PARAM.globalv.nlocal+1; // ++index) // { // g1[ispin] << 0 << " "; @@ -279,7 +280,7 @@ void ModuleIO::save_HSR_sparse(const int& istep, // { // g2 << std::endl; // g2 << std::endl; - // for (int index = 0; index < GlobalV::NLOCAL+1; ++index) + // for (int index = 0; index < PARAM.globalv.nlocal+1; ++index) // { // g2 << 0 << " "; // } @@ -453,6 +454,7 @@ void ModuleIO::save_dH_sparse(const int& istep, if (GlobalV::DRANK == 0) { if (binary) { + int nlocal = PARAM.globalv.nlocal; for (int ispin = 0; ispin < spin_loop; ++ispin) { if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag && step) { @@ -472,19 +474,19 @@ void ModuleIO::save_dH_sparse(const int& istep, } g1x[ispin].write(reinterpret_cast(&step), sizeof(int)); - g1x[ispin].write(reinterpret_cast(&GlobalV::NLOCAL), + g1x[ispin].write(reinterpret_cast(&nlocal), sizeof(int)); g1x[ispin].write(reinterpret_cast(&output_R_number), sizeof(int)); g1y[ispin].write(reinterpret_cast(&step), sizeof(int)); - g1y[ispin].write(reinterpret_cast(&GlobalV::NLOCAL), + g1y[ispin].write(reinterpret_cast(&nlocal), sizeof(int)); g1y[ispin].write(reinterpret_cast(&output_R_number), sizeof(int)); g1z[ispin].write(reinterpret_cast(&step), sizeof(int)); - g1z[ispin].write(reinterpret_cast(&GlobalV::NLOCAL), + g1z[ispin].write(reinterpret_cast(&nlocal), sizeof(int)); g1z[ispin].write(reinterpret_cast(&output_R_number), sizeof(int)); @@ -503,19 +505,19 @@ void ModuleIO::save_dH_sparse(const int& istep, } g1x[ispin] << "STEP: " << step << std::endl; - g1x[ispin] << "Matrix Dimension of dHx(R): " << GlobalV::NLOCAL + g1x[ispin] << "Matrix Dimension of dHx(R): " << PARAM.globalv.nlocal << std::endl; g1x[ispin] << "Matrix number of dHx(R): " << output_R_number << std::endl; g1y[ispin] << "STEP: " << step << std::endl; - g1y[ispin] << "Matrix Dimension of dHy(R): " << GlobalV::NLOCAL + g1y[ispin] << "Matrix Dimension of dHy(R): " << PARAM.globalv.nlocal << std::endl; g1y[ispin] << "Matrix number of dHy(R): " << output_R_number << std::endl; g1z[ispin] << "STEP: " << step << std::endl; - g1z[ispin] << "Matrix Dimension of dHz(R): " << GlobalV::NLOCAL + g1z[ispin] << "Matrix Dimension of dHz(R): " << PARAM.globalv.nlocal << std::endl; g1z[ispin] << "Matrix number of dHz(R): " << output_R_number << std::endl; @@ -714,6 +716,7 @@ void ModuleIO::save_sparse( std::ofstream ofs; if (!reduce || GlobalV::DRANK == 0) { if (binary) { + int nlocal = PARAM.globalv.nlocal; if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag && istep) { ofs.open(sss.str().c_str(), std::ios::binary | std::ios::app); @@ -721,7 +724,7 @@ void ModuleIO::save_sparse( ofs.open(sss.str().c_str(), std::ios::binary); } ofs.write(reinterpret_cast(0), sizeof(int)); - ofs.write(reinterpret_cast(&GlobalV::NLOCAL), sizeof(int)); + ofs.write(reinterpret_cast(&nlocal), sizeof(int)); ofs.write(reinterpret_cast(&output_R_number), sizeof(int)); } else { if (PARAM.inp.calculation == "md" && PARAM.inp.out_app_flag @@ -731,7 +734,7 @@ void ModuleIO::save_sparse( ofs.open(sss.str().c_str()); } ofs << "STEP: " << std::max(istep, 0) << std::endl; - ofs << "Matrix Dimension of " + label + "(R): " << GlobalV::NLOCAL + ofs << "Matrix Dimension of " + label + "(R): " << PARAM.globalv.nlocal << std::endl; ofs << "Matrix number of " + label + "(R): " << output_R_number << std::endl; diff --git a/source/module_io/write_cube.cpp b/source/module_io/write_cube.cpp index 0cc283c6fc3..8fa212c60fa 100644 --- a/source/module_io/write_cube.cpp +++ b/source/module_io/write_cube.cpp @@ -2,92 +2,92 @@ #include "module_io/cube_io.h" #include "module_parameter/parameter.h" #include - -void ModuleIO::write_cube( -#ifdef __MPI - const int& bz, - const int& nbz, - const int& nplane, - const int& startz_current, -#endif - const double* data, - const int& is, - const int& nspin, - const int& iter, +#include "module_hamilt_pw/hamilt_pwdft/parallel_grid.h" + +void ModuleIO::write_vdata_palgrid( + const Parallel_Grid& pgrid, + const double* const data, + const int is, + const int nspin, + const int iter, const std::string& fn, - const int& nx, - const int& ny, - const int& nz, - const double& ef, - const UnitCell* ucell, - const int& precision, - const int& out_fermi) + const double ef, + const UnitCell*const ucell, + const int precision, + const int out_fermi) { - ModuleBase::TITLE("ModuleIO", "write_cube"); + ModuleBase::TITLE("ModuleIO", "write_vdata_palgrid"); const int my_rank = GlobalV::MY_RANK; + const int my_pool = GlobalV::MY_POOL; time_t start; time_t end; - std::ofstream ofs_cube; + std::stringstream ss; - if (my_rank == 0) - { - start = time(NULL); + const int& nx = pgrid.nx; + const int& ny = pgrid.ny; + const int& nz = pgrid.nz; + const int& nxyz = nx * ny * nz; - if (iter == 0) - { - ofs_cube.open(fn.c_str()); - } - else - { - ofs_cube.open(fn.c_str(), std::ios::app); - } + start = time(nullptr); - if (!ofs_cube) - { - ModuleBase::WARNING("ModuleIO::write_cube", "Can't create Output File!"); - } + // reduce + std::vector data_xyz_full(nxyz); // data to be written +#ifdef __MPI // reduce to rank 0 + if (my_pool == 0) + { + pgrid.reduce(data_xyz_full.data(), data); + } + MPI_Barrier(MPI_COMM_WORLD); +#else + std::memcpy(data_xyz_full.data(), data, nxyz * sizeof(double)); +#endif + // build the info structure + if (my_rank == 0) + { /// output header for cube file - ofs_cube << "STEP: " << iter << " Cubefile created from ABACUS. Inner loop is z, followed by y and x" << std::endl; - ofs_cube << nspin << " (nspin) "; + ss << "STEP: " << iter << " Cubefile created from ABACUS. Inner loop is z, followed by y and x" << std::endl; - ofs_cube << std::fixed; - ofs_cube << std::setprecision(6); + ss << nspin << " (nspin) "; + ss << std::fixed; + ss << std::setprecision(6); if (out_fermi == 1) { if (PARAM.globalv.two_fermi) { if (is == 0) { - ofs_cube << ef << " (fermi energy for spin=1, in Ry)" << std::endl; + ss << ef << " (fermi energy for spin=1, in Ry)" << std::endl; } else if (is == 1) { - ofs_cube << ef << " (fermi energy for spin=2, in Ry)" << std::endl; + ss << ef << " (fermi energy for spin=2, in Ry)" << std::endl; } } else { - ofs_cube << ef << " (fermi energy, in Ry)" << std::endl; + ss << ef << " (fermi energy, in Ry)" << std::endl; } } else { - ofs_cube << std::endl; + ss << std::endl; } - ofs_cube << ucell->nat << " 0.0 0.0 0.0 " << std::endl; + std::vector comment(2); + for (int i = 0;i < 2;++i) { std::getline(ss, comment[i]); } + double fac = ucell->lat0; - ofs_cube << nx << " " << fac * ucell->latvec.e11 / double(nx) << " " << fac * ucell->latvec.e12 / double(nx) - << " " << fac * ucell->latvec.e13 / double(nx) << std::endl; - ofs_cube << ny << " " << fac * ucell->latvec.e21 / double(ny) << " " << fac * ucell->latvec.e22 / double(ny) - << " " << fac * ucell->latvec.e23 / double(ny) << std::endl; - ofs_cube << nz << " " << fac * ucell->latvec.e31 / double(nz) << " " << fac * ucell->latvec.e32 / double(nz) - << " " << fac * ucell->latvec.e33 / double(nz) << std::endl; + std::vector dx = { fac * ucell->latvec.e11 / double(nx), fac * ucell->latvec.e12 / double(nx), fac * ucell->latvec.e13 / double(nx) }; + std::vector dy = { fac * ucell->latvec.e21 / double(ny), fac * ucell->latvec.e22 / double(ny), fac * ucell->latvec.e23 / double(ny) }; + std::vector dz = { fac * ucell->latvec.e31 / double(nz), fac * ucell->latvec.e32 / double(nz), fac * ucell->latvec.e33 / double(nz) }; std::string element = ""; + std::vector atom_type; + std::vector atom_charge; + std::vector> atom_pos; for (int it = 0; it < ucell->ntype; it++) { // erase the number in label, such as Fe1. @@ -117,167 +117,79 @@ void ModuleIO::write_cube( break; } } - ofs_cube << " " << z << " " << ucell->atoms[it].ncpp.zv << " " << fac * ucell->atoms[it].tau[ia].x - << " " << fac * ucell->atoms[it].tau[ia].y << " " << fac * ucell->atoms[it].tau[ia].z - << std::endl; + atom_type.push_back(z); + atom_charge.push_back(ucell->atoms[it].ncpp.zv); + atom_pos.push_back({ fac * ucell->atoms[it].tau[ia].x, fac * ucell->atoms[it].tau[ia].y, fac * ucell->atoms[it].tau[ia].z }); } } - ofs_cube.unsetf(std::ostream::fixed); - ofs_cube << std::setprecision(precision); - ofs_cube << std::scientific; + write_cube(fn, comment, ucell->nat, { 0.0, 0.0, 0.0 }, nx, ny, nz, dx, dy, dz, atom_type, atom_charge, atom_pos, data_xyz_full, precision); + end = time(nullptr); + ModuleBase::GlobalFunc::OUT_TIME("write_vdata_palgrid", start, end); } -#ifdef __MPI - - const int my_pool = GlobalV::MY_POOL; - const int rank_in_pool = GlobalV::RANK_IN_POOL; - const int nproc_in_pool = GlobalV::NPROC_IN_POOL; - - // only do in the first pool. - if (my_pool == 0) - { - /// for cube file - const int nxyz = nx * ny * nz; - std::vector data_cube(nxyz, 0.0); - - // num_z: how many planes on processor 'ip' - std::vector num_z(nproc_in_pool, 0); - - for (int iz = 0; iz < nbz; iz++) - { - const int ip = iz % nproc_in_pool; - num_z[ip] += bz; - } - - // start_z: start position of z in - // processor ip. - std::vector start_z(nproc_in_pool, 0); - for (int ip = 1; ip < nproc_in_pool; ip++) - { - start_z[ip] = start_z[ip - 1] + num_z[ip - 1]; - } - - // which_ip: found iz belongs to which ip. - std::vector which_ip(nz, 0); - for (int iz = 0; iz < nz; iz++) - { - for (int ip = 0; ip < nproc_in_pool; ip++) - { - if (iz >= start_z[nproc_in_pool - 1]) - { - which_ip[iz] = nproc_in_pool - 1; - break; - } - else if (iz >= start_z[ip] && iz < start_z[ip + 1]) - { - which_ip[iz] = ip; - break; - } - } - } + return; +} - int count = 0; - const int nxy = nx * ny; - std::vector zpiece(nxy, 0.0); +void ModuleIO::write_cube(const std::string& file, + const std::vector& comment, + const int& natom, + const std::vector& origin, + const int& nx, + const int& ny, + const int& nz, + const std::vector& dx, + const std::vector& dy, + const std::vector& dz, + const std::vector& atom_type, + const std::vector& atom_charge, + const std::vector>& atom_pos, + const std::vector& data, + const int precision, + const int ndata_line) +{ + assert(comment.size() >= 2); + for (int i = 0;i < 2;++i) { assert(comment[i].find("\n") == std::string::npos); } + assert(origin.size() >= 3); + assert(dx.size() >= 3); + assert(dy.size() >= 3); + assert(dz.size() >= 3); + assert(atom_type.size() >= natom); + assert(atom_charge.size() >= natom); + assert(atom_pos.size() >= natom); + for (int i = 0;i < natom;++i) { assert(atom_pos[i].size() >= 3); } + assert(data.size() >= nx * ny * nz); - // save the rho one z by one z. - for (int iz = 0; iz < nz; iz++) - { - zpiece.assign(nxy, 0.0); + std::ofstream ofs(file); - // tag must be different for different iz. - const int tag = iz; - MPI_Status ierror; + for (int i = 0;i < 2;++i) { ofs << comment[i] << "\n"; } - // case 1: the first part of rho in processor 0. - if (which_ip[iz] == 0 && rank_in_pool == 0) - { - for (int ir = 0; ir < nxy; ir++) - { - // mohan change to rho_save on 2012-02-10 - // because this can make our next restart calculation lead - // to the same scf_thr as the one saved. - zpiece[ir] = data[ir * nplane + iz - startz_current]; - } - } - // case 2: > first part rho: send the rho to - // processor 0. - else if (which_ip[iz] == rank_in_pool) - { - for (int ir = 0; ir < nxy; ir++) - { - zpiece[ir] = data[ir * nplane + iz - startz_current]; - } - MPI_Send(zpiece.data(), nxy, MPI_DOUBLE, 0, tag, POOL_WORLD); - } + ofs << std::fixed; + ofs << std::setprecision(1); // as before - // case 2: > first part rho: processor 0 receive the rho - // from other processors - else if (rank_in_pool == 0) - { - MPI_Recv(zpiece.data(), nxy, MPI_DOUBLE, which_ip[iz], tag, POOL_WORLD, &ierror); - } + ofs << natom << " " << origin[0] << " " << origin[1] << " " << origin[2] << " \n"; - if (my_rank == 0) - { - /// for cube file - for (int ir = 0; ir < nxy; ir++) - { - data_cube[ir + iz * nxy] = zpiece[ir]; - } - /// for cube file - } - } // end iz + ofs << std::setprecision(6); //as before + ofs << nx << " " << dx[0] << " " << dx[1] << " " << dx[2] << "\n"; + ofs << ny << " " << dy[0] << " " << dy[1] << " " << dy[2] << "\n"; + ofs << nz << " " << dz[0] << " " << dz[1] << " " << dz[2] << "\n"; - // for cube file - if (my_rank == 0) - { - for (int ix = 0; ix < nx; ix++) - { - for (int iy = 0; iy < ny; iy++) - { - for (int iz = 0; iz < nz; iz++) - { - ofs_cube << " " << data_cube[iz * nx * ny + ix * ny + iy]; - if (iz % 6 == 5 && iz != nz - 1) - { - ofs_cube << "\n"; - } - } - ofs_cube << "\n"; - } - } - } - /// for cube file - } - MPI_Barrier(MPI_COMM_WORLD); -#else - for (int i = 0; i < nx; i++) + for (int i = 0;i < natom;++i) { - for (int j = 0; j < ny; j++) - { - for (int k = 0; k < nz; k++) - { - ofs_cube << " " << data[k * nx * ny + i * ny + j]; - // ++count_cube; - if (k % 6 == 5 && k != nz - 1) - { - ofs_cube << "\n"; - } - } - ofs_cube << "\n"; - } + ofs << " " << atom_type[i] << " " << atom_charge[i] << " " << atom_pos[i][0] << " " << atom_pos[i][1] << " " << atom_pos[i][2] << "\n"; } -#endif - if (my_rank == 0) + ofs.unsetf(std::ofstream::fixed); + ofs << std::setprecision(precision); + ofs << std::scientific; + const int nxy = nx * ny; + for (int ixy = 0; ixy < nxy; ++ixy) { - end = time(NULL); - ModuleBase::GlobalFunc::OUT_TIME("write_cube", start, end); - - /// for cube file - ofs_cube.close(); + for (int iz = 0;iz < nz;++iz) + { + ofs << " " << data[ixy * nz + iz]; + if ((iz + 1) % ndata_line == 0 && iz != nz - 1) { ofs << "\n"; } + } + ofs << "\n"; } - - return; -} + ofs.close(); +} \ No newline at end of file diff --git a/source/module_io/write_dos_lcao.cpp b/source/module_io/write_dos_lcao.cpp index cc7a1ec487c..dcdfc211f0d 100644 --- a/source/module_io/write_dos_lcao.cpp +++ b/source/module_io/write_dos_lcao.cpp @@ -53,7 +53,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, double emin = ekb(0, 0); for (int ik = 0; ik < kv.get_nks(); ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { emax = std::max(emax, ekb(ik, ib)); emin = std::min(emin, ekb(ik, ib)); @@ -94,7 +94,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, const int npoints = static_cast(std::floor((emax - emin) / de_ev)); - int NUM = GlobalV::NLOCAL * npoints; + int NUM = PARAM.globalv.nlocal * npoints; const int np = npoints; ModuleBase::matrix* pdosk = new ModuleBase::matrix[nspin0]; @@ -102,19 +102,19 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, for (int is = 0; is < nspin0; ++is) { - pdosk[is].create(GlobalV::NLOCAL, np, true); + pdosk[is].create(PARAM.globalv.nlocal, np, true); } ModuleBase::matrix* pdos = new ModuleBase::matrix[nspin0]; for (int is = 0; is < nspin0; ++is) { - pdos[is].create(GlobalV::NLOCAL, np, true); + pdos[is].create(PARAM.globalv.nlocal, np, true); } double a = bcoeff; double c = 2 * 3.141592653; double b = sqrt(c) * a; - std::complex* waveg = new std::complex[GlobalV::NLOCAL]; + std::complex* waveg = new std::complex[PARAM.globalv.nlocal]; double* Gauss = new double[np]; @@ -127,9 +127,9 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, psi->fix_k(is); const double* ppsi = psi->get_pointer(); - for (int i = 0; i < GlobalV::NBANDS; ++i) + for (int i = 0; i < PARAM.inp.nbands; ++i) { - ModuleBase::GlobalFunc::ZEROS(waveg, GlobalV::NLOCAL); + ModuleBase::GlobalFunc::ZEROS(waveg, PARAM.globalv.nlocal); ModuleBase::GlobalFunc::ZEROS(Gauss, np); for (int n = 0; n < npoints; ++n) @@ -149,8 +149,8 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, #ifdef __MPI const char T_char = 'T'; pdgemv_(&T_char, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one_float, sk, &one_int, @@ -169,7 +169,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, &one_int); #endif - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { if (pv.in_this_processor(j, i)) @@ -204,7 +204,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, { double y = 0.0; double en = emin + n * de_ev; - for (int i = 0; i < GlobalV::NLOCAL; i++) + for (int i = 0; i < PARAM.globalv.nlocal; i++) { y += pdos[0](i, n); } @@ -219,7 +219,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, double y = 0.0; double z = 0.0; double en = emin + n * de_ev; - for (int i = 0; i < GlobalV::NLOCAL; i++) + for (int i = 0; i < PARAM.globalv.nlocal; i++) { y += pdos[0](i, n); z += pdos[1](i, n); @@ -241,9 +241,9 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, out << "" << std::endl; out << "" << PARAM.inp.nspin << "" << std::endl; if (PARAM.inp.nspin == 4) { - out << "" << std::setw(2) << GlobalV::NLOCAL / 2 << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal / 2 << "" << std::endl; } else { - out << "" << std::setw(2) << GlobalV::NLOCAL << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal << "" << std::endl; } out << "" << std::endl; @@ -332,7 +332,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi* psi, kv.get_nkstot(), kv.wk, kv.isk, - GlobalV::NBANDS, + PARAM.inp.nbands, ekb, wg); } @@ -364,7 +364,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, double emin = ekb(0, 0); for (int ik = 0; ik < kv.get_nks(); ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { emax = std::max(emax, ekb(ik, ib)); emin = std::min(emin, ekb(ik, ib)); @@ -406,7 +406,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, const int npoints = static_cast(std::floor((emax - emin) / de_ev)); - int NUM = GlobalV::NLOCAL * npoints; + int NUM = PARAM.globalv.nlocal * npoints; const int np = npoints; @@ -416,21 +416,21 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, for (int is = 0; is < nspin0; ++is) { - pdosk[is].create(GlobalV::NLOCAL, np, true); + pdosk[is].create(PARAM.globalv.nlocal, np, true); } ModuleBase::matrix* pdos = new ModuleBase::matrix[nspin0]; for (int is = 0; is < nspin0; ++is) { - pdos[is].create(GlobalV::NLOCAL, np, true); + pdos[is].create(PARAM.globalv.nlocal, np, true); } double a = bcoeff; double c = 2 * 3.141592653; double b = sqrt(c) * a; - std::complex* waveg = new std::complex[GlobalV::NLOCAL]; + std::complex* waveg = new std::complex[PARAM.globalv.nlocal]; double* Gauss = new double[np](); @@ -466,10 +466,10 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, p_dwfc[index] = conj(p_dwfc[index]); } - for (int i = 0; i < GlobalV::NBANDS; ++i) + for (int i = 0; i < PARAM.inp.nbands; ++i) { - ModuleBase::GlobalFunc::ZEROS(waveg, GlobalV::NLOCAL); + ModuleBase::GlobalFunc::ZEROS(waveg, PARAM.globalv.nlocal); ModuleBase::GlobalFunc::ZEROS(Gauss, np); for (int n = 0; n < npoints; ++n) @@ -490,8 +490,8 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, #ifdef __MPI pzgemv_(&T_char, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one_float[0], sk, &one_int, @@ -510,7 +510,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, &one_int); #endif - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { if (pv.in_this_processor(j, i)) @@ -551,7 +551,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, { double y = 0.0; double en = emin + n * de_ev; - for (int i = 0; i < GlobalV::NLOCAL; i++) + for (int i = 0; i < PARAM.globalv.nlocal; i++) { y += pdos[0](i, n); } @@ -566,7 +566,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, double y = 0.0; double z = 0.0; double en = emin + n * de_ev; - for (int i = 0; i < GlobalV::NLOCAL; i++) + for (int i = 0; i < PARAM.globalv.nlocal; i++) { y += pdos[0](i, n); z += pdos[1](i, n); @@ -589,11 +589,11 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, out << "" << PARAM.inp.nspin << "" << std::endl; if (PARAM.inp.nspin == 4) { - out << "" << std::setw(2) << GlobalV::NLOCAL / 2 << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal / 2 << "" << std::endl; } else { - out << "" << std::setw(2) << GlobalV::NLOCAL << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal << "" << std::endl; } out << "" << std::endl; @@ -681,7 +681,7 @@ void ModuleIO::write_dos_lcao(const psi::Psi>* psi, kv.get_nkstot(), kv.wk, kv.isk, - GlobalV::NBANDS, + PARAM.inp.nbands, ekb, wg); } diff --git a/source/module_io/write_dos_pw.cpp b/source/module_io/write_dos_pw.cpp index d6e07d20ed3..302c21e16f8 100644 --- a/source/module_io/write_dos_pw.cpp +++ b/source/module_io/write_dos_pw.cpp @@ -22,7 +22,7 @@ void ModuleIO::write_dos_pw(const ModuleBase::matrix& ekb, double emin = ekb(0, 0); for (int ik = 0; ik < kv.get_nks(); ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { emax = std::max(emax, ekb(ik, ib)); emin = std::min(emin, ekb(ik, ib)); @@ -78,7 +78,7 @@ void ModuleIO::write_dos_pw(const ModuleBase::matrix& ekb, kv.get_nkstot(), kv.wk, kv.isk, - GlobalV::NBANDS, + PARAM.inp.nbands, ekb, wg); } diff --git a/source/module_io/write_eband_terms.hpp b/source/module_io/write_eband_terms.hpp index 97ca13f2f96..41f0a42112f 100644 --- a/source/module_io/write_eband_terms.hpp +++ b/source/module_io/write_eband_terms.hpp @@ -87,7 +87,7 @@ namespace ModuleIO hamilt::HContainer v_pp_local_R_ao(pv); if_gamma_fix(v_pp_local_R_ao); std::vector> e_orb_pp_local; - hamilt::Veff> v_pp_local_op(gint, &v_pp_local_k_ao, kv.kvec_d, &pot_local, &v_pp_local_R_ao, &ucell, orb_cutoff, &gd); + hamilt::Veff> v_pp_local_op(gint, &v_pp_local_k_ao, kv.kvec_d, &pot_local, &v_pp_local_R_ao, &ucell, orb_cutoff, &gd, nspin); v_pp_local_op.contributeHR(); for (int ik = 0;ik < kv.get_nks();++ik) { @@ -142,7 +142,7 @@ namespace ModuleIO for (int is = 0; is < nspin0; ++is) { v_hartree_op[is] = new hamilt::Veff>(gint, - &v_hartree_k_ao, kv.kvec_d, &pot_hartree, &v_hartree_R_ao[is], &ucell, orb_cutoff, &gd); + &v_hartree_k_ao, kv.kvec_d, &pot_hartree, &v_hartree_R_ao[is], &ucell, orb_cutoff, &gd, nspin); v_hartree_op[is]->contributeHR(); } std::vector> e_orb_hartree; diff --git a/source/module_io/write_elecstat_pot.cpp b/source/module_io/write_elecstat_pot.cpp index 4a620a3efad..eaf77622853 100644 --- a/source/module_io/write_elecstat_pot.cpp +++ b/source/module_io/write_elecstat_pot.cpp @@ -93,21 +93,12 @@ void write_elecstat_pot( double ef_tmp = 0.0; int out_fermi = 0; - ModuleIO::write_cube( -#ifdef __MPI - bz, - nbz, - rho_basis->nplane, - rho_basis->startz_current, -#endif + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, v_elecstat.data(), is, nspin, istep, fn, - rho_basis->nx, - rho_basis->ny, - rho_basis->nz, ef_tmp, &(GlobalC::ucell), precision, diff --git a/source/module_io/write_elf.cpp b/source/module_io/write_elf.cpp new file mode 100644 index 00000000000..a50063c3950 --- /dev/null +++ b/source/module_io/write_elf.cpp @@ -0,0 +1,143 @@ +#include "write_elf.h" +#include "module_io/cube_io.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" + +namespace ModuleIO +{ +void write_elf( +#ifdef __MPI + const int& bz, + const int& nbz, +#endif + const std::string& out_dir, + const int& istep, + const int& nspin, + const double* const* rho, + const double* const* tau, + ModulePW::PW_Basis* rho_basis, + const UnitCell* ucell_, + const int& precision) +{ + std::vector> elf(nspin, std::vector(rho_basis->nrxx, 0.)); + // 1) calculate the kinetic energy density of vW KEDF + std::vector> tau_vw(nspin, std::vector(rho_basis->nrxx, 0.)); + for (int is = 0; is < nspin; ++is) + { + std::vector> gradient_rho(3, std::vector(rho_basis->nrxx, 0.)); + + std::vector> recip_rho(rho_basis->npw, 0.0); + std::vector> recip_gradient_rho(rho_basis->npw, 0.0); + rho_basis->real2recip(rho[is], recip_rho.data()); + + std::complex img(0.0, 1.0); + for (int j = 0; j < 3; ++j) + { + for (int ip = 0; ip < rho_basis->npw; ++ip) + { + recip_gradient_rho[ip] = img * rho_basis->gcar[ip][j] * recip_rho[ip] * rho_basis->tpiba; + } + + rho_basis->recip2real(recip_gradient_rho.data(), gradient_rho[j].data()); + + for (int ir = 0; ir < rho_basis->nrxx; ++ir) + { + tau_vw[is][ir] += gradient_rho[j][ir] * gradient_rho[j][ir] / (8. * rho[is][ir]) * 2.0; // convert Ha to Ry. + } + } + } + + // 2) calculate the kinetic energy density of TF KEDF + std::vector> tau_TF(nspin, std::vector(rho_basis->nrxx, 0.)); + const double c_tf + = 3.0 / 10.0 * std::pow(3 * std::pow(M_PI, 2.0), 2.0 / 3.0) + * 2.0; // 10/3*(3*pi^2)^{2/3}, multiply by 2 to convert unit from Hartree to Ry, finally in Ry*Bohr^(-2) + if (nspin == 1) + { + for (int ir = 0; ir < rho_basis->nrxx; ++ir) + { + tau_TF[0][ir] = c_tf * std::pow(rho[0][ir], 5.0 / 3.0); + } + } + else if (nspin == 2) + { + for (int is = 0; is < nspin; ++is) + { + for (int ir = 0; ir < rho_basis->nrxx; ++ir) + { + tau_TF[is][ir] = 0.5 * c_tf * std::pow(2.0 * rho[is][ir], 5.0 / 3.0); + } + } + } + + // 3) calculate the enhancement factor F = (tau_KS - tau_vw) / tau_TF, and then ELF = 1 / (1 + F^2) + double eps = 1.0e-5; // suppress the numerical instability in LCAO (Ref: Acta Phys. -Chim. Sin. 2011, 27(12), 2786-2792. doi: 10.3866/PKU.WHXB20112786) + for (int is = 0; is < nspin; ++is) + { + for (int ir = 0; ir < rho_basis->nrxx; ++ir) + { + elf[is][ir] = (tau[is][ir] - tau_vw[is][ir] + eps) / tau_TF[is][ir]; + elf[is][ir] = 1. / (1. + elf[is][ir] * elf[is][ir]); + } + } + + // 4) output the ELF = 1 / (1 + F^2) to cube file + double ef_tmp = 0.0; + int out_fermi = 0; + + if (nspin == 1) + { + std::string fn = out_dir + "/ELF.cube"; + + int is = -1; + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + elf[0].data(), + is, + nspin, + istep, + fn, + ef_tmp, + ucell_, + precision, + out_fermi); + } + else if (nspin == 2) + { + for (int is = 0; is < nspin; ++is) + { + std::string fn_temp = out_dir + "/ELF_SPIN" + std::to_string(is + 1) + ".cube"; + int ispin = is + 1; + + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + elf[is].data(), + ispin, + nspin, + istep, + fn_temp, + ef_tmp, + ucell_, + precision, + out_fermi); + } + + std::vector elf_tot(rho_basis->nrxx, 0.0); + for (int ir = 0; ir < rho_basis->nrxx; ++ir) + { + elf_tot[ir] = (tau[0][ir] + tau[1][ir] - tau_vw[0][ir] - tau_vw[1][ir]) / (tau_TF[0][ir] + tau_TF[1][ir]); + elf_tot[ir] = 1. / (1. + elf_tot[ir] * elf_tot[ir]); + } + std::string fn = out_dir + "/ELF.cube"; + + int is = -1; + ModuleIO::write_vdata_palgrid(GlobalC::Pgrid, + elf_tot.data(), + is, + nspin, + istep, + fn, + ef_tmp, + ucell_, + precision, + out_fermi); + } +} +} \ No newline at end of file diff --git a/source/module_io/write_elf.h b/source/module_io/write_elf.h new file mode 100644 index 00000000000..d122e4e7006 --- /dev/null +++ b/source/module_io/write_elf.h @@ -0,0 +1,25 @@ +#ifndef WRITE_ELF_H +#define WRITE_ELF_H +#include +#include "module_cell/unitcell.h" +#include "module_basis/module_pw/pw_basis.h" +#include "module_elecstate/module_charge/charge.h" + +namespace ModuleIO +{ +void write_elf( +#ifdef __MPI + const int& bz, + const int& nbz, +#endif + const std::string& out_dir, + const int& istep, + const int& nspin, + const double* const* rho, + const double* const* tau, + ModulePW::PW_Basis* rho_basis, + const UnitCell* ucell_, + const int& precision); +} + +#endif \ No newline at end of file diff --git a/source/module_io/write_istate_info.cpp b/source/module_io/write_istate_info.cpp index 5fa53e813e0..f69af911163 100644 --- a/source/module_io/write_istate_info.cpp +++ b/source/module_io/write_istate_info.cpp @@ -41,7 +41,7 @@ void ModuleIO::write_istate_info(const ModuleBase::matrix &ekb,const ModuleBase: << std::setw(25) << "Kpoint = " << ik_global << std::setw(25) << "(" << kv.kvec_d[ik].x << " " << kv.kvec_d[ik].y << " " << kv.kvec_d[ik].z << ")" << std::endl; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { ofsi2.precision(16); ofsi2 << std::setw(6) << ib + 1 << std::setw(25) @@ -67,7 +67,7 @@ void ModuleIO::write_istate_info(const ModuleBase::matrix &ekb,const ModuleBase: << std::setw(25) << "(" << kv.kvec_d[ik].x << " " << kv.kvec_d[ik].y << " " << kv.kvec_d[ik].z << ")" << std::endl; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { ofsi2 << std::setw(6) << ib + 1 << std::setw(25) << ekb(ik, ib) * ModuleBase::Ry_to_eV << std::setw(25) << wg(ik, ib) diff --git a/source/module_io/write_proj_band_lcao.cpp b/source/module_io/write_proj_band_lcao.cpp index c308bc09923..ccd7a0d4b0f 100644 --- a/source/module_io/write_proj_band_lcao.cpp +++ b/source/module_io/write_proj_band_lcao.cpp @@ -39,9 +39,9 @@ void ModuleIO::write_proj_band_lcao( ModuleBase::ComplexMatrix weightk; ModuleBase::matrix weight; - int NUM = GlobalV::NLOCAL * GlobalV::NBANDS * nspin0; - weightk.create(nspin0, GlobalV::NBANDS * GlobalV::NLOCAL, true); - weight.create(nspin0, GlobalV::NBANDS * GlobalV::NLOCAL, true); + int NUM = PARAM.globalv.nlocal * PARAM.inp.nbands * nspin0; + weightk.create(nspin0, PARAM.inp.nbands * PARAM.globalv.nlocal, true); + weight.create(nspin0, PARAM.inp.nbands * PARAM.globalv.nlocal, true); for (int is = 0; is < nspin0; is++) @@ -51,7 +51,7 @@ void ModuleIO::write_proj_band_lcao( Mulk[0].create(pv.ncol, pv.nrow); psi->fix_k(is); - for (int i = 0; i < GlobalV::NBANDS; ++i) + for (int i = 0; i < PARAM.inp.nbands; ++i) { const int NB = i + 1; @@ -60,8 +60,8 @@ void ModuleIO::write_proj_band_lcao( #ifdef __MPI const char T_char = 'T'; pdgemv_(&T_char, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one_float, sk, &one_int, @@ -79,14 +79,14 @@ void ModuleIO::write_proj_band_lcao( pv.desc, &one_int); #endif - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { if (pv.in_this_processor(j, i)) { const int ir = pv.global2local_row(j); const int ic = pv.global2local_col(i); - weightk(is, i * GlobalV::NLOCAL + j) = Mulk[0](ic, ir) * psi[0](ic, ir); + weightk(is, i * PARAM.globalv.nlocal + j) = Mulk[0](ic, ir) * psi[0](ic, ir); } } } // ib @@ -104,12 +104,12 @@ void ModuleIO::write_proj_band_lcao( out << "" << std::endl; out << "" << PARAM.inp.nspin << "" << std::endl; if (PARAM.inp.nspin == 4) - out << "" << std::setw(2) << GlobalV::NLOCAL / 2 << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal / 2 << "" << std::endl; else - out << "" << std::setw(2) << GlobalV::NLOCAL << "" << std::endl; - out << "" + out << "" << std::setw(2) << PARAM.globalv.nlocal << "" << std::endl; + out << "" << std::endl; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) out << " " << (pelec->ekb(is * nks, ib)) * ModuleBase::Ry_to_eV; out << std::endl; out << "" << std::endl; @@ -137,16 +137,16 @@ void ModuleIO::write_proj_band_lcao( out << std::setw(2) << "z=\"" << std::setw(40) << N1 + 1 << "\"" << std::endl; out << ">" << std::endl; out << "" << std::endl; - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (PARAM.inp.nspin == 1 || PARAM.inp.nspin == 2) - out << std::setw(13) << weight(is, ib * GlobalV::NLOCAL + w); + out << std::setw(13) << weight(is, ib * PARAM.globalv.nlocal + w); else if (PARAM.inp.nspin == 4) { int w0 = w - s0; out << std::setw(13) - << weight(is, ib * GlobalV::NLOCAL + s0 + 2 * w0) - + weight(is, ib * GlobalV::NLOCAL + s0 + 2 * w0 + 1); + << weight(is, ib * PARAM.globalv.nlocal + s0 + 2 * w0) + + weight(is, ib * PARAM.globalv.nlocal + s0 + 2 * w0 + 1); } } out << std::endl; @@ -192,9 +192,9 @@ void ModuleIO::write_proj_band_lcao( ModuleBase::ComplexMatrix weightk; ModuleBase::matrix weight; - int NUM = GlobalV::NLOCAL * GlobalV::NBANDS * kv.get_nks(); - weightk.create(kv.get_nks(), GlobalV::NBANDS * GlobalV::NLOCAL, true); - weight.create(kv.get_nks(), GlobalV::NBANDS * GlobalV::NLOCAL, true); + int NUM = PARAM.globalv.nlocal * PARAM.inp.nbands * kv.get_nks(); + weightk.create(kv.get_nks(), PARAM.inp.nbands * PARAM.globalv.nlocal, true); + weight.create(kv.get_nks(), PARAM.inp.nbands * PARAM.globalv.nlocal, true); for (int is = 0; is < nspin0; is++) { @@ -228,7 +228,7 @@ void ModuleIO::write_proj_band_lcao( p_dwfc[index] = conj(p_dwfc[index]); } - for (int i = 0; i < GlobalV::NBANDS; ++i) + for (int i = 0; i < PARAM.inp.nbands; ++i) { const int NB = i + 1; @@ -238,8 +238,8 @@ void ModuleIO::write_proj_band_lcao( const char T_char = 'T'; #ifdef __MPI pzgemv_(&T_char, - &GlobalV::NLOCAL, - &GlobalV::NLOCAL, + &PARAM.globalv.nlocal, + &PARAM.globalv.nlocal, &one_float[0], sk, &one_int, @@ -257,7 +257,7 @@ void ModuleIO::write_proj_band_lcao( pv.desc, &one_int); #endif - for (int j = 0; j < GlobalV::NLOCAL; ++j) + for (int j = 0; j < PARAM.globalv.nlocal; ++j) { if (pv.in_this_processor(j, i)) @@ -266,7 +266,7 @@ void ModuleIO::write_proj_band_lcao( const int ir = pv.global2local_row(j); const int ic = pv.global2local_col(i); - weightk(ik, i * GlobalV::NLOCAL + j) = Mulk[0](ic, ir) * psi[0](ic, ir); + weightk(ik, i * PARAM.globalv.nlocal + j) = Mulk[0](ic, ir) * psi[0](ic, ir); } } @@ -289,19 +289,19 @@ void ModuleIO::write_proj_band_lcao( out << "" << PARAM.inp.nspin << "" << std::endl; if (PARAM.inp.nspin == 4) { - out << "" << std::setw(2) << GlobalV::NLOCAL / 2 << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal / 2 << "" << std::endl; } else { - out << "" << std::setw(2) << GlobalV::NLOCAL << "" << std::endl; + out << "" << std::setw(2) << PARAM.globalv.nlocal << "" << std::endl; } - out << "" + out << "" << std::endl; for (int ik = 0; ik < nks; ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) out << " " << (pelec->ekb(ik + is * nks, ib)) * ModuleBase::Ry_to_eV; out << std::endl; } @@ -332,22 +332,22 @@ void ModuleIO::write_proj_band_lcao( out << "" << std::endl; for (int ik = 0; ik < nks; ik++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { if (PARAM.inp.nspin == 1) { - out << std::setw(13) << weight(ik, ib * GlobalV::NLOCAL + w); + out << std::setw(13) << weight(ik, ib * PARAM.globalv.nlocal + w); } else if (PARAM.inp.nspin == 2) { - out << std::setw(13) << weight(ik + nks * is, ib * GlobalV::NLOCAL + w); + out << std::setw(13) << weight(ik + nks * is, ib * PARAM.globalv.nlocal + w); } else if (PARAM.inp.nspin == 4) { int w0 = w - s0; out << std::setw(13) - << weight(ik, ib * GlobalV::NLOCAL + s0 + 2 * w0) - + weight(ik, ib * GlobalV::NLOCAL + s0 + 2 * w0 + 1); + << weight(ik, ib * PARAM.globalv.nlocal + s0 + 2 * w0) + + weight(ik, ib * PARAM.globalv.nlocal + s0 + 2 * w0 + 1); } } out << std::endl; diff --git a/source/module_io/write_vxc.hpp b/source/module_io/write_vxc.hpp index 04925e02e3f..d6fad87dade 100644 --- a/source/module_io/write_vxc.hpp +++ b/source/module_io/write_vxc.hpp @@ -238,13 +238,7 @@ void write_Vxc(const int nspin, for (int is = 0; is < nspin0; ++is) { vxcs_op_ao[is] = new hamilt::Veff>(gint, - &vxc_k_ao, - kv.kvec_d, - potxc, - &vxcs_R_ao[is], - &ucell, - orb_cutoff, - &gd); + &vxc_k_ao, kv.kvec_d, potxc, &vxcs_R_ao[is], &ucell, orb_cutoff, &gd, nspin); vxcs_op_ao[is]->contributeHR(); } @@ -284,10 +278,10 @@ void write_Vxc(const int nspin, vexxonly_op_ao.contributeHk(ik); std::vector vexx_k_mo = cVc(vexxonly_k_ao.get_hk(), &psi(ik, 0, 0), nbasis, nbands, *pv, p2d); e_orb_exx.emplace_back(orbital_energy(ik, nbands, vexx_k_mo, p2d)); + // ======test======= + // exx_energy += all_band_energy(ik, vexx_k_mo, p2d, wg); + // ======test======= } - // ======test======= - // exx_energy += all_band_energy(ik, vexx_k_mo, p2d, wg); - // ======test======= #endif if (PARAM.inp.dft_plus_u) { diff --git a/source/module_io/write_wfc_pw.cpp b/source/module_io/write_wfc_pw.cpp index b33559af055..dc113429948 100644 --- a/source/module_io/write_wfc_pw.cpp +++ b/source/module_io/write_wfc_pw.cpp @@ -15,54 +15,57 @@ void ModuleIO::write_wfc_pw(const std::string& fn, const K_Vectors& kv, const ModulePW::PW_Basis_K* wfcpw) { - ModuleBase::TITLE("ModuleIO","write_wfc_pw"); + ModuleBase::TITLE("ModuleIO", "write_wfc_pw"); const int nkstot = kv.get_nkstot(); const int nks = kv.get_nks(); - std::string * wfilename; + std::string* wfilename; wfilename = new std::string[nkstot]; - for(int ik = 0; ik < nkstot ; ++ik) - { + for (int ik = 0; ik < nkstot; ++ik) + { std::stringstream wfss; - if(PARAM.inp.out_wfc_pw==1) { - wfss<npwk_max; #ifdef __MPI MPI_Allreduce(&kv.ngk[ik], &ikngtot, 1, MPI_INT, MPI_SUM, POOL_WORLD); @@ -71,147 +74,210 @@ void ModuleIO::write_wfc_pw(const std::string& fn, // To avoid GlobalC, we use get_ik_global instead ikstot = K_Vectors::get_ik_global(ik, nkstot); #else - ikngtot = kv.ngk[ik]; - ikstot=ik; + ikngtot = kv.ngk[ik]; + ikstot = ik; #endif + const int ikngtot_npol = ikngtot * PARAM.globalv.npol; #ifdef __MPI - for( int id=0; idlat0 << std::setw(10) << wfcpw->tpiba << std::endl; - ofs2<<"\n"<G.e11<G.e12<G.e13<G.e21<G.e22<G.e23<G.e31<G.e32<G.e33<\n"<"<npwk[ik]; ++igl) + if (PARAM.inp.out_wfc_pw == 1) { - int isz = wfcpw->igl2isz_k[ik * wfcpw->npwk_max + igl]; - int iz = isz % wfcpw->nz; - int is = isz / wfcpw->nz; - int ixy = wfcpw->is2fftixy[is]; - int ix = ixy / wfcpw->fftny; - int iy = ixy % wfcpw->fftny; + std::ofstream ofs2(wfilename[ikstot].c_str(), std::ios::app); + if (id == 0) + { + ofs2 << std::setprecision(6); + ofs2 << std::setw(10) << "Kpoint" << std::setw(10) << "nKpoint" << std::setw(10) + << "kv.x" << std::setw(10) << "kv.y" << std::setw(10) << "kv.z" << std::setw(10) + << "weight" << std::setw(10) << "ngtot" << std::setw(10) << "nband" + << std::setw(10) << "ecut" << std::setw(10) << "lat0" << std::setw(10) + << "2pi/lat0" << std::endl; + ofs2 << std::setw(10) << ikstot + 1 << std::setw(10) << nkstot << std::setw(10) + << kv.kvec_c[ik].x << std::setw(10) << kv.kvec_c[ik].y << std::setw(10) + << kv.kvec_c[ik].z << std::setw(10) << kv.wk[ik] << std::setw(10) << ikngtot + << std::setw(10) << PARAM.inp.nbands << std::setw(10) << PARAM.inp.ecutwfc + << std::setw(10) << wfcpw->lat0 << std::setw(10) << wfcpw->tpiba << std::endl; + ofs2 << "\n" << std::endl; + ofs2 << std::setw(10) << wfcpw->G.e11 << std::setw(10) << wfcpw->G.e12 << std::setw(10) + << wfcpw->G.e13 << std::endl; + ofs2 << std::setw(10) << wfcpw->G.e21 << std::setw(10) << wfcpw->G.e22 << std::setw(10) + << wfcpw->G.e23 << std::endl; + ofs2 << std::setw(10) << wfcpw->G.e31 << std::setw(10) << wfcpw->G.e32 << std::setw(10) + << wfcpw->G.e33 << std::endl; + ofs2 << "\n" << std::endl; + ofs2 << "" << std::endl; + } + for (int igl = 0; igl < wfcpw->npwk[ik]; ++igl) + { + int isz = wfcpw->igl2isz_k[ik * wfcpw->npwk_max + igl]; + int iz = isz % wfcpw->nz; + int is = isz / wfcpw->nz; + int ixy = wfcpw->is2fftixy[is]; + int ix = ixy / wfcpw->fftny; + int iy = ixy % wfcpw->fftny; - ofs2 << std::setw(10) << ix << std::setw(10) << iy << std::setw(10) << iz << std::endl; + ofs2 << std::setw(10) << ix << std::setw(10) << iy << std::setw(10) << iz << std::endl; + } + if (id == GlobalV::NPROC_IN_POOL - 1) + { + ofs2 << "\n" << std::endl; + } + ofs2.close(); } - if(id==GlobalV::NPROC_IN_POOL-1) + else if (PARAM.inp.out_wfc_pw == 2) { - ofs2<<"\n"<lat0 << wfcpw->tpiba << 72; // 4 int + 7 double is 72B - wfs2<<72<G.e11<G.e12<G.e13 - <G.e21<G.e22<G.e23 - <G.e31<G.e32<G.e33<<72; //9 double is 72B - } - if(id==0) - { - wfs2 << ikngtot * 4 * 3; - } - for (int igl = 0; igl < wfcpw->npwk[ik]; ++igl) - { - int isz = wfcpw->igl2isz_k[ik * wfcpw->npwk_max + igl]; - int iz = isz % wfcpw->nz; - int is = isz / wfcpw->nz; - int ixy = wfcpw->is2fftixy[is]; - int ix = ixy / wfcpw->fftny; - int iy = ixy % wfcpw->fftny; + Binstream wfs2(wfilename[ikstot], "a"); + if (id == 0) + { + wfs2 << int(72) << ikstot + 1 << nkstot << kv.kvec_c[ik].x << kv.kvec_c[ik].y + << kv.kvec_c[ik].z << kv.wk[ik] << ikngtot << PARAM.inp.nbands << PARAM.inp.ecutwfc + << wfcpw->lat0 << wfcpw->tpiba << 72; // 4 int + 7 double is 72B + wfs2 << 72 << wfcpw->G.e11 << wfcpw->G.e12 << wfcpw->G.e13 << wfcpw->G.e21 + << wfcpw->G.e22 << wfcpw->G.e23 << wfcpw->G.e31 << wfcpw->G.e32 << wfcpw->G.e33 + << 72; // 9 double is 72B + } + if (id == 0) + { + wfs2 << ikngtot * 4 * 3; + } + for (int igl = 0; igl < wfcpw->npwk[ik]; ++igl) + { + int isz = wfcpw->igl2isz_k[ik * wfcpw->npwk_max + igl]; + int iz = isz % wfcpw->nz; + int is = isz / wfcpw->nz; + int ixy = wfcpw->is2fftixy[is]; + int ix = ixy / wfcpw->fftny; + int iy = ixy % wfcpw->fftny; - wfs2 << ix << iy << iz; + wfs2 << ix << iy << iz; + } + if (id == GlobalV::NPROC_IN_POOL - 1) + { + wfs2 << ikngtot * 4 * 3; + } + wfs2.close(); } - if(id==GlobalV::NPROC_IN_POOL-1) - { - wfs2 << ikngtot * 4 * 3; - } - wfs2.close(); - } #ifdef __MPI - } - }// end id + } + } // end id #endif - for(int ib=0; ib" <" <" << std::endl; + } + ofs2 << std::scientific; + for (int ig = 0; ig < ng; ig++) + { + if (ig % 4 == 0 && (ig != 0 || id != 0)) + { + ofs2 << "\n"; + } + ofs2 << std::setw(15) << psi(ib, ig).real() << std::setw(15) << psi(ib, ig).imag(); + } // end ig + if (id == GlobalV::NPROC_IN_POOL - 1 && PARAM.globalv.npol == 1) + { + ofs2 << "\n< Band " << ib + 1 << " >" << std::endl; + } + ofs2.close(); + } + else if (PARAM.inp.out_wfc_pw == 2) + { + Binstream wfs2(wfilename[ikstot], "a"); + if (id == 0) + { + wfs2 << ikngtot_npol * 16; + } + for (int ig = 0; ig < ng; ig++) + { + wfs2 << psi(ib, ig).real() << psi(ib, ig).imag(); + } + if (id == GlobalV::NPROC_IN_POOL - 1 && PARAM.globalv.npol == 1) + { + wfs2 << ikngtot_npol * 16; + } + wfs2.close(); + } +#ifdef __MPI } - else if(PARAM.inp.out_wfc_pw==2) + } // end id +#endif + if (PARAM.globalv.npol > 1) + { +#ifdef __MPI + for (int id = 0; id < GlobalV::NPROC_IN_POOL; id++) { - Binstream wfs2(wfilename[ikstot],"a"); - if(id==0) { wfs2<" << std::endl; + } + ofs2.close(); + } + else if (PARAM.inp.out_wfc_pw == 2) + { + Binstream wfs2(wfilename[ikstot], "a"); + for (int ig = 0; ig < ng; ig++) + { + wfs2 << psi(ib, ig + ng_max).real() << psi(ib, ig + ng_max).imag(); + } + if (id == GlobalV::NPROC_IN_POOL - 1) + { + wfs2 << ikngtot_npol * 16; + } + wfs2.close(); + } #ifdef __MPI - } - }// end ip + } // end if rank_in_pool + } // end id #endif + } // end if npol>1 + } // end ib + } // end ik +#ifdef __MPI + } // end if my_pool + } // end ipool +#endif - delete [] wfilename; - return; + delete[] wfilename; + return; } diff --git a/source/module_io/write_wfc_r.cpp b/source/module_io/write_wfc_r.cpp index f8a15edb4bd..b900f8f0bec 100644 --- a/source/module_io/write_wfc_r.cpp +++ b/source/module_io/write_wfc_r.cpp @@ -4,21 +4,25 @@ // DATE : 2021-11-21 //====================== +//====================== +// WARNING: These interfaces will be removed in the future! Do not use them! +// Taoni add 2024-10-08 +//====================== + +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" #include "write_wfc_r.h" #include #include #include -#include "module_base/timer.h" -#include "module_base/tool_title.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" - namespace ModuleIO { - // write ||wfc_r|| for all k-points and all bands - // Input: wfc_g(ik, ib, ig) - // loop order is for(z){for(y){for(x)}} +// write ||wfc_r|| for all k-points and all bands +// Input: wfc_g(ik, ib, ig) +// loop order is for(z){for(y){for(x)}} void write_psi_r_1(const psi::Psi>& wfc_g, const ModulePW::PW_Basis_K* wfcpw, const std::string& folder_name, @@ -31,157 +35,174 @@ void write_psi_r_1(const psi::Psi>& wfc_g, const std::string outdir = PARAM.globalv.global_out_dir + folder_name + "/"; ModuleBase::GlobalFunc::MAKE_DIR(outdir); #ifdef __MPI - std::vector mpi_requests; + std::vector mpi_requests; #endif - for(int ik=0; ik> wfc_r = cal_wfc_r(wfcpw, wfc_g, ik, ib); - - std::vector wfc_r2(wfc_r.size()); - std::vector wfc_i2; - if (square) - for (int ir = 0; ir < wfc_r2.size(); ++ir) - wfc_r2[ir] = std::norm(wfc_r[ir]); // "std::norm(z)" returns |z|^2 - else + for (int ik = 0; ik < wfc_g.get_nk(); ++ik) + { + wfc_g.fix_k(ik); + const int ik_out = (PARAM.inp.nspin != 2) + ? ik + GlobalC::Pkpoints.startk_pool[GlobalV::MY_POOL] + : ik - kv.get_nks() / 2 * kv.isk[ik] + kv.get_nkstot() / 2 * kv.isk[ik] + + GlobalC::Pkpoints.startk_pool[GlobalV::MY_POOL]; + for (int ib = 0; ib < wfc_g.get_nbands(); ++ib) + { + const std::vector> wfc_r = cal_wfc_r(wfcpw, wfc_g, ik, ib); + + std::vector wfc_real(wfc_r.size()); + std::vector wfc_imag; + if (square) + { + for (int ir = 0; ir < wfc_real.size(); ++ir) { - wfc_i2.resize(wfc_r.size()); - for (int ir = 0; ir < wfc_r2.size(); ++ir) - { - wfc_r2[ir] = wfc_r[ir].real(); - wfc_i2[ir] = wfc_r[ir].imag(); - } + wfc_real[ir] = std::norm(wfc_r[ir]); // "std::norm(z)" returns |z|^2 } - const std::string file_name = outdir + "wfc_realspace_" - + ModuleBase::GlobalFunc::TO_STRING(ik_out) - + "_" + ModuleBase::GlobalFunc::TO_STRING(ib); + } + else + { + wfc_imag.resize(wfc_r.size()); + for (int ir = 0; ir < wfc_real.size(); ++ir) + { + wfc_real[ir] = wfc_r[ir].real(); + wfc_imag[ir] = wfc_r[ir].imag(); + } + } + const std::string file_name = outdir + "wfc_realspace_" + ModuleBase::GlobalFunc::TO_STRING(ik_out) + "_" + + ModuleBase::GlobalFunc::TO_STRING(ib); #ifdef __MPI - mpi_requests.push_back({}); - write_chg_r_1(wfcpw, wfc_r2, file_name, mpi_requests.back()); - if (!square) - write_chg_r_1(wfcpw, wfc_i2, file_name + "_imag", mpi_requests.back()); + // Use write_chg_r_1 to output the real and imaginary parts of the wave function to file + mpi_requests.push_back({}); + write_chg_r_1(wfcpw, wfc_real, file_name, mpi_requests.back()); + if (!square) + { + write_chg_r_1(wfcpw, wfc_imag, file_name + "_imag", mpi_requests.back()); + } #else - write_chg_r_1(wfcpw, wfc_r2, file_name); - //if (!square) - //write_chg_r_1(wfc_i2, file_name + "_imag", mpi_requests.back()); + write_chg_r_1(wfcpw, wfc_real, file_name); + // if (!square) + // write_chg_r_1(wfc_imag, file_name + "_imag", mpi_requests.back()); #endif - } - } + } + } #ifdef __MPI - MPI_Waitall( mpi_requests.size(), mpi_requests.data(), MPI_STATUSES_IGNORE ); + MPI_Waitall(mpi_requests.size(), mpi_requests.data(), MPI_STATUSES_IGNORE); #endif - ModuleBase::timer::tick("ModuleIO", "write_psi_r_1"); - } - // processes output pipeline: - // - // t0 t1 t2 t3 t4 t5 t6 t7 - // --------------------------------> - // rank0 k0 k1 k2 k3 k4 k5 - // \ \ \ \ \ \ + ModuleBase::timer::tick("ModuleIO", "write_psi_r_1"); +} +// processes output pipeline: +// +// t0 t1 t2 t3 t4 t5 t6 t7 +// --------------------------------> +// rank0 k0 k1 k2 k3 k4 k5 +// \ \ \ \ \ \ // rank1 k0 k1 k2 k3 k4 k5 - // \ \ \ \ \ \ +// \ \ \ \ \ \ // rank2 k0 k1 k2 k3 k4 k5 - // Input: wfc_g(ib,ig) - // Output: wfc_r[ir] - std::vector> cal_wfc_r(const ModulePW::PW_Basis_K* wfcpw, - const psi::Psi>& wfc_g, - const int ik, - const int ib) - { - ModuleBase::timer::tick("ModuleIO", "cal_wfc_r"); +// Input: wfc_g(ib,ig) +// Output: wfc_r[ir] +std::vector> cal_wfc_r(const ModulePW::PW_Basis_K* wfcpw, + const psi::Psi>& wfc_g, + const int ik, + const int ib) +{ + ModuleBase::timer::tick("ModuleIO", "cal_wfc_r"); - std::vector> wfc_r(wfcpw->nrxx); - wfcpw->recip2real(&wfc_g(ib, 0), wfc_r.data(), ik); + std::vector> wfc_r(wfcpw->nrxx); + wfcpw->recip2real(&wfc_g(ib, 0), wfc_r.data(), ik); - ModuleBase::timer::tick("ModuleIO", "cal_wfc_r"); - return wfc_r; - } + ModuleBase::timer::tick("ModuleIO", "cal_wfc_r"); + return wfc_r; +} - // Input: chg_r[ir] +// Input: chg_r[ir] #ifdef __MPI - void write_chg_r_1(const ModulePW::PW_Basis_K* wfcpw, - const std::vector& chg_r, - const std::string& file_name, - MPI_Request& mpi_request) +void write_chg_r_1(const ModulePW::PW_Basis_K* wfcpw, + const std::vector& chg_r, + const std::string& file_name, + MPI_Request& mpi_request) #else - void write_chg_r_1(const ModulePW::PW_Basis_K* wfcpw, - const std::vector& chg_r, - const std::string& file_name) +void write_chg_r_1(const ModulePW::PW_Basis_K* wfcpw, const std::vector& chg_r, const std::string& file_name) #endif - { - ModuleBase::timer::tick("ModuleIO", "write_chg_r_1"); - std::ofstream ofs; - -#ifdef __MPI - constexpr int mpi_tag=100; - if(GlobalV::RANK_IN_POOL==0) - { +{ + ModuleBase::timer::tick("ModuleIO", "write_chg_r_1"); + std::ofstream ofs; + +#ifdef __MPI + constexpr int mpi_tag = 100; + if (GlobalV::RANK_IN_POOL == 0) + { #endif - ofs.open(file_name); - - ofs<<"calculated by ABACUS"<nx<<" "<ny<<" "<nz<nx << " " << wfcpw->ny << " " << wfcpw->nz << std::endl; +#ifdef __MPI + } + else + { + char recv_tmp; + MPI_Recv(&recv_tmp, 1, MPI_CHAR, GlobalV::RANK_IN_POOL - 1, mpi_tag, POOL_WORLD, MPI_STATUS_IGNORE); + + ofs.open(file_name, std::ofstream::app); + } #endif - assert(wfcpw->nx * wfcpw->ny * wfcpw->nplane == chg_r.size()); - for(int iz=0; iznplane; ++iz) - { - for(int iy=0; iyny; ++iy) - { - for(int ix=0; ixnx; ++ix) - { - const int ir = (ix*wfcpw->ny+iy)*wfcpw->nplane+iz; - ofs<nx * wfcpw->ny * wfcpw->nplane == chg_r.size()); + for (int iz = 0; iz < wfcpw->nplane; ++iz) + { + for (int iy = 0; iy < wfcpw->ny; ++iy) + { + for (int ix = 0; ix < wfcpw->nx; ++ix) + { + const int ir = (ix * wfcpw->ny + iy) * wfcpw->nplane + iz; + ofs << chg_r[ir] << " "; + } + ofs << "\n"; + } + } + ofs.close(); + +#ifdef __MPI + if (GlobalV::RANK_IN_POOL < GlobalV::NPROC_IN_POOL - 1) + { + const char send_tmp = 'c'; + MPI_Isend(&send_tmp, 1, MPI_CHAR, GlobalV::RANK_IN_POOL + 1, mpi_tag, POOL_WORLD, &mpi_request); + } + else + { + mpi_request = MPI_REQUEST_NULL; + } #endif - ModuleBase::timer::tick("ModuleIO", "write_chg_r_1"); - } -}; + ModuleBase::timer::tick("ModuleIO", "write_chg_r_1"); +} +}; // namespace ModuleIO diff --git a/source/module_lr/AX/AX.h b/source/module_lr/AX/AX.h index 360a4c9cec5..36a6d5aebdb 100644 --- a/source/module_lr/AX/AX.h +++ b/source/module_lr/AX/AX.h @@ -13,13 +13,13 @@ namespace LR const psi::Psi& c, const int& nocc, const int& nvirt, - psi::Psi& AX_istate); + double* AX_istate); void cal_AX_blas( const std::vector& V_istate, const psi::Psi& c, const int& nocc, const int& nvirt, - psi::Psi& AX_istate, + double* AX_istate, const bool add_on = true); #ifdef __MPI void cal_AX_pblas( @@ -27,11 +27,11 @@ namespace LR const Parallel_2D& pmat, const psi::Psi& c, const Parallel_2D& pc, - int naos, - int nocc, - int nvirt, - Parallel_2D& pX, - psi::Psi& AX_istate, + const int& naos, + const int& nocc, + const int& nvirt, + const Parallel_2D& pX, + double* AX_istate, const bool add_on=true); #endif // complex @@ -40,13 +40,13 @@ namespace LR const psi::Psi>& c, const int& nocc, const int& nvirt, - psi::Psi>& AX_istate); + std::complex* AX_istate); void cal_AX_blas( const std::vector& V_istate, const psi::Psi>& c, const int& nocc, const int& nvirt, - psi::Psi>& AX_istate, + std::complex* AX_istate, const bool add_on = true); #ifdef __MPI @@ -55,11 +55,11 @@ namespace LR const Parallel_2D& pmat, const psi::Psi>& c, const Parallel_2D& pc, - int naos, - int nocc, - int nvirt, - Parallel_2D& pX, - psi::Psi>& AX_istate, + const int& naos, + const int& nocc, + const int& nvirt, + const Parallel_2D& pX, + std::complex* AX_istate, const bool add_on = true); #endif } \ No newline at end of file diff --git a/source/module_lr/AX/AX_parallel.cpp b/source/module_lr/AX/AX_parallel.cpp index 2b390e431ad..221962416e3 100644 --- a/source/module_lr/AX/AX_parallel.cpp +++ b/source/module_lr/AX/AX_parallel.cpp @@ -14,20 +14,17 @@ namespace LR const Parallel_2D& pmat, const psi::Psi& c, const Parallel_2D& pc, - int naos, - int nocc, - int nvirt, - Parallel_2D& pX, - psi::Psi& AX_istate, + const int& naos, + const int& nocc, + const int& nvirt, + const Parallel_2D& pX, + double* AX_istate, const bool add_on) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_pblas"); - assert(pmat.comm() == pc.comm()); - assert(pmat.blacs_ctxt == pc.blacs_ctxt); - - if (pX.comm() != pmat.comm() || pX.blacs_ctxt != pmat.blacs_ctxt) - LR_Util::setup_2d_division(pX, pmat.get_block_size(), nvirt, nocc, pmat.blacs_ctxt); - else assert(pX.get_local_size() > 0 && AX_istate.get_nbasis() == pX.get_local_size()); + assert(pmat.comm() == pc.comm() && pmat.comm() == pX.comm()); + assert(pmat.blacs_ctxt == pc.blacs_ctxt && pmat.blacs_ctxt == pX.blacs_ctxt); + assert(pX.get_local_size() > 0); const int nks = V_istate.size(); @@ -35,7 +32,7 @@ namespace LR LR_Util::setup_2d_division(pVc, pmat.get_block_size(), naos, nocc, pmat.blacs_ctxt); for (int isk = 0;isk < nks;++isk) { - AX_istate.fix_k(isk); + const int ax_start = isk * pX.get_local_size(); c.fix_k(isk); //Vc @@ -60,7 +57,7 @@ namespace LR pdgemm_(&transa, &transb, &nvirt, &nocc, &naos, &alpha, c.get_pointer(), &i1, &ivirt, pc.desc, Vc.data(), &i1, &i1, pVc.desc, - &beta, AX_istate.get_pointer(), &i1, &i1, pX.desc); + &beta, AX_istate + ax_start, &i1, &i1, pX.desc); } } @@ -70,20 +67,17 @@ namespace LR const Parallel_2D& pmat, const psi::Psi>& c, const Parallel_2D& pc, - int naos, - int nocc, - int nvirt, - Parallel_2D& pX, - psi::Psi>& AX_istate, + const int& naos, + const int& nocc, + const int& nvirt, + const Parallel_2D& pX, + std::complex* AX_istate, const bool add_on) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_plas"); - assert(pmat.comm() == pc.comm()); - assert(pmat.blacs_ctxt == pc.blacs_ctxt); - - if (pX.comm() != pmat.comm() || pX.blacs_ctxt != pmat.blacs_ctxt) - LR_Util::setup_2d_division(pX, pmat.get_block_size(), nvirt, nocc, pmat.blacs_ctxt); - else assert(pX.get_local_size() > 0 && AX_istate.get_nbasis() == pX.get_local_size()); + assert(pmat.comm() == pc.comm() && pmat.comm() == pX.comm()); + assert(pmat.blacs_ctxt == pc.blacs_ctxt && pmat.blacs_ctxt == pX.blacs_ctxt); + assert(pX.get_local_size() > 0); const int nks = V_istate.size(); @@ -91,7 +85,7 @@ namespace LR LR_Util::setup_2d_division(pVc, pmat.get_block_size(), naos, nocc, pmat.blacs_ctxt); for (int isk = 0;isk < nks;++isk) { - AX_istate.fix_k(isk); + const int ax_start = isk * pX.get_local_size(); c.fix_k(isk); //Vc @@ -116,7 +110,7 @@ namespace LR pzgemm_(&transa, &transb, &nvirt, &nocc, &naos, &alpha, c.get_pointer(), &i1, &ivirt, pc.desc, Vc.data>(), &i1, &i1, pVc.desc, - &beta, AX_istate.get_pointer(), &i1, &i1, pX.desc); + &beta, AX_istate + ax_start, &i1, &i1, pX.desc); } } } diff --git a/source/module_lr/AX/AX_serial.cpp b/source/module_lr/AX/AX_serial.cpp index 019fd459288..abe990e5ffd 100644 --- a/source/module_lr/AX/AX_serial.cpp +++ b/source/module_lr/AX/AX_serial.cpp @@ -9,18 +9,17 @@ namespace LR const psi::Psi& c, const int& nocc, const int& nvirt, - psi::Psi& AX_istate) + double* AX_istate) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_forloop"); const int nks = V_istate.size(); int naos = c.get_nbasis(); - AX_istate.fix_k(0); - ModuleBase::GlobalFunc::ZEROS(AX_istate.get_pointer(), nks * nocc * nvirt); + ModuleBase::GlobalFunc::ZEROS(AX_istate, nks * nocc * nvirt); for (int isk = 0;isk < nks;++isk) { c.fix_k(isk); - AX_istate.fix_k(isk); + const int ax_start = isk * nocc * nvirt; for (int i = 0;i < nocc;++i) { for (int a = 0;a < nvirt;++a) @@ -29,7 +28,7 @@ namespace LR { for (int mu = 0;mu < naos;++mu) { - AX_istate(i * nvirt + a) += c(nocc + a, mu) * V_istate[isk].data()[nu * naos + mu] * c(i, nu); + AX_istate[ax_start + i * nvirt + a] += c(nocc + a, mu) * V_istate[isk].data()[nu * naos + mu] * c(i, nu); } } } @@ -41,18 +40,17 @@ namespace LR const psi::Psi>& c, const int& nocc, const int& nvirt, - psi::Psi>& AX_istate) + std::complex* AX_istate) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_forloop"); const int nks = V_istate.size(); int naos = c.get_nbasis(); - AX_istate.fix_k(0); - ModuleBase::GlobalFunc::ZEROS(AX_istate.get_pointer(), nks * nocc * nvirt); + ModuleBase::GlobalFunc::ZEROS(AX_istate, nks * nocc * nvirt); for (int isk = 0;isk < nks;++isk) { c.fix_k(isk); - AX_istate.fix_k(isk); + const int ax_start = isk * nocc * nvirt; for (int i = 0;i < nocc;++i) { for (int a = 0;a < nvirt;++a) @@ -61,7 +59,7 @@ namespace LR { for (int mu = 0;mu < naos;++mu) { - AX_istate(i * nvirt + a) += std::conj(c(nocc + a, mu)) * V_istate[isk].data>()[nu * naos + mu] * c(i, nu); + AX_istate[ax_start + i * nvirt + a] += std::conj(c(nocc + a, mu)) * V_istate[isk].data>()[nu * naos + mu] * c(i, nu); } } } @@ -74,7 +72,7 @@ namespace LR const psi::Psi& c, const int& nocc, const int& nvirt, - psi::Psi& AX_istate, + double* AX_istate, const bool add_on) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_blas"); @@ -84,7 +82,7 @@ namespace LR for (int isk = 0;isk < nks;++isk) { c.fix_k(isk); - AX_istate.fix_k(isk); + const int ax_start = isk * nocc * nvirt; // Vc[naos*nocc] container::Tensor Vc(DAT::DT_DOUBLE, DEV::CpuDevice, { nocc, naos });// (Vc)^T @@ -101,7 +99,7 @@ namespace LR //AX_istate=c^TVc (nvirt major) dgemm_(&transa, &transb, &nvirt, &nocc, &naos, &alpha, c.get_pointer(nocc), &naos, Vc.data(), &naos, &beta, - AX_istate.get_pointer(), &nvirt); + AX_istate + ax_start, &nvirt); } } void cal_AX_blas( @@ -109,7 +107,7 @@ namespace LR const psi::Psi>& c, const int& nocc, const int& nvirt, - psi::Psi>& AX_istate, + std::complex* AX_istate, const bool add_on) { ModuleBase::TITLE("hamilt_lrtd", "cal_AX_blas"); @@ -119,7 +117,7 @@ namespace LR for (int isk = 0;isk < nks;++isk) { c.fix_k(isk); - AX_istate.fix_k(isk); + const int ax_start = isk * nocc * nvirt; // Vc[naos*nocc] (V is hermitian) container::Tensor Vc(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { nocc, naos });// (Vc)^T @@ -136,7 +134,7 @@ namespace LR //AX_istate=c^\dagger Vc (nvirt major) zgemm_(&transa, &transb, &nvirt, &nocc, &naos, &alpha, c.get_pointer(nocc), &naos, Vc.data>(), &naos, &beta, - AX_istate.get_pointer(), &nvirt); + AX_istate + ax_start, &nvirt); } } } \ No newline at end of file diff --git a/source/module_lr/AX/test/AX_test.cpp b/source/module_lr/AX/test/AX_test.cpp index 92ed30f7e94..d7b4b5115e6 100644 --- a/source/module_lr/AX/test/AX_test.cpp +++ b/source/module_lr/AX/test/AX_test.cpp @@ -4,6 +4,7 @@ #include "module_lr/utils/lr_util.h" +#define rand01 (static_cast(rand()) / static_cast(RAND_MAX) - 0.5 ) struct matsize { int nks = 1; @@ -23,7 +24,7 @@ class AXTest : public testing::Test std::vector sizes{ // {2, 3, 2, 1}, {2, 13, 7, 4}, - {2, 14, 8, 5} + // {2, 14, 8, 5} }; int nstate = 2; std::ofstream ofs_running; @@ -41,18 +42,12 @@ class AXTest : public testing::Test } #endif - void set_ones(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = 1.0; -}}; - void set_int(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = static_cast(i + 1); -}}; - void set_int(std::complex* data, int size) { for (int i = 0;i < size;++i) { data[i] = std::complex(i + 1, -i - 1); -}}; - void set_rand(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = double(rand()) / double(RAND_MAX) * 10.0 - 5.0; -}}; - void set_rand(std::complex* data, int size) { for (int i = 0;i < size;++i) { data[i] = std::complex(rand(), rand()) / double(RAND_MAX) * 10.0 - 5.0; -}}; - void check_eq(double* data1, double* data2, int size) { for (int i = 0;i < size;++i) { EXPECT_NEAR(data1[i], data2[i], 1e-10); -}}; + void set_ones(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = 1.0; } }; + void set_int(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = static_cast(i + 1); } }; + void set_int(std::complex* data, int size) { for (int i = 0;i < size;++i) { data[i] = std::complex(i + 1, -i - 1); } }; + void set_rand(double* data, int size) { for (int i = 0;i < size;++i) { data[i] = rand01 * 10; } }; + void set_rand(std::complex* data, int size) { for (int i = 0;i < size;++i) { data[i] = std::complex(rand01 * 10, rand01 * 10); } }; + void check_eq(double* data1, double* data2, int size) { for (int i = 0;i < size;++i) { EXPECT_NEAR(data1[i], data2[i], 1e-10); } }; void check_eq(std::complex* data1, std::complex* data2, int size) { for (int i = 0;i < size;++i) @@ -75,17 +70,12 @@ TEST_F(AXTest, DoubleSerial) { psi::Psi c(s.nks, s.nocc + s.nvirt, s.naos); std::vector V(s.nks, container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); - set_rand(c.get_pointer(), size_c); - for (auto& v : V) {set_rand(v.data(), size_v); -} - AX_for.fix_b(istate); - AX_blas.fix_b(istate); - LR::cal_AX_forloop_serial(V, c, s.nocc, s.nvirt, AX_for); - LR::cal_AX_blas(V, c, s.nocc, s.nvirt, AX_blas, false); + set_rand(&c(0, 0, 0), size_c); + for (auto& v : V) { set_rand(v.data(), size_v); } + LR::cal_AX_forloop_serial(V, c, s.nocc, s.nvirt, &AX_for(istate, 0, 0)); + LR::cal_AX_blas(V, c, s.nocc, s.nvirt, &AX_blas(istate, 0, 0), false); } - AX_for.fix_b(0); - AX_blas.fix_b(0); - check_eq(AX_for.get_pointer(), AX_blas.get_pointer(), nstate * s.nks * s.nocc * s.nvirt); + check_eq(&AX_for(0, 0, 0), &AX_blas(0, 0, 0), nstate * s.nks * s.nocc * s.nvirt); } } @@ -101,17 +91,12 @@ TEST_F(AXTest, ComplexSerial) { psi::Psi> c(s.nks, s.nocc + s.nvirt, s.naos); std::vector V(s.nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); - set_rand(c.get_pointer(), size_c); - for (auto& v : V) {set_rand(v.data>(), size_v); -} - AX_for.fix_b(istate); - AX_blas.fix_b(istate); - LR::cal_AX_forloop_serial(V, c, s.nocc, s.nvirt, AX_for); - LR::cal_AX_blas(V, c, s.nocc, s.nvirt, AX_blas, false); + set_rand(&c(0, 0, 0), size_c); + for (auto& v : V) { set_rand(v.data>(), size_v); } + LR::cal_AX_forloop_serial(V, c, s.nocc, s.nvirt, &AX_for(istate, 0, 0)); + LR::cal_AX_blas(V, c, s.nocc, s.nvirt, &AX_blas(istate, 0, 0), false); } - AX_for.fix_b(0); - AX_blas.fix_b(0); - check_eq(AX_for.get_pointer(), AX_blas.get_pointer(), nstate * s.nks * s.nocc * s.nvirt); + check_eq(&AX_for(0, 0, 0), &AX_blas(0, 0, 0), nstate * s.nks * s.nocc * s.nvirt); } } #ifdef __MPI @@ -135,25 +120,20 @@ TEST_F(AXTest, DoubleParallel) EXPECT_GE(s.nvirt, px.dim0); EXPECT_GE(s.nocc, px.dim1); EXPECT_GE(s.naos, pc.dim0); - psi::Psi AX_pblas_loc(s.nks, nstate, px.get_local_size()); + psi::Psi AX_pblas_loc(s.nks, nstate, px.get_local_size(), nullptr, false); psi::Psi AX_gather(s.nks, nstate, s.nocc * s.nvirt, nullptr, false); for (int istate = 0;istate < nstate;++istate) { for (int isk = 0;isk < s.nks;++isk) { set_rand(V.at(isk).data(), pV.get_local_size()); - c.fix_k(isk); - set_rand(c.get_pointer(), pc.get_local_size()); + set_rand(&c(isk, 0, 0), pc.get_local_size()); } - AX_pblas_loc.fix_b(istate); - AX_gather.fix_b(istate); - LR::cal_AX_pblas(V, pV, c, pc, s.naos, s.nocc, s.nvirt, px, AX_pblas_loc, false); + LR::cal_AX_pblas(V, pV, c, pc, s.naos, s.nocc, s.nvirt, px, &AX_pblas_loc(istate, 0, 0), false); // gather AX and output for (int isk = 0;isk < s.nks;++isk) { - AX_pblas_loc.fix_k(isk); - AX_gather.fix_k(isk); - LR_Util::gather_2d_to_full(px, AX_pblas_loc.get_pointer(), AX_gather.get_pointer(), false/*pblas: row first*/, s.nvirt, s.nocc); + LR_Util::gather_2d_to_full(px, &AX_pblas_loc(istate, isk, 0), &AX_gather(istate, isk, 0), false/*pblas: row first*/, s.nvirt, s.nocc); } // compare to global AX std::vector V_full(s.nks, container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); @@ -161,17 +141,13 @@ TEST_F(AXTest, DoubleParallel) for (int isk = 0;isk < s.nks;++isk) { LR_Util::gather_2d_to_full(pV, V.at(isk).data(), V_full.at(isk).data(), false, s.naos, s.naos); - c.fix_k(isk); - c_full.fix_k(isk); - LR_Util::gather_2d_to_full(pc, c.get_pointer(), c_full.get_pointer(), false, s.naos, s.nocc + s.nvirt); + LR_Util::gather_2d_to_full(pc, &c(isk, 0, 0), &c_full(isk, 0, 0), false, s.naos, s.nocc + s.nvirt); } if (my_rank == 0) { psi::Psi AX_full_istate(s.nks, 1, s.nocc * s.nvirt, nullptr, false); - LR::cal_AX_blas(V_full, c_full, s.nocc, s.nvirt, AX_full_istate, false); - AX_full_istate.fix_b(0); - AX_gather.fix_b(istate); - check_eq(AX_full_istate.get_pointer(), AX_gather.get_pointer(), s.nks * s.nocc * s.nvirt); + LR::cal_AX_blas(V_full, c_full, s.nocc, s.nvirt, &AX_full_istate(0, 0, 0), false); + check_eq(&AX_full_istate(0, 0, 0), &AX_gather(istate, 0, 0), s.nks * s.nocc * s.nvirt); } } } @@ -191,26 +167,21 @@ TEST_F(AXTest, ComplexParallel) Parallel_2D px; LR_Util::setup_2d_division(px, s.nb, s.nvirt, s.nocc, pV.blacs_ctxt); - psi::Psi> AX_pblas_loc(s.nks, nstate, px.get_local_size()); + psi::Psi> AX_pblas_loc(s.nks, nstate, px.get_local_size(), nullptr, false); psi::Psi> AX_gather(s.nks, nstate, s.nocc * s.nvirt, nullptr, false); for (int istate = 0;istate < nstate;++istate) { for (int isk = 0;isk < s.nks;++isk) { set_rand(V.at(isk).data>(), pV.get_local_size()); - c.fix_k(isk); - set_rand(c.get_pointer(), pc.get_local_size()); + set_rand(&c(isk, 0, 0), pc.get_local_size()); } - AX_pblas_loc.fix_b(istate); - AX_gather.fix_b(istate); - LR::cal_AX_pblas(V, pV, c, pc, s.naos, s.nocc, s.nvirt, px, AX_pblas_loc, false); + LR::cal_AX_pblas(V, pV, c, pc, s.naos, s.nocc, s.nvirt, px, &AX_pblas_loc(istate, 0, 0), false); // gather AX and output for (int isk = 0;isk < s.nks;++isk) { - AX_pblas_loc.fix_k(isk); - AX_gather.fix_k(isk); - LR_Util::gather_2d_to_full(px, AX_pblas_loc.get_pointer(), AX_gather.get_pointer(), false/*pblas: row first*/, s.nvirt, s.nocc); + LR_Util::gather_2d_to_full(px, &AX_pblas_loc(istate, isk, 0), &AX_gather(istate, isk, 0), false/*pblas: row first*/, s.nvirt, s.nocc); } // compare to global AX std::vector V_full(s.nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); @@ -218,17 +189,13 @@ TEST_F(AXTest, ComplexParallel) for (int isk = 0;isk < s.nks;++isk) { LR_Util::gather_2d_to_full(pV, V.at(isk).data>(), V_full.at(isk).data>(), false, s.naos, s.naos); - c.fix_k(isk); - c_full.fix_k(isk); - LR_Util::gather_2d_to_full(pc, c.get_pointer(), c_full.get_pointer(), false, s.naos, s.nocc + s.nvirt); + LR_Util::gather_2d_to_full(pc, &c(isk, 0, 0), &c_full(isk, 0, 0), false, s.naos, s.nocc + s.nvirt); } if (my_rank == 0) { psi::Psi> AX_full_istate(s.nks, 1, s.nocc * s.nvirt, nullptr, false); - LR::cal_AX_blas(V_full, c_full, s.nocc, s.nvirt, AX_full_istate, false); - AX_full_istate.fix_b(0); - AX_gather.fix_b(istate); - check_eq(AX_full_istate.get_pointer(), AX_gather.get_pointer(), s.nks * s.nocc * s.nvirt); + LR::cal_AX_blas(V_full, c_full, s.nocc, s.nvirt, &AX_full_istate(0, 0, 0), false); + check_eq(&AX_full_istate(0, 0, 0), &AX_gather(istate, 0, 0), s.nks * s.nocc * s.nvirt); } } } diff --git a/source/module_lr/CMakeLists.txt b/source/module_lr/CMakeLists.txt index 12743eef8fe..4b816f09b3d 100644 --- a/source/module_lr/CMakeLists.txt +++ b/source/module_lr/CMakeLists.txt @@ -15,7 +15,6 @@ if(ENABLE_LCAO) operator_casida/operator_lr_hxc.cpp operator_casida/operator_lr_exx.cpp potentials/pot_hxc_lrtd.cpp - hsolver_lrtd.cpp lr_spectrum.cpp hamilt_casida.cpp esolver_lrtd_lcao.cpp) diff --git a/source/module_lr/dm_trans/dm_trans.h b/source/module_lr/dm_trans/dm_trans.h index a3fdee29387..283d22149ca 100644 --- a/source/module_lr/dm_trans/dm_trans.h +++ b/source/module_lr/dm_trans/dm_trans.h @@ -14,14 +14,14 @@ namespace LR /// \f[ \tilde{\rho}_{\mu_j\mu_b}=\sum_{jb}c_{j,\mu_j}X_{jb}c^*_{b,\mu_b} \f] template std::vector cal_dm_trans_pblas( - const psi::Psi& X_istate, + const T* X_istate, const Parallel_2D& px, const psi::Psi& c, const Parallel_2D& pc, const int naos, const int nocc, const int nvirt, - Parallel_2D& pmat, + const Parallel_2D& pmat, const bool renorm_k = true, const int nspin = 1); #endif @@ -29,7 +29,7 @@ namespace LR /// @brief calculate the 2d-block transition density matrix in AO basis using ?gemm template std::vector cal_dm_trans_blas( - const psi::Psi& X_istate, + const T* X_istate, const psi::Psi& c, const int& nocc, const int& nvirt, const bool renorm_k = true, @@ -39,7 +39,7 @@ namespace LR /// @brief calculate the 2d-block transition density matrix in AO basis using for loop (for test) template std::vector cal_dm_trans_forloop_serial( - const psi::Psi& X_istate, + const T* X_istate, const psi::Psi& c, const int& nocc, const int& nvirt, const bool renorm_k = true, diff --git a/source/module_lr/dm_trans/dm_trans_parallel.cpp b/source/module_lr/dm_trans/dm_trans_parallel.cpp index 68123bf74ca..a21a95c8ee1 100644 --- a/source/module_lr/dm_trans/dm_trans_parallel.cpp +++ b/source/module_lr/dm_trans/dm_trans_parallel.cpp @@ -10,36 +10,30 @@ namespace LR // c: nao*nbands in para2d, nbands*nao in psi (row-para and constructed: nao) // X: nvirt*nocc in para2d, nocc*nvirt in psi (row-para and constructed: nvirt) template <> -std::vector cal_dm_trans_pblas(const psi::Psi& X_istate, - const Parallel_2D& px, - const psi::Psi& c, - const Parallel_2D& pc, - const int naos, - const int nocc, - const int nvirt, - Parallel_2D& pmat, - const bool renorm_k, - const int nspin) +std::vector cal_dm_trans_pblas(const double* X_istate, + const Parallel_2D& px, + const psi::Psi& c, + const Parallel_2D& pc, + const int naos, + const int nocc, + const int nvirt, + const Parallel_2D& pmat, + const bool renorm_k, + const int nspin) { ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_pblas"); - assert(px.comm() == pc.comm()); - assert(px.blacs_ctxt == pc.blacs_ctxt); + assert(px.comm() == pc.comm() && px.comm() == pmat.comm()); + assert(px.blacs_ctxt == pc.blacs_ctxt && px.blacs_ctxt == pmat.blacs_ctxt); + assert(pmat.get_local_size() > 0); - if (pmat.comm() != px.comm() || pmat.blacs_ctxt != px.blacs_ctxt) { - LR_Util::setup_2d_division(pmat, px.get_block_size(), naos, naos, px.blacs_ctxt); - } else { - assert(pmat.get_local_size() > 0); -} - - const int nks = X_istate.get_nk(); + const int nks = c.get_nk(); - std::vector dm_trans( - nks, - container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, {pmat.get_col_size(), pmat.get_row_size()})); + std::vector dm_trans(nks, + container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { pmat.get_col_size(), pmat.get_row_size() })); for (int isk = 0; isk < nks; ++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * px.get_local_size(); int i1 = 1; int ivirt = nocc + 1; char transa = 'N'; @@ -54,79 +48,43 @@ std::vector cal_dm_trans_pblas(const psi::Psi& X_ista DEV::CpuDevice, {pXc.get_col_size(), pXc.get_row_size()}); // row is "inside"(memory contiguity) for pblas Xc.zero(); - pdgemm_(&transa, - &transb, - &naos, - &nvirt, - &nocc, - &alpha, - c.get_pointer(), - &i1, - &i1, - pc.desc, - X_istate.get_pointer(), - &i1, - &i1, - px.desc, - &beta, - Xc.data(), - &i1, - &i1, - pXc.desc); + pdgemm_(&transa, &transb, &naos, &nvirt, &nocc, + &alpha, c.get_pointer(), &i1, &i1, pc.desc, + X_istate + x_start, &i1, &i1, px.desc, + &beta, Xc.data(), &i1, &i1, pXc.desc); // 2. C_virt*[X*C_occ^T] - pdgemm_(&transa, - &transb, - &naos, - &naos, - &nvirt, - &alpha, - c.get_pointer(), - &i1, - &ivirt, - pc.desc, - Xc.data(), - &i1, - &i1, - pXc.desc, - &beta, - dm_trans[isk].data(), - &i1, - &i1, - pmat.desc); + pdgemm_(&transa, &transb, &naos, &naos, &nvirt, + &alpha, c.get_pointer(), &i1, &ivirt, pc.desc, + Xc.data(), &i1, &i1, pXc.desc, + &beta, dm_trans[isk].data(), &i1, &i1, pmat.desc); } return dm_trans; } template <> -std::vector cal_dm_trans_pblas(const psi::Psi>& X_istate, - const Parallel_2D& px, - const psi::Psi>& c, - const Parallel_2D& pc, - const int naos, - const int nocc, - const int nvirt, - Parallel_2D& pmat, - const bool renorm_k, - const int nspin) +std::vector cal_dm_trans_pblas(const std::complex* X_istate, + const Parallel_2D& px, + const psi::Psi>& c, + const Parallel_2D& pc, + const int naos, + const int nocc, + const int nvirt, + const Parallel_2D& pmat, + const bool renorm_k, + const int nspin) { ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_pblas"); - assert(px.comm() == pc.comm()); - assert(px.blacs_ctxt == pc.blacs_ctxt); - - if (pmat.comm() != px.comm() || pmat.blacs_ctxt != px.blacs_ctxt) { - LR_Util::setup_2d_division(pmat, px.get_block_size(), naos, naos, px.blacs_ctxt); - } else { - assert(pmat.get_local_size() > 0); -} - const int nks = X_istate.get_nk(); + assert(px.comm() == pc.comm() && px.comm() == pmat.comm()); + assert(px.blacs_ctxt == pc.blacs_ctxt && px.blacs_ctxt == pmat.blacs_ctxt); + assert(pmat.get_local_size() > 0); + const int nks = c.get_nk(); - std::vector dm_trans( - nks, + std::vector dm_trans(nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, {pmat.get_col_size(), pmat.get_row_size()})); for (int isk = 0; isk < nks; ++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * px.get_local_size(); int i1 = 1; int ivirt = nocc + 1; @@ -141,7 +99,7 @@ std::vector cal_dm_trans_pblas(const psi::Psi beta(0.0, 0.0); // pzgemm_(&transa, &transb, &naos, &nvirt, &nocc, // &alpha, c.get_pointer(), &i1, &i1, pc.desc, - // X_istate.get_pointer(), &i1, &i1, px.desc, + // X_istate + x_start, &i1, &i1, px.desc, // &beta, Xc.data>(), &i1, &i1, pXc.desc); // // 2. C_virt*[X*C_occ^\dagger] @@ -163,48 +121,18 @@ std::vector cal_dm_trans_pblas(const psi::Psi alpha(1.0, 0.0); const std::complex beta(0.0, 0.0); - pzgemm_(&transa, - &transb, - &nvirt, - &naos, - &nocc, - &alpha, - X_istate.get_pointer(), - &i1, - &i1, - px.desc, - c.get_pointer(), - &i1, - &i1, - pc.desc, - &beta, - Xc.data>(), - &i1, - &i1, - pXc.desc); + pzgemm_(&transa, &transb, &nvirt, &naos, &nocc, &alpha, + X_istate + x_start, &i1, &i1, px.desc, + c.get_pointer(), &i1, &i1, pc.desc, + &beta, Xc.data>(), &i1, &i1, pXc.desc); // 2. [X*C_occ^\dagger]^TC_virt^T alpha.real(renorm_k ? 1.0 / static_cast(nks) : 1.0); transa = transb = 'T'; - pzgemm_(&transa, - &transb, - &naos, - &naos, - &nvirt, - &alpha, - Xc.data>(), - &i1, - &i1, - pXc.desc, - c.get_pointer(), - &i1, - &ivirt, - pc.desc, - &beta, - dm_trans[isk].data>(), - &i1, - &i1, - pmat.desc); + pzgemm_(&transa, &transb, &naos, &naos, &nvirt, + &alpha, Xc.data>(), &i1, &i1, pXc.desc, + c.get_pointer(), &i1, &ivirt, pc.desc, + &beta, dm_trans[isk].data>(), &i1, &i1, pmat.desc); } return dm_trans; } diff --git a/source/module_lr/dm_trans/dm_trans_serial.cpp b/source/module_lr/dm_trans/dm_trans_serial.cpp index cbdd63a6c86..70dc6e6542f 100644 --- a/source/module_lr/dm_trans/dm_trans_serial.cpp +++ b/source/module_lr/dm_trans/dm_trans_serial.cpp @@ -6,7 +6,7 @@ namespace LR { template<> std::vector cal_dm_trans_forloop_serial( - const psi::Psi& X_istate, + const double* X_istate, const psi::Psi& c, const int& nocc, const int& nvirt, @@ -15,16 +15,15 @@ namespace LR { // cxc_out_test(X_istate, c); ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_forloop"); - const int nks = X_istate.get_nk(); - assert(nocc * nvirt == X_istate.get_nbasis()); - int naos = c.get_nbasis(); + const int nks = c.get_nk(); + const int naos = c.get_nbasis(); std::vector dm_trans(nks, container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { naos, naos })); for (auto& dm : dm_trans)ModuleBase::GlobalFunc::ZEROS(dm.data(), naos * naos); // loop for AOs for (size_t isk = 0;isk < nks;++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * nocc * nvirt; for (size_t mu = 0;mu < naos;++mu) { for (size_t nu = 0;nu < naos;++nu) @@ -33,7 +32,7 @@ namespace LR for (size_t j = 0;j < nocc;++j) { for (size_t b = 0; b < nvirt;++b) - dm_trans[isk].data()[mu * naos + nu] += c(j, mu) * X_istate(j * nvirt + b) * c(nocc + b, nu); + dm_trans[isk].data()[mu * naos + nu] += c(j, mu) * X_istate[x_start + j * nvirt + b] * c(nocc + b, nu); } } } @@ -42,7 +41,7 @@ namespace LR } template<> std::vector cal_dm_trans_forloop_serial( - const psi::Psi>& X_istate, + const std::complex* X_istate, const psi::Psi>& c, const int& nocc, const int& nvirt, @@ -51,8 +50,7 @@ namespace LR { // cxc_out_test(X_istate, c); ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_forloop"); - const int nks = X_istate.get_nk(); - assert(nocc * nvirt == X_istate.get_nbasis()); + const int nks = c.get_nk(); int naos = c.get_nbasis(); std::vector dm_trans(nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { naos, naos })); for (auto& dm : dm_trans)ModuleBase::GlobalFunc::ZEROS(dm.data>(), naos * naos); @@ -60,7 +58,7 @@ namespace LR for (size_t isk = 0;isk < nks;++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * nocc * nvirt; for (size_t mu = 0;mu < naos;++mu) { for (size_t nu = 0;nu < naos;++nu) @@ -70,7 +68,7 @@ namespace LR { for (size_t b = 0; b < nvirt;++b) dm_trans[isk].data>()[nu * naos + mu] += - std::conj(c(j, mu)) * X_istate(j * nvirt + b) * c(nocc + b, nu) / static_cast(nks / nspin); + std::conj(c(j, mu)) * X_istate[x_start + j * nvirt + b] * c(nocc + b, nu) / static_cast(nks / nspin); } } } @@ -80,7 +78,7 @@ namespace LR template<> std::vector cal_dm_trans_blas( - const psi::Psi& X_istate, + const double* X_istate, const psi::Psi& c, const int& nocc, const int& nvirt, @@ -88,14 +86,13 @@ namespace LR const int nspin) { ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_blas"); - const int nks = X_istate.get_nk(); - assert(nocc * nvirt == X_istate.get_nbasis()); + const int nks = c.get_nk(); int naos = c.get_nbasis(); std::vector dm_trans(nks, container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { naos, naos })); for (size_t isk = 0;isk < nks;++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * nocc * nvirt; // 1. [X*C_occ^T]^T=C_occ*X^T char transa = 'N'; char transb = 'T'; @@ -103,7 +100,7 @@ namespace LR const double beta = 0.0; container::Tensor Xc(DAT::DT_DOUBLE, DEV::CpuDevice, { nvirt, naos }); dgemm_(&transa, &transb, &naos, &nvirt, &nocc, &alpha, - c.get_pointer(), &naos, X_istate.get_pointer(), &nvirt, + c.get_pointer(), &naos, X_istate + x_start, &nvirt, &beta, Xc.data(), &naos); // 2. C_virt*[X*C_occ^T] dgemm_(&transa, &transb, &naos, &naos, &nvirt, &alpha, @@ -115,7 +112,7 @@ namespace LR template<> std::vector cal_dm_trans_blas( - const psi::Psi>& X_istate, + const std::complex* X_istate, const psi::Psi>& c, const int& nocc, const int& nvirt, @@ -123,14 +120,13 @@ namespace LR const int nspin) { ModuleBase::TITLE("hamilt_lrtd", "cal_dm_trans_blas"); - const int nks = X_istate.get_nk(); - assert(nocc * nvirt == X_istate.get_nbasis()); + const int nks = c.get_nk(); int naos = c.get_nbasis(); std::vector dm_trans(nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { naos, naos })); for (size_t isk = 0;isk < nks;++isk) { c.fix_k(isk); - X_istate.fix_k(isk); + const int x_start = isk * nocc * nvirt; char transa = 'N'; char transb = 'C'; @@ -154,7 +150,7 @@ namespace LR // 1. X*C_occ^\dagger container::Tensor Xc(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { naos, nvirt }); zgemm_(&transa, &transb, &nvirt, &naos, &nocc, &alpha, - X_istate.get_pointer(), &nvirt, c.get_pointer(), &naos, + X_istate + x_start, &nvirt, c.get_pointer(), &naos, &beta, Xc.data>(), &nvirt); // 2. [X*C_occ^\dagger]^TC_virt^T transa = transb = 'T'; diff --git a/source/module_lr/dm_trans/dmr_complex.cpp b/source/module_lr/dm_trans/dmr_complex.cpp index cdc3e5139c9..7a400f3bcc4 100644 --- a/source/module_lr/dm_trans/dmr_complex.cpp +++ b/source/module_lr/dm_trans/dmr_complex.cpp @@ -11,7 +11,7 @@ namespace elecstate ModuleBase::timer::tick("DensityMatrix", "cal_DMR"); for (int is = 1; is <= this->_nspin; ++is) { - int ik_begin = this->_nks * (is - 1); // jump this->_nks for spin_down if nspin==2 + int ik_begin = this->_nk * (is - 1); // jump this->_nk for spin_down if nspin==2 hamilt::HContainer>* tmp_DMR = this->_DMR[is - 1]; // set zero since this function is called in every scf step tmp_DMR->set_zero(); @@ -42,13 +42,13 @@ namespace elecstate } #endif // loop over k-points - if (PARAM.inp.nspin != 4) - for (int ik = 0; ik < this->_nks; ++ik) + if (PARAM.inp.nspin != 4) { + for (int ik = 0; ik < this->_nk; ++ik) { // cal k_phase // if TK==std::complex, kphase is e^{ikR} const ModuleBase::Vector3 dR(r_index[0], r_index[1], r_index[2]); - const double arg = (this->_kv->kvec_d[ik] * dR) * ModuleBase::TWO_PI; + const double arg = (this->_kvec_d[ik] * dR) * ModuleBase::TWO_PI; double sinp, cosp; ModuleBase::libm::sincos(arg, &sinp, &cosp); std::complex kphase = std::complex(cosp, sinp); @@ -70,9 +70,11 @@ namespace elecstate tmp_DMR_pointer += this->_paraV->get_col_size(iat2); } } +} // treat DMR as pauli matrix when NSPIN=4 - if (PARAM.inp.nspin == 4) + if (PARAM.inp.nspin == 4) { throw std::runtime_error("complex DM(R) with NSPIN=4 is not implemented yet"); +} } } } diff --git a/source/module_lr/dm_trans/test/dm_trans_test.cpp b/source/module_lr/dm_trans/test/dm_trans_test.cpp index 4e0a034f207..212db64cc86 100644 --- a/source/module_lr/dm_trans/test/dm_trans_test.cpp +++ b/source/module_lr/dm_trans/test/dm_trans_test.cpp @@ -68,8 +68,8 @@ TEST_F(DMTransTest, DoubleSerial) psi::Psi c(s.nks, s.nocc + s.nvirt, s.naos); set_rand(c.get_pointer(), size_c); X.fix_b(istate); - const std::vector& dm_for = LR::cal_dm_trans_forloop_serial(X, c, s.nocc, s.nvirt); - const std::vector& dm_blas = LR::cal_dm_trans_blas(X, c, s.nocc, s.nvirt); + const std::vector& dm_for = LR::cal_dm_trans_forloop_serial(X.get_pointer(), c, s.nocc, s.nvirt); + const std::vector& dm_blas = LR::cal_dm_trans_blas(X.get_pointer(), c, s.nocc, s.nvirt); for (int isk = 0;isk < s.nks;++isk) check_eq(dm_for[isk].data(), dm_blas[isk].data(), s.naos * s.naos); } @@ -87,8 +87,8 @@ TEST_F(DMTransTest, ComplexSerial) psi::Psi> c(s.nks, s.nocc + s.nvirt, s.naos); set_rand(c.get_pointer(), size_c); X.fix_b(istate); - const std::vector& dm_for = LR::cal_dm_trans_forloop_serial(X, c, s.nocc, s.nvirt); - const std::vector& dm_blas = LR::cal_dm_trans_blas(X, c, s.nocc, s.nvirt); + const std::vector& dm_for = LR::cal_dm_trans_forloop_serial(X.get_pointer(), c, s.nocc, s.nvirt); + const std::vector& dm_blas = LR::cal_dm_trans_blas(X.get_pointer(), c, s.nocc, s.nvirt); for (int isk = 0;isk < s.nks;++isk) check_eq(dm_for[isk].data>(), dm_blas[isk].data>(), s.naos * s.naos); } @@ -109,6 +109,7 @@ TEST_F(DMTransTest, DoubleParallel) LR_Util::setup_2d_division(pc, s.nb, s.naos, s.nocc + s.nvirt, px.blacs_ctxt); psi::Psi c(s.nks, pc.get_col_size(), pc.get_row_size()); Parallel_2D pmat; + LR_Util::setup_2d_division(pmat, s.nb, s.naos, s.naos, px.blacs_ctxt); EXPECT_EQ(px.dim0, pc.dim0); EXPECT_EQ(px.dim1, pc.dim1); @@ -137,7 +138,7 @@ TEST_F(DMTransTest, DoubleParallel) X.fix_b(istate); X_full.fix_b(istate); - std::vector dm_pblas_loc = LR::cal_dm_trans_pblas(X, px, c, pc, s.naos, s.nocc, s.nvirt, pmat); + std::vector dm_pblas_loc = LR::cal_dm_trans_pblas(X.get_pointer(), px, c, pc, s.naos, s.nocc, s.nvirt, pmat); // gather dm and output std::vector dm_gather(s.nks, container::Tensor(DAT::DT_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); @@ -154,7 +155,7 @@ TEST_F(DMTransTest, DoubleParallel) } if (my_rank == 0) { - const std::vector& dm_full = LR::cal_dm_trans_blas(X_full, c_full, s.nocc, s.nvirt); + const std::vector& dm_full = LR::cal_dm_trans_blas(X_full.get_pointer(), c_full, s.nocc, s.nvirt); for (int isk = 0;isk < s.nks;++isk) check_eq(dm_full[isk].data(), dm_gather[isk].data(), s.naos * s.naos); } } @@ -173,6 +174,7 @@ TEST_F(DMTransTest, ComplexParallel) LR_Util::setup_2d_division(pc, s.nb, s.naos, s.nocc + s.nvirt, px.blacs_ctxt); psi::Psi> c(s.nks, pc.get_col_size(), pc.get_row_size()); Parallel_2D pmat; + LR_Util::setup_2d_division(pmat, s.nb, s.naos, s.naos, px.blacs_ctxt); set_rand(X.get_pointer(), nstate * s.nks * px.get_local_size()); //set X and X_full psi::Psi> X_full(s.nks, nstate, s.nocc * s.nvirt, nullptr, false); // allocate X_full @@ -195,7 +197,7 @@ TEST_F(DMTransTest, ComplexParallel) X.fix_b(istate); X_full.fix_b(istate); - std::vector dm_pblas_loc = LR::cal_dm_trans_pblas(X, px, c, pc, s.naos, s.nocc, s.nvirt, pmat); + std::vector dm_pblas_loc = LR::cal_dm_trans_pblas(X.get_pointer(), px, c, pc, s.naos, s.nocc, s.nvirt, pmat); // gather dm and output std::vector dm_gather(s.nks, container::Tensor(DAT::DT_COMPLEX_DOUBLE, DEV::CpuDevice, { s.naos, s.naos })); @@ -212,7 +214,7 @@ TEST_F(DMTransTest, ComplexParallel) } if (my_rank == 0) { - std::vector dm_full = LR::cal_dm_trans_blas(X_full, c_full, s.nocc, s.nvirt); + std::vector dm_full = LR::cal_dm_trans_blas(X_full.get_pointer(), c_full, s.nocc, s.nvirt); for (int isk = 0;isk < s.nks;++isk) check_eq(dm_full[isk].data>(), dm_gather[isk].data>(), s.naos * s.naos); } } diff --git a/source/module_lr/esolver_lrtd_lcao.cpp b/source/module_lr/esolver_lrtd_lcao.cpp index f5cb2d9b015..20f3a3a4bd9 100644 --- a/source/module_lr/esolver_lrtd_lcao.cpp +++ b/source/module_lr/esolver_lrtd_lcao.cpp @@ -2,13 +2,14 @@ #include "utils/gint_move.hpp" #include "utils/lr_util.h" #include "hamilt_casida.h" +#include "hamilt_ulr.hpp" #include "module_lr/potentials/pot_hxc_lrtd.h" -#include "module_lr/hsolver_lrtd.h" +#include "module_lr/hsolver_lrtd.hpp" #include "module_lr/lr_spectrum.h" #include #include "module_hamilt_lcao/hamilt_lcaodft/hamilt_lcao.h" #include "module_io/read_wfc_nao.h" -#include "module_io/rho_io.h" +#include "module_io/cube_io.h" #include "module_io/print_info.h" #include "module_cell/module_neighbor/sltk_atom_arrange.h" #include "module_lr/utils/lr_util_print.h" @@ -20,12 +21,14 @@ template<> void LR::ESolver_LR::move_exx_lri(std::shared_ptr>& exx_ks) { + ModuleBase::TITLE("ESolver_LR", "move_exx_lri"); this->exx_lri = exx_ks; exx_ks = nullptr; } template<> void LR::ESolver_LR>::move_exx_lri(std::shared_ptr>>& exx_ks) { + ModuleBase::TITLE("ESolver_LR", "move_exx_lri"); this->exx_lri = exx_ks; exx_ks = nullptr; } @@ -65,10 +68,25 @@ inline void redirect_log(const bool& out_alllog) } } +inline int cal_nupdown_form_occ(const ModuleBase::matrix& wg) +{ // only for nspin=2 + const int& nk = wg.nr / 2; + auto occ_sum_k = [&](const int& is, const int& ib)->double { double o = 0.0; for (int ik = 0;ik < nk;++ik) { o += wg(is * nk + ik, ib); } return o;}; + int nupdown = 0; + for (int ib = 0;ib < wg.nc;++ib) + { + const int nu = static_cast(std::lround(occ_sum_k(0, ib))); + const int nd = static_cast(std::lround(occ_sum_k(1, ib))); + if ((nu + nd) == 0) { break; } + nupdown += nu - nd; + } + return nupdown; +} + template void LR::ESolver_LR::parameter_check()const { - std::set lr_solvers = { "dav", "lapack" , "spectrum", "dav_subspace" }; + std::set lr_solvers = { "dav", "lapack" , "spectrum", "dav_subspace", "cg" }; std::set xc_kernels = { "rpa", "lda", "pbe", "hf" , "hse" }; if (lr_solvers.find(this->input.lr_solver) == lr_solvers.end()) { throw std::invalid_argument("ESolver_LR: unknown type of lr_solver"); @@ -85,32 +103,25 @@ template void LR::ESolver_LR::set_dimension() { this->nspin = PARAM.inp.nspin; - if (nspin == 2) { std::cout << "** Assuming the spin-up and spin-down states are degenerate. **" << std::endl; -} this->nstates = input.lr_nstates; - this->nbasis = GlobalV::NLOCAL; + this->nbasis = PARAM.globalv.nlocal; // calculate the number of occupied and unoccupied states // which determines the basis size of the excited states this->nocc_max = LR_Util::cal_nocc(LR_Util::cal_nelec(ucell)); - this->nocc = std::max(1, std::min(input.nocc, this->nocc_max)); - this->nvirt = GlobalV::NBANDS - this->nocc_max; //nbands-nocc - if (input.nvirt > this->nvirt) { - GlobalV::ofs_warning << "ESolver_LR: input nvirt is too large to cover by nbands, set nvirt = nbands - nocc = " << this->nvirt << std::endl; - } else if (input.nvirt > 0) { this->nvirt = input.nvirt; -} - this->nbands = this->nocc + this->nvirt; - this->npairs = this->nocc * this->nvirt; + this->nocc_in = std::max(1, std::min(input.nocc, this->nocc_max)); + this->nvirt_in = PARAM.inp.nbands - this->nocc_max; //nbands-nocc + if (input.nvirt > this->nvirt_in) { GlobalV::ofs_warning << "ESolver_LR: input nvirt is too large to cover by nbands, set nvirt = nbands - nocc = " << this->nvirt_in << std::endl; } + else if (input.nvirt > 0) { this->nvirt_in = input.nvirt; } + this->nbands = this->nocc_in + this->nvirt_in; this->nk = this->kv.get_nks() / this->nspin; - if (this->nstates > this->nocc * this->nvirt * this->nk) { - throw std::invalid_argument("ESolver_LR: nstates > nocc*nvirt*nk"); -} - + this->nocc.resize(nspin, nocc_in); + this->nvirt.resize(nspin, nvirt_in); + for (int is = 0;is < nspin;++is) { this->npairs.push_back(nocc[is] * nvirt[is]); } GlobalV::ofs_running << "Setting LR-TDDFT parameters: " << std::endl; - GlobalV::ofs_running << "number of occupied bands: " << this->nocc << std::endl; - GlobalV::ofs_running << "number of virtual bands: " << this->nvirt << std::endl; + GlobalV::ofs_running << "number of occupied bands: " << nocc_in << std::endl; + GlobalV::ofs_running << "number of virtual bands: " << nvirt_in << std::endl; GlobalV::ofs_running << "number of Atom orbitals (LCAO-basis size): " << this->nbasis << std::endl; GlobalV::ofs_running << "number of KS bands: " << this->eig_ks.nc << std::endl; - GlobalV::ofs_running << "number of electron-hole pairs (2-particle basis size): " << this->npairs << std::endl; GlobalV::ofs_running << "number of excited states to be solved: " << this->nstates << std::endl; if (input.ri_hartree_benchmark == "aims" && !input.aims_nbasis.empty()) { @@ -119,6 +130,23 @@ void LR::ESolver_LR::set_dimension() } } +template +void LR::ESolver_LR::reset_dim_spin2() +{ + if (nspin != 2) { return; } + if (nupdown == 0) { std::cout << "** Assuming the spin-up and spin-down states are degenerate. **" << std::endl; } + else + { + this->openshell = true; + nupdown > 0 ? ((nocc[1] -= nupdown) && (nvirt[1] += nupdown)) : ((nocc[0] += nupdown) && (nvirt[0] -= nupdown)); + npairs = { nocc[0] * nvirt[0], nocc[1] * nvirt[1] }; + std::cout << "** Solve the spin-up and spin-down states separately for open-shell system. **" << std::endl; + } + for (int is : {0, 1}) { if (npairs[is] <= 0) { throw std::invalid_argument(std::string("ESolver_LR: npairs (nocc*nvirt) <= 0 for spin") + std::string(is == 0 ? "up" : "down")); } } + if (nstates > (npairs[0] + npairs[1]) * nk) { throw std::invalid_argument("ESolver_LR: nstates > nocc*nvirt*nk"); } + if (input.lr_unrestricted) { this->openshell = true; } +} + template LR::ESolver_LR::ESolver_LR(ModuleESolver::ESolver_KS_LCAO&& ks_sol, const Input_para& inp, UnitCell& ucell) @@ -128,7 +156,7 @@ LR::ESolver_LR::ESolver_LR(ModuleESolver::ESolver_KS_LCAO&& ks_sol #endif { redirect_log(inp.out_alllog); - ModuleBase::TITLE("ESolver_LR", "ESolver_LR"); + ModuleBase::TITLE("ESolver_LR", "ESolver_LR(KS)"); if (this->input.lr_solver == "spectrum") { throw std::invalid_argument("when lr_solver==spectrum, esolver_type must be set to `lr` to skip the KS calculation."); @@ -164,12 +192,12 @@ LR::ESolver_LR::ESolver_LR(ModuleESolver::ESolver_KS_LCAO&& ks_sol this->eig_ks = std::move(ks_sol.pelec->ekb); }; #ifdef __MPI - if (this->nbands == GlobalV::NBANDS) { move_gs(); } + if (this->nbands == PARAM.inp.nbands) { move_gs(); } else // copy the part of ground state info according to paraC_ { this->psi_ks = new psi::Psi(this->kv.get_nks(), this->paraC_.get_col_size(), this->paraC_.get_row_size()); this->eig_ks.create(this->kv.get_nks(), this->nbands); - const int start_band = this->nocc_max - this->nocc; + const int start_band = this->nocc_max - std::max(nocc[0], nocc[1]); for (int ik = 0;ik < this->kv.get_nks();++ik) { Cpxgemr2d(this->nbasis, this->nbands, &(*ks_sol.psi)(ik, 0, 0), 1, start_band + 1, ks_sol.pv.desc_wfc, @@ -180,12 +208,18 @@ LR::ESolver_LR::ESolver_LR(ModuleESolver::ESolver_KS_LCAO&& ks_sol #else move_gs(); #endif + if (nspin == 2) + { + this->nupdown = cal_nupdown_form_occ(ks_sol.pelec->wg); + reset_dim_spin2(); + } //grid integration this->gt_ = std::move(ks_sol.GridT); if (std::is_same::value) { this->gint_g_ = std::move(ks_sol.GG); } else { this->gint_k_ = std::move(ks_sol.GK); } this->set_gint(); + this->gint_->reset_DMRGint(1); // move pw basis delete this->pw_rho; // newed in ESolver_FP::ESolver_FP @@ -209,7 +243,7 @@ LR::ESolver_LR::ESolver_LR(ModuleESolver::ESolver_KS_LCAO&& ks_sol // set ccp_type according to the xc_kernel if (xc_kernel == "hf") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; } else if (xc_kernel == "hse") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hse; } - this->exx_lri = std::make_shared>(exx_info.info_ri); + this->exx_lri = std::make_shared>(exx_info.info_ri, exx_info.info_ewald); this->exx_lri->init(MPI_COMM_WORLD, this->kv, ks_sol.orb_); this->exx_lri->cal_exx_ions(input.out_ri_cv); } @@ -226,7 +260,7 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu #endif { redirect_log(inp.out_alllog); - ModuleBase::TITLE("ESolver_LR", "ESolver_LR"); + ModuleBase::TITLE("ESolver_LR", "ESolver_LR(from scratch)"); // xc kernel this->xc_kernel = inp.xc_kernel; std::transform(xc_kernel.begin(), xc_kernel.end(), xc_kernel.begin(), tolower); @@ -236,7 +270,6 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu this->pelec = new elecstate::ElecStateLCAO(); // necessary steps in ESolver_KS::before_all_runners : symmetry and k-points - ucell.cal_nelec(GlobalV::nelec); if (ModuleSymmetry::Symmetry::symm_flag == 1) { GlobalC::ucell.symm.analy_sys(ucell.lat, ucell.st, ucell.atoms, GlobalV::ofs_running); @@ -244,7 +277,7 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu } this->kv.set(ucell.symm, PARAM.inp.kpoint_file, PARAM.inp.nspin, ucell.G, ucell.latvec, GlobalV::ofs_running); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); - Print_Info::setup_parameters(ucell, this->kv); + ModuleIO::setup_parameters(ucell, this->kv); this->parameter_check(); @@ -274,6 +307,11 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu this->paraMat_.ncol_bands, this->paraMat_.get_row_size()); this->read_ks_wfc(); + if (nspin == 2) + { + this->nupdown = cal_nupdown_form_occ(this->pelec->wg); + reset_dim_spin2(); + } LR_Util::setup_2d_division(this->paraC_, 1, this->nbasis, this->nbands #ifdef __MPI @@ -371,7 +409,7 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu this->pw_rho->startz_current, &ucell, &orb); - this->gint_->initialize_pvpR(ucell, &GlobalC::GridD); + this->gint_->initialize_pvpR(ucell, &GlobalC::GridD, 1); // always use nspin=1 for transition density // if EXX from scratch, init 2-center integral and calculate Cs, Vs #ifdef __EXX @@ -380,7 +418,7 @@ LR::ESolver_LR::ESolver_LR(const Input_para& inp, UnitCell& ucell) : inpu // set ccp_type according to the xc_kernel if (xc_kernel == "hf") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; } else if (xc_kernel == "hse") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hse; } - this->exx_lri = std::make_shared>(exx_info.info_ri); + this->exx_lri = std::make_shared>(exx_info.info_ri, exx_info.info_ewald); this->exx_lri->init(MPI_COMM_WORLD, this->kv, orb); this->exx_lri->cal_exx_ions(input.out_ri_cv); } @@ -397,35 +435,63 @@ void LR::ESolver_LR::runner(int istep, UnitCell& cell) this->setup_eigenvectors_X(); this->pelec->ekb.create(nspin, this->nstates); + auto efile = [&](const std::string& label)->std::string {return PARAM.globalv.global_out_dir + "Excitation_Energy_" + label + ".dat";}; + auto vfile = [&](const std::string& label)->std::string {return PARAM.globalv.global_out_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(GlobalV::MY_RANK) + ".dat";}; if (this->input.lr_solver != "spectrum") { + auto write_states = [&](const std::string& label, const Real* e, const T* v, const int& dim, const int& nst, const int& prec = 8)->void + { + if (GlobalV::MY_RANK == 0) { assert(nst == LR_Util::write_value(efile(label), prec, e, nst)); } + assert(nst * dim == LR_Util::write_value(vfile(label), prec, v, nst, dim)); + }; // allocate and initialize A matrix and density matrix - std::vector spin_type = { "Spin Singlet", "Spin Triplet" }; - for (int is = 0;is < nspin;++is) + if (openshell) { - if (nspin == 2) { std::cout << "Calculating " << spin_type[is] << " excitations" << std::endl; } - hamilt::Hamilt* phamilt = new HamiltCasidaLR(xc_kernel, nspin, this->nbasis, this->nocc, this->nvirt, this->ucell, orb_cutoff_, GlobalC::GridD, this->psi_ks, this->eig_ks, + std::cout << "Solving spin-conserving excitation for open-shell system." << std::endl; + HamiltULR hulr(xc_kernel, nspin, this->nbasis, this->nocc, this->nvirt, this->ucell, orb_cutoff_, GlobalC::GridD, *this->psi_ks, this->eig_ks, #ifdef __EXX this->exx_lri, this->exx_info.info_global.hybrid_alpha, #endif - this->gint_, this->pot[is], this->kv, & this->paraX_, & this->paraC_, & this->paraMat_, - spin_type[is], input.ri_hartree_benchmark, (input.ri_hartree_benchmark == "aims" ? input.aims_nbasis : std::vector({}))); - // solve the Casida equation - HSolverLR hsol(nk, this->npairs, is, this->input.out_wfc_lr); - hsol.set_diagethr(hsol.diag_ethr, 0, 0, std::max(1e-13, this->input.lr_thr)); - hsol.solve(phamilt, *this->X[is], this->pelec, this->input.lr_solver/*, - !std::set({ "hf", "hse" }).count(this->xc_kernel)*/); //whether the kernel is Hermitian - delete phamilt; + this->gint_, this->pot, this->kv, this->paraX_, this->paraC_, this->paraMat_); + LR::HSolver::solve(hulr, this->X[0].template data(), nloc_per_band, nstates, this->pelec->ekb.c, this->input.lr_solver, this->input.lr_thr); + if (input.out_wfc_lr) { write_states("openshell", this->pelec->ekb.c, this->X[0].template data(), nloc_per_band, nstates); } + } + else + { + auto spin_types = std::vector({ "singlet", "triplet" }); + for (int is = 0;is < nspin;++is) + { + std::cout << "Calculating " << spin_types[is] << " excitations" << std::endl; + HamiltLR hlr(xc_kernel, nspin, this->nbasis, this->nocc, this->nvirt, this->ucell, orb_cutoff_, GlobalC::GridD, *this->psi_ks, this->eig_ks, +#ifdef __EXX + this->exx_lri, this->exx_info.info_global.hybrid_alpha, +#endif + this->gint_, this->pot[is], this->kv, this->paraX_, this->paraC_, this->paraMat_, + spin_types[is], input.ri_hartree_benchmark, (input.ri_hartree_benchmark == "aims" ? input.aims_nbasis : std::vector({}))); + // solve the Casida equation + LR::HSolver::solve(hlr, this->X[is].template data(), nloc_per_band, nstates, + this->pelec->ekb.c + is * nstates, this->input.lr_solver, this->input.lr_thr/*, + !std::set({ "hf", "hse" }).count(this->xc_kernel)*/); //whether the kernel is Hermitian + if (input.out_wfc_lr) { write_states(spin_types[is], this->pelec->ekb.c + is * nstates, this->X[is].template data(), nloc_per_band, nstates); } + } } } else // read the eigenvalues { - std::ifstream ifs(PARAM.globalv.global_readin_dir + "Excitation_Energy.dat"); - std::cout << "reading the excitation energies from file: \n"; - for (int is = 0;is < nspin;++is) + auto read_states = [&](const std::string& label, Real* e, T* v, const int& dim, const int& nst)->void + { + if (GlobalV::MY_RANK == 0) { assert(nst == LR_Util::read_value(efile(label), e, nst)); } + assert(nst * dim == LR_Util::read_value(vfile(label), v, nst, dim)); + }; + std::cout << "reading the excitation amplitudes from file: \n"; + if (openshell) + { + read_states("openshell", this->pelec->ekb.c, this->X[0].template data(), nloc_per_band, nstates); + } + else { - for (int i = 0;i < this->nstates;++i) { ifs >> this->pelec->ekb(is, i); } - for (int i = 0;i < this->nstates;++i) { std::cout << this->pelec->ekb(is, i) << " "; } + auto spin_types = std::vector({ "singlet", "triplet" }); + for (int is = 0;is < nspin;++is) { read_states(spin_types[is], this->pelec->ekb.c + is * nstates, this->X[is].template data(), nloc_per_band, nstates); } } } return; @@ -439,99 +505,92 @@ void LR::ESolver_LR::after_all_runners() //cal spectrum std::vector freq(100); std::vector abs_wavelen_range({ 20, 200 });//default range - if (input.abs_wavelen_range.size() == 2 && std::abs(input.abs_wavelen_range[1] - input.abs_wavelen_range[0]) > 0.02) + if (input.abs_wavelen_range.size() >= 2 && std::abs(input.abs_wavelen_range[1] - input.abs_wavelen_range[0]) > 0.02) { abs_wavelen_range = input.abs_wavelen_range; } double lambda_diff = std::abs(abs_wavelen_range[1] - abs_wavelen_range[0]); double lambda_min = std::min(abs_wavelen_range[1], abs_wavelen_range[0]); for (int i = 0;i < freq.size();++i) { freq[i] = 91.126664 / (lambda_min + 0.01 * static_cast(i + 1) * lambda_diff); } - for (int is = 0;is < this->nspin;++is) + auto spin_types = (nspin == 2 && !openshell) ? std::vector({ "singlet", "triplet" }) : std::vector({ "updown" }); + for (int is = 0;is < this->X.size();++is) { - LR_Spectrum spectrum(&this->pelec->ekb.c[is * this->nstates], *this->X[is], - this->nspin, this->nbasis, this->nocc, this->nvirt, this->gint_, *this->pw_rho, *this->psi_ks, - this->ucell, this->kv, this->paraX_, this->paraC_, this->paraMat_); - spectrum.oscillator_strength(); - spectrum.transition_analysis(is); - spectrum.optical_absorption(freq, input.abs_broadening, is); + LR_Spectrum spectrum(nspin, this->nbasis, this->nocc, this->nvirt, this->gint_, *this->pw_rho, *this->psi_ks, + this->ucell, this->kv, GlobalC::GridD, this->orb_cutoff_, + this->paraX_, this->paraC_, this->paraMat_, + &this->pelec->ekb.c[is * nstates], this->X[is].template data(), nstates, openshell); + spectrum.transition_analysis(spin_types[is]); + spectrum.optical_absorption(freq, input.abs_broadening, spin_types[is]); } } - template void LR::ESolver_LR::setup_eigenvectors_X() { ModuleBase::TITLE("ESolver_LR", "setup_eigenvectors_X"); - LR_Util::setup_2d_division(this->paraX_, 1, this->nvirt, this->nocc + for (int is = 0;is < nspin;++is) + { + Parallel_2D px; + LR_Util::setup_2d_division(px, /*nb2d=*/1, this->nvirt[is], this->nocc[is] #ifdef __MPI - , this->paraC_.blacs_ctxt + , this->paraC_.blacs_ctxt #endif - );//nvirt - row, nocc - col - this->X.resize(this->nspin); - const std::vector spin_types = { "Spin Singlet", "Spin Triplet" }; - // if spectrum-only, read the LR-eigenstates from file and return - if (this->input.lr_solver == "spectrum") - { - std::cout << "reading the excitation amplitudes from file: \n"; - for (int is = 0; is < this->nspin; ++is) - { - this->X[is] = std::make_shared>(LR_Util::read_psi_bandfirst( - PARAM.globalv.global_readin_dir + "Excitation_Amplitude_" + spin_types[is], GlobalV::MY_RANK)); - } - } - else - { - for (int is = 0; is < this->nspin; ++is) - { - this->X[is] = std::make_shared>(this->nk, - this->nstates, - this->paraX_.get_local_size(), - nullptr, - false); // band(state)-first - this->X[is]->zero_out(); - } - set_X_initial_guess(); + );//nvirt - row, nocc - col + this->paraX_.emplace_back(std::move(px)); } + this->nloc_per_band = nk * (openshell ? paraX_[0].get_local_size() + paraX_[1].get_local_size() : paraX_[0].get_local_size()); + + this->X.resize(openshell ? 1 : nspin, LR_Util::newTensor({ nstates, nloc_per_band })); + for (auto& x : X) { x.zero(); } + + auto spin_types = (nspin == 2 && !openshell) ? std::vector({ "singlet", "triplet" }) : std::vector({ "updown" }); + // if spectrum-only, read the LR-eigenstates from file and return + if (this->input.lr_solver != "spectrum") { set_X_initial_guess(); } } template void LR::ESolver_LR::set_X_initial_guess() { // set the initial guess of X - // if (E_{lumo}-E_{homo-1} < E_{lumo+1}-E{homo}), mode = 0, else 1(smaller first) - bool ix_mode = false; //default - if (this->eig_ks.nc > nocc + 1 && nocc >= 2 && eig_ks(0, nocc) - eig_ks(0, nocc - 2) - 1e-5 > eig_ks(0, nocc + 1) - eig_ks(0, nocc - 1)) { ix_mode = true; } - GlobalV::ofs_running << "setting the initial guess of X: " << std::endl; - if (nocc >= 2 && eig_ks.nc > nocc) { GlobalV::ofs_running << "E_{lumo}-E_{homo-1}=" << eig_ks(0, nocc) - eig_ks(0, nocc - 2) << std::endl; } - if (nocc >= 1 && eig_ks.nc > nocc + 1) { GlobalV::ofs_running << "E_{lumo+1}-E{homo}=" << eig_ks(0, nocc + 1) - eig_ks(0, nocc - 1) << std::endl; } - GlobalV::ofs_running << "mode of X-index: " << ix_mode << std::endl; - - /// global index map between (i,c) and ix - ModuleBase::matrix ioiv2ix; - std::vector> ix2ioiv; - std::pair>> indexmap = - LR_Util::set_ix_map_diagonal(ix_mode, nocc, nvirt); - - ioiv2ix = std::move(std::get<0>(indexmap)); - ix2ioiv = std::move(std::get<1>(indexmap)); - - // use unit vectors as the initial guess - // for (int i = 0; i < std::min(this->nstates * PARAM.inp.pw_diag_ndim, nocc * nvirt); i++) for (int is = 0;is < this->nspin;++is) { - for (int s = 0; s < nstates; ++s) + const int& no = this->nocc[is]; + const int& nv = this->nvirt[is]; + const int& np = this->npairs[is]; + const Parallel_2D& px = this->paraX_[is]; + + // if (E_{lumo}-E_{homo-1} < E_{lumo+1}-E{homo}), mode = 0, else 1(smaller first) + bool ix_mode = false; //default + if (this->eig_ks.nc > no + 1 && no >= 2 && eig_ks(is, no) - eig_ks(is, no - 2) - 1e-5 > eig_ks(is, no + 1) - eig_ks(is, no - 1)) { ix_mode = true; } + GlobalV::ofs_running << "setting the initial guess of X of spin" << is << std::endl; + if (no >= 2 && eig_ks.nc > no) { GlobalV::ofs_running << "E_{lumo}-E_{homo-1}=" << eig_ks(is, no) - eig_ks(is, no - 2) << std::endl; } + if (no >= 1 && eig_ks.nc > no + 1) { GlobalV::ofs_running << "E_{lumo+1}-E{homo}=" << eig_ks(is, no + 1) - eig_ks(is, no - 1) << std::endl; } + GlobalV::ofs_running << "mode of X-index: " << ix_mode << std::endl; + + /// global index map between (i,c) and ix + ModuleBase::matrix ioiv2ix; + std::vector> ix2ioiv; + std::pair>> indexmap = + LR_Util::set_ix_map_diagonal(ix_mode, no, nv); + + ioiv2ix = std::move(std::get<0>(indexmap)); + ix2ioiv = std::move(std::get<1>(indexmap)); + + for (int ib = 0; ib < nstates; ++ib) { - this->X[is]->fix_b(s); - int ipair = s % (npairs); - int occ_global = std::get<0>(ix2ioiv[ipair]); // occ - int virt_global = std::get<1>(ix2ioiv[ipair]); // virt - int ik = s / (npairs); - if (this->paraX_.in_this_processor(virt_global, occ_global)) - (*X[is])(ik, this->paraX_.global2local_col(occ_global) * this->paraX_.get_row_size() - + this->paraX_.global2local_row(virt_global)) - = (static_cast(1.0) / static_cast(nk)); + const int ipair = ib % np; + const int occ_global = std::get<0>(ix2ioiv[ipair]); // occ + const int virt_global = std::get<1>(ix2ioiv[ipair]); // virt + const int ik = ib / np; + const int xstart_b = ib * nloc_per_band; //start index of band ib + const int xstart_bs = (openshell && is == 1) ? xstart_b + nk * paraX_[0].get_local_size() : xstart_b; // start index of band ib, spin is + const int is_in_x = openshell ? 0 : is; // if openshell, spin-up and spin-down are put together + if (px.in_this_processor(virt_global, occ_global)) + { + const int ipair_loc = px.global2local_col(occ_global) * px.get_row_size() + px.global2local_row(virt_global); + X[is_in_x].data()[xstart_bs + ipair_loc] = (static_cast(1.0) / static_cast(nk)); + } } - this->X[is]->fix_b(0); //recover the pointer } } @@ -542,12 +601,13 @@ void LR::ESolver_LR::init_pot(const Charge& chg_gs) if (this->input.ri_hartree_benchmark != "none") { return; } //no need to initialize potential for Hxc kernel in the RI-benchmark routine switch (nspin) { + using ST = PotHxcLR::SpinType; case 1: - this->pot[0] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, PotHxcLR::SpinType::S1); + this->pot[0] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, ST::S1); break; case 2: - this->pot[0] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, PotHxcLR::SpinType::S2_singlet); - this->pot[1] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, PotHxcLR::SpinType::S2_triplet); + this->pot[0] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, openshell ? ST::S2_updown : ST::S2_singlet); + this->pot[1] = std::make_shared(xc_kernel, this->pw_rho, &ucell, &chg_gs, openshell ? ST::S2_updown : ST::S2_triplet); break; default: throw std::invalid_argument("ESolver_LR: nspin must be 1 or 2"); @@ -565,8 +625,8 @@ void LR::ESolver_LR::read_ks_wfc() { #ifdef __EXX int ncore = 0; - std::vector eig_ks_vec = RI_Benchmark::read_aims_ebands(PARAM.globalv.global_readin_dir + "band_out", nocc, nvirt, ncore); - std::cout << "ncore=" << ncore << ", nocc=" << nocc << ", nvirt=" << nvirt << ", nbands=" << this->nbands << std::endl; + std::vector eig_ks_vec = RI_Benchmark::read_aims_ebands(PARAM.globalv.global_readin_dir + "band_out", nocc_in, nvirt_in, ncore); + std::cout << "ncore=" << ncore << ", nocc=" << nocc_in << ", nvirt=" << nvirt_in << ", nbands=" << this->nbands << std::endl; std::cout << "eig_ks_vec.size()=" << eig_ks_vec.size() << std::endl; if(eig_ks_vec.size() != this->nbands) {ModuleBase::WARNING_QUIT("ESolver_LR", "read_aims_ebands failed.");}; for (int i = 0;i < nbands;++i) { this->pelec->ekb(0, i) = eig_ks_vec[i]; } @@ -576,7 +636,7 @@ void LR::ESolver_LR::read_ks_wfc() #endif } else if (!ModuleIO::read_wfc_nao(PARAM.globalv.global_readin_dir, this->paraMat_, *this->psi_ks, this->pelec, - /*skip_bands=*/this->nocc_max - this->nocc)) { + /*skip_bands=*/this->nocc_max - this->nocc_in)) { ModuleBase::WARNING_QUIT("ESolver_LR", "read ground-state wavefunction failed."); } this->eig_ks = std::move(this->pelec->ekb); @@ -594,24 +654,12 @@ void LR::ESolver_LR::read_ks_chg(Charge& chg_gs) ssc << PARAM.globalv.global_readin_dir << "SPIN" << is + 1 << "_CHG.cube"; GlobalV::ofs_running << ssc.str() << std::endl; double ef; - if (ModuleIO::read_rho( -#ifdef __MPI - & (GlobalC::Pgrid), -#endif + if (ModuleIO::read_vdata_palgrid(GlobalC::Pgrid, GlobalV::MY_RANK, - PARAM.inp.esolver_type, - GlobalV::RANK_IN_STOGROUP, - is, GlobalV::ofs_running, - this->nspin, ssc.str(), chg_gs.rho[is], - this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz, - ef, - &(GlobalC::ucell), - chg_gs.prenspin)) { + ucell.nat)) { GlobalV::ofs_running << " Read in the charge density: " << ssc.str() << std::endl; } else { // prenspin for nspin=4 is not supported currently ModuleBase::WARNING_QUIT( diff --git a/source/module_lr/esolver_lrtd_lcao.h b/source/module_lr/esolver_lrtd_lcao.h index f9db98d7656..62e27e4fa8d 100644 --- a/source/module_lr/esolver_lrtd_lcao.h +++ b/source/module_lr/esolver_lrtd_lcao.h @@ -65,20 +65,28 @@ namespace LR /// @brief ground state bands, read from the file, or moved from ESolver_FP::pelec.ekb ModuleBase::matrix eig_ks;///< energy of ground state - /// @brief Excited state info. size: nstates * nks * (nocc(local) * nvirt (local)) - std::vector>> X; - - int nocc = 1; + /// @brief Excited state wavefunction (locc, lvirt are local size of nocc and nvirt in each process) + /// size of X: [neq][{nstate, nloc_per_band}], namely: + /// - [nspin][{nstates, nk* (locc* lvirt}] for close- shell, + /// - [1][{nstates, nk * (locc[0] * lvirt[0]) + nk * (locc[1] * lvirt[1])}] for open-shell + std::vector X; + int nloc_per_band = 1; + + std::vector nocc; ///< number of occupied orbitals for each spin used in the calculation + int nocc_in = 1; ///< nocc read from input (adjusted by nelec): max(spin-up, spindown) int nocc_max = 1; ///< nelec/2 - int nvirt = 1; + std::vector nvirt; ///< number of virtual orbitals for each spin used in the calculation + int nvirt_in = 1; ///< nvirt read from input (adjusted by nelec): min(spin-up, spindown) int nbands = 2; int nbasis = 2; /// n_occ*nvirt, the basis size of electron-hole pair representation - int npairs = 1; + std::vector npairs; /// how many 2-particle states to be solved int nstates = 1; int nspin = 1; int nk = 1; + int nupdown = 0; + bool openshell = false; std::string xc_kernel; Grid_Technique gt_; @@ -90,7 +98,7 @@ namespace LR /// @brief variables for parallel distribution of KS orbitals Parallel_2D paraC_; /// @brief variables for parallel distribution of excited states - Parallel_2D paraX_; + std::vector paraX_; /// @brief variables for parallel distribution of matrix in AO representation Parallel_Orbitals paraMat_; @@ -111,6 +119,8 @@ namespace LR void parameter_check() const; /// @brief set nocc, nvirt, nbasis, npairs and nstates void set_dimension(); + /// reset nocc, nvirt, npairs after read ground-state wavefunction when nspin=2 + void reset_dim_spin2(); #ifdef __EXX /// Tdata of Exx_LRI is same as T, for the reason, see operator_lr_exx.h diff --git a/source/module_lr/hamilt_casida.cpp b/source/module_lr/hamilt_casida.cpp index 08a00bb09ea..a29429d5bea 100644 --- a/source/module_lr/hamilt_casida.cpp +++ b/source/module_lr/hamilt_casida.cpp @@ -1,58 +1,57 @@ #include "hamilt_casida.h" +#include "module_lr/utils/lr_util_print.h" namespace LR { template - std::vector HamiltCasidaLR::matrix() + std::vector HamiltLR::matrix()const { - ModuleBase::TITLE("HamiltCasidaLR", "matrix"); - int npairs = this->nocc * this->nvirt; + ModuleBase::TITLE("HamiltLR", "matrix"); + const int no = this->nocc[0]; + const int nv = this->nvirt[0]; + const auto& px = this->pX[0]; + const int ldim = nk * px.get_local_size(); + int npairs = no * nv; std::vector Amat_full(this->nk * npairs * this->nk * npairs, 0.0); for (int ik = 0;ik < this->nk;++ik) - for (int j = 0;j < nocc;++j) - for (int b = 0;b < nvirt;++b) + for (int j = 0;j < no;++j) + for (int b = 0;b < nv;++b) {//calculate A^{ai} for each bj - int bj = j * nvirt + b; - int kbj = ik * npairs + bj; - psi::Psi X_bj(1, 1, this->nk * this->pX->get_local_size()); // k1-first, like in iterative solver + int bj = j * nv + b; //global + int kbj = ik * npairs + bj; //global + psi::Psi X_bj(1, 1, this->nk * px.get_local_size()); // k1-first, like in iterative solver X_bj.zero_out(); - // X_bj(0, 0, lj * this->pX->get_row_size() + lb) = this->one(); - int lj = this->pX->global2local_col(j); - int lb = this->pX->global2local_row(b); - if (this->pX->in_this_processor(b, j)) X_bj(0, 0, ik * this->pX->get_local_size() + lj * this->pX->get_row_size() + lb) = this->one(); - psi::Psi A_aibj(1, 1, this->nk * this->pX->get_local_size()); // k1-first + // X_bj(0, 0, lj * px.get_row_size() + lb) = this->one(); + int lj = px.global2local_col(j); + int lb = px.global2local_row(b); + if (px.in_this_processor(b, j)) { X_bj(0, 0, ik * px.get_local_size() + lj * px.get_row_size() + lb) = this->one(); } + psi::Psi A_aibj(1, 1, this->nk * px.get_local_size()); // k1-first A_aibj.zero_out(); + this->cal_dm_trans(0, X_bj.get_pointer()); hamilt::Operator* node(this->ops); while (node != nullptr) { // act() on and return the k1-first type of psi - node->act(X_bj, A_aibj, 1); + node->act(1, ldim, /*npol=*/1, X_bj.get_pointer(), A_aibj.get_pointer()); node = (hamilt::Operator*)(node->next_op); } // reduce ai for a fixed bj A_aibj.fix_kb(0, 0); #ifdef __MPI for (int ik_ai = 0;ik_ai < this->nk;++ik_ai) - LR_Util::gather_2d_to_full(*this->pX, &A_aibj.get_pointer()[ik_ai * this->pX->get_local_size()], + LR_Util::gather_2d_to_full(px, &A_aibj.get_pointer()[ik_ai * px.get_local_size()], Amat_full.data() + kbj * this->nk * npairs /*col, bj*/ + ik_ai * npairs/*row, ai*/, - false, this->nvirt, this->nocc); + false, nv, no); #endif } // output Amat - std::cout << "Amat_full:" << std::endl; - for (int i = 0;i < this->nk * npairs;++i) - { - for (int j = 0;j < this->nk * npairs;++j) - { - std::cout << Amat_full[i * this->nk * npairs + j] << " "; - } - std::cout << std::endl; - } + std::cout << "Full A matrix: (elements < 1e-10 is set to 0)" << std::endl; + LR_Util::print_value(Amat_full.data(), nk * npairs, nk * npairs); return Amat_full; } - template<> double HamiltCasidaLR::one() { return 1.0; } - template<> std::complex HamiltCasidaLR>::one() { return std::complex(1.0, 0.0); } + template<> double HamiltLR::one() const { return 1.0; } + template<> std::complex HamiltLR>::one() const { return std::complex(1.0, 0.0); } - template class HamiltCasidaLR; - template class HamiltCasidaLR>; + template class HamiltLR; + template class HamiltLR>; } \ No newline at end of file diff --git a/source/module_lr/hamilt_casida.h b/source/module_lr/hamilt_casida.h index f203316dfff..ab40c826111 100644 --- a/source/module_lr/hamilt_casida.h +++ b/source/module_lr/hamilt_casida.h @@ -1,9 +1,11 @@ #pragma once +#include #include "module_hamilt_general/hamilt.h" #include "module_elecstate/module_dm/density_matrix.h" #include "module_lr/operator_casida/operator_lr_diag.h" #include "module_lr/operator_casida/operator_lr_hxc.h" #include "module_basis/module_ao/parallel_orbitals.h" +#include "module_lr/dm_trans/dm_trans.h" #ifdef __EXX #include "module_lr/operator_casida/operator_lr_exx.h" #include "module_lr/ri_benchmark/operator_ri_hartree.h" @@ -12,19 +14,19 @@ namespace LR { template - class HamiltCasidaLR : public hamilt::Hamilt + class HamiltLR { public: template - HamiltCasidaLR(std::string& xc_kernel, + HamiltLR(std::string& xc_kernel, const int& nspin, const int& naos, - const int& nocc, - const int& nvirt, + const std::vector& nocc, + const std::vector& nvirt, const UnitCell& ucell_in, const std::vector& orb_cutoff, Grid_Driver& gd_in, - const psi::Psi* psi_ks_in, + const psi::Psi& psi_ks_in, const ModuleBase::matrix& eig_ks, #ifdef __EXX std::weak_ptr> exx_lri_in, @@ -33,20 +35,22 @@ namespace LR TGint* gint_in, std::weak_ptr pot_in, const K_Vectors& kv_in, - Parallel_2D* pX_in, - Parallel_2D* pc_in, - Parallel_Orbitals* pmat_in, + const std::vector& pX_in, + const Parallel_2D& pc_in, + const Parallel_Orbitals& pmat_in, const std::string& spin_type, const std::string& ri_hartree_benchmark = "none", - const std::vector& aims_nbasis = {}) : nocc(nocc), nvirt(nvirt), pX(pX_in), nk(kv_in.get_nks() / nspin) + const std::vector& aims_nbasis = {}) : nspin(nspin), nocc(nocc), nvirt(nvirt), pX(pX_in), nk(kv_in.get_nks() / nspin) { - ModuleBase::TITLE("HamiltCasidaLR", "HamiltCasidaLR"); + ModuleBase::TITLE("HamiltLR", "HamiltLR"); if (ri_hartree_benchmark != "aims") { assert(aims_nbasis.empty()); } - this->classname = "HamiltCasidaLR"; - this->DM_trans.resize(1); - this->DM_trans[0] = LR_Util::make_unique>(&kv_in, pmat_in, nspin); + // always use nspin=1 for transition density matrix + this->DM_trans = LR_Util::make_unique>(&pmat_in, 1, kv_in.kvec_d, nk); + if (ri_hartree_benchmark == "none") { LR_Util::initialize_DMR(*this->DM_trans, pmat_in, ucell_in, gd_in, orb_cutoff); } + // this->DM_trans->init_DMR(&gd_in, &ucell_in); // too large due to not restricted by orb_cutoff + // add the diag operator (the first one) - this->ops = new OperatorLRDiag(eig_ks, pX_in, nk, nocc, nvirt); + this->ops = new OperatorLRDiag(eig_ks.c, pX[0], nk, nocc[0], nvirt[0]); //add Hxc operator #ifdef __EXX using TAC = std::pair>; @@ -63,7 +67,7 @@ namespace LR if (ri_hartree_benchmark != "none") { #ifdef __EXX - if (spin_type == "Spin Singlet") + if (spin_type == "singlet") { if (ri_hartree_benchmark == "aims") { @@ -77,11 +81,11 @@ namespace LR } if (!std::set({ "rpa", "hf" }).count(xc_kernel)) { throw std::runtime_error("ri_hartree_benchmark is only supported for xc_kernel rpa and hf"); } RI_Benchmark::OperatorRIHartree* ri_hartree_op - = new RI_Benchmark::OperatorRIHartree(ucell_in, naos, nocc, nvirt, *psi_ks_in, + = new RI_Benchmark::OperatorRIHartree(ucell_in, naos, nocc[0], nvirt[0], psi_ks_in, Cs_read, Vs_read, ri_hartree_benchmark == "aims", aims_nbasis); this->ops->add(ri_hartree_op); } - else if (spin_type == "Spin Triplet") {std::cout<<"f_Hxc based on grid integral is not needed."<reset_Cs(Cs_read); exx_lri_in.lock()->reset_Vs(Vs_read); } // std::cout << "exx_alpha=" << exx_alpha << std::endl; // the default value of exx_alpha is 0.25 when dft_functional is pbe or hse - hamilt::Operator* lr_exx = new OperatorLREXX(nspin, naos, nocc, nvirt, ucell_in, psi_ks_in, - this->DM_trans, exx_lri_in, kv_in, pX_in, pc_in, pmat_in, + hamilt::Operator* lr_exx = new OperatorLREXX(nspin, naos, nocc[0], nvirt[0], ucell_in, psi_ks_in, + this->DM_trans, exx_lri_in, kv_in, pX_in[0], pc_in, pmat_in, xc_kernel == "hf" ? 1.0 : exx_alpha, //alpha - ri_hartree_benchmark != "none"/*whether to cal_dm_trans first here*/, aims_nbasis); this->ops->add(lr_exx); } #endif + + this->cal_dm_trans = [&, this](const int& is, const T* X)->void + { + const auto psi_ks_is = LR_Util::get_psi_spin(psi_ks_in, is, nk); +#ifdef __MPI + std::vector dm_trans_2d = cal_dm_trans_pblas(X, pX[is], psi_ks_is, pc_in, naos, nocc[is], nvirt[is], pmat_in); + if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat_in); +#else + std::vector dm_trans_2d = cal_dm_trans_blas(X, psi_ks_is, nocc[is], nvirt[is]); + if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); +#endif + // LR_Util::print_tensor(dm_trans_2d[0], "dm_trans_2d[0]", &pmat_in); + // tensor to vector, then set DMK + for (int ik = 0;ik < nk;++ik) { this->DM_trans->set_DMK_pointer(ik, dm_trans_2d[ik].data()); } + }; } - ~HamiltCasidaLR() + ~HamiltLR() { delete this->ops; } + + std::vector matrix()const; + + void hPsi(const T* psi_in, T* hpsi, const int ld_psi, const int& nband) const { - if (this->ops != nullptr) + assert(ld_psi == nk * pX[0].get_local_size()); + for (int ib = 0;ib < nband;++ib) { - delete this->ops; + const int offset = ib * ld_psi; + this->cal_dm_trans(0, psi_in + offset); // calculate transition density matrix here + hamilt::Operator* node(this->ops); + while (node != nullptr) + { + node->act(/*nband=*/1, ld_psi, /*npol=*/1, psi_in + offset, hpsi + offset); + node = (hamilt::Operator*)(node->next_op); + } } - }; + } - virtual std::vector matrix() override; + void global2local(T* lvec, const T* gvec, const int& nband) const + { + const int npairs = nocc[0] * nvirt[0]; + for (int ib = 0;ib < nband;++ib) + { + const int loffset_b = ib * nk * pX[0].get_local_size(); + const int goffset_b = ib * nk * npairs; + for (int ik = 0;ik < nk;++ik) + { + const int loffset = loffset_b + ik * pX[0].get_local_size(); + const int goffset = goffset_b + ik * npairs; + for (int lo = 0;lo < pX[0].get_col_size();++lo) + { + const int go = pX[0].local2global_col(lo); + for (int lv = 0;lv < pX[0].get_row_size();++lv) + { + const int gv = pX[0].local2global_row(lv); + lvec[loffset + lo * pX[0].get_row_size() + lv] = gvec[goffset + go * nvirt[0] + gv]; + } + } + } + } + } private: - int nocc; - int nvirt; - int nk; - Parallel_2D* pX = nullptr; - T one(); + const std::vector& nocc; + const std::vector& nvirt; + const int nspin = 1; + const int nk = 1; + const bool tdm_sym = false; ///< whether to symmetrize the transition density matrix + const std::vector& pX; + T one()const; /// transition density matrix in AO representation - /// Hxc only: size=1, calculate on the same address for each bands - /// Hxc+Exx: size=nbands, store the result of each bands for common use - std::vector>> DM_trans; + /// calculate on the same address for each bands, and commonly used by all the operators + std::unique_ptr> DM_trans; + + /// first node operator, add operations from each operators + hamilt::Operator* ops = nullptr; + + std::function cal_dm_trans; }; } diff --git a/source/module_lr/hamilt_ulr.hpp b/source/module_lr/hamilt_ulr.hpp new file mode 100644 index 00000000000..77ee62ce738 --- /dev/null +++ b/source/module_lr/hamilt_ulr.hpp @@ -0,0 +1,230 @@ +#pragma once +#include "module_hamilt_general/hamilt.h" +#include "module_elecstate/module_dm/density_matrix.h" +#include "module_lr/operator_casida/operator_lr_diag.h" +#include "module_lr/operator_casida/operator_lr_hxc.h" +#include "module_lr/utils/lr_util_print.h" +#ifdef __EXX +#include "module_lr/operator_casida/operator_lr_exx.h" +#endif +namespace LR +{ + /// Unristricted TDDFT (TDA) for open-shell systems + /// The A matrix is diveded by 4 blocks: uu, ud, du, dd + template + class HamiltULR + { + public: + template + HamiltULR(std::string& xc_kernel, + const int& nspin, + const int& naos, + const std::vector& nocc, ///< {up, down} + const std::vector& nvirt, ///< {up, down} + const UnitCell& ucell_in, + const std::vector& orb_cutoff, + Grid_Driver& gd_in, + const psi::Psi& psi_ks_in, + const ModuleBase::matrix& eig_ks, +#ifdef __EXX + std::weak_ptr> exx_lri_in, + const double& exx_alpha, +#endif + TGint* gint_in, + std::vector>& pot_in, + const K_Vectors& kv_in, + const std::vector& pX_in, ///< {up, down} + const Parallel_2D& pc_in, + const Parallel_Orbitals& pmat_in) :nocc(nocc), nvirt(nvirt), pX(pX_in), nk(kv_in.get_nks() / nspin), + ldim(nk* pX[0].get_local_size() + nk * pX[1].get_local_size()), + gdim(nk* std::inner_product(nocc.begin(), nocc.end(), nvirt.begin(), 0)) + { + ModuleBase::TITLE("HamiltULR", "HamiltULR"); + this->DM_trans = LR_Util::make_unique>(&pmat_in, 1, kv_in.kvec_d, nk); + LR_Util::initialize_DMR(*this->DM_trans, pmat_in, ucell_in, gd_in, orb_cutoff); + // this->DM_trans->init_DMR(&gd_in, &ucell_in); // too large due to not restricted by orb_cutoff + this->ops.resize(4); + + this->ops[0] = new OperatorLRDiag(eig_ks.c, pX_in[0], nk, nocc[0], nvirt[0]); + this->ops[3] = new OperatorLRDiag(eig_ks.c + nk * (nocc[0] + nvirt[0]), pX_in[1], nk, nocc[1], nvirt[1]); + + auto newHxc = [&](const int& sl, const int& sr) { return new OperatorLRHxc(nspin, naos, nocc, nvirt, psi_ks_in, + this->DM_trans, gint_in, pot_in[sl], ucell_in, orb_cutoff, gd_in, kv_in, pX_in, pc_in, pmat_in, { sl,sr }); }; + this->ops[0]->add(newHxc(0, 0)); + this->ops[1] = newHxc(0, 1); + this->ops[2] = newHxc(1, 0); + this->ops[3]->add(newHxc(1, 1)); + +#ifdef __EXX + if (xc_kernel == "hf" || xc_kernel == "hse") + { + std::vector> psi_ks_spin = { LR_Util::get_psi_spin(psi_ks_in, 0, nk), LR_Util::get_psi_spin(psi_ks_in, 1, nk) }; + for (int is : {0, 1}) + { + this->ops[(is << 1) + is]->add(new OperatorLREXX(nspin, naos, nocc[is], nvirt[is], ucell_in, psi_ks_spin[is], + this->DM_trans, exx_lri_in, kv_in, pX_in[is], pc_in, pmat_in, + xc_kernel == "hf" ? 1.0 : exx_alpha)); + } + } +#endif + + this->cal_dm_trans = [&, this](const int& is, const T* X)->void + { + const auto psi_ks_is = LR_Util::get_psi_spin(psi_ks_in, is, nk); + // LR_Util::print_value(X, pX_in[is].get_local_size()); +#ifdef __MPI + std::vector dm_trans_2d = cal_dm_trans_pblas(X, pX[is], psi_ks_is, pc_in, naos, nocc[is], nvirt[is], pmat_in); + if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat_in); +#else + std::vector dm_trans_2d = cal_dm_trans_blas(X, psi_ks_is, nocc[is], nvirt[is]); + if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); +#endif + // LR_Util::print_tensor(dm_trans_2d[0], "DMtrans(k=0)", &pmat_in); + // tensor to vector, then set DMK + for (int ik = 0;ik < nk;++ik) { this->DM_trans->set_DMK_pointer(ik, dm_trans_2d[ik].data()); } + }; + } + ~HamiltULR() + { + for (auto& op : ops) { delete op; } + } + void hPsi(const T* psi_in, T* hpsi, const int ld_psi, const int& nband) const + { + ModuleBase::TITLE("HamiltULR", "hPsi"); + assert(ld_psi == this->ldim); + const std::vector xdim_is = { nk * pX[0].get_local_size(), nk * pX[1].get_local_size() }; + /// band-wise act (also works for close-shell, but not efficient) + for (int ib = 0;ib < nband;++ib) + { + const int offset_band = ib * ld_psi; + for (int is_bj : {0, 1}) + { + const int offset_bj = offset_band + is_bj * xdim_is[0]; + cal_dm_trans(is_bj, psi_in + offset_bj); // calculate transition density matrix here + for (int is_ai : {0, 1}) + { + const int offset_ai = offset_band + is_ai * xdim_is[0]; + hamilt::Operator* node(this->ops[(is_ai << 1) + is_bj]); + while (node != nullptr) + { + node->act(/*nband=*/1, xdim_is[is_bj], /*npol=*/1, psi_in + offset_bj, hpsi + offset_ai); + node = (hamilt::Operator*)(node->next_op); + } + } + } + } + } + std::vector matrix()const + { + ModuleBase::TITLE("HamiltULR", "matrix"); + const std::vector npairs = { this->nocc[0] * this->nvirt[0], this->nocc[1] * this->nvirt[1] }; + const std::vector ldim_is = { nk * pX[0].get_local_size(), nk * pX[1].get_local_size() }; + const std::vector gdim_is = { nk * npairs[0], nk * npairs[1] }; + std::vector Amat_full(gdim * gdim); + for (int is_bj : {0, 1}) + { + const int no = this->nocc[is_bj]; + const int nv = this->nvirt[is_bj]; + const auto& px = this->pX[is_bj]; + const int loffset_bj = is_bj * ldim_is[0]; + const int goffset_bj = is_bj * gdim_is[0]; + for (int ik_bj = 0;ik_bj < nk;++ik_bj) + { + for (int j = 0;j < no;++j) + { + for (int b = 0;b < nv;++b) + { + const int gcol = goffset_bj + ik_bj * npairs[is_bj] + j * nv + b;//global + std::vector X_bj(this->ldim, T(0)); + const int lj = px.global2local_col(j); + const int lb = px.global2local_row(b); + const int lcol = loffset_bj + ik_bj * px.get_local_size() + lj * px.get_row_size() + lb;//local + if (px.in_this_processor(b, j)) { X_bj[lcol] = T(1); } + this->cal_dm_trans(is_bj, X_bj.data() + loffset_bj); + std::vector Aloc_col(this->ldim, T(0)); // a col of A matrix (local) + for (int is_ai : {0, 1}) + { + const int goffset_ai = is_ai * gdim_is[0]; + const int loffset_ai = is_ai * ldim_is[0]; + const auto& pax = this->pX[is_ai]; + hamilt::Operator* node(this->ops[(is_ai << 1) + is_bj]); + while (node != nullptr) + { + node->act(1, ldim_is[is_bj], /*npol=*/1, X_bj.data() + loffset_bj, Aloc_col.data() + loffset_ai); + node = (hamilt::Operator*)(node->next_op); + } +#ifdef __MPI + for (int ik_ai = 0;ik_ai < this->nk;++ik_ai) + { + LR_Util::gather_2d_to_full(pax, Aloc_col.data() + loffset_ai + ik_ai * pax.get_local_size(), + Amat_full.data() + gcol * gdim /*col, bj*/ + goffset_ai + ik_ai * npairs[is_ai]/*row, ai*/, + false, nv, no); + } +#else + std::memcpy(Amat_full.data() + gcol * gdim + goffset_ai, Aloc_col.data() + goffset_ai, gdim_is[is_ai] * sizeof(T)); +#endif + } + } + } + } + } + std::cout << "Full A matrix:" << std::endl; + LR_Util::print_value(Amat_full.data(), gdim, gdim); + return Amat_full; + } + + /// copy global data (eigenvectors) to local memory + void global2local(T* lvec, const T* gvec, const int& nband) const + { + const std::vector npairs = { this->nocc[0] * this->nvirt[0], this->nocc[1] * this->nvirt[1] }; + const std::vector ldim_is = { nk * pX[0].get_local_size(), nk * pX[1].get_local_size() }; + const std::vector gdim_is = { nk * npairs[0], nk * npairs[1] }; + for (int ib = 0;ib < nband;++ib) + { + const int loffset_b = ib * this->ldim; + const int goffset_b = ib * this->gdim; + for (int is : {0, 1}) + { + const int loffset_bs = loffset_b + is * ldim_is[0]; + const int goffset_bs = goffset_b + is * gdim_is[0]; + for (int ik = 0;ik < nk;++ik) + { + const int loffset = loffset_bs + ik * pX[is].get_local_size(); + const int goffset = goffset_bs + ik * npairs[is]; + for (int lo = 0;lo < pX[is].get_col_size();++lo) + { + const int go = pX[is].local2global_col(lo); + for (int lv = 0;lv < pX[is].get_row_size();++lv) + { + const int gv = pX[is].local2global_row(lv); + lvec[loffset + lo * pX[is].get_row_size() + lv] = gvec[goffset + go * nvirt[is] + gv]; + } + } + } + } + } + } + + private: + const std::vector& nocc; + const std::vector& nvirt; + + const std::vector& pX; + + + const int nk = 1; + const int ldim = 1; + const int gdim = 1; + + /// 4 operator lists: uu, ud, du, dd + std::vector*> ops; + + /// transition density matrix in AO representation + /// Hxc only: size=1, calculate on the same address for each bands + /// Hxc+Exx: size=nbands, store the result of each bands for common use + std::unique_ptr> DM_trans; + + std::function cal_dm_trans; + const bool tdm_sym = false; ///< whether to symmetrize the transition density matrix + }; +} \ No newline at end of file diff --git a/source/module_lr/hsolver_lrtd.cpp b/source/module_lr/hsolver_lrtd.cpp deleted file mode 100644 index 638ae6e8079..00000000000 --- a/source/module_lr/hsolver_lrtd.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "hsolver_lrtd.h" -#include "module_parameter/parameter.h" -#include "module_hsolver/diago_david.h" -#include "module_hsolver/diago_dav_subspace.h" -#include "module_hsolver/diago_cg.h" -#include "module_lr/utils/lr_util.h" -#include "module_lr/utils/lr_util_print.h" - -namespace LR -{ - inline double square(double x) { return x * x; }; - inline double square(std::complex x) { return x.real() * x.real() + x.imag() * x.imag(); }; - template - inline void print_eigs(const std::vector& eigs, const std::string& label = "", const double factor = 1.0) - { - std::cout << label << std::endl; - for (auto& e : eigs)std::cout << e * factor << " "; - std::cout << std::endl; - } - template - void HSolverLR::solve(hamilt::Hamilt* pHamilt, - psi::Psi& psi, - elecstate::ElecState* pes, - const std::string method_in, - const bool hermitian) - { - ModuleBase::TITLE("HSolverLR", "solve"); - assert(psi.get_nk() == nk); - const std::vector spin_types = { "Spin Singlet", "Spin Triplet" }; - // note: if not TDA, the eigenvalues will be complex - // then we will need a new constructor of DiagoDavid - - // 1. allocate precondition and eigenvalue - std::vector precondition(psi.get_nk() * psi.get_nbasis()); - std::vector eigenvalue(psi.get_nbands()); //nstates - // 2. select the method - this->method = method_in; -#ifdef __MPI - const hsolver::diag_comm_info comm_info = { POOL_WORLD, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL }; -#else - const hsolver::diag_comm_info comm_info = { GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL }; -#endif - - if (this->method == "lapack") - { - std::vector Amat_full = pHamilt->matrix(); - eigenvalue.resize(nk * npairs); - if (hermitian) { LR_Util::diag_lapack(nk * npairs, Amat_full.data(), eigenvalue.data()); } - else - { - std::vector> eig_complex(nk * npairs); - LR_Util::diag_lapack_nh(nk * npairs, Amat_full.data(), eig_complex.data()); - print_eigs(eig_complex, "Right eigenvalues: of the non-Hermitian matrix: (Ry)"); - for (int i = 0; i < nk * npairs; i++) { eigenvalue[i] = eig_complex[i].real(); } - } - psi.fix_kb(0, 0); - // copy eigenvectors - for (int i = 0;i < psi.size();++i) { psi.get_pointer()[i] = Amat_full[i]; -} - } - else - { - // 3. set precondition and diagethr - for (int i = 0; i < psi.get_nk() * psi.get_nbasis(); ++i) { - precondition[i] = static_cast(1.0); -} - - // wrap band-first psi as k1-first psi_k1_dav - psi::Psi psi_k1_dav = LR_Util::bfirst_to_k1_wrapper(psi); - assert(psi_k1_dav.get_nbands() == psi.get_nbands()); - assert(psi_k1_dav.get_nbasis() == psi.get_nbasis() * psi.get_nk()); - - const int david_maxiter = hsolver::DiagoIterAssist::PW_DIAG_NMAX; - - if (this->method == "dav") - { - // Allow 5 tries at most. If ntry > ntry_max = 5, exit diag loop. - const int ntry_max = 5; - // In non-self consistent calculation, do until totally converged. Else allow 5 eigenvecs to be NOT - // converged. - const int notconv_max = ("nscf" == PARAM.inp.calculation) ? 0 : 5; - // do diag and add davidson iteration counts up to avg_iter - - auto hpsi_func = [pHamilt]( - T* psi_in, - T* hpsi_out, - const int nband_in, - const int nbasis_in, - const int band_index1, - const int band_index2) - { - auto psi_iter_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_in, nullptr); - psi::Range bands_range(true, 0, band_index1, band_index2); - using hpsi_info = typename hamilt::Operator::hpsi_info; - hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); - pHamilt->ops->hPsi(info); - }; - auto spsi_func = [pHamilt](const T* psi_in, T* spsi_out, - const int nrow, const int npw, const int nbands){ - // sPsi determines S=I or not by GlobalV::use_uspp inside - pHamilt->sPsi(psi_in, spsi_out, nrow, npw, nbands); - }; - - const int& dim = psi_k1_dav.get_nbasis(); //equals to leading dimension here - const int& nband = psi_k1_dav.get_nbands(); - hsolver::DiagoDavid david(precondition.data(), nband, dim, PARAM.inp.pw_diag_ndim, PARAM.inp.use_paw, comm_info); - hsolver::DiagoIterAssist::avg_iter += static_cast(david.diag(hpsi_func, spsi_func, - dim, psi_k1_dav.get_pointer(), eigenvalue.data(), this->diag_ethr, david_maxiter, ntry_max, 0)); - } - else if (this->method == "dav_subspace") //need refactor - { - hsolver::Diago_DavSubspace dav_subspace(precondition, - psi_k1_dav.get_nbands(), - psi_k1_dav.get_nbasis(), - PARAM.inp.pw_diag_ndim, - this->diag_ethr, - david_maxiter, - false, //always do the subspace diag (check the implementation) - comm_info); - - std::function hpsi_func = [pHamilt]( - T* psi_in, - T* hpsi_out, - const int nband_in, - const int nbasis_in, - const int band_index1, - const int band_index2) - { - auto psi_iter_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_in, nullptr); - psi::Range bands_range(true, 0, band_index1, band_index2); - using hpsi_info = typename hamilt::Operator::hpsi_info; - hpsi_info info(&psi_iter_wrapper, bands_range, hpsi_out); - pHamilt->ops->hPsi(info); - }; - auto subspace_func = [pHamilt](T* psi_out, - T* psi_in, - Real* eigenvalue_in_hsolver, - const int nband_in, - const int nbasis_max_in) { - // Convert "pointer data stucture" to a psi::Psi object - auto psi_in_wrapper = psi::Psi(psi_in, 1, nband_in, nbasis_max_in, nullptr); - auto psi_out_wrapper = psi::Psi(psi_out, 1, nband_in, nbasis_max_in, nullptr); - - hsolver::DiagoIterAssist::diagH_subspace(pHamilt, - psi_in_wrapper, - psi_out_wrapper, - eigenvalue_in_hsolver, - nband_in); - }; - - hsolver::DiagoIterAssist::avg_iter - += static_cast(dav_subspace.diag( - hpsi_func, psi_k1_dav.get_pointer(), - psi_k1_dav.get_nbasis(), - eigenvalue.data(), - std::vector(psi_k1_dav.get_nbands(), true), - false /*scf*/)); - } - // else if (this->method == "cg") - // { - // this->pdiagh = new DiagoCG(precondition.data()); - // this->pdiagh->method = this->method; - // } - else {throw std::runtime_error("HSolverLR::solve: method not implemented");} - } - - // 5. copy eigenvalue to pes - for (int ist = 0;ist < psi.get_nbands();++ist) { pes->ekb(ispin_solve, ist) = eigenvalue[ist];} - - - // 6. output eigenvalues and eigenvectors - print_eigs(eigenvalue, "eigenvalues: (Ry)"); - print_eigs(eigenvalue, "eigenvalues: (eV)", ModuleBase::Ry_to_eV); - if (out_wfc_lr) - { - if (GlobalV::MY_RANK == 0) - { - std::ofstream ofs(PARAM.globalv.global_out_dir + "Excitation_Energy_" + spin_types[ispin_solve] + ".dat"); - ofs << std::setprecision(8) << std::scientific; - for (auto& e : eigenvalue) {ofs << e << " ";} - ofs.close(); - } - LR_Util::write_psi_bandfirst(psi, PARAM.globalv.global_out_dir + "Excitation_Amplitude_" + spin_types[ispin_solve], GlobalV::MY_RANK); - } - - // normalization is already satisfied - // std::cout << "check normalization of eigenvectors:" << std::endl; - // for (int ist = 0;ist < psi.get_nbands();++ist) - // { - // double norm2 = 0; - // for (int ik = 0;ik < psi.get_nk();++ik) - // { - // for (int ib = 0;ib < psi.get_nbasis();++ib) - // { - // norm2 += square(psi(ist, ik, ib)); - // // std::cout << "norm2_now=" << norm2 << std::endl; - // } - // } - // std::cout << "state " << ist << ", norm2=" << norm2 << std::endl; - // } - - // output iters - std::cout << "Average iterative diagonalization steps: " << hsolver::DiagoIterAssist::avg_iter - << " ; where current threshold is: " << hsolver::DiagoIterAssist::PW_DIAG_THR << " . " << std::endl; - // castmem_2d_2h_op()(cpu_ctx, cpu_ctx, pes->ekb.c, eigenvalues.data(), pes->ekb.nr * pes->ekb.nc); - } - template class HSolverLR; - template class HSolverLR>; -}; \ No newline at end of file diff --git a/source/module_lr/hsolver_lrtd.h b/source/module_lr/hsolver_lrtd.h deleted file mode 100644 index 7248a5a4f1f..00000000000 --- a/source/module_lr/hsolver_lrtd.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "module_hsolver/hsolver.h" -#include "module_hsolver/diago_iter_assist.h" -#include "module_psi/psi.h" -namespace LR -{ - template - class HSolverLR - { - using Real = typename GetTypeReal::type; - const int& nk; - const int& npairs; - const int& ispin_solve; - const bool out_wfc_lr = false; - public: - HSolverLR(const int& nk_in, const int& npairs_in, const int& ispin_solve_in = 0, const bool& out_wfc_lr_in = false) - :nk(nk_in), npairs(npairs_in), out_wfc_lr(out_wfc_lr_in), ispin_solve(ispin_solve_in) {}; - Real set_diagethr(Real diag_ethr_in, const int istep, const int iter, const Real ethr) - { - this->diag_ethr = ethr; - return ethr; - } - void solve(hamilt::Hamilt* pHamilt, - psi::Psi& psi, - elecstate::ElecState* pes, - const std::string method_in, - const bool hermitian = true); - - Real diag_ethr = 0.0; // threshold for diagonalization - - private: - std::string method = "none"; - }; -}; \ No newline at end of file diff --git a/source/module_lr/hsolver_lrtd.hpp b/source/module_lr/hsolver_lrtd.hpp new file mode 100644 index 00000000000..17771234685 --- /dev/null +++ b/source/module_lr/hsolver_lrtd.hpp @@ -0,0 +1,179 @@ +#pragma once +#include "module_parameter/parameter.h" +#include "module_hsolver/diago_david.h" +#include "module_hsolver/diago_dav_subspace.h" +#include "module_hsolver/diago_cg.h" +#include "module_hsolver/diago_iter_assist.h" +#include "module_hsolver/diago_cg.h" +#include "module_lr/utils/lr_util.h" +#include "module_lr/utils/lr_util_print.h" +#include "module_base/module_container/ATen/core/tensor_map.h" + +namespace LR +{ + template using Real = typename GetTypeReal::type; + + namespace HSolver + { + template + inline void print_eigs(const std::vector& eigs, const std::string& label = "", const double factor = 1.0) + { + std::cout << label << std::endl; + for (auto& e : eigs) { std::cout << e * factor << " "; } + std::cout << std::endl; + } + + /// eigensolver for common Hamilt + template + void solve(const THamilt& hm, + T* psi, + const int& dim, ///< local leading dimension (or nbasis) + const int& nband, ///< nstates in LR-TDDFT, not (nocc+nvirt) + double* eig, + const std::string method, + const Real& diag_ethr, ///< threshold for diagonalization + const bool hermitian = true) + { + ModuleBase::TITLE("HSolverLR", "solve"); + const std::vector spin_types = { "singlet", "triplet" }; + // note: if not TDA, the eigenvalues will be complex + // then we will need a new constructor of DiagoDavid + + // 1. allocate precondition and eigenvalue + std::vector> precondition(dim); + std::vector> eigenvalue(nband); //nstates + // 2. select the method +#ifdef __MPI + const hsolver::diag_comm_info comm_info = { POOL_WORLD, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL }; +#else + const hsolver::diag_comm_info comm_info = { GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL }; +#endif + + if (method == "lapack") + { + std::vector Amat_full = hm.matrix(); + const int gdim = std::sqrt(Amat_full.size()); + eigenvalue.resize(gdim); + if (hermitian) { LR_Util::diag_lapack(gdim, Amat_full.data(), eigenvalue.data()); } + else + { + std::vector> eig_complex(gdim); + LR_Util::diag_lapack_nh(gdim, Amat_full.data(), eig_complex.data()); + print_eigs(eig_complex, "Right eigenvalues: of the non-Hermitian matrix: (Ry)"); + for (int i = 0; i < gdim; i++) { eigenvalue[i] = eig_complex[i].real(); } + } + // copy eigenvectors + hm.global2local(psi, Amat_full.data(), nband); + } + else + { + // 3. set precondition and diagethr + for (int i = 0; i < dim; ++i) { precondition[i] = static_cast>(1.0); } + + const int maxiter = hsolver::DiagoIterAssist::PW_DIAG_NMAX; + + auto hpsi_func = [&hm](T* psi_in, T* hpsi, const int ld_psi, const int nvec) {hm.hPsi(psi_in, hpsi, ld_psi, nvec);}; + auto spsi_func = [&hm](const T* psi_in, T* spsi, const int ld_psi, const int nvec) + { std::memcpy(spsi, psi_in, sizeof(T) * ld_psi * nvec); }; + + if (method == "dav") + { + // Allow 5 tries at most. If ntry > ntry_max = 5, exit diag loop. + const int ntry_max = 5; + // In non-self consistent calculation, do until totally converged. Else allow 5 eigenvecs to be NOT + // converged. + const int notconv_max = ("nscf" == PARAM.inp.calculation) ? 0 : 5; + // do diag and add davidson iteration counts up to avg_iter + hsolver::DiagoDavid david(precondition.data(), nband, dim, PARAM.inp.pw_diag_ndim, PARAM.inp.use_paw, comm_info); + hsolver::DiagoIterAssist::avg_iter += static_cast(david.diag(hpsi_func, spsi_func, + dim, psi, eigenvalue.data(), diag_ethr, maxiter, ntry_max, 0)); + } + else if (method == "dav_subspace") //need refactor + { + hsolver::Diago_DavSubspace dav_subspace(precondition, + nband, + dim, + PARAM.inp.pw_diag_ndim, + diag_ethr, + maxiter, + false, //always do the subspace diag (check the implementation) + comm_info); + std::vector ethr_band(nband, diag_ethr); + hsolver::DiagoIterAssist::avg_iter + += static_cast(dav_subspace.diag( + hpsi_func, psi, + dim, + eigenvalue.data(), + ethr_band.data(), + false /*scf*/)); + } + else if (method == "cg") + { + ////// `diagH_subspace` needs refactor: + ////// replace `Hamilt*` with `hpsi_func` + ////// or I cannot use `is_subspace=true` as my `HamiltLR` does not inherit `Hamilt`. + + // auto subspace_func = [&hm](const ct::Tensor& psi_in, ct::Tensor& psi_out) { + // const auto ndim = psi_in.shape().ndim(); + // REQUIRES_OK(ndim == 2, "dims of psi_in should be less than or equal to 2"); + // // Convert a Tensor object to a psi::Psi object + // auto psi_in_wrapper = psi::Psi(psi_in.data(), + // 1, + // psi_in.shape().dim_size(0), + // psi_in.shape().dim_size(1)); + // auto psi_out_wrapper = psi::Psi(psi_out.data(), + // 1, + // psi_out.shape().dim_size(0), + // psi_out.shape().dim_size(1)); + // auto eigen = ct::Tensor(ct::DataTypeToEnum>::value, + // ct::DeviceType::CpuDevice, + // ct::TensorShape({ psi_in.shape().dim_size(0) })); + // hsolver::DiagoIterAssist::diagH_subspace(hm, psi_in_wrapper, psi_out_wrapper, eigen.data>()); + // }; + + ////// why diago_cg depends on basis_type? + // hsolver::DiagoCG cg("lcao", "nscf", true, subspace_func, diag_ethr, maxiter, GlobalV::NPROC_IN_POOL); + + auto subspace_func = [](const ct::Tensor& psi_in, ct::Tensor& psi_out) {}; + hsolver::DiagoCG cg("lcao", "nscf", false, subspace_func, diag_ethr, maxiter, GlobalV::NPROC_IN_POOL); + + auto psi_tensor = ct::TensorMap(psi, ct::DataTypeToEnum::value, ct::DeviceType::CpuDevice, ct::TensorShape({ nband, dim })); + auto eigen_tensor = ct::TensorMap(eigenvalue.data(), ct::DataTypeToEnum>::value, ct::DeviceType::CpuDevice, ct::TensorShape({ nband })); + auto precon_tensor = ct::TensorMap(precondition.data(), ct::DataTypeToEnum>::value, ct::DeviceType::CpuDevice, ct::TensorShape({ dim })); + auto hpsi_func = [&hm](const ct::Tensor& psi_in, ct::Tensor& hpsi) {hm.hPsi(psi_in.data(), hpsi.data(), psi_in.shape().dim_size(0) /*nbasis_local*/, 1/*band-by-band*/);}; + auto spsi_func = [&hm](const ct::Tensor& psi_in, ct::Tensor& spsi) + { std::memcpy(spsi.data(), psi_in.data(), sizeof(T) * psi_in.NumElements()); }; + cg.diag(hpsi_func, spsi_func, psi_tensor, eigen_tensor, precon_tensor); + } + else { throw std::runtime_error("HSolverLR::solve: method not implemented"); } + } + + // 5. copy eigenvalues + for (int ist = 0;ist < nband;++ist) { eig[ist] = eigenvalue[ist]; } + + // 6. output eigenvalues and eigenvectors + print_eigs(eigenvalue, "eigenvalues: (Ry)"); + print_eigs(eigenvalue, "eigenvalues: (eV)", ModuleBase::Ry_to_eV); + + // normalization is already satisfied + // std::cout << "check normalization of eigenvectors:" << std::endl; + // for (int ist = 0;ist < nband;++ist) + // { + // double norm2 = 0; + // for (int ik = 0;ik < psi.get_nk();++ik) + // { + // for (int ib = 0;ib < psi.get_nbasis();++ib) + // { + // norm2 += std::norm(psi(ist, ik, ib)); + // // std::cout << "norm2_now=" << norm2 << std::endl; + // } + // } + // std::cout << "state " << ist << ", norm2=" << norm2 << std::endl; + // } + + // output iters + std::cout << "Average iterative diagonalization steps: " << hsolver::DiagoIterAssist::avg_iter + << " ; where current threshold is: " << hsolver::DiagoIterAssist::PW_DIAG_THR << " . " << std::endl; + } + } +} \ No newline at end of file diff --git a/source/module_lr/lr_spectrum.cpp b/source/module_lr/lr_spectrum.cpp index f39940bc2cd..5cd9acfdb39 100644 --- a/source/module_lr/lr_spectrum.cpp +++ b/source/module_lr/lr_spectrum.cpp @@ -7,12 +7,10 @@ #include "module_lr/utils/lr_util_hcontainer.h" #include "module_lr/utils/lr_util_print.h" template -void LR::LR_Spectrum::cal_gint_rho(double** rho, const int& nspin_solve, const int& nrxx) +void LR::LR_Spectrum::cal_gint_rho(double** rho, const int& nrxx) { - for (int is = 0;is < nspin_solve;++is) { - ModuleBase::GlobalFunc::ZEROS(rho[is], nrxx); -} - Gint_inout inout_rho(rho, Gint_Tools::job_type::rho, false); + ModuleBase::GlobalFunc::ZEROS(rho[0], nrxx); + Gint_inout inout_rho(rho, Gint_Tools::job_type::rho, 1, false); this->gint->cal_gint(&inout_rho); } @@ -26,53 +24,52 @@ inline void check_sum_rule(const double& osc_tot) } template<> -void LR::LR_Spectrum::oscillator_strength() +void LR::LR_Spectrum::oscillator_strength(Grid_Driver& gd, const std::vector& orb_cutoff) { ModuleBase::TITLE("LR::LR_Spectrum", "oscillator_strength"); std::vector& osc = this->oscillator_strength_; // unit: Ry - osc.resize(X.get_nbands(), 0.0); - // const int nspin0 = (this->nspin == 2) ? 2 : 1; use this in NSPIN=4 implementation + osc.resize(nstate, 0.0); double osc_tot = 0.0; - elecstate::DensityMatrix DM_trans(&this->kv, &this->pmat, this->nspin); - DM_trans.init_DMR(&GlobalC::GridD, &this->ucell); - this->transition_dipole_.resize(X.get_nbands(), ModuleBase::Vector3(0.0, 0.0, 0.0)); - for (int istate = 0;istate < X.get_nbands();++istate) + elecstate::DensityMatrix DM_trans(&this->pmat, 1, this->kv.kvec_d, this->nk); + LR_Util::initialize_DMR(DM_trans, this->pmat, this->ucell, gd, orb_cutoff); + this->transition_dipole_.resize(nstate, ModuleBase::Vector3(0.0, 0.0, 0.0)); + for (int istate = 0;istate < nstate;++istate) { - X.fix_b(istate); - - // LR_Util::print_psi_bandfirst(X, "final X", istate); - - //1. transition density + const int offset_b = istate * ldim; //start index of band istate + for (int is = 0;is < this->nspin_x;++is) + { + const int offset_x = offset_b + is * nk * pX[0].get_local_size(); + //1. transition density #ifdef __MPI - std::vector dm_trans_2d = cal_dm_trans_pblas(X, this->pX, this->psi_ks, this->pc, this->naos, this->nocc, this->nvirt, this->pmat); - // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat); + std::vector dm_trans_2d = cal_dm_trans_pblas(X + offset_x, this->pX[is], psi_ks[is], this->pc, this->naos, this->nocc[is], this->nvirt[is], this->pmat); + // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat); #else - std::vector dm_trans_2d = cal_dm_trans_blas(X, this->psi_ks, this->nocc, this->nvirt); - // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); + std::vector dm_trans_2d = cal_dm_trans_blas(X + offset_x, this->psi_ks[is], this->nocc[is], this->nvirt[is]); + // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); #endif - for (int ik = 0;ik < this->nk;++ik) { DM_trans.set_DMK_pointer(ik, dm_trans_2d[ik].data()); } - DM_trans.cal_DMR(); - this->gint->transfer_DM2DtoGrid(DM_trans.get_DMR_vector()); + for (int ik = 0;ik < this->nk;++ik) { DM_trans.set_DMK_pointer(ik, dm_trans_2d[ik].data()); } + DM_trans.cal_DMR(); + this->gint->transfer_DM2DtoGrid(DM_trans.get_DMR_vector()); - // 2. transition density - double** rho_trans; - // LR_Util::new_p2(rho_trans, nspin_solve, this->rho_basis.nrxx); - LR_Util::new_p2(rho_trans, nspin, this->rho_basis.nrxx); // currently gint_kernel_rho uses PARAM.inp.nspin, it needs refactor - this->cal_gint_rho(rho_trans, nspin_solve, this->rho_basis.nrxx); + // 2. transition density + double** rho_trans; + LR_Util::new_p2(rho_trans, 1, this->rho_basis.nrxx); + this->cal_gint_rho(rho_trans, this->rho_basis.nrxx); - // 3. transition dipole moment - for (int ir = 0; ir < rho_basis.nrxx; ++ir) - { - int i = ir / (rho_basis.ny * rho_basis.nplane); - int j = ir / rho_basis.nplane - i * rho_basis.ny; - int k = ir % rho_basis.nplane + rho_basis.startz_current; - ModuleBase::Vector3 rd(static_cast(i) / rho_basis.nx, static_cast(j) / rho_basis.ny, static_cast(k) / rho_basis.nz); //+1/2 better? - rd -= ModuleBase::Vector3(0.5, 0.5, 0.5); //shift to the center of the grid (need ?) - ModuleBase::Vector3 rc = rd * ucell.latvec * ucell.lat0; // real coordinate - for (int is = 0;is < nspin_solve;++is) transition_dipole_[istate] += rc * rho_trans[is][ir]; + // 3. transition dipole moment + for (int ir = 0; ir < rho_basis.nrxx; ++ir) + { + int i = ir / (rho_basis.ny * rho_basis.nplane); + int j = ir / rho_basis.nplane - i * rho_basis.ny; + int k = ir % rho_basis.nplane + rho_basis.startz_current; + ModuleBase::Vector3 rd(static_cast(i) / rho_basis.nx, static_cast(j) / rho_basis.ny, static_cast(k) / rho_basis.nz); //+1/2 better? + rd -= ModuleBase::Vector3(0.5, 0.5, 0.5); //shift to the center of the grid (need ?) + ModuleBase::Vector3 rc = rd * ucell.latvec * ucell.lat0; // real coordinate + transition_dipole_[istate] += rc * rho_trans[0][ir]; + } + LR_Util::delete_p2(rho_trans, 1); } transition_dipole_[istate] *= (ucell.omega / static_cast(gint->get_ncxyz())); // dv - LR_Util::delete_p2(rho_trans, nspin_solve); Parallel_Reduce::reduce_all(transition_dipole_[istate].x); Parallel_Reduce::reduce_all(transition_dipole_[istate].y); Parallel_Reduce::reduce_all(transition_dipole_[istate].z); @@ -83,73 +80,70 @@ void LR::LR_Spectrum::oscillator_strength() } template<> -void LR::LR_Spectrum>::oscillator_strength() +void LR::LR_Spectrum>::oscillator_strength(Grid_Driver& gd, const std::vector& orb_cutoff) { ModuleBase::TITLE("LR::LR_Spectrum", "oscillator_strength"); std::vector& osc = this->oscillator_strength_; // unit: Ry - osc.resize(X.get_nbands(), 0.0); - // const int nspin0 = (this->nspin == 2) ? 2 : 1; use this in NSPIN=4 implementation + osc.resize(nstate, 0.0); double osc_tot = 0.0; - elecstate::DensityMatrix, std::complex> DM_trans(&this->kv, &this->pmat, this->nspin); - DM_trans.init_DMR(&GlobalC::GridD, &this->ucell); - elecstate::DensityMatrix, double> DM_trans_real_imag(&this->kv, &this->pmat, this->nspin); - DM_trans_real_imag.init_DMR(&GlobalC::GridD, &this->ucell); + elecstate::DensityMatrix, std::complex> DM_trans(&this->pmat, 1, this->kv.kvec_d, this->nk); + LR_Util::initialize_DMR(DM_trans, this->pmat, this->ucell, gd, orb_cutoff); + elecstate::DensityMatrix, double> DM_trans_real_imag(&this->pmat, 1, this->kv.kvec_d, this->nk); + LR_Util::initialize_DMR(DM_trans_real_imag, this->pmat, this->ucell, gd, orb_cutoff); - this->transition_dipole_.resize(X.get_nbands(), ModuleBase::Vector3>(0.0, 0.0, 0.0)); - for (int istate = 0;istate < X.get_nbands();++istate) + this->transition_dipole_.resize(nstate, ModuleBase::Vector3>(0.0, 0.0, 0.0)); + for (int istate = 0;istate < nstate;++istate) { - X.fix_b(istate); - // LR_Util::print_psi_bandfirst(X, "final X", istate); - - //1. transition density + const int offset_b = istate * ldim; //start index of band istate + for (int is = 0;is < this->nspin_x;++is) + { + const int offset_x = offset_b + is * nk * pX[0].get_local_size(); + //1. transition density #ifdef __MPI - std::vector dm_trans_2d = cal_dm_trans_pblas(X, this->pX, this->psi_ks, this->pc, this->naos, this->nocc, this->nvirt, this->pmat, /*renorm_k=*/false, this->nspin_solve); - // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat); + std::vector dm_trans_2d = cal_dm_trans_pblas(X + offset_x, this->pX[is], psi_ks[is], this->pc, this->naos, this->nocc[is], this->nvirt[is], this->pmat, /*renorm_k=*/false, 1); + // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, pmat); #else - std::vector dm_trans_2d = cal_dm_trans_blas(X, this->psi_ks, this->nocc, this->nvirt,/*renorm_k=*/false, this->nspin_solve); - // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); + std::vector dm_trans_2d = cal_dm_trans_blas(X + offset_x, psi_ks[is], this->nocc[is], this->nvirt[is],/*renorm_k=*/false, 1); + // if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); #endif - for (int ik = 0;ik < this->nk;++ik) { DM_trans.set_DMK_pointer(ik, dm_trans_2d[ik].data>()); } - // for (int ik = 0;ik < this->nk;++ik) - // LR_Util::print_tensor>(dm_trans_2d[ik], "1.DMK[ik=" + std::to_string(ik) + "]", dynamic_cast(&this->pmat)); - - DM_trans.cal_DMR(); - - // 2. transition density - double** rho_trans_real; - double** rho_trans_imag; - LR_Util::new_p2(rho_trans_real, nspin_solve, this->rho_basis.nrxx); - LR_Util::new_p2(rho_trans_imag, nspin_solve, this->rho_basis.nrxx); - // real part - LR_Util::get_DMR_real_imag_part(DM_trans, DM_trans_real_imag, ucell.nat, 'R'); - this->gint->transfer_DM2DtoGrid(DM_trans_real_imag.get_DMR_vector()); - this->cal_gint_rho(rho_trans_real, nspin_solve, this->rho_basis.nrxx); - // LR_Util::print_grid_nonzero(rho_trans_real[0], this->rho_basis.nrxx, 10, "rho_trans"); - - // imag part - LR_Util::get_DMR_real_imag_part(DM_trans, DM_trans_real_imag, ucell.nat, 'I'); - this->gint->transfer_DM2DtoGrid(DM_trans_real_imag.get_DMR_vector()); - this->cal_gint_rho(rho_trans_imag, nspin_solve, this->rho_basis.nrxx); - // LR_Util::print_grid_nonzero(rho_trans_imag[0], this->rho_basis.nrxx, 10, "rho_trans"); - - - // 3. transition dipole moment - for (int ir = 0; ir < rho_basis.nrxx; ++ir) - { - int i = ir / (rho_basis.ny * rho_basis.nplane); - int j = ir / rho_basis.nplane - i * rho_basis.ny; - int k = ir % rho_basis.nplane + rho_basis.startz_current; - ModuleBase::Vector3 rd(static_cast(i) / rho_basis.nx, static_cast(j) / rho_basis.ny, static_cast(k) / rho_basis.nz); //+1/2 better? - rd -= ModuleBase::Vector3(0.5, 0.5, 0.5); //shift to the center of the grid (need ?) - ModuleBase::Vector3 rc = rd * ucell.latvec * ucell.lat0; // real coordinate - ModuleBase::Vector3> rc_complex(rc.x, rc.y, rc.z); - for (int is = 0;is < nspin_solve;++is) - transition_dipole_[istate] += rc_complex * - std::complex(rho_trans_real[is][ir], rho_trans_imag[is][ir]); + for (int ik = 0;ik < this->nk;++ik) { DM_trans.set_DMK_pointer(ik, dm_trans_2d[ik].data>()); } + // for (int ik = 0;ik < this->nk;++ik) + // LR_Util::print_tensor>(dm_trans_2d[ik], "1.DMK[ik=" + std::to_string(ik) + "]", dynamic_cast(&this->pmat)); + DM_trans.cal_DMR(); + + // 2. transition density + double** rho_trans_real; + double** rho_trans_imag; + LR_Util::new_p2(rho_trans_real, 1, this->rho_basis.nrxx); + LR_Util::new_p2(rho_trans_imag, 1, this->rho_basis.nrxx); + // real part + LR_Util::get_DMR_real_imag_part(DM_trans, DM_trans_real_imag, ucell.nat, 'R'); + this->gint->transfer_DM2DtoGrid(DM_trans_real_imag.get_DMR_vector()); + this->cal_gint_rho(rho_trans_real, this->rho_basis.nrxx); + // LR_Util::print_grid_nonzero(rho_trans_real[0], this->rho_basis.nrxx, 10, "rho_trans"); + + // imag part + LR_Util::get_DMR_real_imag_part(DM_trans, DM_trans_real_imag, ucell.nat, 'I'); + this->gint->transfer_DM2DtoGrid(DM_trans_real_imag.get_DMR_vector()); + this->cal_gint_rho(rho_trans_imag, this->rho_basis.nrxx); + // LR_Util::print_grid_nonzero(rho_trans_imag[0], this->rho_basis.nrxx, 10, "rho_trans"); + + // 3. transition dipole moment + for (int ir = 0; ir < rho_basis.nrxx; ++ir) + { + int i = ir / (rho_basis.ny * rho_basis.nplane); + int j = ir / rho_basis.nplane - i * rho_basis.ny; + int k = ir % rho_basis.nplane + rho_basis.startz_current; + ModuleBase::Vector3 rd(static_cast(i) / rho_basis.nx, static_cast(j) / rho_basis.ny, static_cast(k) / rho_basis.nz); //+1/2 better? + rd -= ModuleBase::Vector3(0.5, 0.5, 0.5); //shift to the center of the grid (need ?) + ModuleBase::Vector3 rc = rd * ucell.latvec * ucell.lat0; // real coordinate + ModuleBase::Vector3> rc_complex(rc.x, rc.y, rc.z); + transition_dipole_[istate] += rc_complex * std::complex(rho_trans_real[0][ir], rho_trans_imag[0][ir]); + } + LR_Util::delete_p2(rho_trans_real, 1); + LR_Util::delete_p2(rho_trans_imag, 1); } transition_dipole_[istate] *= (ucell.omega / static_cast(gint->get_ncxyz())); // dv - LR_Util::delete_p2(rho_trans_real, nspin_solve); - LR_Util::delete_p2(rho_trans_imag, nspin_solve); Parallel_Reduce::reduce_all(transition_dipole_[istate].x); Parallel_Reduce::reduce_all(transition_dipole_[istate].y); Parallel_Reduce::reduce_all(transition_dipole_[istate].z); @@ -164,11 +158,11 @@ void LR::LR_Spectrum>::oscillator_strength() check_sum_rule(osc_tot); } template -void LR::LR_Spectrum::optical_absorption(const std::vector& freq, const double eta, const int ispin) +void LR::LR_Spectrum::optical_absorption(const std::vector& freq, const double eta, const std::string& spintype) { ModuleBase::TITLE("LR::LR_Spectrum", "optical_absorption"); std::vector& osc = this->oscillator_strength_; - std::ofstream ofs(PARAM.globalv.global_out_dir + "absorption_" + this->spin_types[ispin] + ".dat"); + std::ofstream ofs(PARAM.globalv.global_out_dir + "absorption_" + spintype + ".dat"); if (GlobalV::MY_RANK == 0) { ofs << "Frequency (eV) | wave length(nm) | Absorption (a.u.)" << std::endl; } double FourPI_div_c = ModuleBase::FOUR_PI / 137.036; for (int f = 0;f < freq.size();++f) @@ -182,17 +176,17 @@ void LR::LR_Spectrum::optical_absorption(const std::vector& freq, con } template -void LR::LR_Spectrum::transition_analysis(const int ispin) +void LR::LR_Spectrum::transition_analysis(const std::string& spintype) { ModuleBase::TITLE("LR::LR_Spectrum", "transition_analysis"); std::ofstream& ofs = GlobalV::ofs_running; ofs << "==================================================================== " << std::endl; - ofs << std::setw(40) << this->spin_types[ispin] << std::endl; + ofs << std::setw(40) << spintype << std::endl; ofs << "==================================================================== " << std::endl; ofs << std::setw(8) << "State" << std::setw(30) << "Excitation Energy (Ry, eV)" << std::setw(45) << "Transition dipole x, y, z (a.u.)" << std::setw(30) << "Oscillator strength(a.u.)" << std::endl; ofs << "------------------------------------------------------------------------------------ " << std::endl; - for (int istate = 0;istate < X.get_nbands();++istate) + for (int istate = 0;istate < nstate;++istate) ofs << std::setw(8) << istate << std::setw(15) << std::setprecision(6) << eig[istate] << std::setw(15) << eig[istate] * ModuleBase::Ry_to_eV << std::setw(15) << transition_dipole_[istate].x << std::setw(15) << transition_dipole_[istate].y << std::setw(15) << transition_dipole_[istate].z << std::setw(30) << oscillator_strength_[istate] << std::endl; @@ -202,38 +196,54 @@ void LR::LR_Spectrum::transition_analysis(const int ispin) << std::setw(30) << "Excitation rate" << std::setw(10) << "k-point" << std::endl; ofs << "------------------------------------------------------------------------------------ " << std::endl; - for (int istate = 0;istate < X.get_nbands();++istate) + for (int istate = 0;istate < nstate;++istate) { /// find the main contributions (> 0.5) - X.fix_b(istate); - psi::Psi X_full(X.get_nk(), 1, nocc * nvirt, nullptr, false);// one-band - X_full.zero_out(); - for (int ik = 0;ik < X.get_nk();++ik) + const int loffset_b = istate * ldim; + std::vector X_full(gdim, T(0));// one-band, global + for (int is = 0;is < nspin_x;++is) { - X.fix_k(ik); - X_full.fix_k(ik); + const int loffset_bs = loffset_b + is * nk * pX[0].get_local_size(); + const int goffset_s = is * nk * nocc[0] * nvirt[0]; + for (int ik = 0;ik < nk;++ik) + { + const int loffset_x = loffset_bs + ik * pX[is].get_local_size(); + const int goffset_x = goffset_s + ik * nocc[is] * nvirt[is]; #ifdef __MPI - LR_Util::gather_2d_to_full(this->pX, X.get_pointer(), X_full.get_pointer(), false, nvirt, nocc); + LR_Util::gather_2d_to_full(this->pX[is], X + loffset_x, X_full.data() + goffset_x, false, nvirt[is], nocc[is]); #endif + } } std::map> abs_order; - X_full.fix_k(0); - for (int i = 0;i < X.get_nk() * nocc * nvirt;++i) { double abs = std::abs(X_full.get_pointer()[i]);if (abs > 0.3) { abs_order[abs] = i; } } + for (int i = 0;i < gdim;++i) { double abs = std::abs(X_full.at(i));if (abs > ana_thr) { abs_order[abs] = i; } } if (abs_order.size() > 0) { for (auto it = abs_order.cbegin();it != abs_order.cend();++it) { - int ik = it->second / (nocc * nvirt); - int ipair = it->second - ik * nocc * nvirt; + auto pair_info = get_pair_info(it->second); + const int& is = pair_info["ispin"]; + const std::string s = nspin_x == 2 ? (is == 0 ? "a" : "b") : ""; ofs << std::setw(8) << (it == abs_order.cbegin() ? std::to_string(istate) : " ") - << std::setw(20) << ipair / nvirt + 1 << std::setw(20) << ipair % nvirt + nocc + 1// iocc and ivirt - << std::setw(30) << X_full(ik, ipair) - << std::setw(30) << std::norm(X_full(ik, ipair)) - << std::setw(10) << ik << std::endl; + << std::setw(20) << std::to_string(pair_info["iocc"] + 1) + s << std::setw(20) << std::to_string(pair_info["ivirt"] + nocc[is] + 1) + s// iocc and ivirt + << std::setw(30) << X_full.at(it->second) + << std::setw(30) << std::norm(X_full.at(it->second)) + << std::setw(10) << pair_info["ik"] + 1 << std::endl; } } } ofs << "==================================================================== " << std::endl; - X.fix_kb(0, 0); +} + +template +std::map LR::LR_Spectrum::get_pair_info(const int i) +{ + assert(i >= 0 && i < gdim); + const int dim_spin0 = nk * nocc[0] * nvirt[0]; + const int ispin = (nspin_x == 2 && i >= dim_spin0) ? 1 : 0; + const int ik = (i - ispin*dim_spin0) / (nocc[ispin] * nvirt[ispin]); + const int ipair = (i - ispin*dim_spin0) - ik * nocc[ispin] * nvirt[ispin]; + const int iocc = ipair / nvirt[ispin]; + const int ivirt = ipair % nvirt[ispin]; + return { {"ispin", ispin}, {"ik", ik}, {"iocc", iocc}, {"ivirt", ivirt} }; } template class LR::LR_Spectrum; diff --git a/source/module_lr/lr_spectrum.h b/source/module_lr/lr_spectrum.h index 4888e5e6b32..4b521cd5646 100644 --- a/source/module_lr/lr_spectrum.h +++ b/source/module_lr/lr_spectrum.h @@ -1,6 +1,8 @@ +#include "module_cell/klist.h" #include "module_lr/utils/gint_template.h" #include "module_psi/psi.h" #include "module_elecstate/module_dm/density_matrix.h" +#include "module_lr/utils/lr_util.h" namespace LR { @@ -8,38 +10,50 @@ namespace LR class LR_Spectrum { public: - LR_Spectrum(const double* eig, const psi::Psi& X, const int& nspin, const int& naos, const int& nocc, const int& nvirt, - typename TGint::type* gint, const ModulePW::PW_Basis& rho_basis, psi::Psi& psi_ks, - const UnitCell& ucell, const K_Vectors& kv_in, Parallel_2D& pX_in, Parallel_2D& pc_in, Parallel_Orbitals& pmat_in) : - eig(eig), X(X), nspin(nspin), naos(naos), nocc(nocc), nvirt(nvirt), nk(kv_in.get_nks() / nspin), - gint(gint), rho_basis(rho_basis), psi_ks(psi_ks), - ucell(ucell), kv(kv_in), pX(pX_in), pc(pc_in), pmat(pmat_in) {}; - /// $$2/3\Omega\sum_{ia\sigma} |\braket{\psi_{i}|\mathbf{r}|\psi_{a}} |^2\int \rho_{\alpha\beta}(\mathbf{r}) \mathbf{r} d\mathbf{r}$$ - void oscillator_strength(); + LR_Spectrum(const int& nspin_global, const int& naos, const std::vector& nocc, const std::vector& nvirt, + typename TGint::type* gint, const ModulePW::PW_Basis& rho_basis, psi::Psi& psi_ks_in, + const UnitCell& ucell, const K_Vectors& kv_in, Grid_Driver& gd, const std::vector& orb_cutoff, + const std::vector& pX_in, const Parallel_2D& pc_in, const Parallel_Orbitals& pmat_in, + const double* eig, const T* X, const int& nstate, const bool& openshell) : + nspin_x(openshell ? 2 : 1), naos(naos), nocc(nocc), nvirt(nvirt), nk(kv_in.get_nks() / nspin_global), + gint(gint), rho_basis(rho_basis), ucell(ucell), kv(kv_in), + pX(pX_in), pc(pc_in), pmat(pmat_in), + eig(eig), X(X), nstate(nstate), + ldim(nk* (nspin_x == 2 ? pX_in[0].get_local_size() + pX_in[1].get_local_size() : pX_in[0].get_local_size())), + gdim(nk* std::inner_product(nocc.begin(), nocc.end(), nvirt.begin(), 0)) + { + for (int is = 0;is < nspin_global;++is) { psi_ks.emplace_back(LR_Util::get_psi_spin(psi_ks_in, is, nk)); } + this->oscillator_strength(gd, orb_cutoff); + }; /// @brief calculate the optical absorption spectrum - void optical_absorption(const std::vector& freq, const double eta, const int ispin = 0); + void optical_absorption(const std::vector& freq, const double eta, const std::string& spintype); /// @brief print out the transition dipole moment and the main contributions to the transition amplitude - void transition_analysis(const int ispin = 0); + void transition_analysis(const std::string& spintype); private: - const int& nspin; - const int nspin_solve = 1; - const int& naos; - const int& nocc; - const int& nvirt; + /// $$2/3\Omega\sum_{ia\sigma} |\braket{\psi_{i}|\mathbf{r}|\psi_{a}} |^2\int \rho_{\alpha\beta}(\mathbf{r}) \mathbf{r} d\mathbf{r}$$ + void oscillator_strength(Grid_Driver& gd, const std::vector& orb_cutoff); + const int nspin_x = 1; ///< 1 for singlet/triplet, 2 for updown(openshell) + const int naos = 1; + const std::vector& nocc; + const std::vector& nvirt; const int nk = 1; + const int nstate = 1; + const int ldim = 1;///< local leading dimension of X, or the data size of each state + const int gdim = 1;///< global leading dimension of X + const double ana_thr = 0.3; ///< {abs(X) > thr} will appear in the transition analysis log const double* eig; - const psi::Psi& X; + const T* X; const K_Vectors& kv; - const psi::Psi& psi_ks; - Parallel_2D& pX; - Parallel_2D& pc; - Parallel_Orbitals& pmat; + std::vector> psi_ks; + const std::vector& pX; + const Parallel_2D& pc; + const Parallel_Orbitals& pmat; typename TGint::type* gint = nullptr; const ModulePW::PW_Basis& rho_basis; const UnitCell& ucell; - const std::vector spin_types = { "Spin Singlet", "Spin Triplet" }; - void cal_gint_rho(double** rho, const int& nspin, const int& nrxx); + void cal_gint_rho(double** rho, const int& nrxx); + std::map get_pair_info(const int i); ///< given the index in X, return its ispin, ik, iocc, ivirt std::vector> transition_dipole_; ///< $\braket{ \psi_{i} | \mathbf{r} | \psi_{a} }$ std::vector oscillator_strength_;///< $2/3\Omega |\sum_{ia\sigma} \braket{\psi_{i}|\mathbf{r}|\psi_{a}} |^2$ diff --git a/source/module_lr/operator_casida/operator_lr_diag.h b/source/module_lr/operator_casida/operator_lr_diag.h index fb2910c1e7f..d6255caabe3 100644 --- a/source/module_lr/operator_casida/operator_lr_diag.h +++ b/source/module_lr/operator_casida/operator_lr_diag.h @@ -12,50 +12,49 @@ namespace LR class OperatorLRDiag : public hamilt::Operator { public: - OperatorLRDiag(const ModuleBase::matrix& eig_ks_in, const Parallel_2D* pX_in, const int& nk_in, const int& nocc_in, const int& nvirt_in) - : eig_ks(eig_ks_in), pX(pX_in), nk(nk_in), nocc(nocc_in), nvirt(nvirt_in) + OperatorLRDiag(const double* eig_ks, const Parallel_2D& pX_in, const int& nk_in, const int& nocc_in, const int& nvirt_in) + : pX(pX_in), nk(nk_in), nocc(nocc_in), nvirt(nvirt_in) { // calculate the difference of eigenvalues ModuleBase::TITLE("OperatorLRDiag", "OperatorLRDiag"); -#ifdef __MPI - Parallel_Common::bcast_double(eig_ks.c, eig_ks.nr * eig_ks.nc); -#endif - this->act_type = 2; + const int nbands = nocc + nvirt; this->cal_type = hamilt::calculation_type::no; - this->eig_ks_diff.create(nk, pX->get_local_size(), false); + this->eig_ks_diff.create(nk, pX.get_local_size(), false); for (int ik = 0;ik < nk;++ik) - for (int io = 0;io < pX->get_col_size();++io) //nocc_local - for (int iv = 0;iv < pX->get_row_size();++iv) //nvirt_local + { + const int& istart = ik * nbands; + for (int io = 0;io < pX.get_col_size();++io) //nocc_local + { + for (int iv = 0;iv < pX.get_row_size();++iv) //nvirt_local { - int io_g = pX->local2global_col(io); - int iv_g = pX->local2global_row(iv); - this->eig_ks_diff(ik, io * pX->get_row_size() + iv) = eig_ks(ik, nocc + iv_g) - eig_ks(ik, io_g); + int io_g = pX.local2global_col(io); + int iv_g = pX.local2global_row(iv); + this->eig_ks_diff(ik, io * pX.get_row_size() + iv) = eig_ks[istart + nocc + iv_g] - eig_ks[istart + io_g]; } + } + } }; void init(const int ik_in) override {}; /// caution: put this operator at the head of the operator list, /// because vector_mul_vector_op directly assign to (rather than add on) psi_out. - virtual void act(const psi::Psi& psi_in, psi::Psi& psi_out, const int nbands) const override + virtual void act(const int nbands, + const int nbasis, + const int npol, + const T* psi_in, + T* hpsi, + const int ngk_ik = 0, + const bool is_first_node = false)const override { ModuleBase::TITLE("OperatorLRDiag", "act"); - assert(nbands <= psi_in.get_nbands()); - - psi::Psi psi_in_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_in, this->nk, this->pX->get_local_size()); - psi::Psi psi_out_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_out, this->nk, this->pX->get_local_size()); - for (int ib = 0;ib < nbands;++ib) - { - psi_in_bfirst.fix_b(ib); - psi_out_bfirst.fix_b(ib); - hsolver::vector_mul_vector_op()(this->ctx, - psi_in_bfirst.get_nk() * psi_in_bfirst.get_nbasis(), - psi_out_bfirst.get_pointer(), - psi_in_bfirst.get_pointer(), - this->eig_ks_diff.c); - } + const int nlocal_ph = nk * pX.get_local_size(); // local size of particle-hole basis + hsolver::vector_mul_vector_op()(this->ctx, + nk * pX.get_local_size(), + hpsi, + psi_in, + this->eig_ks_diff.c); } private: - const ModuleBase::matrix& eig_ks; - const Parallel_2D* pX; + const Parallel_2D& pX; ModuleBase::matrix eig_ks_diff; const int& nk; const int& nocc; diff --git a/source/module_lr/operator_casida/operator_lr_exx.cpp b/source/module_lr/operator_casida/operator_lr_exx.cpp index 311a274c57e..47bdcb23998 100644 --- a/source/module_lr/operator_casida/operator_lr_exx.cpp +++ b/source/module_lr/operator_casida/operator_lr_exx.cpp @@ -10,24 +10,21 @@ namespace LR void OperatorLREXX::allocate_Ds_onebase() { ModuleBase::TITLE("OperatorLREXX", "allocate_Ds_onebase"); - this->Ds_onebase.resize(this->nspin_solve); - for (int is = 0;is < this->nspin_solve;++is) { - for (int iat1 = 0;iat1 < ucell.nat;++iat1) { - const int it1 = ucell.iat2it[iat1]; - for (int iat2 = 0;iat2 < ucell.nat;++iat2) { - const int it2=ucell.iat2it[iat2]; - for (auto cell : this->BvK_cells) { - this->Ds_onebase[is][iat1][std::make_pair(iat2, cell)] = aims_nbasis.empty() ? - RI::Tensor({ static_cast(ucell.atoms[it1].nw), static_cast(ucell.atoms[it2].nw) }) : - RI::Tensor({ static_cast( aims_nbasis[it1]), static_cast( aims_nbasis[it2]) }); - } + for (int iat1 = 0;iat1 < ucell.nat;++iat1) { + const int it1 = ucell.iat2it[iat1]; + for (int iat2 = 0;iat2 < ucell.nat;++iat2) { + const int it2 = ucell.iat2it[iat2]; + for (auto cell : this->BvK_cells) { + this->Ds_onebase[iat1][std::make_pair(iat2, cell)] = aims_nbasis.empty() ? + RI::Tensor({ static_cast(ucell.atoms[it1].nw), static_cast(ucell.atoms[it2].nw) }) : + RI::Tensor({ static_cast(aims_nbasis[it1]), static_cast(aims_nbasis[it2]) }); } } } } template<> - void OperatorLREXX::cal_DM_onebase(const int io, const int iv, const int ik, const int is) const + void OperatorLREXX::cal_DM_onebase(const int io, const int iv, const int ik) const { ModuleBase::TITLE("OperatorLREXX", "cal_DM_onebase"); assert(ik == 0); @@ -40,18 +37,19 @@ namespace LR { int iat1 = ucell.itia2iat(it1, ia1); int iat2 = ucell.itia2iat(it2, ia2); - auto& D2d = this->Ds_onebase[is][iat1][std::make_pair(iat2, cell)]; + auto& D2d = this->Ds_onebase[iat1][std::make_pair(iat2, cell)]; const int nw1 = aims_nbasis.empty() ? ucell.atoms[it1].nw : aims_nbasis[it1]; const int nw2 = aims_nbasis.empty() ? ucell.atoms[it2].nw : aims_nbasis[it2]; for (int iw1 = 0;iw1 < nw1;++iw1) for (int iw2 = 0;iw2 < nw2;++iw2) - D2d(iw1, iw2) = this->psi_ks_full(ik, io, ucell.itiaiw2iwt(it1, ia1, iw1)) * this->psi_ks_full(ik, nocc + iv, ucell.itiaiw2iwt(it2, ia2, iw2)); + if (this->pmat.in_this_processor(ucell.itiaiw2iwt(it1, ia1, iw1), ucell.itiaiw2iwt(it2, ia2, iw2))) + D2d(iw1, iw2) = this->psi_ks_full(ik, io, ucell.itiaiw2iwt(it1, ia1, iw1)) * this->psi_ks_full(ik, nocc + iv, ucell.itiaiw2iwt(it2, ia2, iw2)); } } } template<> - void OperatorLREXX>::cal_DM_onebase(const int io, const int iv, const int ik, const int is) const + void OperatorLREXX>::cal_DM_onebase(const int io, const int iv, const int ik) const { ModuleBase::TITLE("OperatorLREXX", "cal_DM_onebase"); for (auto cell : this->BvK_cells) @@ -65,92 +63,74 @@ namespace LR { int iat1 = ucell.itia2iat(it1, ia1); int iat2 = ucell.itia2iat(it2, ia2); - auto& D2d = this->Ds_onebase[is][iat1][std::make_pair(iat2, cell)]; + auto& D2d = this->Ds_onebase[iat1][std::make_pair(iat2, cell)]; const int nw1 = aims_nbasis.empty() ? ucell.atoms[it1].nw : aims_nbasis[it1]; const int nw2 = aims_nbasis.empty() ? ucell.atoms[it2].nw : aims_nbasis[it2]; for (int iw1 = 0;iw1 < nw1;++iw1) for (int iw2 = 0;iw2 < nw2;++iw2) - D2d(iw1, iw2) = frac * std::conj(this->psi_ks_full(ik, io, ucell.itiaiw2iwt(it1, ia1, iw1))) * this->psi_ks_full(ik, nocc + iv, ucell.itiaiw2iwt(it2, ia2, iw2)); + if (this->pmat.in_this_processor(ucell.itiaiw2iwt(it1, ia1, iw1), ucell.itiaiw2iwt(it2, ia2, iw2))) + D2d(iw1, iw2) = frac * std::conj(this->psi_ks_full(ik, io, ucell.itiaiw2iwt(it1, ia1, iw1))) * this->psi_ks_full(ik, nocc + iv, ucell.itiaiw2iwt(it2, ia2, iw2)); } } } template - void OperatorLREXX::act(const psi::Psi& psi_in, psi::Psi& psi_out, const int nbands) const + void OperatorLREXX::act(const int nbands, const int nbasis, const int npol, const T* psi_in, T* hpsi, const int ngk_ik, const bool is_first_node)const { ModuleBase::TITLE("OperatorLREXX", "act"); - assert(nbands <= psi_in.get_nbands()); const int& nk = this->kv.get_nks() / this->nspin; - psi::Psi psi_in_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_in, nk, this->pX->get_local_size()); - psi::Psi psi_out_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_out, nk, this->pX->get_local_size()); // convert parallel info to LibRI interfaces - std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(*this->pmat); - for (int ib = 0;ib < nbands;++ib) - { - psi_out_bfirst.fix_b(ib); - // suppose Cs,Vs, have already been calculated in the ion-step of ground state, - // DM_trans(k) and DM_trans(R) has already been calculated from psi_in in OperatorLRHxc::act - // but int RI_benchmark, DM_trans(k) should be first calculated here - if (cal_dm_trans) - { -#ifdef __MPI - std::vector dm_trans_2d = cal_dm_trans_pblas(psi_in_bfirst, *pX, *psi_ks, *pc, naos, nocc, nvirt, *pmat); - if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, *pmat); -#else - std::vector dm_trans_2d = cal_dm_trans_blas(psi_in_bfirst, *psi_ks, nocc, nvirt); - if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); -#endif - // tensor to vector, then set DMK - for (int ik = 0;ik < nk;++ik) { this->DM_trans[ib]->set_DMK_pointer(ik, dm_trans_2d[ik].data()); } - } + std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(this->pmat); - // 1. set_Ds (once) - // convert to vector for the interface of RI_2D_Comm::split_m2D_ktoR (interface will be unified to ct::Tensor) - std::vector> DMk_trans_vector = this->DM_trans[ib]->get_DMK_vector(); - // assert(DMk_trans_vector.size() == nk); - std::vector*> DMk_trans_pointer(nk); - for (int ik = 0;ik < nk;++ik) {DMk_trans_pointer[ik] = &DMk_trans_vector[ik];} - // if multi-k, DM_trans(TR=double) -> Ds_trans(TR=T=complex) - std::vector>>> Ds_trans = - aims_nbasis.empty() ? - RI_2D_Comm::split_m2D_ktoR(this->kv, DMk_trans_pointer, *this->pmat, this->nspin_solve) - : RI_Benchmark::split_Ds(DMk_trans_vector, aims_nbasis, ucell); //0.5 will be multiplied - // LR_Util::print_CV(Ds_trans[0], "Ds_trans in OperatorLREXX", 1e-10); - // 2. cal_Hs - auto lri = this->exx_lri.lock(); - for (int is = 0;is < nspin_solve;++is) - { - // LR_Util::print_CV(Ds_trans[is], "Ds_trans in OperatorLREXX", 1e-10); - lri->exx_lri.set_Ds(std::move(Ds_trans[is]), lri->info.dm_threshold); - lri->exx_lri.cal_Hs(); - lri->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( - lri->mpi_comm, std::move(lri->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); - lri->post_process_Hexx(lri->Hexxs[is]); - } + // suppose Cs,Vs, have already been calculated in the ion-step of ground state + // and DM_trans has been calculated in hPsi() outside. + + // 1. set_Ds (once) + // convert to vector for the interface of RI_2D_Comm::split_m2D_ktoR (interface will be unified to ct::Tensor) + std::vector> DMk_trans_vector = this->DM_trans->get_DMK_vector(); + // assert(DMk_trans_vector.size() == nk); + std::vector*> DMk_trans_pointer(nk); + for (int ik = 0;ik < nk;++ik) { DMk_trans_pointer[ik] = &DMk_trans_vector[ik]; } + // if multi-k, DM_trans(TR=double) -> Ds_trans(TR=T=complex) + std::vector>>> Ds_trans = + aims_nbasis.empty() ? + RI_2D_Comm::split_m2D_ktoR(this->kv, DMk_trans_pointer, this->pmat, 1) + : RI_Benchmark::split_Ds(DMk_trans_vector, aims_nbasis, ucell); //0.5 will be multiplied + // LR_Util::print_CV(Ds_trans[0], "Ds_trans in OperatorLREXX", 1e-10); + // 2. cal_Hs + auto lri = this->exx_lri.lock(); - // 3. set [AX]_iak = DM_onbase * Hexxs for each occ-virt pair and each k-point - // caution: parrallel + // LR_Util::print_CV(Ds_trans[is], "Ds_trans in OperatorLREXX", 1e-10); + lri->exx_lri.set_Ds(std::move(Ds_trans[0]), lri->info.dm_threshold); + lri->exx_lri.cal_Hs(); + lri->Hexxs[0] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( + lri->mpi_comm, std::move(lri->exx_lri.Hs), std::get<0>(judge[0]), std::get<1>(judge[0])); + lri->post_process_Hexx(lri->Hexxs[0]); - for (int io = 0;io < this->pX->get_col_size();++io) // nocc for serial + // 3. set [AX]_iak = DM_onbase * Hexxs for each occ-virt pair and each k-point + // caution: parrallel + + for (int io = 0;io < this->nocc;++io) + { + for (int iv = 0;iv < this->nvirt;++iv) { - for (int iv = 0;iv < this->pX->get_row_size();++iv) // nvirt for serial + for (int ik = 0;ik < nk;++ik) { - for (int ik = 0;ik < nk;++ik) + const int xstart_bk = ik * pX.get_local_size(); + this->cal_DM_onebase(io, iv, ik); //set Ds_onebase for all e-h pairs (not only on this processor) + // LR_Util::print_CV(Ds_onebase[is], "Ds_onebase of occ " + std::to_string(io) + ", virtual " + std::to_string(iv) + " in OperatorLREXX", 1e-10); + const T& ene = 2 * alpha * //minus for exchange(but here plus is right, why?), 2 for Hartree to Ry + lri->exx_lri.post_2D.cal_energy(this->Ds_onebase, lri->Hexxs[0]); + if (this->pX.in_this_processor(iv, io)) { - for (int is = 0;is < this->nspin_solve;++is) - { - this->cal_DM_onebase(this->pX->local2global_col(io), this->pX->local2global_row(iv), ik, is); //set Ds_onebase - // LR_Util::print_CV(Ds_onebase[is], "Ds_onebase of occ " + std::to_string(io) + ", virtual " + std::to_string(iv) + " in OperatorLREXX", 1e-10); - psi_out_bfirst(ik, io * this->pX->get_row_size() + iv) += 2 * //minus for exchange(but here plus is right, why?), 2 for Hartree to Ry - alpha * lri->exx_lri.post_2D.cal_energy(this->Ds_onebase[is], lri->Hexxs[is]); - } + hpsi[xstart_bk + ik * pX.get_local_size() + this->pX.global2local_col(io) * this->pX.get_row_size() + this->pX.global2local_row(iv)] += ene; } } } - } + } template class OperatorLREXX; template class OperatorLREXX>; diff --git a/source/module_lr/operator_casida/operator_lr_exx.h b/source/module_lr/operator_casida/operator_lr_exx.h index ec39cc788cc..657f4c4af2c 100644 --- a/source/module_lr/operator_casida/operator_lr_exx.h +++ b/source/module_lr/operator_casida/operator_lr_exx.h @@ -22,67 +22,70 @@ namespace LR const int& nocc, const int& nvirt, const UnitCell& ucell_in, - const psi::Psi* psi_ks_in, - std::vector>>& DM_trans_in, + const psi::Psi& psi_ks_in, + std::unique_ptr>& DM_trans_in, // HContainer* hR_in, std::weak_ptr> exx_lri_in, const K_Vectors& kv_in, - Parallel_2D* pX_in, - Parallel_2D* pc_in, - Parallel_Orbitals* pmat_in, + const Parallel_2D& pX_in, + const Parallel_2D& pc_in, + const Parallel_Orbitals& pmat_in, const double& alpha = 1.0, - const bool& cal_dm_trans = false, const std::vector& aims_nbasis = {}) : nspin(nspin), naos(naos), nocc(nocc), nvirt(nvirt), psi_ks(psi_ks_in), DM_trans(DM_trans_in), exx_lri(exx_lri_in), kv(kv_in), - pX(pX_in), pc(pc_in), pmat(pmat_in), ucell(ucell_in), alpha(alpha), cal_dm_trans(cal_dm_trans), + pX(pX_in), pc(pc_in), pmat(pmat_in), ucell(ucell_in), alpha(alpha), aims_nbasis(aims_nbasis) { ModuleBase::TITLE("OperatorLREXX", "OperatorLREXX"); this->cal_type = hamilt::calculation_type::lcao_exx; - this->act_type = 2; this->is_first_node = false; // reduce psi_ks for later use - this->psi_ks_full.resize(this->kv.get_nks(), this->psi_ks->get_nbands(), this->naos); - LR_Util::gather_2d_to_full(*this->pc, this->psi_ks->get_pointer(), this->psi_ks_full.get_pointer(), false, this->naos, this->psi_ks->get_nbands()); + this->psi_ks_full.resize(this->kv.get_nks(), nocc + nvirt, this->naos); + LR_Util::gather_2d_to_full(this->pc, this->psi_ks.get_pointer(), this->psi_ks_full.get_pointer(), false, this->naos, nocc + nvirt); // get cells in BvK supercell const TC period = RI_Util::get_Born_vonKarmen_period(kv_in); this->BvK_cells = RI_Util::get_Born_von_Karmen_cells(period); this->allocate_Ds_onebase(); - this->exx_lri.lock()->Hexxs.resize(this->nspin_solve); + this->exx_lri.lock()->Hexxs.resize(1); }; void init(const int ik_in) override {}; - // virtual psi::Psi act(const psi::Psi& psi_in) const override; - virtual void act(const psi::Psi& psi_in, psi::Psi& psi_out, const int nbands) const override; - private: + virtual void act(const int nbands, + const int nbasis, + const int npol, + const T* psi_in, + T* hpsi, + const int ngk_ik = 0, + const bool is_first_node = false) const override; + + private: //global sizes const int& nspin; - const int nspin_solve = 1; const int& naos; const int& nocc; const int& nvirt; - const double& alpha; + const double alpha = 1.0; //(allow non-ref constant) const bool cal_dm_trans = false; const bool tdm_sym = false; ///< whether transition density matrix is symmetric const K_Vectors& kv; /// ground state wavefunction - const psi::Psi* psi_ks = nullptr; + const psi::Psi& psi_ks = nullptr; psi::Psi psi_ks_full; const std::vector aims_nbasis={}; ///< number of basis functions for each type of atom in FHI-aims /// transition density matrix - std::vector>>& DM_trans; + std::unique_ptr>& DM_trans; /// density matrix of a certain (i, a, k), with full naos*naos size for each key /// D^{iak}_{\mu\nu}(k): 1/N_k * c^*_{ak,\mu} c_{ik,\nu} /// D^{iak}_{\mu\nu}(R): D^{iak}_{\mu\nu}(k)e^{-ikR} // elecstate::DensityMatrix* DM_onebase; - mutable std::vector>>> Ds_onebase; + mutable std::map>> Ds_onebase; // cells in the Born von Karmen supercell (direct) std::vector> BvK_cells; @@ -99,15 +102,15 @@ namespace LR const UnitCell& ucell; ///parallel info - Parallel_2D* pc = nullptr; - Parallel_2D* pX = nullptr; - Parallel_Orbitals* pmat = nullptr; + const Parallel_2D& pc; + const Parallel_2D& pX; + const Parallel_Orbitals& pmat; // allocate Ds_onebase void allocate_Ds_onebase(); - void cal_DM_onebase(const int io, const int iv, const int ik, const int is) const; + void cal_DM_onebase(const int io, const int iv, const int ik) const; }; } diff --git a/source/module_lr/operator_casida/operator_lr_hxc.cpp b/source/module_lr/operator_casida/operator_lr_hxc.cpp index f9bc15f2f1a..31e64a9acfc 100644 --- a/source/module_lr/operator_casida/operator_lr_hxc.cpp +++ b/source/module_lr/operator_casida/operator_lr_hxc.cpp @@ -8,7 +8,6 @@ #include "module_lr/utils/lr_util_print.h" // #include "module_hamilt_lcao/hamilt_lcaodft/DM_gamma_2d_to_grid.h" #include "module_hamilt_lcao/module_hcontainer/hcontainer_funcs.h" -#include "module_lr/dm_trans/dm_trans.h" #include "module_lr/AX/AX.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" @@ -18,127 +17,83 @@ inline std::complex conj(std::complex a) { return std::conj(a); namespace LR { template - void OperatorLRHxc::act(const psi::Psi& psi_in, psi::Psi& psi_out, const int nbands) const + void OperatorLRHxc::act(const int nbands, const int nbasis, const int npol, const T* psi_in, T* hpsi, const int ngk_ik, const bool is_first_node)const { ModuleBase::TITLE("OperatorLRHxc", "act"); - assert(nbands <= psi_in.get_nbands()); - const int& nk = this->kv.get_nks() / this->nspin; - - //print - // if (this->first_print) LR_Util::print_psi_kfirst(*psi_ks, "psi_ks"); + const int& sl = ispin_ks[0]; + const auto psil_ks = LR_Util::get_psi_spin(psi_ks, sl, nk); + const int& lgd = gint->gridt->lgd; - this->init_DM_trans(nbands, this->DM_trans); // initialize transion density matrix + this->DM_trans->cal_DMR(); //DM_trans->get_DMR_vector() is 2d-block parallized + // LR_Util::print_DMR(*DM_trans, ucell.nat, "DMR"); - psi::Psi psi_in_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_in, nk, this->pX->get_local_size()); - psi::Psi psi_out_bfirst = LR_Util::k1_to_bfirst_wrapper(psi_out, nk, this->pX->get_local_size()); + // ========================= begin grid calculation========================= + this->grid_calculation(nbands); //DM(R) to H(R) + // ========================= end grid calculation ========================= - const int& lgd = gint->gridt->lgd; - for (int ib = 0;ib < nbands;++ib) - { - // if (this->first_print) LR_Util::print_psi_bandfirst(psi_in_bfirst, "psi_in_bfirst", ib); + // V(R)->V(k) + std::vector v_hxc_2d(nk, LR_Util::newTensor({ pmat.get_col_size(), pmat.get_row_size() })); + for (auto& v : v_hxc_2d) v.zero(); + int nrow = ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) ? this->pmat.get_row_size() : this->pmat.get_col_size(); + for (int ik = 0;ik < nk;++ik) { folding_HR(*this->hR, v_hxc_2d[ik].data(), this->kv.kvec_d[ik], nrow, 1); } // V(R) -> V(k) + // LR_Util::print_HR(*this->hR, this->ucell.nat, "4.VR"); + // if (this->first_print) + // for (int ik = 0;ik < nk;++ik) + // LR_Util::print_tensor(v_hxc_2d[ik], "4.V(k)[ik=" + std::to_string(ik) + "]", &this->pmat); - // if Hxc-only, the memory of single-band DM_trans is enough. - // if followed by EXX, we need to allocate memory for all bands. - int ib_dm = (this->next_op == nullptr) ? 0 : ib; - psi_in_bfirst.fix_b(ib); - psi_out_bfirst.fix_b(ib); - - // 1. transition density matrix + // 5. [AX]^{Hxc}_{ai}=\sum_{\mu,\nu}c^*_{a,\mu,}V^{Hxc}_{\mu,\nu}c_{\nu,i} #ifdef __MPI - std::vector dm_trans_2d = cal_dm_trans_pblas(psi_in_bfirst, *pX, *psi_ks, *pc, naos, nocc, nvirt, *pmat); - if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos, *pmat); + cal_AX_pblas(v_hxc_2d, this->pmat, psil_ks, this->pc, naos, nocc[sl], nvirt[sl], this->pX[sl], hpsi); #else - std::vector dm_trans_2d = cal_dm_trans_blas(psi_in_bfirst, *psi_ks, nocc, nvirt); - if (this->tdm_sym) for (auto& t : dm_trans_2d) LR_Util::matsym(t.data(), naos); + cal_AX_blas(v_hxc_2d, psil_ks, nocc[sl], nvirt[sl], hpsi); #endif - // tensor to vector, then set DMK - for (int ik = 0;ik < nk;++ik) { this->DM_trans[ib_dm]->set_DMK_pointer(ik, dm_trans_2d[ik].data()); } - - // if (this->first_print) - // for (int ik = 0;ik < nk;++ik) - // LR_Util::print_tensor>(dm_trans_2d[ik], "1.DMK[ik=" + std::to_string(ik) + "]", this->pmat); - - // use cal_DMR to get DMR form DMK by FT - this->DM_trans[ib_dm]->cal_DMR(); //DM_trans->get_DMR_vector() is 2d-block parallized - // LR_Util::print_DMR(*this->DM_trans[0], ucell.nat, "DM(R) (complex)"); - - // ========================= begin grid calculation========================= - this->grid_calculation(nbands, ib_dm); //DM(R) to H(R) - // ========================= end grid calculation ========================= - - // V(R)->V(k) - std::vector v_hxc_2d(this->kv.get_nks(), - ct::Tensor(ct::DataTypeToEnum::value, ct::DeviceTypeToEnum::value, - { pmat->get_col_size(), pmat->get_row_size() })); - for (auto& v : v_hxc_2d) v.zero(); - int nrow = ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) ? this->pmat->get_row_size() : this->pmat->get_col_size(); - for (int ik = 0;ik < nk;++ik) { folding_HR(*this->hR, v_hxc_2d[ik].data(), this->kv.kvec_d[ik], nrow, 1); } // V(R) -> V(k) - // LR_Util::print_HR(*this->hR, this->ucell.nat, "4.VR"); - // if (this->first_print) - // for (int ik = 0;ik < nk;++ik) - // LR_Util::print_tensor(v_hxc_2d[ik], "4.V(k)[ik=" + std::to_string(ik) + "]", this->pmat); - - // 5. [AX]^{Hxc}_{ai}=\sum_{\mu,\nu}c^*_{a,\mu,}V^{Hxc}_{\mu,\nu}c_{\nu,i} -#ifdef __MPI - cal_AX_pblas(v_hxc_2d, *this->pmat, *this->psi_ks, *this->pc, naos, nocc, nvirt, *this->pX, psi_out_bfirst); -#else - cal_AX_blas(v_hxc_2d, *this->psi_ks, nocc, nvirt, psi_out_bfirst); -#endif - // if (this->first_print) LR_Util::print_psi_bandfirst(psi_out_bfirst, "5.AX", ib); - } } template<> - void OperatorLRHxc::grid_calculation(const int& nbands, const int& iband_dm) const + void OperatorLRHxc::grid_calculation(const int& nbands) const { ModuleBase::TITLE("OperatorLRHxc", "grid_calculation(real)"); ModuleBase::timer::tick("OperatorLRHxc", "grid_calculation"); - this->gint->transfer_DM2DtoGrid(this->DM_trans[iband_dm]->get_DMR_vector()); // 2d block to grid + this->gint->transfer_DM2DtoGrid(this->DM_trans->get_DMR_vector()); // 2d block to grid // 2. transition electron density // \f[ \tilde{\rho}(r)=\sum_{\mu_j, \mu_b}\tilde{\rho}_{\mu_j,\mu_b}\phi_{\mu_b}(r)\phi_{\mu_j}(r) \f] double** rho_trans; const int& nrxx = this->pot.lock()->nrxx; - // LR_Util::new_p2(rho_trans, nspin_solve, nrxx); - LR_Util::new_p2(rho_trans, nspin, nrxx); // currently gint_kernel_rho uses PARAM.inp.nspin, it needs refactor - for (int is = 0;is < nspin_solve;++is)ModuleBase::GlobalFunc::ZEROS(rho_trans[is], nrxx); - Gint_inout inout_rho(rho_trans, Gint_Tools::job_type::rho, false); + LR_Util::new_p2(rho_trans, 1, nrxx); // currently gint_kernel_rho uses PARAM.inp.nspin, it needs refactor + ModuleBase::GlobalFunc::ZEROS(rho_trans[0], nrxx); + Gint_inout inout_rho(rho_trans, Gint_Tools::job_type::rho, 1, false); this->gint->cal_gint(&inout_rho); // 3. v_hxc = f_hxc * rho_trans - ModuleBase::matrix vr_hxc(nspin_solve, nrxx); //grid - this->pot.lock()->cal_v_eff(rho_trans, &GlobalC::ucell, vr_hxc); - LR_Util::delete_p2(rho_trans, nspin_solve); + ModuleBase::matrix vr_hxc(1, nrxx); //grid + this->pot.lock()->cal_v_eff(rho_trans, &GlobalC::ucell, vr_hxc, ispin_ks); + LR_Util::delete_p2(rho_trans, 1); // 4. V^{Hxc}_{\mu,\nu}=\int{dr} \phi_\mu(r) v_{Hxc}(r) \phi_\mu(r) - // V(R) for each spin - for (int is = 0;is < nspin_solve;++is) - { - double* vr_hxc_is = &vr_hxc.c[is * nrxx]; //v(r) at current spin - Gint_inout inout_vlocal(vr_hxc_is, is, Gint_Tools::job_type::vlocal); - this->gint->get_hRGint()->set_zero(); - this->gint->cal_gint(&inout_vlocal); - } + Gint_inout inout_vlocal(vr_hxc.c, 0, Gint_Tools::job_type::vlocal); + this->gint->get_hRGint()->set_zero(); + this->gint->cal_gint(&inout_vlocal); this->hR->set_zero(); // clear hR for each bands this->gint->transfer_pvpR(&*this->hR, &GlobalC::ucell); //grid to 2d block ModuleBase::timer::tick("OperatorLRHxc", "grid_calculation"); } template<> - void OperatorLRHxc, base_device::DEVICE_CPU>::grid_calculation(const int& nbands, const int& iband_dm) const + void OperatorLRHxc, base_device::DEVICE_CPU>::grid_calculation(const int& nbands) const { ModuleBase::TITLE("OperatorLRHxc", "grid_calculation(complex)"); ModuleBase::timer::tick("OperatorLRHxc", "grid_calculation"); - elecstate::DensityMatrix, double> DM_trans_real_imag(&kv, pmat, nspin); + elecstate::DensityMatrix, double> DM_trans_real_imag(&pmat, 1, kv.kvec_d, kv.get_nks() / nspin); DM_trans_real_imag.init_DMR(*this->hR); - hamilt::HContainer HR_real_imag(GlobalC::ucell, this->pmat); - this->initialize_HR(HR_real_imag, ucell, gd, this->pmat); + hamilt::HContainer HR_real_imag(GlobalC::ucell, &this->pmat); + LR_Util::initialize_HR, double>(HR_real_imag, ucell, gd, orb_cutoff_); - auto dmR_to_hR = [&, this](const int& iband_dm, const char& type) -> void + auto dmR_to_hR = [&, this](const char& type) -> void { - LR_Util::get_DMR_real_imag_part(*this->DM_trans[iband_dm], DM_trans_real_imag, ucell.nat, type); + LR_Util::get_DMR_real_imag_part(*this->DM_trans, DM_trans_real_imag, ucell.nat, type); // if (this->first_print)LR_Util::print_DMR(DM_trans_real_imag, ucell.nat, "DMR(2d, real)"); this->gint->transfer_DM2DtoGrid(DM_trans_real_imag.get_DMR_vector()); @@ -147,28 +102,25 @@ namespace LR // 2. transition electron density double** rho_trans; const int& nrxx = this->pot.lock()->nrxx; - // LR_Util::new_p2(rho_trans, nspin_solve, nrxx); - LR_Util::new_p2(rho_trans, nspin, nrxx); // currently gint_kernel_rho uses PARAM.inp.nspin, it needs refactor - for (int is = 0;is < nspin_solve;++is)ModuleBase::GlobalFunc::ZEROS(rho_trans[is], nrxx); - Gint_inout inout_rho(rho_trans, Gint_Tools::job_type::rho, false); + + LR_Util::new_p2(rho_trans, 1, nrxx); // nspin=1 for transition density + ModuleBase::GlobalFunc::ZEROS(rho_trans[0], nrxx); + Gint_inout inout_rho(rho_trans, Gint_Tools::job_type::rho, 1, false); this->gint->cal_gint(&inout_rho); // print_grid_nonzero(rho_trans[0], nrxx, 10, "rho_trans"); // 3. v_hxc = f_hxc * rho_trans - ModuleBase::matrix vr_hxc(nspin_solve, nrxx); //grid - this->pot.lock()->cal_v_eff(rho_trans, &GlobalC::ucell, vr_hxc); + ModuleBase::matrix vr_hxc(1, nrxx); //grid + this->pot.lock()->cal_v_eff(rho_trans, &GlobalC::ucell, vr_hxc, ispin_ks); // print_grid_nonzero(vr_hxc.c, this->poticab->nrxx, 10, "vr_hxc"); - LR_Util::delete_p2(rho_trans, nspin_solve); + LR_Util::delete_p2(rho_trans, 1); // 4. V^{Hxc}_{\mu,\nu}=\int{dr} \phi_\mu(r) v_{Hxc}(r) \phi_\mu(r) - for (int is = 0;is < nspin_solve;++is) - { - double* vr_hxc_is = &vr_hxc.c[is * nrxx]; //v(r) at current spin - Gint_inout inout_vlocal(vr_hxc_is, is, Gint_Tools::job_type::vlocal); - this->gint->get_hRGint()->set_zero(); - this->gint->cal_gint(&inout_vlocal); - } + Gint_inout inout_vlocal(vr_hxc.c, 0, Gint_Tools::job_type::vlocal); + this->gint->get_hRGint()->set_zero(); + this->gint->cal_gint(&inout_vlocal); + // LR_Util::print_HR(*this->gint->get_hRGint(), this->ucell.nat, "VR(grid)"); HR_real_imag.set_zero(); this->gint->transfer_pvpR(&HR_real_imag, &GlobalC::ucell, &GlobalC::GridD); @@ -176,8 +128,8 @@ namespace LR LR_Util::set_HR_real_imag_part(HR_real_imag, *this->hR, GlobalC::ucell.nat, type); }; this->hR->set_zero(); - dmR_to_hR(iband_dm, 'R'); //real - if (kv.get_nks() / this->nspin > 1) { dmR_to_hR(iband_dm, 'I'); } //imag for multi-k + dmR_to_hR('R'); //real + if (kv.get_nks() / this->nspin > 1) { dmR_to_hR('I'); } //imag for multi-k ModuleBase::timer::tick("OperatorLRHxc", "grid_calculation"); } diff --git a/source/module_lr/operator_casida/operator_lr_hxc.h b/source/module_lr/operator_casida/operator_lr_hxc.h index 1c5ac175917..1c97c907b8e 100644 --- a/source/module_lr/operator_casida/operator_lr_hxc.h +++ b/source/module_lr/operator_casida/operator_lr_hxc.h @@ -1,4 +1,5 @@ #pragma once +#include "module_cell/klist.h" #include "module_hamilt_general/operator.h" #include "module_lr/utils/gint_template.h" #include "module_hamilt_lcao/module_gint/grid_technique.h" @@ -16,104 +17,69 @@ namespace LR //when nspin=2, nks is 2 times of real number of k-points. else (nspin=1 or 4), nks is the real number of k-points OperatorLRHxc(const int& nspin, const int& naos, - const int& nocc, - const int& nvirt, - const psi::Psi* psi_ks_in, - std::vector>>& DM_trans_in, + const std::vector& nocc, + const std::vector& nvirt, + const psi::Psi& psi_ks_in, + std::unique_ptr>& DM_trans_in, typename TGint::type* gint_in, std::weak_ptr pot_in, const UnitCell& ucell_in, const std::vector& orb_cutoff, Grid_Driver& gd_in, const K_Vectors& kv_in, - Parallel_2D* pX_in, - Parallel_2D* pc_in, - Parallel_Orbitals* pmat_in) - : nspin(nspin), naos(naos), nocc(nocc), nvirt(nvirt), + const std::vector& pX_in, + const Parallel_2D& pc_in, + const Parallel_Orbitals& pmat_in, + const std::vector& ispin_ks = { 0 }) + : nspin(nspin), naos(naos), nocc(nocc), nvirt(nvirt), nk(kv_in.get_nks() / nspin), psi_ks(psi_ks_in), DM_trans(DM_trans_in), gint(gint_in), pot(pot_in), ucell(ucell_in), orb_cutoff_(orb_cutoff), gd(gd_in), kv(kv_in), - pX(pX_in), pc(pc_in), pmat(pmat_in) + pX(pX_in), pc(pc_in), pmat(pmat_in), ispin_ks(ispin_ks) { ModuleBase::TITLE("OperatorLRHxc", "OperatorLRHxc"); this->cal_type = hamilt::calculation_type::lcao_gint; - this->act_type = 2; this->is_first_node = true; - this->hR = std::unique_ptr>(new hamilt::HContainer(pmat_in)); - this->initialize_HR(*this->hR, ucell_in, gd_in, pmat_in); - this->DM_trans[0]->init_DMR(*this->hR); + this->hR = std::unique_ptr>(new hamilt::HContainer(&pmat_in)); + LR_Util::initialize_HR(*this->hR, ucell_in, gd_in, orb_cutoff); + assert(&pmat_in == this->hR->get_paraV()); }; ~OperatorLRHxc() { }; void init(const int ik_in) override {}; - // virtual psi::Psi act(const psi::Psi& psi_in) const override; - virtual void act(const psi::Psi& psi_in, psi::Psi& psi_out, const int nbands) const override; - private: - template //T=double, TR=double; T=std::complex, TR=std::complex/double - void initialize_HR(hamilt::HContainer& hR, const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals* pmat) const - { - for (int iat1 = 0; iat1 < ucell.nat; iat1++) - { - auto tau1 = ucell.get_tau(iat1); - int T1, I1; - ucell.iat2iait(iat1, &I1, &T1); - AdjacentAtomInfo adjs; - gd.Find_atom(ucell, tau1, T1, I1, &adjs); - for (int ad = 0; ad < adjs.adj_num + 1; ++ad) - { - const int T2 = adjs.ntype[ad]; - const int I2 = adjs.natom[ad]; - int iat2 = this->ucell.itia2iat(T2, I2); - if (pmat->get_row_size(iat1) <= 0 || pmat->get_col_size(iat2) <= 0) { continue; } - const ModuleBase::Vector3& R_index = adjs.box[ad]; - if (ucell.cal_dtau(iat1, iat2, R_index).norm() * this->ucell.lat0 >= orb_cutoff_[T1] + orb_cutoff_[T2]) { continue; } - hamilt::AtomPair tmp(iat1, iat2, R_index.x, R_index.y, R_index.z, pmat); - hR.insert_pair(tmp); - } - } - hR.allocate(nullptr, true); - hR.set_paraV(pmat); - if (std::is_same::value) { hR.fix_gamma(); } - } - template - void init_DM_trans(const int& nbands, std::vector>>& DM_trans)const - { - // LR_Util::print_DMR(*this->DM_trans[0], ucell.nat, "DMR[ib=" + std::to_string(0) + "]"); - if (this->next_op != nullptr) - { - int prev_size = DM_trans.size(); - if (prev_size > nbands) { for (int ib = nbands;ib < prev_size;++ib) { DM_trans[ib].reset(); } } - DM_trans.resize(nbands); - for (int ib = prev_size;ib < nbands;++ib) - { - // the first dimenstion of DensityMatrix is nk=nks/nspin - DM_trans[ib] = LR_Util::make_unique>(&this->kv, this->pmat, this->nspin); - DM_trans[ib]->init_DMR(*this->hR); - } - } - } - void grid_calculation(const int& nbands, const int& iband_dm)const; + virtual void act(const int nbands, + const int nbasis, + const int npol, + const T* psi_in, + T* hpsi, + const int ngk_ik = 0, + const bool is_first_node = false) const override; + + private: + void grid_calculation(const int& nbands)const; //global sizes const int& nspin; - const int nspin_solve = 1; ///< in singlet-triplet calculation, the Casida equation is solved respectively so nspin_solve in a single problem is 1 const int& naos; - const int& nocc; - const int& nvirt; + const int nk = 1; + // const int nloc_per_band = 1; ///< local size of each state of X (passed by nbasis in act()) + const std::vector& nocc; + const std::vector& nvirt; + const std::vector ispin_ks = { 0 }; ///< the index of spin of psi_ks used in {AX, DM_trans} const K_Vectors& kv; /// ground state wavefunction - const psi::Psi* psi_ks = nullptr; + const psi::Psi& psi_ks = nullptr; /// transition density matrix - std::vector>>& DM_trans; + std::unique_ptr>& DM_trans; /// transition hamiltonian in AO representation std::unique_ptr> hR = nullptr; /// parallel info - Parallel_2D* pc = nullptr; - Parallel_2D* pX = nullptr; - Parallel_Orbitals* pmat = nullptr; + const Parallel_2D& pc; + const std::vector& pX; + const Parallel_Orbitals& pmat; std::weak_ptr pot; @@ -123,8 +89,6 @@ namespace LR std::vector orb_cutoff_; Grid_Driver& gd; - bool tdm_sym = false; ///< whether transition density matrix is symmetric - /// test mutable bool first_print = true; }; diff --git a/source/module_lr/potentials/kernel_xc.cpp b/source/module_lr/potentials/kernel_xc.cpp index fad91e0aa4c..dee51ef3c5a 100644 --- a/source/module_lr/potentials/kernel_xc.cpp +++ b/source/module_lr/potentials/kernel_xc.cpp @@ -5,13 +5,17 @@ #include "module_lr/utils/lr_util.h" #ifdef USE_LIBXC #include +#include "module_hamilt_general/module_xc/xc_functional_libxc.h" + void LR::KernelXC::f_xc_libxc(const int& nspin, const double& omega, const double& tpiba, const Charge* chg_gs) { ModuleBase::TITLE("XC_Functional", "f_xc_libxc"); ModuleBase::timer::tick("XC_Functional", "f_xc_libxc"); // https://www.tddft.org/programs/libxc/manual/libxc-5.1.x/ - std::vector funcs = XC_Functional::init_func((1 == nspin) ? XC_UNPOLARIZED : XC_POLARIZED); + std::vector funcs = XC_Functional_Libxc::init_func( + XC_Functional::get_func_id(), + (1 == nspin) ? XC_UNPOLARIZED : XC_POLARIZED); int nrxx = chg_gs->nrxx; // converting rho (extract it as a subfuntion in the future) @@ -116,8 +120,8 @@ void LR::KernelXC::f_xc_libxc(const int& nspin, const double& omega, const doubl for (xc_func_type& func : funcs) { - constexpr double rho_threshold = 1E-6; - constexpr double grho_threshold = 1E-10; + const double rho_threshold = 1E-6; + const double grho_threshold = 1E-10; xc_func_set_dens_threshold(&func, rho_threshold); @@ -217,7 +221,7 @@ void LR::KernelXC::f_xc_libxc(const int& nspin, const double& omega, const doubl } } } // end for( xc_func_type &func : funcs ) - XC_Functional::finish_func(funcs); + XC_Functional_Libxc::finish_func(funcs); if (1 == PARAM.inp.nspin || 2 == PARAM.inp.nspin) return; // else if (4 == PARAM.inp.nspin) diff --git a/source/module_lr/potentials/pot_hxc_lrtd.cpp b/source/module_lr/potentials/pot_hxc_lrtd.cpp index b2713c8670f..ebdb8747c5c 100644 --- a/source/module_lr/potentials/pot_hxc_lrtd.cpp +++ b/source/module_lr/potentials/pot_hxc_lrtd.cpp @@ -6,11 +6,13 @@ #include "module_hamilt_general/module_xc/xc_functional.h" #include #include "module_lr/utils/lr_util.h" + +#define FXC_PARA_TYPE const double* const rho, ModuleBase::matrix& v_eff, const std::vector& ispin_op = { 0,0 } namespace LR { // constructor for exchange-correlation kernel PotHxcLR::PotHxcLR(const std::string& xc_kernel_in, const ModulePW::PW_Basis* rho_basis_in, const UnitCell* ucell_in, - const Charge* chg_gs/*ground state*/, SpinType st_in) + const Charge* chg_gs/*ground state*/, const SpinType& st_in) :xc_kernel(xc_kernel_in), tpiba_(ucell_in->tpiba), spin_type_(st_in) { this->rho_basis_ = rho_basis_in; @@ -32,29 +34,28 @@ namespace LR } } - void PotHxcLR::cal_v_eff(double** rho, const UnitCell* ucell, ModuleBase::matrix& v_eff) + void PotHxcLR::cal_v_eff(double** rho, const UnitCell* ucell, ModuleBase::matrix& v_eff, const std::vector& ispin_op) { ModuleBase::TITLE("PotHxcLR", "cal_v_eff"); ModuleBase::timer::tick("PotHxcLR", "cal_v_eff"); auto& fxc = this->xc_kernel_components_; - const int& nspin_solve = v_eff.nr; - assert(nspin_solve == 1); // Hartree switch (this->spin_type_) { - case SpinType::S1: // check the coefficient: does S1 already include the factor 2? - v_eff += elecstate::H_Hartree_pw::v_hartree(*ucell, const_cast(this->rho_basis_), nspin_solve, rho); + case SpinType::S1: case SpinType::S2_updown: + v_eff += elecstate::H_Hartree_pw::v_hartree(*ucell, const_cast(this->rho_basis_), 1, rho); break; case SpinType::S2_singlet: - v_eff += 2 * elecstate::H_Hartree_pw::v_hartree(*ucell, const_cast(this->rho_basis_), nspin_solve, rho); + v_eff += 2 * elecstate::H_Hartree_pw::v_hartree(*ucell, const_cast(this->rho_basis_), 1, rho); + break; default: break; } // XC if (xc_kernel == "rpa" || xc_kernel == "hf") { return; } // no xc #ifdef USE_LIBXC - this->kernel_to_potential_[spin_type_](rho[0], v_eff); + this->kernel_to_potential_[spin_type_](rho[0], v_eff, ispin_op); #else throw std::domain_error("GlobalV::XC_Functional::get_func_type() =" + std::to_string(XC_Functional::get_func_type()) + " unfinished in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); @@ -70,13 +71,13 @@ namespace LR if (xc == XCType::LDA) switch (s) { case SpinType::S1: - funcs[s] = [this, &fxc](const double* const rho, ModuleBase::matrix& v_eff)->void + funcs[s] = [this, &fxc](FXC_PARA_TYPE)->void { for (int ir = 0;ir < nrxx;++ir) { v_eff(0, ir) += ModuleBase::e2 * fxc.get_kernel("v2rho2").at(ir) * rho[ir]; } }; break; case SpinType::S2_singlet: - funcs[s] = [this, &fxc](const double* const rho, ModuleBase::matrix& v_eff)->void + funcs[s] = [this, &fxc](FXC_PARA_TYPE)->void { for (int ir = 0;ir < nrxx;++ir) { @@ -87,7 +88,7 @@ namespace LR }; break; case SpinType::S2_triplet: - funcs[s] = [this, &fxc](const double* const rho, ModuleBase::matrix& v_eff)->void + funcs[s] = [this, &fxc](FXC_PARA_TYPE)->void { for (int ir = 0;ir < nrxx;++ir) { @@ -97,6 +98,14 @@ namespace LR } }; break; + case SpinType::S2_updown: + funcs[s] = [this, &fxc](FXC_PARA_TYPE)->void + { + assert(ispin_op.size() >= 2); + const int is = ispin_op[0] + ispin_op[1]; + for (int ir = 0;ir < nrxx;++ir) { v_eff(0, ir) += ModuleBase::e2 * fxc.get_kernel("v2rho2").at(3 * ir + is) * rho[ir]; } + }; + break; default: throw std::domain_error("SpinType =" + std::to_string(static_cast(s)) + " unfinished in " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); @@ -105,7 +114,7 @@ namespace LR else if (xc == XCType::GGA || xc == XCType::HYB_GGA) switch (s) { case SpinType::S1: - funcs[s] = [this, &fxc](const double* const rho, ModuleBase::matrix& v_eff)->void + funcs[s] = [this, &fxc](FXC_PARA_TYPE)->void { // test: output drho // double thr = 1e-1; diff --git a/source/module_lr/potentials/pot_hxc_lrtd.h b/source/module_lr/potentials/pot_hxc_lrtd.h index 6a4df0fd190..a04ab42bb9c 100644 --- a/source/module_lr/potentials/pot_hxc_lrtd.h +++ b/source/module_lr/potentials/pot_hxc_lrtd.h @@ -12,14 +12,14 @@ namespace LR /// S1: K^Hartree + K^xc /// S2_singlet: 2*K^Hartree + K^xc_{upup} + K^xc_{updown} /// S2_triplet: K^xc_{upup} - K^xc_{updown} - enum SpinType { S1 = 0, S2_singlet = 1, S2_triplet = 2 }; + enum SpinType { S1 = 0, S2_singlet = 1, S2_triplet = 2, S2_updown = 3 }; enum XCType { None = 0, LDA = 1, GGA = 2, HYB_GGA = 4 }; /// constructor for exchange-correlation kernel PotHxcLR(const std::string& xc_kernel_in, const ModulePW::PW_Basis* rho_basis_in, const UnitCell* ucell_in, const Charge* chg_gs/*ground state*/, - SpinType st_in = SpinType::S1); + const SpinType& st_in = SpinType::S1); ~PotHxcLR() {} void cal_v_eff(const Charge* chg/*excited state*/, const UnitCell* ucell, ModuleBase::matrix& v_eff) override {}; - void cal_v_eff(double** rho, const UnitCell* ucell, ModuleBase::matrix& v_eff); + void cal_v_eff(double** rho, const UnitCell* ucell, ModuleBase::matrix& v_eff, const std::vector& ispin_op = { 0,0 }); int nrxx; private: int nspin; @@ -31,14 +31,15 @@ namespace LR KernelXC xc_kernel_components_; const std::string xc_kernel; const double& tpiba_; - SpinType spin_type_ = SpinType::S1; + const SpinType spin_type_ = SpinType::S1; XCType xc_type_ = XCType::None; // enum class as key for unordered_map is not supported in C++11 sometimes // https://github.com/llvm/llvm-project/issues/49601 // struct SpinHash { std::size_t operator()(const SpinType& s) const { return std::hash()(static_cast(s)); } }; using Tfunc = std::function; + ModuleBase::matrix& /**<[out] v_eff */, + const std::vector& ispin_op) >; // std::unordered_map kernel_to_potential_; std::map kernel_to_potential_; diff --git a/source/module_lr/ri_benchmark/operator_ri_hartree.h b/source/module_lr/ri_benchmark/operator_ri_hartree.h index 311f15cd538..fbeb8e60f5f 100644 --- a/source/module_lr/ri_benchmark/operator_ri_hartree.h +++ b/source/module_lr/ri_benchmark/operator_ri_hartree.h @@ -1,3 +1,4 @@ +#pragma once #include "module_hamilt_general/operator.h" #include "module_lr/ri_benchmark/ri_benchmark.h" #include "module_lr/utils/lr_util_print.h" @@ -49,22 +50,24 @@ namespace RI_Benchmark } }; ~OperatorRIHartree() {} - void act(const psi::Psi& X_in, psi::Psi& X_out, const int nbands) const override + void act(const int nbands, + const int nbasis, + const int npol, + const T* psi_in, + T* hpsi, + const int ngk_ik = 0, + const bool is_first_node = false) const override { assert(GlobalV::MY_RANK == 0); // only serial now - const int nk = 1; - const psi::Psi& X = LR_Util::k1_to_bfirst_wrapper(X_in, nk, npairs); - psi::Psi AX = LR_Util::k1_to_bfirst_wrapper(X_out, nk, npairs); - for (int ib = 0;ib < nbands;++ib) - { - TLRIX CsX_vo = cal_CsX(Cs_vo_mo, &X(ib, 0, 0)); - TLRIX CsX_ov = cal_CsX(Cs_ov_mo, &X(ib, 0, 0)); - // LR_Util::print_CsX(Cs_bX, nvirt, "Cs_bX of state " + std::to_string(ib)); - cal_AX(CV_vo, CsX_vo, &AX(ib, 0, 0), 4.); - cal_AX(CV_vo, CsX_ov, &AX(ib, 0, 0), 4.); - cal_AX(CV_ov, CsX_vo, &AX(ib, 0, 0), 4.); - cal_AX(CV_ov, CsX_ov, &AX(ib, 0, 0), 4.); - } + assert(nbasis == npairs); + TLRIX CsX_vo = cal_CsX(Cs_vo_mo, psi_in); + TLRIX CsX_ov = cal_CsX(Cs_ov_mo, psi_in); + // LR_Util::print_CsX(Cs_bX, nvirt, "Cs_bX of state " + std::to_string(ib)); + // 4 for 4 terms in the expansion of local RI + cal_AX(CV_vo, CsX_vo, hpsi, 4.); + cal_AX(CV_vo, CsX_ov, hpsi, 4.); + cal_AX(CV_ov, CsX_vo, hpsi, 4.); + cal_AX(CV_ov, CsX_ov, hpsi, 4.); } protected: const int& naos; diff --git a/source/module_lr/ri_benchmark/ri_benchmark.hpp b/source/module_lr/ri_benchmark/ri_benchmark.hpp index 671ccd7774b..82ab9249acc 100644 --- a/source/module_lr/ri_benchmark/ri_benchmark.hpp +++ b/source/module_lr/ri_benchmark/ri_benchmark.hpp @@ -153,7 +153,7 @@ namespace RI_Benchmark return Amat_full; } template - TLRIX cal_CsX(const TLRI& Cs_mo, TK* X) + TLRIX cal_CsX(const TLRI& Cs_mo, const TK* X) { TLRIX CsX; for (auto& it1 : Cs_mo) diff --git a/source/module_lr/utils/gint_move.hpp b/source/module_lr/utils/gint_move.hpp index acdbdad9972..7d21ca6037e 100644 --- a/source/module_lr/utils/gint_move.hpp +++ b/source/module_lr/utils/gint_move.hpp @@ -9,15 +9,15 @@ template using D2 = void(*) (T**, size_t); -template -using D3 = void(*) (T***, size_t, size_t); +// template +// using D3 = void(*) (T***, size_t, size_t); // template // D2 d2 = LR_Util::delete_p2; // template // D3 d3 = LR_Util::delete_p3; // Change to C++ 11 D2 d2 = LR_Util::delete_p2; -D3 d3 = LR_Util::delete_p3; +// D3 d3 = LR_Util::delete_p3; Gint& Gint::operator=(Gint&& rhs) diff --git a/source/module_lr/utils/lr_util.cpp b/source/module_lr/utils/lr_util.cpp index 7634fe15742..a8964d5c973 100644 --- a/source/module_lr/utils/lr_util.cpp +++ b/source/module_lr/utils/lr_util.cpp @@ -212,7 +212,7 @@ namespace LR_Util int info = 0; char jobz = 'V', uplo = 'U'; double work_tmp; - constexpr int minus_one = -1; + const int minus_one = -1; dsyev_(&jobz, &uplo, &n, mat, &n, eig, &work_tmp, &minus_one, &info); // get best lwork const int lwork = work_tmp; double* work2 = new double[lwork]; @@ -241,7 +241,7 @@ namespace LR_Util int info = 0; char jobvl = 'N', jobvr = 'V'; //calculate right eigenvectors double work_tmp; - constexpr int minus_one = -1; + const int minus_one = -1; std::vector eig_real(n); std::vector eig_imag(n); const int ldvl = 1, ldvr = n; diff --git a/source/module_lr/utils/lr_util.h b/source/module_lr/utils/lr_util.h index 136b9481f1a..93f26be2a6a 100644 --- a/source/module_lr/utils/lr_util.h +++ b/source/module_lr/utils/lr_util.h @@ -50,21 +50,17 @@ namespace LR_Util /// =================ALGORITHM==================== //====== newers and deleters======== - //(arbitrary dimention will be supported in the future) - /// @brief delete 2d pointer - /// @tparam T - /// @param p2 - /// @param size + /// @brief delete 2d pointer template void delete_p2(T** p2, size_t size); - - /// @brief delete 3d pointer - /// @tparam T - /// @param p2 - /// @param size1 - /// @param size2 + /// @brief new 2d pointer template - void delete_p3(T*** p3, size_t size1, size_t size2); + void new_p2(T**& p2, size_t size1, size_t size2); + + template ct::Tensor newTensor(const ct::TensorShape& shape) + { + return ct::Tensor(ct::DataTypeToEnum::value, ct::DeviceTypeToEnum::value, shape); + } ///================ BLAS ====================== /// calculate (A+A^T)/2 diff --git a/source/module_lr/utils/lr_util.hpp b/source/module_lr/utils/lr_util.hpp index eb916171115..97a5113eb7a 100644 --- a/source/module_lr/utils/lr_util.hpp +++ b/source/module_lr/utils/lr_util.hpp @@ -27,8 +27,6 @@ namespace LR_Util } //====== newers and deleters======== - //(arbitrary dimention will be supported in the future) - /// @brief new 2d pointer /// @tparam T /// @param size1 @@ -43,21 +41,6 @@ namespace LR_Util } }; - /// @brief new 3d pointer - /// @tparam T - /// @param size1 - /// @param size2 - /// @param size3 - template - void new_p3(T***& p3, size_t size1, size_t size2, size_t size3) - { - p3 = new T * *[size1]; - for (size_t i = 0; i < size1; ++i) - { - new_p2(p3[i], size2, size3); - } - }; - /// @brief delete 2d pointer /// @tparam T /// @param p2 @@ -69,31 +52,12 @@ namespace LR_Util { for (size_t i = 0; i < size; ++i) { - if (p2[i] != nullptr) { delete[] p2[i]; -} + if (p2[i] != nullptr) { delete[] p2[i]; } } delete[] p2; } }; - /// @brief delete 3d pointer - /// @tparam T - /// @param p2 - /// @param size1 - /// @param size2 - template - void delete_p3(T*** p3, size_t size1, size_t size2) - { - if (p3 != nullptr) - { - for (size_t i = 0; i < size1; ++i) - { - delete_p2(p3[i], size2); - } - delete[] p3; - } - }; - inline double get_conj(const double& x) { return x; @@ -131,6 +95,13 @@ namespace LR_Util } } + /// get the Psi wrapper of the selected spin from the Psi object + template + psi::Psi get_psi_spin(const psi::Psi& psi_in, const int& is, const int& nk) + { + return psi::Psi(&psi_in(is * nk, 0, 0), psi_in, nk, psi_in.get_nbands()); + } + /// psi(nk=1, nbands=nb, nk * nbasis) -> psi(nb, nk, nbasis) without memory copy template psi::Psi k1_to_bfirst_wrapper(const psi::Psi& psi_kfirst, int nk_in, int nbasis_in) diff --git a/source/module_lr/utils/lr_util_hcontainer.h b/source/module_lr/utils/lr_util_hcontainer.h index 0e0b87d1243..4ac4ccb1f37 100644 --- a/source/module_lr/utils/lr_util_hcontainer.h +++ b/source/module_lr/utils/lr_util_hcontainer.h @@ -44,4 +44,39 @@ namespace LR_Util hamilt::HContainer>& HR, const int& nat, const char& type = 'R'); + + template + void initialize_HR(hamilt::HContainer& hR, const UnitCell& ucell, Grid_Driver& gd, const std::vector& orb_cutoff) + { + const auto& pmat = *hR.get_paraV(); + for (int iat1 = 0; iat1 < ucell.nat; iat1++) + { + auto tau1 = ucell.get_tau(iat1); + int T1, I1; + ucell.iat2iait(iat1, &I1, &T1); + AdjacentAtomInfo adjs; + gd.Find_atom(ucell, tau1, T1, I1, &adjs); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + int iat2 = ucell.itia2iat(T2, I2); + if (pmat.get_row_size(iat1) <= 0 || pmat.get_col_size(iat2) <= 0) { continue; } + const ModuleBase::Vector3& R_index = adjs.box[ad]; + if (ucell.cal_dtau(iat1, iat2, R_index).norm() * ucell.lat0 >= orb_cutoff[T1] + orb_cutoff[T2]) { continue; } + hamilt::AtomPair tmp(iat1, iat2, R_index.x, R_index.y, R_index.z, &pmat); + hR.insert_pair(tmp); + } + } + hR.allocate(nullptr, true); + // hR.set_paraV(&pmat); + if (std::is_same::value) { hR.fix_gamma(); } + } + template + void initialize_DMR(elecstate::DensityMatrix& dm, const Parallel_Orbitals& pmat, const UnitCell& ucell, Grid_Driver& gd, const std::vector& orb_cutoff) + { + hamilt::HContainer hR_tmp(&pmat); + initialize_HR(hR_tmp, ucell, gd, orb_cutoff); + dm.init_DMR(hR_tmp); + } } \ No newline at end of file diff --git a/source/module_lr/utils/lr_util_print.h b/source/module_lr/utils/lr_util_print.h index 8ef6981f97f..80f6a704eca 100644 --- a/source/module_lr/utils/lr_util_print.h +++ b/source/module_lr/utils/lr_util_print.h @@ -12,6 +12,64 @@ namespace LR_Util return (std::abs(v) > threshold ? v : 0); } + template + int read_value(std::ifstream& ifs, T* ptr, const int& size) { for (int i = 0;i < size;++i) { ifs >> ptr[i]; } return size; } + template + int read_value(std::ifstream& ifs, T* ptr, const int& size, Args&&... args) + { + int size_now = 0; + for (int i = 0;i < size;++i) { size_now += read_value(ifs, ptr + size_now, args...); } + return size_now; + } + template + int read_value(const std::string& file, T* ptr, const int& size, Args&&... args) + { + std::ifstream ifs(file); + const int res = read_value(ifs, ptr, size, args...); + ifs.close(); + return res; + } + + template + int write_value(std::ofstream& ofs, const T* ptr, const int& size) + { + for (int i = 0;i < size;++i) { ofs << filter(ptr[i]) << " "; } + ofs << std::endl; + return size; + } + template + int write_value(std::ofstream& ofs, const T* ptr, const int& size, Args&&... args) + { + int size_now = 0; + for (int i = 0;i < size;++i) { size_now += write_value(ofs, ptr + size_now, args...); } + ofs << std::endl; + return size_now; + } + template + int write_value(const std::string& file, const int& prec, const T* ptr, const int& size, Args&&... args) + { + std::ofstream ofs(file); + ofs << std::setprecision(prec) << std::scientific; + const int res = write_value(ofs, ptr, size, args...); + ofs.close(); + return res; + } + template + int print_value(const T* ptr, const int& size) + { + for (int i = 0;i < size;++i) { std::cout << filter(ptr[i]) << " "; } + std::cout << std::endl; + return size; + } + template + int print_value(const T* ptr, const int& size, Args&&... args) + { + int size_now = 0; + for (int i = 0;i < size;++i) { size_now += print_value(ptr + size_now, args...); } + std::cout << std::endl; + return size_now; + } + template void print_psi_bandfirst(const psi::Psi& psi, const std::string& label, const int& ib, const double& threshold = 1e-10) { @@ -34,17 +92,17 @@ namespace LR_Util std::ofstream ofs(filename + "_" + std::to_string(rank) + ".dat"); ofs << std::setprecision(precision) << std::scientific; ofs << psi.get_nbands() << " " << psi.get_nk() << " " << psi.get_nbasis() << "\n"; - for (int ib = 0;ib < psi.get_nbands();++ib) - { - for (int ik = 0;ik < psi.get_nk();++ik) - { - for (int i = 0;i < psi.get_nbasis();++i) - { - ofs << filter(psi(ib, ik, i)) << " "; - } - ofs << "\n"; - } - } + assert(psi.size() == write_value(ofs, &psi(0, 0, 0), psi.get_nbands(), psi.get_nk(), psi.get_nbasis())); + ofs.close(); + } + template + void write_psi_bandfirst(const T* psi, const int& nband, const int& nk, const int& nbasis, + const std::string& filename, const int& rank, const double& threshold = 1e-10, const int& precision = 8) + { + std::ofstream ofs(filename + "_" + std::to_string(rank) + ".dat"); + ofs << std::setprecision(precision) << std::scientific; + ofs << nband << " " << nk << " " << nbasis << "\n"; + assert(nband * nk * nbasis == write_value(ofs, psi, nband, nk, nbasis)); ofs.close(); } template @@ -54,13 +112,7 @@ namespace LR_Util int nbands, nks, nbasis; ifs >> nbands >> nks >> nbasis; psi::Psi psi(nks, nbands, nbasis, nullptr, false); - for (int ib = 0;ib < psi.get_nbands();++ib) { - for (int ik = 0;ik < psi.get_nk();++ik) { - for (int i = 0;i < psi.get_nbasis();++i) { - ifs >> psi(ib, ik, i); -} -} -} + assert(psi.size() == read_value(ifs, psi.get_pointer(), nbands, nks, nbasis)); ifs.close(); return psi; } @@ -101,9 +153,7 @@ namespace LR_Util { std::cout << "first " << nnz << " non-zero elements of " << label << "\n"; int inz = 0;int i = 0; - while (inz < nnz && i < nrxx) { - if (rho[++i] - 0.0 > threshold) { std::cout << rho[i] << " ";++inz; } -}; + while (inz < nnz && i < nrxx) { if (rho[++i] - 0.0 > threshold) { std::cout << rho[i] << " ";++inz; } }; } diff --git a/source/module_lr/utils/test/CMakeLists.txt b/source/module_lr/utils/test/CMakeLists.txt index 6e494804053..53d1db607ec 100644 --- a/source/module_lr/utils/test/CMakeLists.txt +++ b/source/module_lr/utils/test/CMakeLists.txt @@ -4,6 +4,7 @@ AddTest( LIBS parameter base ${math_libs} device container SOURCES lr_util_physics_test.cpp ../lr_util.cpp ../../../module_basis/module_ao/parallel_2d.cpp + ../../../module_io/orb_io.cpp ) AddTest( diff --git a/source/module_lr/utils/test/lr_util_algorithms_test.cpp b/source/module_lr/utils/test/lr_util_algorithms_test.cpp index f47f46e9415..f33105d32bf 100644 --- a/source/module_lr/utils/test/lr_util_algorithms_test.cpp +++ b/source/module_lr/utils/test/lr_util_algorithms_test.cpp @@ -1,6 +1,7 @@ #include #include "../lr_util.h" +#include "../lr_util_print.h" TEST(LR_Util, PsiWrapper) { @@ -130,6 +131,27 @@ TEST(LR_Util, MatSymComplex) } } +TEST(LR_Util, RWValue) +{ + const std::string file = "RWValue.txt"; + std::ofstream ofs(file); + std::vector vec(2 * 3 * 4 * 5, 0); + for (int i = 0;i < vec.size();++i) vec[i] = i; + LR_Util::write_value(ofs, vec.data(), 2, 3, 4, 5); + ofs.close(); + + std::vector vec1(2 * 3 * 4 * 5, 0); + std::ifstream ifs1(file); + EXPECT_EQ(LR_Util::read_value(ifs1, vec1.data(), 2, 3, 4, 5), 120); + ifs1.close(); + for (int i = 0;i < vec1.size();++i) { EXPECT_EQ(vec1[i], vec[i]); }; + std::vector vec2(2 * 3 * 4 * 5, 0); + std::ifstream ifs2(file); + EXPECT_EQ(LR_Util::read_value(ifs2, vec2.data(), 2 * 3, 4 * 5), 120); + ifs2.close(); + for (int i = 0;i < vec2.size();++i) { EXPECT_EQ(vec2[i], vec[i]); }; +} + int main(int argc, char** argv) { srand(time(NULL)); // for random number generator diff --git a/source/module_md/fire.cpp b/source/module_md/fire.cpp index 3299e05795b..98f294db190 100644 --- a/source/module_md/fire.cpp +++ b/source/module_md/fire.cpp @@ -74,7 +74,8 @@ void FIRE::print_md(std::ofstream& ofs, const bool& cal_stress) { MD_base::print_md(ofs, cal_stress); - ofs << " LARGEST GRAD (eV/A) : " << max * ModuleBase::Hartree_to_eV * ModuleBase::ANGSTROM_AU << std::endl; + ofs << "\n Largest gradient in force is " << max * ModuleBase::Hartree_to_eV * ModuleBase::ANGSTROM_AU << " eV/A." << std::endl; + ofs << " Threshold is " << PARAM.inp.force_thr_ev << " eV/A." << std::endl; std::cout << " LARGEST GRAD (eV/A) : " << max * ModuleBase::Hartree_to_eV * ModuleBase::ANGSTROM_AU << std::endl; return; diff --git a/source/module_md/md_base.cpp b/source/module_md/md_base.cpp index f7503db7d59..30e344dbe20 100644 --- a/source/module_md/md_base.cpp +++ b/source/module_md/md_base.cpp @@ -60,7 +60,7 @@ void MD_base::setup(ModuleESolver::ESolver* p_esolver, const std::string& global restart(global_readin_dir); } - Print_Info::print_screen(0, 0, step_ + step_rst_); + ModuleIO::print_screen(0, 0, step_ + step_rst_); MD_func::force_virial(p_esolver, step_, ucell, potential, force, cal_stress, virial); MD_func::compute_stress(ucell, vel, allmass, cal_stress, virial, stress); diff --git a/source/module_md/run_md.cpp b/source/module_md/run_md.cpp index 35928a9fc3c..1f855259797 100644 --- a/source/module_md/run_md.cpp +++ b/source/module_md/run_md.cpp @@ -55,7 +55,7 @@ void md_line(UnitCell& unit_in, ModuleESolver::ESolver* p_esolver, const Paramet } else { - Print_Info::print_screen(0, 0, mdrun->step_ + mdrun->step_rst_); + ModuleIO::print_screen(0, 0, mdrun->step_ + mdrun->step_rst_); mdrun->first_half(GlobalV::ofs_running); /// update force and virial due to the update of atom positions @@ -122,8 +122,6 @@ void md_line(UnitCell& unit_in, ModuleESolver::ESolver* p_esolver, const Paramet mdrun->step_++; } - ModuleBase::Global_File::delete_tmp_files(); - delete mdrun; ModuleBase::timer::tick("Run_MD", "md_line"); return; diff --git a/source/module_md/test/CMakeLists.txt b/source/module_md/test/CMakeLists.txt index 64e21fc6f65..e92f8cc3698 100644 --- a/source/module_md/test/CMakeLists.txt +++ b/source/module_md/test/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND depend_files ../../module_base/matrix3.cpp ../../module_base/matrix.cpp ../../module_base/timer.cpp + ../../module_base/blas_connector.cpp ../../module_base/memory.cpp ../../module_base/global_variable.cpp ../../module_base/global_function.cpp diff --git a/source/module_md/test/fire_test.cpp b/source/module_md/test/fire_test.cpp index fda23e72853..2ecdf3030b6 100644 --- a/source/module_md/test/fire_test.cpp +++ b/source/module_md/test/fire_test.cpp @@ -205,11 +205,13 @@ TEST_F(FIREtest, PrintMD) output_str, testing::HasSubstr( " ------------------------------------------------------------------------------------------------")); - for (int i = 0; i < 10; ++i) + for (int i = 0; i < 11; ++i) { getline(ifs, output_str); } - EXPECT_THAT(output_str, testing::HasSubstr(" LARGEST GRAD (eV/A) : 0.049479926")); + EXPECT_THAT(output_str, testing::HasSubstr(" Largest gradient in force is 0.049479926 eV/A")); + getline(ifs, output_str); + EXPECT_THAT(output_str, testing::HasSubstr(" Threshold is -1 eV/A.")); ifs.close(); remove("running.log"); } diff --git a/source/module_parameter/input_parameter.h b/source/module_parameter/input_parameter.h index 29f00705b11..aec42a4bf75 100644 --- a/source/module_parameter/input_parameter.h +++ b/source/module_parameter/input_parameter.h @@ -33,7 +33,7 @@ struct Input_para int kpar = 1; ///< ecch pool is for one k point int bndpar = 1; ///< parallel for stochastic/deterministic bands std::string latname = "none"; ///< lattice name - double ecutwfc = 50; ///< energy cutoff for wavefunctions + double ecutwfc = 0; ///< energy cutoff for wavefunctions double ecutrho = 0; ///< energy cutoff for charge/potential int nx = 0, ny = 0, nz = 0; ///< three dimension of FFT wavefunc @@ -44,10 +44,9 @@ struct Input_para double erf_height = 0; ///< the height of the energy step for reciprocal vectors double erf_sigma = 0.1; ///< the width of the energy step for reciprocal vectors int fft_mode = 0; ///< fftw mode 0: estimate, 1: measure, 2: patient, 3: exhaustive - bool diago_full_acc = false; ///< all the empty states are diagonalized std::string init_wfc = "atomic"; ///< "file","atomic","random" bool psi_initializer = false; ///< whether use psi_initializer to initialize wavefunctions - int pw_seed = 1; ///< random seed for initializing wave functions qianrui 2021-8-12 + int pw_seed = 0; ///< random seed for initializing wave functions std::string init_chg = "atomic"; ///< "file","atomic" bool dm_to_rho = false; ///< read density matrix from npz format and calculate charge density std::string chg_extrap = "default"; ///< xiaohui modify 2015-02-01 @@ -57,8 +56,8 @@ struct Input_para std::string stru_file = "STRU"; ///< file contains atomic positions -- ///< xiaohui modify 2015-02-01 std::string kpoint_file = "KPT"; ///< file contains k-points -- xiaohui modify 2015-02-01 - std::string pseudo_dir = ""; ///< directory of pseudopotential - std::string orbital_dir = ""; ///< directory of orbital file + std::string pseudo_dir = ""; ///< directory of pseudopotential + std::string orbital_dir = ""; ///< directory of orbital file std::string read_file_dir = "auto"; ///< directory of files for reading bool restart_load = false; std::string wannier_card = "none"; ///< input card for wannier functions. @@ -68,7 +67,7 @@ struct Input_para std::vector kspacing = {0.0, 0.0, 0.0}; ///< kspacing for k-point generation double min_dist_coef = 0.2; ///< allowed minimum distance between two atoms - std::string device = "cpu"; + std::string device = "auto"; std::string precision = "double"; // ============== #Parameters (2.Electronic structure) =========================== @@ -110,13 +109,16 @@ struct Input_para bool mixing_dftu = false; ///< whether to mix locale in DFT+U bool mixing_dmr = false; ///< whether to mix real space density matrix - bool gamma_only = false; ///< for plane wave. - int scf_nmax = 100; ///< number of max elec iter - double scf_thr = -1.0; ///< \sum |rhog_out - rhog_in |^2 + bool gamma_only = false; ///< for plane wave. + int scf_nmax = 100; ///< number of max elec iter + double scf_thr = -1.0; ///< \sum |rhog_out - rhog_in |^2 double scf_ene_thr = -1.0; ///< energy threshold for scf convergence, in eV - int scf_thr_type = -1; ///< type of the criterion of scf_thr, 1: reci drho, 2: real drho - bool final_scf= false; ///< whether to do final scf - + int scf_thr_type = -1; ///< type of the criterion of scf_thr, 1: reci drho, 2: real drho + bool final_scf = false; ///< whether to do final scf + bool scf_os_stop = false; ///< whether to stop scf when oscillation is detected + double scf_os_thr = -0.01; ///< drho threshold for oscillation + int scf_os_ndim = 0; ///< number of old iterations used for oscillation detection + bool lspinorb = false; ///< consider the spin-orbit interaction bool noncolin = false; ///< using non-collinear-spin double soc_lambda = 1.0; ///< The fraction of averaged SOC pseudopotential @@ -303,7 +305,8 @@ struct Input_para std::string lr_solver = "dav"; ///< the eigensolver for LR-TDDFT double lr_thr = 1e-2; ///< convergence threshold of the LR-TDDFT eigensolver bool out_wfc_lr = false; ///< whether to output the eigenvectors (excitation amplitudes) in the particle-hole basis - std::vector abs_wavelen_range = {0., 0.}; ///< the range of wavelength(nm) to output the absorption spectrum + bool lr_unrestricted = false; ///< whether to use the unrestricted construction for LR-TDDFT + std::vector abs_wavelen_range = {}; ///< the range of wavelength(nm) to output the absorption spectrum double abs_broadening = 0.01; ///< the broadening (eta) for LR-TDDFT absorption spectrum std::string ri_hartree_benchmark = "none"; ///< whether to use the RI approximation for the Hartree potential in LR-TDDFT for benchmark (with FHI-aims/ABACUS read-in style) std::vector aims_nbasis = {}; ///< the number of basis functions for each atom type used in FHI-aims (for benchmark) @@ -331,11 +334,11 @@ struct Input_para bool out_mat_hs2 = false; ///< LiuXh add 2019-07-16, output H(R) matrix and ///< S(R) matrix in local basis. bool out_mat_dh = false; - bool out_mat_xc = false; ///< output exchange-correlation matrix in - ///< KS-orbital representation. - bool out_eband_terms = false; ///< output the band energy terms separately - bool out_hr_npz = false; ///< output exchange-correlation matrix in - ///< KS-orbital representation. + bool out_mat_xc = false; ///< output exchange-correlation matrix in + ///< KS-orbital representation. + bool out_eband_terms = false; ///< output the band energy terms separately + bool out_hr_npz = false; ///< output exchange-correlation matrix in + ///< KS-orbital representation. bool out_dm_npz = false; int out_interval = 1; @@ -354,8 +357,12 @@ struct Input_para bool restart_save = false; ///< restart //Peize Lin add 2020-04-04 bool rpa = false; ///< rpa calculation int nbands_istate = 5; ///< number of bands around fermi level for get_pchg calculation. - std::vector bands_to_print = {}; ///< specify the bands to be calculated in the get_pchg + std::vector bands_to_print = {}; ///< specify the bands to be calculated for partial charge + std::vector out_pchg = {}; ///< specify the bands to be calculated for partial charge + std::vector out_wfc_norm = {}; ///< specify the bands to be calculated for norm of wfc + std::vector out_wfc_re_im = {}; ///< specify the bands to be calculated for real and imaginary parts of wfc bool if_separate_k = false; ///< whether to write partial charge for all k-points to individual files or merge them + std::vector out_elf = {0, 3}; ///< output the electron localization function (ELF). 0: no; 1: yes // ============== #Parameters (12.Postprocess) =========================== double dos_emin_ev = -15.0; @@ -458,7 +465,12 @@ struct Input_para // Peize Lin add 2018-06-20 // ========================================================== std::string exx_hybrid_alpha = "default"; ///< fraction of Fock exchange in hybrid functionals - double exx_hse_omega = 0.11; ///< range-separation parameter in HSE functional + std::string exx_hse_omega = "default"; ///< range-separation parameter in HSE/CAM/LR functional + std::string exx_cam_alpha = "default"; ///< range-separation parameter in CAM/LR functional + std::string exx_cam_beta = "default"; ///< range-separation parameter in CAM/LR functional + bool exx_use_ewald = false; ///< if 1, Ewald method is used for HF or CAM/LR hybrid functions + int exx_fq_type = 1; /// auxiliary-function fq used in correction to V(q) at q->0 + double exx_ewald_qdiv = 2; /// the order of q-divergence in auxiliary function bool exx_separate_loop = true; ///< if 1, a two-step method is employed, else it will start ///< with a GGA-Loop, and then Hybrid-Loop int exx_hybrid_step = 100; ///< the maximal electronic iteration number in @@ -466,7 +478,7 @@ struct Input_para double exx_mixing_beta = 1.0; ///< mixing_beta for outer-loop when exx_separate_loop=1 double exx_lambda = 0.3; ///< used to compensate for divergence points at G=0 in the ///< evaluation of Fock exchange using lcao_in_pw method - std::string exx_real_number = "0"; ///< exx calculated in real or complex + std::string exx_real_number = "default"; ///< exx calculated in real or complex double exx_pca_threshold = 0.0001; ///< threshold to screen on-site ABFs in exx double exx_c_threshold = 0.0001; ///< threshold to screen C matrix in exx double exx_v_threshold = 0.1; ///< threshold to screen C matrix in exx @@ -481,7 +493,7 @@ struct Input_para ///< inequality double exx_cauchy_stress_threshold = 1e-07; ///< threshold to screen exx stress using Cauchy-Schwartz ///< inequality - std::string exx_ccp_rmesh_times = "1"; ///< how many times larger the radial mesh required for + std::string exx_ccp_rmesh_times = "default"; ///< how many times larger the radial mesh required for ///< calculating Columb potential is to that of atomic orbitals std::string exx_distribute_type = "htime"; ///< distribute type (assuming default as no specific value ///< provided) @@ -560,27 +572,27 @@ struct Input_para double pexsi_zero_thr = 1e-10; // ============== #Parameters (20.Test) ==================== - bool out_alllog = false; ///< output all logs. - int nurse = 0; ///< used for debug. - bool t_in_h = true; ///< calculate the T or not. - bool vl_in_h = true; ///< calculate the vloc or not. - bool vnl_in_h = true; ///< calculate the vnl or not. - bool vh_in_h = true; ///< calculate the hartree potential or not - bool vion_in_h = true; ///< calculate the local ionic potential or not - ///< //only relevant when vl_in_h = 1 - bool test_force = false; ///< test the force. - bool test_stress = false; ///< test the stress. - bool test_skip_ewald = false; ///< variables for test only - bool test_atom_input = false; ///< variables for test_atom_input only - bool test_symmetry = false; ///< variables for test_lattice only - int test_wf = 0; ///< variables for test_wf only - int test_grid = false; ///< variables for test_grid only - bool test_charge = false; ///< variables for test_vloc only - bool test_energy = false; ///< variables for test_energy only - bool test_gridt = false; ///< variables for test_gridt only - bool test_pseudo_cell = false; ///< variables for test_pseudo_cell only - int test_pp = 0; ///< variables for test_pp only - bool test_relax_method = false; ///< variables for test_relax_method only - int test_deconstructor = false; ///< variables for test_deconstructor only + bool out_alllog = false; ///< output all logs. + int nurse = 0; ///< used for debug. + bool t_in_h = true; ///< calculate the T or not. + bool vl_in_h = true; ///< calculate the vloc or not. + bool vnl_in_h = true; ///< calculate the vnl or not. + bool vh_in_h = true; ///< calculate the hartree potential or not + bool vion_in_h = true; ///< calculate the local ionic potential or not + ///< //only relevant when vl_in_h = 1 + bool test_force = false; ///< test the force. + bool test_stress = false; ///< test the stress. + bool test_skip_ewald = false; ///< variables for test only + int test_atom_input = false; ///< variables for test_atom_input only + int test_symmetry = false; ///< variables for test_lattice only + int test_wf = 0; ///< variables for test_wf only + int test_grid = false; ///< variables for test_grid only + int test_charge = false; ///< variables for test_vloc only + int test_energy = false; ///< variables for test_energy only + int test_gridt = false; ///< variables for test_gridt only + int test_pseudo_cell = false; ///< variables for test_pseudo_cell only + int test_pp = 0; ///< variables for test_pp only + int test_relax_method = false; ///< variables for test_relax_method only + int test_deconstructor = false; ///< variables for test_deconstructor only }; #endif diff --git a/source/module_parameter/parameter.cpp b/source/module_parameter/parameter.cpp index 45c9a044779..f49f528eed5 100644 --- a/source/module_parameter/parameter.cpp +++ b/source/module_parameter/parameter.cpp @@ -2,10 +2,12 @@ Parameter PARAM; -void Parameter::set_rank_nproc(const int& myrank, const int& nproc) +// changed from set_rank_nproc in 2024-1018 +void Parameter::set_pal_param(const int& myrank, const int& nproc, const int& nthread_per_proc) { sys.myrank = myrank; sys.nproc = nproc; + sys.nthread_per_proc = nthread_per_proc; } void Parameter::set_start_time(const std::time_t& start_time) diff --git a/source/module_parameter/parameter.h b/source/module_parameter/parameter.h index 38b544f2ed5..0705f562d29 100644 --- a/source/module_parameter/parameter.h +++ b/source/module_parameter/parameter.h @@ -6,6 +6,7 @@ namespace ModuleIO { class ReadInput; } +class CalAtomInfo; class Parameter { public: @@ -26,14 +27,19 @@ class Parameter // We can only read the value of globalv parameters, but cannot modify it. const System_para& globalv = sys; - // Set the rank & nproc - void set_rank_nproc(const int& myrank, const int& nproc); + // Set the rank & nproc & nthreads_per_proc + // changed from set_rank_nproc in 2024-1018 + void set_pal_param(const int& myrank, const int& nproc, const int& nthread_per_proc); // Set the start time void set_start_time(const std::time_t& start_time); private: - // Only ReadInput can modify the value of Parameter. - friend class ModuleIO::ReadInput; + // Only ReadInput and CalAtomInfo can modify the value of Parameter. + // Do not add extra friend class here!!! + friend class ModuleIO::ReadInput; // ReadInput read INPUT file and give the value to Parameter + friend class CalAtomsInfo; // CalAtomInfo calculate the atom information from pseudopotential and give the value to + // Parameter + // INPUT parameters Input_para input; // System parameters diff --git a/source/module_parameter/system_parameter.h b/source/module_parameter/system_parameter.h index 6c0d48fe283..04d2ca870e1 100644 --- a/source/module_parameter/system_parameter.h +++ b/source/module_parameter/system_parameter.h @@ -10,6 +10,7 @@ struct System_para // --------------------------------------------------------------- int myrank = 0; int nproc = 1; + int nthread_per_proc = 1; int mypool = 0; int npool = 1; int nproc_in_pool = 1; @@ -19,8 +20,9 @@ struct System_para // ------------ parameters not defined in INPUT file ------------- // ------------ but decided by INPUT parameters ------------- // --------------------------------------------------------------- + int nlocal = 0; ///< total number of local basis. bool two_fermi = false; ///< true if "nupdown" is set - + bool use_uspp = false; ///< true if "uspp" is set bool dos_setemin = false; ///< true: "dos_emin_ev" is set bool dos_setemax = false; ///< true: "dos_emax_ev" is set @@ -36,7 +38,8 @@ struct System_para ///< for plane wave basis. bool gamma_only_local = false; ///< true if "gamma_only" is true and "lcao" ///< is true; for local orbitals. - std::string global_in_card = "INPUT"; ///< global input directory + std::string global_in_card = "INPUT"; ///< input file + std::string global_in_stru = "STRU"; ///< stru file std::string global_out_dir = ""; ///< global output directory std::string global_readin_dir = ""; ///< global readin directory std::string global_stru_dir = ""; ///< global structure directory @@ -47,7 +50,6 @@ struct System_para bool domag = false; /// 1 : calculate the magnetism with x, y, z component bool domag_z = false; /// 1 : constrain the magnetism to z axis - std::string device_flag = "cpu"; ///< device flag, "cpu" or "gpu" bool double_grid = false; ///< true if "ndx,ndy,ndz" is larger than "nx,ny,nz" double uramping = -10.0 / 13.6; /// U-Ramping method (Ry) std::vector hubbard_u = {}; ///< Hubbard Coulomb interaction parameter U (Ry) diff --git a/source/module_psi/psi.h b/source/module_psi/psi.h index 39956321fd7..283c641204c 100644 --- a/source/module_psi/psi.h +++ b/source/module_psi/psi.h @@ -143,10 +143,16 @@ class Psi bool allocate_inside = true; ///; +#ifdef __DSP + using delete_memory_op = base_device::memory::delete_memory_op_mt; + using resize_memory_op = base_device::memory::resize_memory_op_mt; +#else using delete_memory_op = base_device::memory::delete_memory_op; using resize_memory_op = base_device::memory::resize_memory_op; +#endif + using set_memory_op = base_device::memory::set_memory_op; using synchronize_memory_op = base_device::memory::synchronize_memory_op; + }; } // end of namespace psi diff --git a/source/module_psi/psi_initializer.cpp b/source/module_psi/psi_initializer.cpp index d4ee02d09b4..ef09d98a89d 100644 --- a/source/module_psi/psi_initializer.cpp +++ b/source/module_psi/psi_initializer.cpp @@ -16,89 +16,64 @@ psi::Psi>* psi_initializer::allocate(const bool { ModuleBase::timer::tick("psi_initializer", "allocate"); /* - WARNING: when basis_type = "pw", the variable GlobalV::NLOCAL will also be set, in this case, it is set to + WARNING: when basis_type = "pw", the variable PARAM.globalv.nlocal will also be set, in this case, it is set to 9 = 1 + 3 + 5, which is the maximal number of orbitals spd, I don't think it is reasonable The way of calculating this->p_ucell_->natomwfc is, for each atom, read pswfc and for s, it is 1, for p, it is 3 , then multiplied by the number of atoms, and then add them together. */ - int prefactor = 1; int nbands_actual = 0; if(this->method_ == "random") { - nbands_actual = GlobalV::NBANDS; + nbands_actual = PARAM.inp.nbands; this->nbands_complem_ = 0; } else { if(this->method_.substr(0, 6) == "atomic") { - if(this->p_ucell_->natomwfc >= GlobalV::NBANDS) - { - nbands_actual = this->p_ucell_->natomwfc; - this->nbands_complem_ = 0; - } - else - { - nbands_actual = GlobalV::NBANDS; - this->nbands_complem_ = GlobalV::NBANDS - this->p_ucell_->natomwfc; - } + nbands_actual = std::max(this->p_ucell_->natomwfc, PARAM.inp.nbands); + this->nbands_complem_ = nbands_actual - this->p_ucell_->natomwfc; } else if(this->method_.substr(0, 3) == "nao") { /* - previously GlobalV::NLOCAL is used here, however it is wrong. GlobalV::NLOCAL is fixed to 9*nat. + previously PARAM.globalv.nlocal is used here, however it is wrong. PARAM.globalv.nlocal is fixed to 9*nat. */ int nbands_local = 0; for(int it = 0; it < this->p_ucell_->ntype; it++) { - for(int ia = 0; ia < this->p_ucell_->atoms[it].na; ia++) + for(int l = 0; l < this->p_ucell_->atoms[it].nwl + 1; l++) { - /* FOR EVERY ATOM */ - for(int l = 0; l < this->p_ucell_->atoms[it].nwl + 1; l++) - { - /* EVERY ZETA FOR (2l+1) ORBS */ - /* - non-rotate basis, nbands_local*=2 for PARAM.globalv.npol = 2 is enough - */ - //nbands_local += this->p_ucell_->atoms[it].l_nchi[l]*(2*l+1) * PARAM.globalv.npol; - /* - rotate basis, nbands_local*=4 for p, d, f,... orbitals, and nbands_local*=2 for s orbitals - risky when NSPIN = 4, problematic psi value, needed to be checked - */ - if(l == 0) - { - nbands_local += this->p_ucell_->atoms[it].l_nchi[l] * PARAM.globalv.npol; - } - else - { - nbands_local += this->p_ucell_->atoms[it].l_nchi[l]*(2*l+1) * PARAM.globalv.npol; - } - } + /* EVERY ZETA FOR (2l+1) ORBS */ + const int nchi = this->p_ucell_->atoms[it].l_nchi[l]; + const int degen_l = (l == 0)? 1 : 2*l+1; + nbands_local += nchi * degen_l * PARAM.globalv.npol * this->p_ucell_->atoms[it].na; + /* + non-rotate basis, nbands_local*=2 for PARAM.globalv.npol = 2 is enough + */ + //nbands_local += this->p_ucell_->atoms[it].l_nchi[l]*(2*l+1) * PARAM.globalv.npol; + /* + rotate basis, nbands_local*=4 for p, d, f,... orbitals, and nbands_local*=2 for s orbitals + risky when NSPIN = 4, problematic psi value, needed to be checked + */ } } - if(nbands_local >= GlobalV::NBANDS) - { - nbands_actual = nbands_local; - this->nbands_complem_ = 0; - } - else - { - nbands_actual = GlobalV::NBANDS; - this->nbands_complem_ = GlobalV::NBANDS - nbands_local; - } + nbands_actual = std::max(nbands_local, PARAM.inp.nbands); + this->nbands_complem_ = nbands_actual - nbands_local; } } + assert(this->nbands_complem_ >= 0); - const int nks_psi = (PARAM.inp.calculation == "nscf" && this->mem_saver_ == 1)? 1 : this->pw_wfc_->nks; + const int nks_psi = (PARAM.inp.calculation == "nscf" && this->mem_saver_ == 1)? 1 : this->pw_wfc_->nks; const int nbasis_actual = this->pw_wfc_->npwk_max * PARAM.globalv.npol; psi::Psi>* psi_out = nullptr; if(!only_psig) { psi_out = new psi::Psi>(nks_psi, - GlobalV::NBANDS, // because no matter what, the wavefunction finally needed has GlobalV::NBANDS bands + PARAM.inp.nbands, // because no matter what, the wavefunction finally needed has PARAM.inp.nbands bands nbasis_actual, this->pw_wfc_->npwk); - double memory_cost_psi = nks_psi * GlobalV::NBANDS * this->pw_wfc_->npwk_max * PARAM.globalv.npol* + double memory_cost_psi = nks_psi * PARAM.inp.nbands * this->pw_wfc_->npwk_max * PARAM.globalv.npol* sizeof(std::complex); #ifdef __MPI // get the correct memory cost for psi by all-reduce sum @@ -107,10 +82,9 @@ psi::Psi>* psi_initializer::allocate(const bool // std::cout << " MEMORY FOR PSI PER PROCESSOR (MB) : " << double(memory_cost_psi)/1024.0/1024.0 << std::endl; ModuleBase::Memory::record("Psi_PW", memory_cost_psi); } - // for memory saving, the psig can always only hold one k-point data. But for lcao_in_pw, the psig - // is actcually a transformation matrix. During the SCF, the projection might be quite time- - // consuming. - const int nks_psig = (this->mem_saver_ == 1 && PARAM.inp.basis_type != "lcao_in_pw")? 1 : nks_psi; + // psi_initializer also works for basis transformation tasks. In this case, psig needs to allocate memory for + // each kpoint, otherwise, for initializing pw wavefunction, only one kpoint's space is enough. + const int nks_psig = (PARAM.inp.basis_type == "pw")? 1 : nks_psi; this->psig_ = std::make_shared>(nks_psig, nbands_actual, nbasis_actual, @@ -126,11 +100,11 @@ psi::Psi>* psi_initializer::allocate(const bool GlobalV::ofs_running << "Allocate memory for psi and psig done.\n" << "Print detailed information of dimension of psi and psig:\n" - << "psi: (" << nks_psi << ", " << GlobalV::NBANDS << ", " << nbasis_actual << ")\n" + << "psi: (" << nks_psi << ", " << PARAM.inp.nbands << ", " << nbasis_actual << ")\n" << "psig: (" << nks_psig << ", " << nbands_actual << ", " << nbasis_actual << ")\n" << "nks (psi) = " << nks_psi << "\n" << "nks (psig) = " << nks_psig << "\n" - << "GlobalV::NBANDS = " << GlobalV::NBANDS << "\n" + << "PARAM.inp.nbands = " << PARAM.inp.nbands << "\n" << "nbands_actual = " << nbands_actual << "\n" << "nbands_complem = " << this->nbands_complem_ << "\n" << "nbasis_actual = " << nbasis_actual << "\n" @@ -164,6 +138,7 @@ void psi_initializer::random_t(T* psi, const int iw_start, const int std::vector stickarg(nz); std::vector tmprr(nstnz); std::vector tmparg(nstnz); + for (int iw = iw_start; iw < iw_end; iw++) { // get the starting memory address of iw band @@ -177,6 +152,7 @@ void psi_initializer::random_t(T* psi, const int iw_start, const int // if the stick is not on present processor, then skip if(this->pw_wfc_->fftixy2ip[ir] < 0) { continue; } // otherwise + // the following code is very time-consuming, but it can be skipped with pw_seed = 0 if(GlobalV::RANK_IN_POOL == 0) { // generate random number for (x,y) and all z, the stick will must @@ -195,7 +171,8 @@ void psi_initializer::random_t(T* psi, const int iw_start, const int #endif } // then for each g-component, initialize the wavefunction value - for (int ig = 0;ig < ng;ig++) + #pragma omp parallel for schedule(static, 4096/sizeof(T)) + for (int ig = 0; ig < ng; ig++) { // get the correct value of "rr" and "arg" by indexing map "getigl2isz" const double rr = tmprr[this->pw_wfc_->getigl2isz(ik, ig)]; @@ -214,6 +191,8 @@ void psi_initializer::random_t(T* psi, const int iw_start, const int for (int iw = iw_start ;iw < iw_end; iw++) { T* psi_slice = &(psi[iw * this->pw_wfc_->npwk_max * PARAM.globalv.npol]); // get the memory to write directly. For nspin 4, nbasis*2 + + #pragma omp parallel for schedule(static, 4096/sizeof(T)) for (int ig = 0; ig < ng; ig++) { const double rr = std::rand()/double(RAND_MAX); //qianrui add RAND_MAX @@ -221,8 +200,9 @@ void psi_initializer::random_t(T* psi, const int iw_start, const int const double gk2 = this->pw_wfc_->getgk2(ik, ig); psi_slice[ig] = this->template cast_to_T(std::complex(rr*cos(arg)/(gk2 + 1.0), rr*sin(arg)/(gk2 + 1.0))); } - if(PARAM.globalv.npol==2) // additionally for nspin 4... + if(PARAM.globalv.npol == 2) // additionally for nspin 4... { + #pragma omp parallel for schedule(static, 4096/sizeof(T)) for (int ig = this->pw_wfc_->npwk_max; ig < this->pw_wfc_->npwk_max + ng; ig++) { const double rr = std::rand()/double(RAND_MAX); diff --git a/source/module_psi/psi_initializer.h b/source/module_psi/psi_initializer.h index 059a8b258b6..ec1efd605e0 100644 --- a/source/module_psi/psi_initializer.h +++ b/source/module_psi/psi_initializer.h @@ -175,7 +175,7 @@ class psi_initializer // avoid memory leak std::shared_ptr> psig_; private: - int mem_saver_ = 1; + int mem_saver_ = 0; std::string method_ = "none"; int nbands_complem_ = 0; double random_mix_ = 0; diff --git a/source/module_psi/psi_initializer_nao.cpp b/source/module_psi/psi_initializer_nao.cpp index a88b0ed9f80..c2b0f83c04a 100644 --- a/source/module_psi/psi_initializer_nao.cpp +++ b/source/module_psi/psi_initializer_nao.cpp @@ -17,6 +17,12 @@ #include "module_base/parallel_reduce.h" #endif #include "module_parameter/parameter.h" +#include "module_io/orb_io.h" +// GlobalV::NQX and GlobalV::DQ are here +#include "module_parameter/parameter.h" + +#include +#include /* I don't know why some variables are distributed while others not... for example the orbital_files... @@ -40,214 +46,79 @@ template void psi_initializer_nao::read_external_orbs(std::string* orbital_files, const int& rank) { ModuleBase::timer::tick("psi_initializer_nao", "read_external_orbs"); - if (rank == 0) - { - for (int itype = 0; itype < this->p_ucell_->ntype; itype++) - { - this->orbital_files_.push_back(orbital_files[itype]); - } - for (int it = 0; it < this->p_ucell_->ntype; it++) - { - // number of chi per atomtype - int nchi = 0; - for (int l = 0; l <= this->p_ucell_->atoms[it].nwl; l++) - { - nchi += this->p_ucell_->atoms[it].l_nchi[l]; - } - - std::vector n_rgrid_it; - std::vector> rgrid_it; - std::vector> rvalue_it; - - std::ifstream ifs_it; - ifs_it.open(PARAM.inp.orbital_dir + this->orbital_files_[it]); - - if (!ifs_it) - { - GlobalV::ofs_warning << "psi_initializer_nao::read_orbital_files: cannot open orbital file: " - << this->orbital_files_[it] << std::endl; - ModuleBase::WARNING_QUIT("psi_initializer_nao::read_orbital_files", - "cannot open orbital file."); - } - else - { - GlobalV::ofs_running << "psi_initializer_nao::read_orbital_files: reading orbital file: " - << this->orbital_files_[it] << std::endl; - } - ifs_it.close(); - int ichi_overall = 0; - // check nwl and nchi for each rank + this->orbital_files_.resize(this->p_ucell_->ntype); + this->nr_.resize(this->p_ucell_->ntype); + this->rgrid_.resize(this->p_ucell_->ntype); + this->chi_.resize(this->p_ucell_->ntype); - for (int l = 0; l <= this->p_ucell_->atoms[it].nwl; l++) - { - for (int ichi = 0; ichi < this->p_ucell_->atoms[it].l_nchi[l]; ichi++) - { - int n_rgrid_ichi; - std::vector rgrid_ichi; - std::vector rvalue_ichi; - - GlobalV::ofs_running << "-------------------------------------- " << std::endl; - GlobalV::ofs_running << " reading orbital of element " << this->p_ucell_->atoms[it].label - << std::endl - << " angular momentum l = " << l << std::endl - << " index of chi = " << ichi << std::endl; - - ifs_it.open(PARAM.inp.orbital_dir + this->orbital_files_[it]); - double dr = 0.0; - char word[80]; - - while (ifs_it.good()) - { - ifs_it >> word; - if (std::strcmp(word, "END") == 0) - { - break; - } - } - ModuleBase::CHECK_NAME(ifs_it, "Mesh"); - ifs_it >> n_rgrid_ichi; - - if (n_rgrid_ichi % 2 == 0) - { - ++n_rgrid_ichi; - } - GlobalV::ofs_running << " number of radial grid = " << n_rgrid_ichi << std::endl; - - ModuleBase::CHECK_NAME(ifs_it, "dr"); - ifs_it >> dr; - GlobalV::ofs_running << " dr = " << dr << std::endl; - - for (int ir = 0; ir < n_rgrid_ichi; ir++) - { - rgrid_ichi.push_back(ir * dr); - } - GlobalV::ofs_running << " maximal radial grid point = " << rgrid_ichi[n_rgrid_ichi - 1] - << " Angstrom" << std::endl; - - std::string title1, title2, title3; - int it_read = 0; - int l_read = 0; - int nchi_read = 0; - bool find = false; - while (!find) - { - if (ifs_it.eof()) - { - GlobalV::ofs_warning << " psi_initializer_nao::read_orbital_files: cannot find " - "orbital of element " - << this->p_ucell_->atoms[it].label << std::endl - << " angular momentum l = " << l << std::endl - << " index of chi = " << ichi << std::endl; - } - ifs_it >> title1 >> title2 >> title3; - assert(title1 == "Type"); - ifs_it >> it_read >> l_read >> nchi_read; - if (l_read == l && nchi_read == ichi) - { - for (int ir = 0; ir < n_rgrid_ichi; ir++) - { - double rvalue_ichi_ir; - ifs_it >> rvalue_ichi_ir; - rvalue_ichi.push_back(rvalue_ichi_ir); - } - find = true; - } - else - { - double discard; - for (int ir = 0; ir < n_rgrid_ichi; ir++) - { - ifs_it >> discard; - } - } - } - ifs_it.close(); - n_rgrid_it.push_back(n_rgrid_ichi); - rgrid_it.push_back(rgrid_ichi); - // before push back, normalize the rvalue_ichi, 2024/03/19, kirk0830 - // turn off normalize, 2024/03/22, kirk0830 - // normalize(rgrid_ichi, rvalue_ichi); - rvalue_it.push_back(rvalue_ichi); - ++ichi_overall; - } - } - this->n_rgrid_.push_back(n_rgrid_it); - this->rgrid_.push_back(rgrid_it); - this->rvalue_.push_back(rvalue_it); - GlobalV::ofs_running << "-------------------------------------- " << std::endl; - } - } -// MPI additional implementation #ifdef __MPI - // bcast fname - if (rank != 0) + if (rank == 0) { - this->orbital_files_.resize(this->p_ucell_->ntype); +#endif + std::copy(orbital_files, orbital_files + this->p_ucell_->ntype, this->orbital_files_.begin()); +#ifdef __MPI } Parallel_Common::bcast_string(this->orbital_files_.data(), this->p_ucell_->ntype); - - // bcast orbital data - // resize - if (rank != 0) - { - this->n_rgrid_.resize(this->p_ucell_->ntype); - } - - std::vector nchi(this->p_ucell_->ntype); - if (rank == 0) +#endif + for (int it = 0; it < this->p_ucell_->ntype; it++) { - for (int it = 0; it < this->p_ucell_->ntype; it++) + std::ifstream ifs_it; + bool is_open = false; + if (rank == 0) { - nchi[it] = this->n_rgrid_[it].size(); + ifs_it.open(PARAM.inp.orbital_dir + this->orbital_files_[it]); + is_open = ifs_it.is_open(); } - } - - // bcast - Parallel_Common::bcast_int(nchi.data(), this->p_ucell_->ntype); - // resize - if (rank != 0) - { - this->n_rgrid_.resize(this->p_ucell_->ntype); - this->rgrid_.resize(this->p_ucell_->ntype); - this->rvalue_.resize(this->p_ucell_->ntype); - for (int it = 0; it < this->p_ucell_->ntype; it++) +#ifdef __MPI + Parallel_Common::bcast_bool(is_open); +#endif + if (!is_open) { - this->n_rgrid_[it].resize(nchi[it]); - this->rgrid_[it].resize(nchi[it]); - this->rvalue_[it].resize(nchi[it]); + GlobalV::ofs_warning << "psi_initializer_nao::read_orbital_files: cannot open orbital file: " + << this->orbital_files_[it] << std::endl; + ModuleBase::WARNING_QUIT("psi_initializer_nao::read_orbital_files", + "cannot open orbital file."); } - } - - // bcast - for (int it = 0; it < this->p_ucell_->ntype; it++) - { - Parallel_Common::bcast_int(this->n_rgrid_[it].data(), nchi[it]); - } + else + { + GlobalV::ofs_running << "psi_initializer_nao::read_orbital_files: reading orbital file: " + << this->orbital_files_[it] << std::endl; + } + std::string elem; // garbage value, will discard + double ecut; // garbage value, will discard + int nr; + double dr; + std::vector nzeta; + std::vector> radials; + ModuleIO::read_abacus_orb(ifs_it, elem, ecut, nr, dr, nzeta, radials, rank); - // resize - if (rank != 0) - { - for (int it = 0; it < this->p_ucell_->ntype; it++) + if (rank == 0) { - for (int ichi = 0; ichi < nchi[it]; ichi++) - { - this->rgrid_[it][ichi].resize(this->n_rgrid_[it][ichi]); - this->rvalue_[it][ichi].resize(this->n_rgrid_[it][ichi]); - } + ifs_it.close(); } - } - // bcast - for (int it = 0; it < this->p_ucell_->ntype; it++) - { - for (int ichi = 0; ichi < nchi[it]; ichi++) + const int nchi = std::accumulate(nzeta.begin(), nzeta.end(), 0); + // nr_ + this->nr_[it].resize(nchi); + std::for_each(this->nr_[it].begin(), this->nr_[it].end(), [nr](int& numr) { numr = nr; }); + // rgrid_ + this->rgrid_[it].resize(nchi); + std::for_each(this->rgrid_[it].begin(), this->rgrid_[it].end(), [nr, dr](std::vector& rgrid) { + rgrid.resize(nr); + std::iota(rgrid.begin(), rgrid.end(), 0); + std::for_each(rgrid.begin(), rgrid.end(), [dr](double& r) { r = r * dr; }); + }); + // chi_ + this->chi_[it].resize(nchi); + std::for_each(this->chi_[it].begin(), this->chi_[it].end(), [nr](std::vector& chi) { + chi.resize(nr); + }); + for (int ichi = 0; ichi < nchi; ichi++) { - Parallel_Common::bcast_double(this->rgrid_[it][ichi].data(), this->n_rgrid_[it][ichi]); - Parallel_Common::bcast_double(this->rvalue_[it][ichi].data(), this->n_rgrid_[it][ichi]); + std::copy(radials[ichi].begin(), radials[ichi].end(), this->chi_[it][ichi].begin()); } } -#endif ModuleBase::timer::tick("psi_initializer_nao", "read_external_orbs"); } @@ -255,26 +126,27 @@ template void psi_initializer_nao::allocate_table() { // find correct dimension for ovlp_flzjlq - int dim1 = this->p_ucell_->ntype; - int dim2 = 0; // dim2 should be the maximum number of zeta for each atomtype + int ntype = this->p_ucell_->ntype; + int lmaxmax = 0; // lmaxmax + int nzeta_max = 0; // dim3 should be the maximum number of zeta for each atomtype for (int it = 0; it < this->p_ucell_->ntype; it++) { int nzeta = 0; - for (int l = 0; l < this->p_ucell_->atoms[it].nwl + 1; l++) + int lmax = this->p_ucell_->atoms[it].nwl; + lmaxmax = (lmaxmax > lmax) ? lmaxmax : lmax; + for (int l = 0; l < lmax + 1; l++) { nzeta += this->p_ucell_->atoms[it].l_nchi[l]; } - dim2 = (nzeta > dim2) ? nzeta : dim2; + nzeta_max = (nzeta > nzeta_max) ? nzeta : nzeta_max; } - if (dim2 == 0) + if (nzeta_max == 0) { ModuleBase::WARNING_QUIT("psi_initializer_nao::psi_initializer_nao", "there is not ANY numerical atomic orbital read in present system, quit."); } - int dim3 = PARAM.globalv.nqx; - // allocate memory for ovlp_flzjlq - this->ovlp_flzjlq_.create(dim1, dim2, dim3); - this->ovlp_flzjlq_.zero_out(); + // allocate a map (it, l, izeta) -> i, should allocate memory of ntype * lmax * nzeta_max + this->projmap_.create(ntype, lmaxmax + 1, nzeta_max); } #ifdef __MPI @@ -288,6 +160,7 @@ void psi_initializer_nao::initialize(Structure_Factor* sf, const int& rank) { ModuleBase::timer::tick("psi_initializer_nao", "initialize_mpi"); + // import this->sf_ = sf; this->pw_wfc_ = pw_wfc; @@ -295,11 +168,11 @@ void psi_initializer_nao::initialize(Structure_Factor* sf, this->p_parakpts_ = p_parakpts; this->p_pspot_nl_ = p_pspot_nl; this->random_seed_ = random_seed; + // allocate this->allocate_table(); this->read_external_orbs(this->p_ucell_->orbital_fn, rank); - // this->cal_ovlp_flzjlq(); //because PARAM.globalv.nqx will change during vcrelax, so it should be called in both init - // and init_after_vc + // then for generate random number to fill in the wavefunction this->ixy2is_.clear(); this->ixy2is_.resize(this->pw_wfc_->fftnxy); @@ -315,17 +188,18 @@ void psi_initializer_nao::initialize(Structure_Factor* sf, pseudopot_cell_vnl* p_pspot_nl) { ModuleBase::timer::tick("psi_initializer_nao", "initialize_serial"); + // import this->sf_ = sf; this->pw_wfc_ = pw_wfc; this->p_ucell_ = p_ucell; this->p_pspot_nl_ = p_pspot_nl; this->random_seed_ = random_seed; + // allocate this->allocate_table(); this->read_external_orbs(this->p_ucell_->orbital_fn, 0); - // this->cal_ovlp_flzjlq(); //because PARAM.globalv.nqx will change during vcrelax, so it should be called in both init - // and init_after_vc + // then for generate random number to fill in the wavefunction this->ixy2is_.clear(); this->ixy2is_.resize(this->pw_wfc_->fftnxy); @@ -338,7 +212,32 @@ template void psi_initializer_nao::tabulate() { ModuleBase::timer::tick("psi_initializer_nao", "tabulate"); - this->ovlp_flzjlq_.zero_out(); + + // a uniformed qgrid + std::vector qgrid(PARAM.globalv.nqx); + std::iota(qgrid.begin(), qgrid.end(), 0); + std::for_each(qgrid.begin(), qgrid.end(), [this](double& q) { q = q * PARAM.globalv.dq; }); + + // only when needed, allocate memory for cubspl_ + if (this->cubspl_.get()) { this->cubspl_.reset(); } + this->cubspl_ = std::unique_ptr( + new ModuleBase::CubicSpline(qgrid.size(), qgrid.data())); + + // calculate the total number of radials and call reserve to allocate memory + int nchi = 0; + for (int it = 0; it < this->p_ucell_->ntype; it++) + { + for (int l = 0; l < this->p_ucell_->atoms[it].nwl + 1; l++) + { + nchi += this->p_ucell_->atoms[it].l_nchi[l]; + } + } + this->cubspl_->reserve(nchi); + ModuleBase::SphericalBesselTransformer sbt_(true); // bool: enable cache + + // tabulate the spherical bessel transform of numerical orbital function + std::vector Jlfq(PARAM.globalv.nqx, 0.0); + int i = 0; for (int it = 0; it < this->p_ucell_->ntype; it++) { int ic = 0; @@ -346,23 +245,15 @@ void psi_initializer_nao::tabulate() { for (int izeta = 0; izeta < this->p_ucell_->atoms[it].l_nchi[l]; izeta++) { - std::vector ovlp_flzjlq_q(PARAM.globalv.nqx); - std::vector qgrid(PARAM.globalv.nqx); - for (int iq = 0; iq < PARAM.globalv.nqx; iq++) - { - qgrid[iq] = iq * PARAM.globalv.dq; - } - this->sbt.direct(l, - this->n_rgrid_[it][ic], - this->rgrid_[it][ic].data(), - this->rvalue_[it][ic].data(), - PARAM.globalv.nqx, - qgrid.data(), - ovlp_flzjlq_q.data()); - for (int iq = 0; iq < PARAM.globalv.nqx; iq++) - { - this->ovlp_flzjlq_(it, ic, iq) = ovlp_flzjlq_q[iq]; - } + sbt_.direct(l, + this->nr_[it][ic], + this->rgrid_[it][ic].data(), + this->chi_[it][ic].data(), + PARAM.globalv.nqx, + qgrid.data(), + Jlfq.data()); + this->cubspl_->add(Jlfq.data()); + this->projmap_(it, l, izeta) = i++; // index it ++ic; } } @@ -382,15 +273,19 @@ void psi_initializer_nao::proj_ao_onkG(const int ik) ModuleBase::matrix ylm(total_lm, npw); std::vector> aux(npw); - std::vector> gk(npw); + std::vector qnorm(npw); + std::vector> q(npw); + + #pragma omp parallel for schedule(static, 4096 / sizeof(double)) for (int ig = 0; ig < npw; ig++) { - gk[ig] = this->pw_wfc_->getgpluskcar(ik, ig); + q[ig] = this->pw_wfc_->getgpluskcar(ik, ig); + qnorm[ig] = q[ig].norm() * this->p_ucell_->tpiba; } - ModuleBase::YlmReal::Ylm_Real(total_lm, npw, gk.data(), ylm); + ModuleBase::YlmReal::Ylm_Real(total_lm, npw, q.data(), ylm); // int index = 0; - std::vector ovlp_flzjlg(npw); + std::vector Jlfq(npw, 0.0); int ibasis = 0; for (int it = 0; it < this->p_ucell_->ntype; it++) { @@ -411,17 +306,10 @@ void psi_initializer_nao::proj_ao_onkG(const int ik) transformation of numerical orbital function, is indiced by it and ic, is needed to interpolate everytime when ic updates, therefore everytime when present orbital is done */ - for (int ig = 0; ig < npw; ig++) - { - ovlp_flzjlg[ig] = ModuleBase::PolyInt::Polynomial_Interpolation( - this->ovlp_flzjlq_, // the spherical bessel transform of numerical orbital function - it, - ic, // each (it, ic)-pair defines a unique numerical orbital function - PARAM.globalv.nqx, - PARAM.globalv.dq, // grid number and grid spacing of q - gk[ig].norm() * this->p_ucell_->tpiba // norm of (G+k) = K - ); - } + + // use cublic spline instead of previous polynomial interpolation + this->cubspl_->eval(npw, qnorm.data(), Jlfq.data(), nullptr, nullptr, this->projmap_(it, L, N)); + /* FOR EVERY NAO IN EACH ATOM */ if (PARAM.inp.nspin == 4) { @@ -447,10 +335,13 @@ void psi_initializer_nao::proj_ao_onkG(const int ik) for (int m = 0; m < 2 * L + 1; m++) { const int lm = L * L + m; + #pragma omp parallel for for (int ig = 0; ig < npw; ig++) { - aux[ig] = sk[ig] * ylm(lm, ig) * ovlp_flzjlg[ig]; + aux[ig] = sk[ig] * ylm(lm, ig) * Jlfq[ig]; } + + #pragma omp parallel for for (int ig = 0; ig < npw; ig++) { fup = cos(0.5 * alpha) * aux[ig]; @@ -483,10 +374,11 @@ void psi_initializer_nao::proj_ao_onkG(const int ik) for (int m = 0; m < 2 * L + 1; m++) { const int lm = L * L + m; + #pragma omp parallel for for (int ig = 0; ig < npw; ig++) { (*(this->psig_))(ibasis, ig) - = this->template cast_to_T(lphase * sk[ig] * ylm(lm, ig) * ovlp_flzjlg[ig]); + = this->template cast_to_T(lphase * sk[ig] * ylm(lm, ig) * Jlfq[ig]); } ++ibasis; } diff --git a/source/module_psi/psi_initializer_nao.h b/source/module_psi/psi_initializer_nao.h index 5ef7d1b6ca0..b7643d38d74 100644 --- a/source/module_psi/psi_initializer_nao.h +++ b/source/module_psi/psi_initializer_nao.h @@ -2,7 +2,8 @@ #define PSI_INITIALIZER_NAO_H #include "psi_initializer.h" #include "module_base/realarray.h" - +#include "module_base/cubic_spline.h" +#include /* Psi (planewave based wavefunction) initializer: numerical atomic orbital method */ @@ -40,13 +41,13 @@ class psi_initializer_nao : public psi_initializer virtual void tabulate() override; std::vector external_orbs() const { return orbital_files_; } - std::vector> n_rgrid() const { return n_rgrid_; } - std::vector n_rgrid(const int& itype) const { return n_rgrid_[itype]; } - int n_rgrid(const int& itype, const int& ichi) const { return n_rgrid_[itype][ichi]; } - std::vector>> rvalue() const { return rvalue_; } - std::vector> rvalue(const int& itype) const { return rvalue_[itype]; } - std::vector rvalue(const int& itype, const int& ichi) const { return rvalue_[itype][ichi]; } - double rvalue(const int& itype, const int& ichi, const int& ir) const { return rvalue_[itype][ichi][ir]; } + std::vector> nr() const { return nr_; } + std::vector nr(const int& itype) const { return nr_[itype]; } + int nr(const int& itype, const int& ichi) const { return nr_[itype][ichi]; } + std::vector>> chi() const { return chi_; } + std::vector> chi(const int& itype) const { return chi_[itype]; } + std::vector chi(const int& itype, const int& ichi) const { return chi_[itype][ichi]; } + double chi(const int& itype, const int& ichi, const int& ir) const { return chi_[itype][ichi][ir]; } std::vector>> rgrid() const { return rgrid_; } std::vector> rgrid(const int& itype) const { return rgrid_[itype]; } std::vector rgrid(const int& itype, const int& ichi) const { return rgrid_[itype][ichi]; } @@ -54,11 +55,14 @@ class psi_initializer_nao : public psi_initializer private: std::vector orbital_files_; - ModuleBase::realArray ovlp_flzjlq_; + /// @brief cubic spline for interpolation + std::unique_ptr cubspl_; + /// @brief radial map, [itype][l][izeta] -> i + ModuleBase::realArray projmap_; /// @brief number of realspace grids per type per chi, [itype][ichi] - std::vector> n_rgrid_; + std::vector> nr_; /// @brief data of numerical atomic orbital per type per chi per position, [itype][ichi][ir] - std::vector>> rvalue_; + std::vector>> chi_; /// @brief r of numerical atomic orbital per type per chi per position, [itype][ichi][ir] std::vector>> rgrid_; }; diff --git a/source/module_psi/test/CMakeLists.txt b/source/module_psi/test/CMakeLists.txt index 110e73e058c..08ef34ded78 100644 --- a/source/module_psi/test/CMakeLists.txt +++ b/source/module_psi/test/CMakeLists.txt @@ -16,6 +16,7 @@ AddTest( ../../module_cell/atom_spec.cpp ../../module_cell/parallel_kpoints.cpp ../../module_cell/test/support/mock_unitcell.cpp + ../../module_io/orb_io.cpp ) endif() diff --git a/source/module_psi/test/psi_initializer_unit_test.cpp b/source/module_psi/test/psi_initializer_unit_test.cpp index 989d1f045ab..bc0941e1218 100644 --- a/source/module_psi/test/psi_initializer_unit_test.cpp +++ b/source/module_psi/test/psi_initializer_unit_test.cpp @@ -115,7 +115,7 @@ class PsiIntializerUnitTest : public ::testing::Test { this->p_parakpts = new Parallel_Kpoints(); #endif // mock - GlobalV::NBANDS = 1; + PARAM.input.nbands = 1; PARAM.input.nspin = 1; PARAM.input.orbital_dir = "./support/"; PARAM.input.pseudo_dir = "./support/"; diff --git a/source/module_relax/relax_driver.cpp b/source/module_relax/relax_driver.cpp index c549812f638..9806ea975c7 100644 --- a/source/module_relax/relax_driver.cpp +++ b/source/module_relax/relax_driver.cpp @@ -2,12 +2,13 @@ #include "module_base/global_file.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" // use chr. +#include "module_io/cif_io.h" #include "module_io/json_output/output_info.h" +#include "module_io/output_log.h" #include "module_io/print_info.h" #include "module_io/read_exit_file.h" #include "module_io/write_wfc_r.h" #include "module_parameter/parameter.h" -#include "module_io/cif_io.h" void Relax_Driver::relax_driver(ModuleESolver::ESolver* p_esolver) { ModuleBase::TITLE("Ions", "opt_ions"); @@ -39,7 +40,7 @@ void Relax_Driver::relax_driver(ModuleESolver::ESolver* p_esolver) || PARAM.inp.calculation == "nscf") && (PARAM.inp.esolver_type != "lr")) { - Print_Info::print_screen(stress_step, force_step, istep); + ModuleIO::print_screen(stress_step, force_step, istep); } #ifdef __RAPIDJSON @@ -128,37 +129,7 @@ void Relax_Driver::relax_driver(ModuleESolver::ESolver* p_esolver) "data_?"); } - if (p_esolver && stop && p_esolver->get_maxniter() == p_esolver->get_niter() - && !(p_esolver->get_conv_elec())) - { - std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - << std::endl; - std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - << std::endl; - std::cout << " Relaxation is converged, but the SCF is unconverged! The results are unreliable. " - << std::endl; - std::cout - << " It is suggested to increase the maximum SCF step and/or perform the relaxation again." - << std::endl; - std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - << std::endl; - std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" - << std::endl; - GlobalV::ofs_running - << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; - GlobalV::ofs_running - << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; - GlobalV::ofs_running - << "\n Relaxation is converged, but the SCF is unconverged! The results are unreliable.. " - << std::endl; - GlobalV::ofs_running - << "\n It is suggested to increase the maximum SCF step and/or perform the relaxation again. " - << std::endl; - GlobalV::ofs_running - << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; - GlobalV::ofs_running - << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; - } + ModuleIO::output_after_relax(stop, p_esolver->conv_esolver, GlobalV::ofs_running); } #ifdef __RAPIDJSON @@ -188,11 +159,6 @@ void Relax_Driver::relax_driver(ModuleESolver::ESolver* p_esolver) std::cout << " ION DYNAMICS FINISHED :)" << std::endl; } - if (PARAM.inp.calculation == "relax" || PARAM.inp.calculation == "cell-relax") - { - ModuleBase::Global_File::delete_tmp_files(); - } - ModuleBase::timer::tick("Ions", "opt_ions"); return; } diff --git a/source/module_relax/relax_new/relax.cpp b/source/module_relax/relax_new/relax.cpp index 8507e6a2c95..41d7b28bffa 100644 --- a/source/module_relax/relax_new/relax.cpp +++ b/source/module_relax/relax_new/relax.cpp @@ -140,6 +140,9 @@ bool Relax::setup_gradient(const ModuleBase::matrix& force, const ModuleBase::ma std::cout << " LARGEST GRAD (eV/A) : " << max_grad << std::endl; etot_p = etot; } + + GlobalV::ofs_running << "\n Largest gradient in force is " << max_grad << " eV/A." << std::endl; + GlobalV::ofs_running << " Threshold is " << PARAM.inp.force_thr_ev << " eV/A." << std::endl; //========================================= //set gradient for cell degrees of freedom //========================================= @@ -223,8 +226,8 @@ bool Relax::setup_gradient(const ModuleBase::matrix& force, const ModuleBase::ma force_converged = false; } - GlobalV::ofs_running << "\n Largest gradient in stress is " << largest_grad << std::endl; - GlobalV::ofs_running << "\n Threshold is = " << PARAM.inp.stress_thr << std::endl; + GlobalV::ofs_running << "\n Largest gradient in stress is " << largest_grad << " kbar." << std::endl; + GlobalV::ofs_running << " Threshold is " << PARAM.inp.stress_thr << " kbar." << std::endl; } if(force_converged) diff --git a/source/module_relax/relax_new/test/CMakeLists.txt b/source/module_relax/relax_new/test/CMakeLists.txt index 2416e195a78..1835f0eca3d 100644 --- a/source/module_relax/relax_new/test/CMakeLists.txt +++ b/source/module_relax/relax_new/test/CMakeLists.txt @@ -17,6 +17,6 @@ AddTest( SOURCES relax_test.cpp ../relax.cpp ../line_search.cpp ../../../module_base/tool_quit.cpp ../../../module_base/global_variable.cpp ../../../module_base/global_file.cpp ../../../module_base/memory.cpp ../../../module_base/timer.cpp ../../../module_base/matrix3.cpp ../../../module_base/intarray.cpp ../../../module_base/tool_title.cpp ../../../module_base/global_function.cpp ../../../module_base/complexmatrix.cpp ../../../module_base/matrix.cpp - ../../../module_base/complexarray.cpp ../../../module_base/tool_quit.cpp ../../../module_base/realarray.cpp + ../../../module_base/complexarray.cpp ../../../module_base/tool_quit.cpp ../../../module_base/realarray.cpp ../../../module_base/blas_connector.cpp LIBS parameter ${math_libs} ) \ No newline at end of file diff --git a/source/module_relax/relax_old/ions_move_basic.cpp b/source/module_relax/relax_old/ions_move_basic.cpp index 2215b4daba4..a68dbeb7e05 100644 --- a/source/module_relax/relax_old/ions_move_basic.cpp +++ b/source/module_relax/relax_old/ions_move_basic.cpp @@ -147,6 +147,10 @@ void Ions_Move_Basic::check_converged(const UnitCell &ucell, const double *grad) std::cout << " ETOT DIFF (eV) : " << Ions_Move_Basic::ediff * ModuleBase::Ry_to_eV << std::endl; std::cout << " LARGEST GRAD (eV/A) : " << Ions_Move_Basic::largest_grad * ModuleBase::Ry_to_eV / 0.529177 << std::endl; + + GlobalV::ofs_running << "\n Largest gradient in force is " << largest_grad * ModuleBase::Ry_to_eV / 0.529177 + << " eV/A." << std::endl; + GlobalV::ofs_running << " Threshold is " << PARAM.inp.force_thr_ev << " eV/A." << std::endl; } const double etot_diff = std::abs(Ions_Move_Basic::ediff); @@ -165,8 +169,6 @@ void Ions_Move_Basic::check_converged(const UnitCell &ucell, const double *grad) { GlobalV::ofs_running << "\n Ion relaxation is converged!" << std::endl; GlobalV::ofs_running << "\n Energy difference (Ry) = " << etot_diff << std::endl; - GlobalV::ofs_running << "\n Largest gradient is (eV/A) = " << largest_grad * ModuleBase::Ry_to_eV / 0.529177 - << std::endl; Ions_Move_Basic::converged = true; ++Ions_Move_Basic::update_iter; diff --git a/source/module_relax/relax_old/lattice_change_basic.cpp b/source/module_relax/relax_old/lattice_change_basic.cpp index b506f07b7c4..c145d36ee84 100644 --- a/source/module_relax/relax_old/lattice_change_basic.cpp +++ b/source/module_relax/relax_old/lattice_change_basic.cpp @@ -72,8 +72,8 @@ void Lattice_Change_Basic::change_lattice(UnitCell &ucell, double *move, double { ModuleBase::TITLE("Lattice_Change_Basic", "change_lattice"); - assert(move != NULL); - assert(lat != NULL); + assert(move != nullptr); + assert(lat != nullptr); /* std::cout<<" LATTICE CONSTANT OLD:"< 0) { ModuleBase::matrix move_mat_t(3, 3); - for (int i = 0;i < 3;++i)for (int j = 0;j < 3;++j)move_mat_t(j, i) = move[i * 3 + j] / ucell.lat0; //transpose + for (int i = 0;i < 3;++i) {for (int j = 0;j < 3;++j) {move_mat_t(j, i) = move[i * 3 + j] / ucell.lat0; //transpose +} +} ModuleBase::matrix symm_move_mat_t = (move_mat_t * ucell.G.to_matrix());//symmetrize (latvec^{-1} * move_mat)^T ucell.symm.symmetrize_mat3(symm_move_mat_t, ucell.lat); move_mat_t = symm_move_mat_t * ucell.latvec.Transpose().to_matrix();//G^{-1}=latvec^T - for (int i = 0;i < 3;++i)for (int j = 0;j < 3;++j)move[i * 3 + j] = move_mat_t(j, i) * ucell.lat0;//transpose back + for (int i = 0;i < 3;++i) {for (int j = 0;j < 3;++j) {move[i * 3 + j] = move_mat_t(j, i) * ucell.lat0;//transpose back +} +} } if (ucell.lc[0] != 0) @@ -167,8 +171,9 @@ void Lattice_Change_Basic::check_converged(const UnitCell &ucell, ModuleBase::ma { for (int i = 0; i < 3; i++) { - if (stress_ii_max < std::abs(stress(i, i))) + if (stress_ii_max < std::abs(stress(i, i))) { stress_ii_max = std::abs(stress(i, i)); +} for (int j = 0; j < 3; j++) { if (Lattice_Change_Basic::largest_grad < std::abs(stress(i, j))) @@ -207,14 +212,15 @@ void Lattice_Change_Basic::check_converged(const UnitCell &ucell, ModuleBase::ma if (Lattice_Change_Basic::largest_grad < PARAM.inp.stress_thr && stress_ii_max < PARAM.inp.stress_thr) { GlobalV::ofs_running << "\n Lattice relaxation is converged!" << std::endl; - GlobalV::ofs_running << "\n Largest gradient is = " << largest_grad << std::endl; + GlobalV::ofs_running << "\n Largest gradient in stress is " << largest_grad << " kbar." << std::endl; + GlobalV::ofs_running << " Threshold is " << PARAM.inp.stress_thr << " kbar." << std::endl; Lattice_Change_Basic::converged = true; ++Lattice_Change_Basic::update_iter; } else { GlobalV::ofs_running << "\n Lattice relaxation is not converged yet (threshold is " << PARAM.inp.stress_thr - << ")" << std::endl; + << " kbar)" << std::endl; Lattice_Change_Basic::converged = false; } } @@ -227,14 +233,15 @@ void Lattice_Change_Basic::check_converged(const UnitCell &ucell, ModuleBase::ma if (Lattice_Change_Basic::largest_grad < 10 * PARAM.inp.stress_thr) { GlobalV::ofs_running << "\n Lattice relaxation is converged!" << std::endl; - GlobalV::ofs_running << "\n Largest gradient is = " << largest_grad << std::endl; + GlobalV::ofs_running << "\n Largest gradient in stress is " << largest_grad << " kbar." << std::endl; + GlobalV::ofs_running << " Threshold is " << PARAM.inp.stress_thr << " kbar." << std::endl; Lattice_Change_Basic::converged = true; ++Lattice_Change_Basic::update_iter; } else { GlobalV::ofs_running << "\n Lattice relaxation is not converged yet (threshold is " << PARAM.inp.stress_thr - << ")" << std::endl; + << " kbar)" << std::endl; Lattice_Change_Basic::converged = false; } } @@ -242,7 +249,7 @@ void Lattice_Change_Basic::check_converged(const UnitCell &ucell, ModuleBase::ma return; } -void Lattice_Change_Basic::terminate(void) +void Lattice_Change_Basic::terminate() { ModuleBase::TITLE("Lattice_Change_Basic", "terminate"); if (Lattice_Change_Basic::converged) diff --git a/source/module_relax/relax_old/test/CMakeLists.txt b/source/module_relax/relax_old/test/CMakeLists.txt index 005d749c08c..e237b2032b7 100644 --- a/source/module_relax/relax_old/test/CMakeLists.txt +++ b/source/module_relax/relax_old/test/CMakeLists.txt @@ -16,7 +16,10 @@ AddTest( AddTest( TARGET lattice_change_cg_test LIBS parameter ${math_libs} base device - SOURCES lattice_change_cg_test.cpp ../lattice_change_cg.cpp ../lattice_change_basic.cpp + SOURCES lattice_change_cg_test.cpp + ../lattice_change_cg.cpp + ../lattice_change_basic.cpp + ../../../module_io/orb_io.cpp ) AddTest( @@ -40,13 +43,20 @@ AddTest( AddTest( TARGET ions_move_bfgs_test LIBS parameter ${math_libs} base device - SOURCES ions_move_bfgs_test.cpp ../ions_move_bfgs.cpp ../ions_move_basic.cpp ../bfgs_basic.cpp + SOURCES ions_move_bfgs_test.cpp + ../ions_move_bfgs.cpp + ../ions_move_basic.cpp + ../bfgs_basic.cpp + ../../../module_io/orb_io.cpp ) AddTest( TARGET ions_move_cg_test LIBS parameter ${math_libs} base device - SOURCES ions_move_cg_test.cpp ../ions_move_cg.cpp ../ions_move_basic.cpp + SOURCES ions_move_cg_test.cpp + ../ions_move_cg.cpp + ../ions_move_basic.cpp + ../../../module_io/orb_io.cpp ) AddTest( diff --git a/source/module_relax/relax_old/test/ions_move_basic_test.cpp b/source/module_relax/relax_old/test/ions_move_basic_test.cpp index af2595ea21f..fb38d17dfc0 100644 --- a/source/module_relax/relax_old/test/ions_move_basic_test.cpp +++ b/source/module_relax/relax_old/test/ions_move_basic_test.cpp @@ -132,7 +132,8 @@ TEST_F(IonsMoveBasicTest, CheckConvergedCase1) std::string expected_ofs = " old total energy (ry) = 0\n new total energy (ry) = 0\n " - " energy difference (ry) = 0\n largest gradient (ry/bohr) = 0\n largest force is 0, no " + " energy difference (ry) = 0\n largest gradient (ry/bohr) = 0\n\n" + " Largest gradient in force is 0 eV/A.\n Threshold is -1 eV/A.\n largest force is 0, no " "movement is possible.\n it may converged, otherwise no movement of atom is allowed.\n"; std::string expected_std = " ETOT DIFF (eV) : 0\n LARGEST GRAD (eV/A) : 0\n"; @@ -170,8 +171,9 @@ TEST_F(IonsMoveBasicTest, CheckConvergedCase2) std::string expected_ofs = " old total energy (ry) = 0\n new total energy (ry) = 0\n " - " energy difference (ry) = 0\n largest gradient (ry/bohr) = 0.1\n\n Ion relaxation is " - "converged!\n\n Energy difference (Ry) = 0\n\n Largest gradient is (eV/A) = 2.57111\n"; + " energy difference (ry) = 0\n largest gradient (ry/bohr) = 0.1\n\n" + " Largest gradient in force is 2.57111 eV/A.\n Threshold is -1 eV/A.\n\n Ion relaxation is " + "converged!\n\n Energy difference (Ry) = 0\n"; std::string expected_std = " ETOT DIFF (eV) : 0\n LARGEST GRAD (eV/A) : 2.57111\n"; EXPECT_EQ(expected_ofs, ofs_output); @@ -208,7 +210,8 @@ TEST_F(IonsMoveBasicTest, CheckConvergedCase3) std::string expected_ofs = " old total energy (ry) = 0\n new total energy (ry) = 0\n " - " energy difference (ry) = 1\n largest gradient (ry/bohr) = 0.1\n\n Ion relaxation is not " + " energy difference (ry) = 1\n largest gradient (ry/bohr) = 0.1\n\n" + " Largest gradient in force is 2.57111 eV/A.\n Threshold is -1 eV/A.\n\n Ion relaxation is not " "converged yet (threshold is 25.7111)\n"; std::string expected_std = " ETOT DIFF (eV) : 13.6057\n LARGEST GRAD (eV/A) : 2.57111\n"; diff --git a/source/module_relax/relax_old/test/ions_move_cg_test.cpp b/source/module_relax/relax_old/test/ions_move_cg_test.cpp index ce184b410d9..40cb7048491 100644 --- a/source/module_relax/relax_old/test/ions_move_cg_test.cpp +++ b/source/module_relax/relax_old/test/ions_move_cg_test.cpp @@ -89,7 +89,8 @@ TEST_F(IonsMoveCGTest, TestStartConverged) GlobalV::ofs_running.close(); // Check output - std::string expected_output = " largest force is 0, no movement is possible.\n it may converged, otherwise no " + std::string expected_output = "\n Largest gradient in force is 0 eV/A.\n Threshold is -1 eV/A.\n" + " largest force is 0, no movement is possible.\n it may converged, otherwise no " "movement of atom is allowed.\n end of geometry optimization\n " " istep = 1\n update iteration = 5\n"; std::ifstream ifs("log"); @@ -122,7 +123,8 @@ TEST_F(IonsMoveCGTest, TestStartSd) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); @@ -159,7 +161,8 @@ TEST_F(IonsMoveCGTest, TestStartTrialGoto) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.0257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); @@ -195,7 +198,8 @@ TEST_F(IonsMoveCGTest, TestStartTrial) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); @@ -233,7 +237,8 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase1) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.0257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); @@ -270,7 +275,8 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase2) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); @@ -308,7 +314,8 @@ TEST_F(IonsMoveCGTest, TestStartNoTrial) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 0.0257111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); diff --git a/source/module_relax/relax_old/test/ions_move_sd_test.cpp b/source/module_relax/relax_old/test/ions_move_sd_test.cpp index 5292fac7048..51e232094ad 100644 --- a/source/module_relax/relax_old/test/ions_move_sd_test.cpp +++ b/source/module_relax/relax_old/test/ions_move_sd_test.cpp @@ -84,7 +84,8 @@ TEST_F(IonsMoveSDTest, TestStartConverged) GlobalV::ofs_running.close(); // Check output - std::string expected_output = " largest force is 0, no movement is possible.\n it may converged, otherwise no " + std::string expected_output = "\n Largest gradient in force is 0 eV/A.\n Threshold is -1 eV/A.\n" + " largest force is 0, no movement is possible.\n it may converged, otherwise no " "movement of atom is allowed.\n end of geometry optimization\n " " istep = 1\n update iteration = 5\n"; std::ifstream ifs("log"); @@ -122,7 +123,8 @@ TEST_F(IonsMoveSDTest, TestStartNotConverged) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Ion relaxation is not converged yet (threshold is 0.0257111)\n"; + std::string expected_output = "\n Largest gradient in force is 25.7111 eV/A.\n Threshold is -1 eV/A.\n\n" + " Ion relaxation is not converged yet (threshold is 0.0257111)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); diff --git a/source/module_relax/relax_old/test/lattice_change_basic_test.cpp b/source/module_relax/relax_old/test/lattice_change_basic_test.cpp index 60491197900..61578ae68f9 100644 --- a/source/module_relax/relax_old/test/lattice_change_basic_test.cpp +++ b/source/module_relax/relax_old/test/lattice_change_basic_test.cpp @@ -241,7 +241,7 @@ TEST_F(LatticeChangeBasicTest, CheckConvergedCase1) // Check the results std::ifstream ifs("log"); - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 10)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 10 kbar)\n"; std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); EXPECT_EQ(output, expected_output); EXPECT_EQ(Lattice_Change_Basic::update_iter, 0); @@ -316,7 +316,7 @@ TEST_F(LatticeChangeBasicTest, CheckConvergedCase3) // Check the results std::ifstream ifs("log"); - std::string expected_output = "\n Lattice relaxation is converged!\n\n Largest gradient is = 0.147105\n"; + std::string expected_output = "\n Lattice relaxation is converged!\n\n Largest gradient in stress is 0.147105 kbar.\n Threshold is 10 kbar.\n"; std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); EXPECT_EQ(output, expected_output); EXPECT_EQ(Lattice_Change_Basic::update_iter, 1); @@ -353,7 +353,7 @@ TEST_F(LatticeChangeBasicTest, CheckConvergedCase4) // Check the results std::ifstream ifs("log"); - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 10)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 10 kbar)\n"; std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); EXPECT_EQ(output, expected_output); EXPECT_EQ(Lattice_Change_Basic::update_iter, 0); @@ -428,7 +428,7 @@ TEST_F(LatticeChangeBasicTest, CheckConvergedCase6) // Check the results std::ifstream ifs("log"); - std::string expected_output = "\n Lattice relaxation is converged!\n\n Largest gradient is = 0.147105\n"; + std::string expected_output = "\n Lattice relaxation is converged!\n\n Largest gradient in stress is 0.147105 kbar.\n Threshold is 10 kbar.\n"; std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); EXPECT_EQ(output, expected_output); EXPECT_EQ(Lattice_Change_Basic::update_iter, 1); diff --git a/source/module_relax/relax_old/test/lattice_change_cg_test.cpp b/source/module_relax/relax_old/test/lattice_change_cg_test.cpp index 9eff776989f..1a11148dd12 100644 --- a/source/module_relax/relax_old/test/lattice_change_cg_test.cpp +++ b/source/module_relax/relax_old/test/lattice_change_cg_test.cpp @@ -120,7 +120,7 @@ TEST_F(LatticeChangeCGTest, TestStartSd) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -152,7 +152,7 @@ TEST_F(LatticeChangeCGTest, TestStartTrialGoto) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -182,7 +182,7 @@ TEST_F(LatticeChangeCGTest, TestStartTrial) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -213,7 +213,7 @@ TEST_F(LatticeChangeCGTest, TestStartNoTrialGotoCase1) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -247,7 +247,7 @@ TEST_F(LatticeChangeCGTest, TestStartNoTrialGotoCase2) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); @@ -280,7 +280,7 @@ TEST_F(LatticeChangeCGTest, TestStartNoTrial) GlobalV::ofs_running.close(); // Check output - std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5)\n"; + std::string expected_output = "\n Lattice relaxation is not converged yet (threshold is 0.5 kbar)\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); diff --git a/source/module_ri/ABFs_Construct-PCA.cpp b/source/module_ri/ABFs_Construct-PCA.cpp index 31b1731bce5..9463e75f4c2 100644 --- a/source/module_ri/ABFs_Construct-PCA.cpp +++ b/source/module_ri/ABFs_Construct-PCA.cpp @@ -96,8 +96,12 @@ namespace PCA } Matrix_Orbs21 m_abfslcaos_lcaos; - m_abfslcaos_lcaos.init( 1, orb, kmesh_times, 1 ); - m_abfslcaos_lcaos.init_radial( abfs, lcaos, lcaos ); + ORB_gaunt_table MGT; + int Lmax; + m_abfslcaos_lcaos.init( 1, orb, kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_abfslcaos_lcaos.init_radial( abfs, lcaos, lcaos, MGT ); std::map>> delta_R; for( std::size_t it=0; it!=abfs.size(); ++it ) { diff --git a/source/module_ri/CMakeLists.txt b/source/module_ri/CMakeLists.txt index 10dc30d9a09..e0e5f58aeb0 100644 --- a/source/module_ri/CMakeLists.txt +++ b/source/module_ri/CMakeLists.txt @@ -10,10 +10,13 @@ if (ENABLE_LIBRI) exx_lip.cpp Mix_DMk_2D.cpp Mix_Matrix.cpp + gaussian_abfs.cpp + singular_value.cpp ) if(ENABLE_LCAO) list(APPEND objects + Faddeeva.cc conv_coulomb_pot_k.cpp exx_abfs-abfs_index.cpp exx_abfs-construct_orbs.cpp diff --git a/source/module_ri/Exx_LRI.h b/source/module_ri/Exx_LRI.h index bb04a3f3582..d849094f36f 100644 --- a/source/module_ri/Exx_LRI.h +++ b/source/module_ri/Exx_LRI.h @@ -7,26 +7,26 @@ #define EXX_LRI_H #include "LRI_CV.h" -#include "module_hamilt_general/module_xc/exx_info.h" -#include "module_basis/module_ao/ORB_atomic_lm.h" +#include "ewald_Vq.h" #include "module_base/matrix.h" -#include +#include "module_basis/module_ao/ORB_atomic_lm.h" +#include "module_hamilt_general/module_xc/exx_info.h" -#include +#include #include -#include #include +#include #include #include "module_exx_symmetry/symmetry_rotation.h" - class Parallel_Orbitals; - - template - class RPA_LRI; +class Parallel_Orbitals; + +template +class RPA_LRI; - template - class Exx_LRI_Interface; +template +class Exx_LRI_Interface; namespace LR { @@ -49,7 +49,7 @@ class Exx_LRI using TatomR = std::array; // tmp public: - Exx_LRI(const Exx_Info::Exx_Info_RI& info_in) :info(info_in) {} + Exx_LRI(const Exx_Info::Exx_Info_RI& info_in, const Exx_Info::Exx_Info_Ewald& info_ewald_in) :info(info_in), info_ewald(info_ewald_in), evq(info, info_ewald) {} Exx_LRI operator=(const Exx_LRI&) = delete; Exx_LRI operator=(Exx_LRI&&); @@ -61,24 +61,28 @@ class Exx_LRI void cal_exx_stress(); std::vector> get_abfs_nchis() const; - std::vector< std::map>>> Hexxs; + std::vector>>> Hexxs; double Eexx; ModuleBase::matrix force_exx; ModuleBase::matrix stress_exx; -private: - const Exx_Info::Exx_Info_RI &info; - MPI_Comm mpi_comm; - const K_Vectors *p_kv = nullptr; - std::vector orb_cutoff_; - - std::vector>> lcaos; - std::vector>> abfs; - std::vector>> abfs_ccp; - - LRI_CV cv; - RI::Exx exx_lri; + private: + const Exx_Info::Exx_Info_RI& info; + const Exx_Info::Exx_Info_Ewald& info_ewald; + MPI_Comm mpi_comm; + const K_Vectors* p_kv = nullptr; + ORB_gaunt_table MGT; + std::vector orb_cutoff_; + + std::vector>> lcaos; + std::vector>> abfs; + std::vector>> abfs_ccp; + std::vector>> abfs_ccp_sr; + LRI_CV cv; + LRI_CV sr_cv; + RI::Exx exx_lri; + Ewald_Vq evq; void cal_exx_ions(const bool write_cv = false); void cal_exx_elec(const std::vector>>>& Ds, @@ -99,4 +103,4 @@ class Exx_LRI #include "Exx_LRI.hpp" -#endif +#endif diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index 356cead4049..344bc267e04 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -1,332 +1,453 @@ -//======================= -// AUTHOR : Peize Lin -#include "module_parameter/parameter.h" -// DATE : 2022-08-17 -//======================= - -#ifndef EXX_LRI_HPP -#define EXX_LRI_HPP - -#include "Exx_LRI.h" -#include "RI_2D_Comm.h" -#include "RI_Util.h" -#include "module_ri/exx_abfs-construct_orbs.h" -#include "module_ri/exx_abfs-io.h" -#include "module_ri/conv_coulomb_pot_k.h" -#include "module_base/tool_title.h" -#include "module_base/timer.h" -#include "module_ri/serialization_cereal.h" -#include "module_ri/Mix_DMk_2D.h" -#include "module_basis/module_ao/parallel_orbitals.h" - -#include -#include - -#include -#include - -template -void Exx_LRI::init(const MPI_Comm &mpi_comm_in, const K_Vectors &kv_in, const LCAO_Orbitals& orb) -{ - ModuleBase::TITLE("Exx_LRI","init"); - ModuleBase::timer::tick("Exx_LRI", "init"); - -// if(GlobalC::exx_info.info_global.separate_loop) -// { -// Hexx_para.mixing_mode = Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::No; -// Hexx_para.mixing_beta = 0; -// } -// else -// { -// if("plain"==GlobalC::CHR.mixing_mode) -// Hexx_para.mixing_mode = Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::Plain; -// else if("pulay"==GlobalC::CHR.mixing_mode) -// Hexx_para.mixing_mode = Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::Pulay; -// else -// throw std::invalid_argument("exx mixing error. exx_separate_loop==false, mixing_mode!=plain or pulay"); -// Hexx_para.mixing_beta = GlobalC::CHR.mixing_beta; -// } - - this->mpi_comm = mpi_comm_in; - this->p_kv = &kv_in; - this->orb_cutoff_ = orb.cutoffs(); - - this->lcaos = Exx_Abfs::Construct_Orbs::change_orbs( orb, this->info.kmesh_times ); - -// #ifdef __MPI -// Exx_Abfs::Util::bcast( this->info.files_abfs, 0, this->mpi_comm ); -// #endif - - const std::vector>> - abfs_same_atom = Exx_Abfs::Construct_Orbs::abfs_same_atom( orb, this->lcaos, this->info.kmesh_times, this->info.pca_threshold ); - if(this->info.files_abfs.empty()) { - this->abfs = abfs_same_atom; - } else { - this->abfs = Exx_Abfs::IO::construct_abfs( abfs_same_atom, orb, this->info.files_abfs, this->info.kmesh_times ); -} - Exx_Abfs::Construct_Orbs::print_orbs_size(this->abfs, GlobalV::ofs_running); - - auto get_ccp_parameter = [this]() -> std::map - { - switch(this->info.ccp_type) - { - case Conv_Coulomb_Pot_K::Ccp_Type::Ccp: - return {}; - case Conv_Coulomb_Pot_K::Ccp_Type::Hf: - { - // 4/3 * pi * Rcut^3 = V_{supercell} = V_{unitcell} * Nk - const int nspin0 = (PARAM.inp.nspin==2) ? 2 : 1; - const double hf_Rcut = std::pow(0.75 * this->p_kv->get_nkstot_full()/nspin0 * GlobalC::ucell.omega / (ModuleBase::PI), 1.0/3.0); - return {{"hf_Rcut", hf_Rcut}}; - } - case Conv_Coulomb_Pot_K::Ccp_Type::Hse: - return {{"hse_omega", this->info.hse_omega}}; - default: - throw std::domain_error(std::string(__FILE__)+" line "+std::to_string(__LINE__)); break; - } - }; - this->abfs_ccp = Conv_Coulomb_Pot_K::cal_orbs_ccp(this->abfs, this->info.ccp_type, get_ccp_parameter(), this->info.ccp_rmesh_times); - - - for( size_t T=0; T!=this->abfs.size(); ++T ) { - GlobalC::exx_info.info_ri.abfs_Lmax = std::max( GlobalC::exx_info.info_ri.abfs_Lmax, static_cast(this->abfs[T].size())-1 ); -} - - this->cv.set_orbitals( - orb, - this->lcaos, this->abfs, this->abfs_ccp, - this->info.kmesh_times, this->info.ccp_rmesh_times ); - - ModuleBase::timer::tick("Exx_LRI", "init"); -} - -template -void Exx_LRI::cal_exx_ions(const bool write_cv) -{ - ModuleBase::TITLE("Exx_LRI","cal_exx_ions"); - ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); - -// init_radial_table_ions( cal_atom_centres_core(atom_pairs_core_origin), atom_pairs_core_origin ); - -// this->m_abfsabfs.init_radial_table(Rradial); -// this->m_abfslcaos_lcaos.init_radial_table(Rradial); - - std::vector atoms(GlobalC::ucell.nat); - for(int iat=0; iat atoms_pos; - for(int iat=0; iat latvec - = {RI_Util::Vector3_to_array3(GlobalC::ucell.a1), - RI_Util::Vector3_to_array3(GlobalC::ucell.a2), - RI_Util::Vector3_to_array3(GlobalC::ucell.a3)}; - const std::array period = {this->p_kv->nmp[0], this->p_kv->nmp[1], this->p_kv->nmp[2]}; - - this->exx_lri.set_parallel(this->mpi_comm, atoms_pos, latvec, period); - - // std::max(3) for gamma_only, list_A2 should contain cell {-1,0,1}. In the future distribute will be neighbour. - const std::array period_Vs = LRI_CV_Tools::cal_latvec_range(1+this->info.ccp_rmesh_times, orb_cutoff_); - const std::pair, std::vector>>>> - list_As_Vs = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, atoms, period_Vs, 2, false); - - std::map>> - Vs = this->cv.cal_Vs( - list_As_Vs.first, list_As_Vs.second[0], - {{"writable_Vws",true}}); - this->cv.Vws = LRI_CV_Tools::get_CVws(Vs); - this->exx_lri.set_Vs(std::move(Vs), this->info.V_threshold); - - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) - { - std::array>>,3> - dVs = this->cv.cal_dVs( - list_As_Vs.first, list_As_Vs.second[0], - {{"writable_dVws",true}}); - this->cv.dVws = LRI_CV_Tools::get_dCVws(dVs); - this->exx_lri.set_dVs(std::move(dVs), this->info.V_grad_threshold); - if(PARAM.inp.cal_stress) - { - std::array>>,3>,3> dVRs = LRI_CV_Tools::cal_dMRs(dVs); - this->exx_lri.set_dVRs(std::move(dVRs), this->info.V_grad_R_threshold); - } - } - - const std::array period_Cs = LRI_CV_Tools::cal_latvec_range(2, orb_cutoff_); - const std::pair, std::vector>>>> - list_As_Cs = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, atoms, period_Cs, 2, false); - - std::pair>>, std::array>>,3>> - Cs_dCs = this->cv.cal_Cs_dCs( - list_As_Cs.first, list_As_Cs.second[0], - {{"cal_dC",PARAM.inp.cal_force||PARAM.inp.cal_stress}, - {"writable_Cws",true}, {"writable_dCws",true}, {"writable_Vws",false}, {"writable_dVws",false}}); - std::map>> &Cs = std::get<0>(Cs_dCs); - this->cv.Cws = LRI_CV_Tools::get_CVws(Cs); - if (write_cv && GlobalV::MY_RANK == 0) { LRI_CV_Tools::write_Cs_ao(Cs, PARAM.globalv.global_out_dir + "Cs"); } - this->exx_lri.set_Cs(std::move(Cs), this->info.C_threshold); - - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) - { - std::array>>,3> &dCs = std::get<1>(Cs_dCs); - this->cv.dCws = LRI_CV_Tools::get_dCVws(dCs); - this->exx_lri.set_dCs(std::move(dCs), this->info.C_grad_threshold); - if(PARAM.inp.cal_stress) - { - std::array>>,3>,3> dCRs = LRI_CV_Tools::cal_dMRs(dCs); - this->exx_lri.set_dCRs(std::move(dCRs), this->info.C_grad_R_threshold); - } - } - ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); -} - -template -void Exx_LRI::cal_exx_elec(const std::vector>>>& Ds, - const Parallel_Orbitals& pv, - const ModuleSymmetry::Symmetry_rotation* p_symrot) -{ - ModuleBase::TITLE("Exx_LRI","cal_exx_elec"); - ModuleBase::timer::tick("Exx_LRI", "cal_exx_elec"); - - const std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(pv); - - this->Hexxs.resize(PARAM.inp.nspin); - this->Eexx = 0; - (p_symrot) ? this->exx_lri.set_symmetry(true, p_symrot->get_irreducible_sector()) : this->exx_lri.set_symmetry(false, {}); - for(int is=0; isexx_lri.set_Ds(Ds[is], this->info.dm_threshold, suffix); - this->exx_lri.cal_Hs({ "","",suffix }); - - if (!p_symrot) - { - this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( - this->mpi_comm, std::move(this->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); - } - else - { - // reduce but not repeat - auto Hs_a2D = this->exx_lri.post_2D.set_tensors_map2(this->exx_lri.Hs); - // rotate locally without repeat - Hs_a2D = p_symrot->restore_HR(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', Hs_a2D); - // cal energy using full Hs without repeat - this->exx_lri.energy = this->exx_lri.post_2D.cal_energy( - this->exx_lri.post_2D.saves["Ds_" + suffix], - this->exx_lri.post_2D.set_tensors_map2(Hs_a2D)); - // get repeated full Hs for abacus - this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( - this->mpi_comm, std::move(Hs_a2D), std::get<0>(judge[is]), std::get<1>(judge[is])); - } - this->Eexx += std::real(this->exx_lri.energy); - post_process_Hexx(this->Hexxs[is]); - } - this->Eexx = post_process_Eexx(this->Eexx); - this->exx_lri.set_symmetry(false, {}); - ModuleBase::timer::tick("Exx_LRI", "cal_exx_elec"); -} - -template -void Exx_LRI::post_process_Hexx( std::map>> &Hexxs_io ) const -{ - ModuleBase::TITLE("Exx_LRI","post_process_Hexx"); - constexpr Tdata frac = -1 * 2; // why? Hartree to Ry? - const std::function&)> - multiply_frac = [&frac](RI::Tensor &t) - { t = t*frac; }; - RI::Map_Operator::for_each( Hexxs_io, multiply_frac ); -} - -template -double Exx_LRI::post_process_Eexx(const double& Eexx_in) const -{ - ModuleBase::TITLE("Exx_LRI","post_process_Eexx"); - const double SPIN_multiple = std::map{ {1,2}, {2,1}, {4,1} }.at(PARAM.inp.nspin); // why? - const double frac = -SPIN_multiple; - return frac * Eexx_in; -} - -/* -post_process_old -{ - // D - const std::map SPIN_multiple = {{1,0.5}, {2,1}, {4,1}}; // ??? - DR *= SPIN_multiple.at(NSPIN); - - // H - HR *= -2; - - // E - const std::map SPIN_multiple = {{1,2}, {2,1}, {4,1}}; // ??? - energy *= SPIN_multiple.at(PARAM.inp.nspin); // ? - energy /= 2; // /2 for Ry -} -*/ - -template -void Exx_LRI::cal_exx_force() -{ - ModuleBase::TITLE("Exx_LRI","cal_exx_force"); - ModuleBase::timer::tick("Exx_LRI", "cal_exx_force"); - - this->force_exx.create(GlobalC::ucell.nat, Ndim); - for(int is=0; isexx_lri.cal_force({"","",std::to_string(is),"",""}); - for(std::size_t idim=0; idimexx_lri.force[idim]) { - this->force_exx(force_item.first, idim) += std::real(force_item.second); -} -} - } - - const double SPIN_multiple = std::map{{1,2}, {2,1}, {4,1}}.at(PARAM.inp.nspin); // why? - const double frac = -2 * SPIN_multiple; // why? - this->force_exx *= frac; - ModuleBase::timer::tick("Exx_LRI", "cal_exx_force"); -} - - -template -void Exx_LRI::cal_exx_stress() -{ - ModuleBase::TITLE("Exx_LRI","cal_exx_stress"); - ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); - - this->stress_exx.create(Ndim, Ndim); - for(int is=0; isexx_lri.cal_stress({"","",std::to_string(is),"",""}); - for(std::size_t idim0=0; idim0stress_exx(idim0,idim1) += std::real(this->exx_lri.stress(idim0,idim1)); -} -} - } - - const double SPIN_multiple = std::map{{1,2}, {2,1}, {4,1}}.at(PARAM.inp.nspin); // why? - const double frac = 2 * SPIN_multiple / GlobalC::ucell.omega * GlobalC::ucell.lat0; // why? - this->stress_exx *= frac; - - ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); -} - -template -std::vector> Exx_LRI::get_abfs_nchis() const -{ - std::vector> abfs_nchis; - for (const auto& abfs_T : this->abfs) - { - std::vector abfs_nchi_T; - for (const auto& abfs_L : abfs_T) { - abfs_nchi_T.push_back(abfs_L.size()); -} - abfs_nchis.push_back(abfs_nchi_T); - } - return abfs_nchis; -} - -#endif +//======================= +// AUTHOR : Peize Lin +#include "module_parameter/parameter.h" +// DATE : 2022-08-17 +//======================= + +#ifndef EXX_LRI_HPP +#define EXX_LRI_HPP + +#include "Exx_LRI.h" +#include "RI_2D_Comm.h" +#include "RI_Util.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "module_basis/module_ao/parallel_orbitals.h" +#include "module_ri/Mix_DMk_2D.h" +#include "module_ri/conv_coulomb_pot_k.h" +#include "module_ri/exx_abfs-construct_orbs.h" +#include "module_ri/exx_abfs-io.h" +#include "module_ri/serialization_cereal.h" + +#include +#include +#include +#include + +template +void Exx_LRI::init(const MPI_Comm &mpi_comm_in, const K_Vectors &kv_in, const LCAO_Orbitals& orb) +{ + ModuleBase::TITLE("Exx_LRI","init"); + ModuleBase::timer::tick("Exx_LRI", "init"); + + // if(GlobalC::exx_info.info_global.separate_loop) + // { + // Hexx_para.mixing_mode = + // Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::No; + // Hexx_para.mixing_beta = 0; + // } + // else + // { + // if("plain"==GlobalC::CHR.mixing_mode) + // Hexx_para.mixing_mode = + // Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::Plain; else + // if("pulay"==GlobalC::CHR.mixing_mode) Hexx_para.mixing_mode = + // Exx_Abfs::Parallel::Communicate::Hexx::Mixing_Mode::Pulay; else + // throw std::invalid_argument("exx mixing error. exx_separate_loop==false, + // mixing_mode!=plain or pulay"); Hexx_para.mixing_beta = + // GlobalC::CHR.mixing_beta; + // } + + this->mpi_comm = mpi_comm_in; + this->p_kv = &kv_in; + this->orb_cutoff_ = orb.cutoffs(); + + this->lcaos = Exx_Abfs::Construct_Orbs::change_orbs( orb, this->info.kmesh_times ); + + // #ifdef __MPI + // Exx_Abfs::Util::bcast( this->info.files_abfs, 0, this->mpi_comm ); + // #endif + + const std::vector>> + abfs_same_atom = Exx_Abfs::Construct_Orbs::abfs_same_atom( orb, this->lcaos, this->info.kmesh_times, this->info.pca_threshold ); + if(this->info.files_abfs.empty()) { + this->abfs = abfs_same_atom; + } else { + this->abfs = Exx_Abfs::IO::construct_abfs( abfs_same_atom, orb, this->info.files_abfs, this->info.kmesh_times ); +} + Exx_Abfs::Construct_Orbs::print_orbs_size(this->abfs, GlobalV::ofs_running); + + auto get_ccp_parameter = [this]() -> std::map { + switch (this->info.ccp_type) { + case Conv_Coulomb_Pot_K::Ccp_Type::Ccp: + return {}; + case Conv_Coulomb_Pot_K::Ccp_Type::Hf: { + // 4/3 * pi * Rcut^3 = V_{supercell} = V_{unitcell} * Nk + const int nspin0 = (PARAM.inp.nspin == 2) ? 2 : 1; + const double hf_Rcut + = std::pow(0.75 * this->p_kv->get_nkstot_full() / nspin0 + * GlobalC::ucell.omega / (ModuleBase::PI), + 1.0 / 3.0); + return {{"hf_Rcut", hf_Rcut}}; + } + case Conv_Coulomb_Pot_K::Ccp_Type::Hse: + return {{"hse_omega", this->info.hse_omega}}; + case Conv_Coulomb_Pot_K::Ccp_Type::Cam: { + // 4/3 * pi * Rcut^3 = V_{supercell} = V_{unitcell} * Nk + const int nspin0 = (PARAM.inp.nspin == 2) ? 2 : 1; + const double hf_Rcut + = std::pow(0.75 * this->p_kv->get_nkstot_full() / nspin0 + * GlobalC::ucell.omega / (ModuleBase::PI), + 1.0 / 3.0); + return {{"hse_omega", this->info.hse_omega}, + {"cam_alpha", this->info.cam_alpha}, + {"cam_beta", this->info.cam_beta}, + {"hf_Rcut", hf_Rcut}}; + } + case Conv_Coulomb_Pot_K::Ccp_Type::Ccp_Cam: + return {{"hse_omega", this->info.hse_omega}, + {"cam_alpha", this->info.cam_alpha}, + {"cam_beta", this->info.cam_beta}}; + default: + throw std::domain_error(std::string(__FILE__) + " line " + + std::to_string(__LINE__)); + break; + } + }; + this->abfs_ccp + = Conv_Coulomb_Pot_K::cal_orbs_ccp(this->abfs, + this->info.ccp_type, + get_ccp_parameter(), + this->info.ccp_rmesh_times); + + for (size_t T = 0; T != this->abfs.size(); ++T) + GlobalC::exx_info.info_ri.abfs_Lmax + = std::max(GlobalC::exx_info.info_ri.abfs_Lmax, + static_cast(this->abfs[T].size()) - 1); + + this->cv.set_orbitals(orb, + this->lcaos, + this->abfs, + this->abfs_ccp, + this->info.kmesh_times, + this->MGT, + true, + true); + + if (this->info_ewald.use_ewald) { + if (this->info.cam_beta) { + this->abfs_ccp_sr = Conv_Coulomb_Pot_K::cal_orbs_ccp( + this->abfs, + Conv_Coulomb_Pot_K::Ccp_Type::Hse, + {{"hse_omega", this->info.hse_omega}}, + this->info.ccp_rmesh_times); + this->sr_cv.set_orbitals(orb, + this->lcaos, + this->abfs, + this->abfs_ccp_sr, + this->info.kmesh_times, + this->MGT, + false, + false); + } + this->evq.init(orb, + this->mpi_comm, + this->p_kv, + this->lcaos, + this->abfs, + get_ccp_parameter(), + this->MGT); + } + + ModuleBase::timer::tick("Exx_LRI", "init"); +} + +template +void Exx_LRI::cal_exx_ions(const bool write_cv) +{ + ModuleBase::TITLE("Exx_LRI","cal_exx_ions"); + ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); + + // init_radial_table_ions( cal_atom_centres_core(atom_pairs_core_origin), + // atom_pairs_core_origin ); + + // this->m_abfsabfs.init_radial_table(Rradial); + // this->m_abfslcaos_lcaos.init_radial_table(Rradial); + + std::vector atoms(GlobalC::ucell.nat); + for (int iat = 0; iat < GlobalC::ucell.nat; ++iat) + atoms[iat] = iat; + std::map atoms_pos; + for (int iat = 0; iat < GlobalC::ucell.nat; ++iat) + atoms_pos[iat] = RI_Util::Vector3_to_array3( + GlobalC::ucell.atoms[GlobalC::ucell.iat2it[iat]] + .tau[GlobalC::ucell.iat2ia[iat]]); + const std::array latvec + = {RI_Util::Vector3_to_array3(GlobalC::ucell.a1), + RI_Util::Vector3_to_array3(GlobalC::ucell.a2), + RI_Util::Vector3_to_array3(GlobalC::ucell.a3)}; + const std::array period + = {this->p_kv->nmp[0], this->p_kv->nmp[1], this->p_kv->nmp[2]}; + + this->exx_lri.set_parallel(this->mpi_comm, atoms_pos, latvec, period); + + // std::max(3) for gamma_only, list_A2 should contain cell {-1,0,1}. In the future distribute will be neighbour. + const std::array period_Vs = LRI_CV_Tools::cal_latvec_range(1+this->info.ccp_rmesh_times, orb_cutoff_); + const std::pair, std::vector>>>> + list_As_Vs = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, atoms, period_Vs, 2, false); + + std::map>> Vs + = this->cv.cal_Vs(list_As_Vs.first, + list_As_Vs.second[0], + {{"writable_Vws", true}}); + + this->cv.Vws = LRI_CV_Tools::get_CVws(Vs); + if (this->info_ewald.use_ewald) { + std::map>> Vs_sr; + if (this->info.cam_beta) { + Vs_sr = this->sr_cv.cal_Vs(list_As_Vs.first, + list_As_Vs.second[0], + {{"writable_Vws", true}}); + Vs_sr = LRI_CV_Tools::mul2( + RI::Global_Func::convert(-this->info.cam_beta), + Vs_sr); + this->sr_cv.Vws = LRI_CV_Tools::get_CVws(Vs_sr); + } + this->evq.init_ions(period_Vs); + double chi = this->evq.get_singular_chi(this->info_ewald.fq_type, + this->info_ewald.ewald_qdiv); + std::map>> Vs_full + = this->evq.cal_Vs(chi, Vs); + Vs_full = LRI_CV_Tools::mul2( + RI::Global_Func::convert(this->info.cam_alpha), + Vs_full); + Vs = this->info.cam_beta ? LRI_CV_Tools::minus(Vs_full, Vs_sr) + : Vs_full; + } + + if (write_cv && GlobalV::MY_RANK == 0) { LRI_CV_Tools::write_Vs_abf(Vs, PARAM.globalv.global_out_dir + "Vs"); } + this->exx_lri.set_Vs(std::move(Vs), this->info.V_threshold); + + if (PARAM.inp.cal_force || PARAM.inp.cal_stress) { + std::map, Ndim>>> dVs + = this->cv.cal_dVs(list_As_Vs.first, + list_As_Vs.second[0], + {{"writable_dVws", true}}); + this->cv.dVws = LRI_CV_Tools::get_dCVws(dVs); + + if (this->info_ewald.use_ewald) { + std::map, Ndim>>> + dVs_sr; + if (this->info.cam_beta) { + dVs_sr = this->sr_cv.cal_dVs(list_As_Vs.first, + list_As_Vs.second[0], + {{"writable_dVws", true}}); + dVs_sr = LRI_CV_Tools::mul2( + RI::Global_Func::convert(-this->info.cam_beta), + dVs_sr); + this->sr_cv.dVws = LRI_CV_Tools::get_dCVws(dVs_sr); + } + // const double chi = 1.0 / this->lambda; + // dVs = this->evq.cal_dVs(chi, dVs); + std::map, Ndim>>> + dVs_full = LRI_CV_Tools::mul2( + RI::Global_Func::convert(this->info.cam_alpha), + dVs); + dVs = this->info.cam_beta ? LRI_CV_Tools::minus(dVs_full, dVs_sr) + : dVs_full; + } + + std::array>>, Ndim> + dVs_order = LRI_CV_Tools::change_order(std::move(dVs)); + + this->exx_lri.set_dVs(std::move(dVs_order), + this->info.V_grad_threshold); + if(PARAM.inp.cal_stress) + { + std::array>>,3>,3> dVRs = LRI_CV_Tools::cal_dMRs(dVs_order); + this->exx_lri.set_dVRs(std::move(dVRs), this->info.V_grad_R_threshold); + } + } + + const std::array period_Cs + = LRI_CV_Tools::cal_latvec_range(2, orb_cutoff_); + const std::pair< + std::vector, + std::vector>>>> + list_As_Cs + = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, + atoms, + period_Cs, + 2, + false); + + std::pair>>, + std::map, 3>>>> + Cs_dCs = this->cv.cal_Cs_dCs( + list_As_Cs.first, + list_As_Cs.second[0], + {{"cal_dC", PARAM.inp.cal_force||PARAM.inp.cal_stress}, + {"writable_Cws", true}, + {"writable_dCws", true}, + {"writable_Vws", false}, + {"writable_dVws", false}}); + std::map>>& Cs = std::get<0>(Cs_dCs); + this->cv.Cws = LRI_CV_Tools::get_CVws(Cs); + if (write_cv && GlobalV::MY_RANK == 0) { LRI_CV_Tools::write_Cs_ao(Cs, PARAM.globalv.global_out_dir + "Cs"); } + this->exx_lri.set_Cs(std::move(Cs), this->info.C_threshold); + + if (PARAM.inp.cal_force || PARAM.inp.cal_stress) { + std::map, 3>>>& dCs + = std::get<1>(Cs_dCs); + this->cv.dCws = LRI_CV_Tools::get_dCVws(dCs); + std::array>>, Ndim> + dCs_order = LRI_CV_Tools::change_order(std::move(dCs)); + this->exx_lri.set_dCs(std::move(dCs_order), + this->info.C_grad_threshold); + if(PARAM.inp.cal_stress) + { + std::array>>,3>,3> dCRs = LRI_CV_Tools::cal_dMRs(dCs_order); + this->exx_lri.set_dCRs(std::move(dCRs), this->info.C_grad_R_threshold); + } + } + ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); +} + +template +void Exx_LRI::cal_exx_elec(const std::vector>>>& Ds, + const Parallel_Orbitals& pv, + const ModuleSymmetry::Symmetry_rotation* p_symrot) +{ + ModuleBase::TITLE("Exx_LRI","cal_exx_elec"); + ModuleBase::timer::tick("Exx_LRI", "cal_exx_elec"); + + const std::vector, std::set>> judge + = RI_2D_Comm::get_2D_judge(pv); + + this->Hexxs.resize(PARAM.inp.nspin); + this->Eexx = 0; + (p_symrot) ? this->exx_lri.set_symmetry(true, p_symrot->get_irreducible_sector()) : this->exx_lri.set_symmetry(false, {}); + for(int is=0; isexx_lri.set_Ds(Ds[is], this->info.dm_threshold, suffix); + this->exx_lri.cal_Hs({ "","",suffix }); + + if (!p_symrot) + { + this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( + this->mpi_comm, std::move(this->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); + } + else + { + // reduce but not repeat + auto Hs_a2D = this->exx_lri.post_2D.set_tensors_map2(this->exx_lri.Hs); + // rotate locally without repeat + Hs_a2D = p_symrot->restore_HR(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', Hs_a2D); + // cal energy using full Hs without repeat + this->exx_lri.energy = this->exx_lri.post_2D.cal_energy( + this->exx_lri.post_2D.saves["Ds_" + suffix], + this->exx_lri.post_2D.set_tensors_map2(Hs_a2D)); + // get repeated full Hs for abacus + this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( + this->mpi_comm, std::move(Hs_a2D), std::get<0>(judge[is]), std::get<1>(judge[is])); + } + this->Eexx += std::real(this->exx_lri.energy); + post_process_Hexx(this->Hexxs[is]); + } + this->Eexx = post_process_Eexx(this->Eexx); + this->exx_lri.set_symmetry(false, {}); + ModuleBase::timer::tick("Exx_LRI", "cal_exx_elec"); +} + +template +void Exx_LRI::post_process_Hexx( + std::map>>& Hexxs_io) const { + ModuleBase::TITLE("Exx_LRI", "post_process_Hexx"); + constexpr Tdata frac = -1 * 2; // why? Hartree to Ry? + const std::function&)> multiply_frac + = [&frac](RI::Tensor& t) { t = t * frac; }; + RI::Map_Operator::for_each(Hexxs_io, multiply_frac); +} + +template +double Exx_LRI::post_process_Eexx(const double& Eexx_in) const +{ + ModuleBase::TITLE("Exx_LRI","post_process_Eexx"); + const double SPIN_multiple = std::map{ {1,2}, {2,1}, {4,1} }.at(PARAM.inp.nspin); // why? + const double frac = -SPIN_multiple; + return frac * Eexx_in; +} + +/* +post_process_old +{ + // D + const std::map SPIN_multiple = {{1,0.5}, {2,1}, {4,1}}; +// ??? DR *= SPIN_multiple.at(NSPIN); + + // H + HR *= -2; + + // E + const std::map SPIN_multiple = {{1,2}, {2,1}, {4,1}}; // ??? + energy *= SPIN_multiple.at(PARAM.inp.nspin); // ? + energy /= 2; // /2 for Ry +} +*/ + +template +void Exx_LRI::cal_exx_force() +{ + ModuleBase::TITLE("Exx_LRI","cal_exx_force"); + ModuleBase::timer::tick("Exx_LRI", "cal_exx_force"); + + this->force_exx.create(GlobalC::ucell.nat, Ndim); + for(int is=0; isexx_lri.cal_force({"","",std::to_string(is),"",""}); + for(std::size_t idim=0; idimexx_lri.force[idim]) { + this->force_exx(force_item.first, idim) += std::real(force_item.second); +} +} + } + + const double SPIN_multiple = std::map{{1,2}, {2,1}, {4,1}}.at(PARAM.inp.nspin); // why? + const double frac = -2 * SPIN_multiple; // why? + this->force_exx *= frac; + ModuleBase::timer::tick("Exx_LRI", "cal_exx_force"); +} + + +template +void Exx_LRI::cal_exx_stress() +{ + ModuleBase::TITLE("Exx_LRI","cal_exx_stress"); + ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); + + this->stress_exx.create(Ndim, Ndim); + for(int is=0; isexx_lri.cal_stress({"","",std::to_string(is),"",""}); + for(std::size_t idim0=0; idim0stress_exx(idim0,idim1) += std::real(this->exx_lri.stress(idim0,idim1)); +} +} + } + + const double SPIN_multiple = std::map{{1,2}, {2,1}, {4,1}}.at(PARAM.inp.nspin); // why? + const double frac = 2 * SPIN_multiple / GlobalC::ucell.omega * GlobalC::ucell.lat0; // why? + this->stress_exx *= frac; + + ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); +} + +template +std::vector> Exx_LRI::get_abfs_nchis() const +{ + std::vector> abfs_nchis; + for (const auto& abfs_T : this->abfs) + { + std::vector abfs_nchi_T; + for (const auto& abfs_L : abfs_T) { + abfs_nchi_T.push_back(abfs_L.size()); +} + abfs_nchis.push_back(abfs_nchi_T); + } + return abfs_nchis; +} + +#endif diff --git a/source/module_ri/Exx_LRI_interface.h b/source/module_ri/Exx_LRI_interface.h index d1b64c56df5..b3d358a9252 100644 --- a/source/module_ri/Exx_LRI_interface.h +++ b/source/module_ri/Exx_LRI_interface.h @@ -48,16 +48,25 @@ class Exx_LRI_Interface double& get_Eexx() const { return this->exx_ptr->Eexx; } // Processes in ESolver_KS_LCAO + /// @brief in before_all_runners: set symmetry according to irreducible k-points + /// since k-points are not reduced again after the variation of the cell and exx-symmetry must be consistent with k-points. + /// In the future, we will reduce k-points again during cell-relax, then this setting can be moved to `exx_beforescf`. + void exx_before_all_runners(const K_Vectors& kv, const UnitCell& ucell, const Parallel_2D& pv); + /// @brief in beforescf: set xc type, opt_orb, do DM mixing - void exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const Parallel_2D& pv, const LCAO_Orbitals& orb); + void exx_beforescf(const int istep, const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const LCAO_Orbitals& orb); /// @brief in eachiterinit: do DM mixing and calculate Hexx when entering 2nd SCF - void exx_eachiterinit(const elecstate::DensityMatrix& dm/**< double should be Tdata if complex-PBE-DM is supported*/, + void exx_eachiterinit(const int istep, const elecstate::DensityMatrix& dm/**< double should be Tdata if complex-PBE-DM is supported*/, const K_Vectors& kv, const int& iter); /// @brief in hamilt2density: calculate Hexx and Eexx void exx_hamilt2density(elecstate::ElecState& elec, const Parallel_Orbitals& pv, const int iter); + /// @brief in iter_finish: write Hexx, do something according to whether SCF is converged + void exx_iter_finish(const K_Vectors& kv, const UnitCell& ucell, + hamilt::Hamilt& hamilt, elecstate::ElecState& elec, Charge_Mixing& chgmix, + const double& scf_ene_thr, int& iter, const int istep, bool& conv_esolver); /// @brief: in do_after_converge: add exx operators; do DM mixing if seperate loop bool exx_after_converge( hamilt::Hamilt& hamilt, @@ -65,10 +74,12 @@ class Exx_LRI_Interface const K_Vectors& kv, const int& nspin, int& iter, + const int& istep, const double& etot, const double& scf_ene_thr); int two_level_step = 0; double etot_last_outer_loop = 0.0; + elecstate::DensityMatrix* dm_last_step; private: std::shared_ptr> exx_ptr; Mix_DMk_2D mix_DMk_2D; diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index 8fa6d8b84a8..a86c65771a7 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -13,6 +13,7 @@ #include #include "module_io/csr_reader.h" #include "module_io/write_HS_sparse.h" +#include "module_elecstate/elecstate_lcao.h" template void Exx_LRI_Interface::write_Hexxs_cereal(const std::string& file_name) const @@ -37,15 +38,36 @@ void Exx_LRI_Interface::read_Hexxs_cereal(const std::string& file_name } template -void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const Parallel_2D& pv, const LCAO_Orbitals& orb) +void Exx_LRI_Interface::exx_before_all_runners(const K_Vectors& kv, const UnitCell& ucell, const Parallel_2D& pv) +{ + // initialize the rotation matrix in AO representation + this->exx_spacegroup_symmetry = (PARAM.inp.nspin < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); + if (this->exx_spacegroup_symmetry) + { + const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); + this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, + RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); + // this->symrot_.set_Cs_rotation(this->exx_ptr->get_abfs_nchis()); + this->symrot_.cal_Ms(kv, ucell, pv); + } +} + +template +void Exx_LRI_Interface::exx_beforescf(const int istep, const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const LCAO_Orbitals& orb) { #ifdef __MPI if (GlobalC::exx_info.info_global.cal_exx) { if (GlobalC::restart.info_load.load_H_finish && !GlobalC::restart.info_load.restart_exx) { XC_Functional::set_xc_type(GlobalC::ucell.atoms[0].ncpp.xc_func); - } else + } + else if (istep > 0) { XC_Functional::set_xc_type(GlobalC::ucell.atoms[0].ncpp.xc_func); + } + else { - if (ucell.atoms[0].ncpp.xc_func == "HF" || ucell.atoms[0].ncpp.xc_func == "PBE0" || ucell.atoms[0].ncpp.xc_func == "HSE") + if (ucell.atoms[0].ncpp.xc_func == "HF" || ucell.atoms[0].ncpp.xc_func == "PBE0" || ucell.atoms[0].ncpp.xc_func == "HSE" || + ucell.atoms[0].ncpp.xc_func == "LC_PBE" || ucell.atoms[0].ncpp.xc_func == "LC_WPBE" || + ucell.atoms[0].ncpp.xc_func == "LRC_WPBEH" || ucell.atoms[0].ncpp.xc_func == "CAM_PBEH" + ) { XC_Functional::set_xc_type("pbe"); } @@ -54,17 +76,6 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg XC_Functional::set_xc_type("scan"); } } - // initialize the rotation matrix in AO representation - this->exx_spacegroup_symmetry = (PARAM.inp.nspin < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); - if (this->exx_spacegroup_symmetry) - { - const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); - this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, - RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); - // this->symrot_.set_Cs_rotation(this->exx_ptr->get_abfs_nchis()); - this->symrot_.cal_Ms(kv, ucell, pv); - } - this->exx_ptr->cal_exx_ions(PARAM.inp.out_ri_cv); } @@ -96,21 +107,28 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg } template -void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatrix& dm, const K_Vectors& kv, const int& iter) +void Exx_LRI_Interface::exx_eachiterinit(const int istep, const elecstate::DensityMatrix& dm, const K_Vectors& kv, const int& iter) { if (GlobalC::exx_info.info_global.cal_exx) { - if (!GlobalC::exx_info.info_global.separate_loop && this->two_level_step) + if (!GlobalC::exx_info.info_global.separate_loop && (this->two_level_step || istep > 0)) { const bool flag_restart = (iter == 1) ? true : false; - if (this->exx_spacegroup_symmetry) { this->mix_DMk_2D.mix(symrot_.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), flag_restart); } - else { this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); } - const std::vector>,RI::Tensor>>> - Ds = PARAM.globalv.gamma_only_local - ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), PARAM.inp.nspin) - : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), PARAM.inp.nspin, this->exx_spacegroup_symmetry); - if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.exx_symmetry_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } - else { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); } + auto cal = [this, &kv, &flag_restart](const elecstate::DensityMatrix& dm_in) + { + if (this->exx_spacegroup_symmetry) { this->mix_DMk_2D.mix(symrot_.restore_dm(kv,dm_in.get_DMK_vector(), *dm_in.get_paraV_pointer()), flag_restart); } + else { this->mix_DMk_2D.mix(dm_in.get_DMK_vector(), flag_restart); } + const std::vector>,RI::Tensor>>> + Ds = PARAM.globalv.gamma_only_local + ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm_in.get_paraV_pointer(), PARAM.inp.nspin) + : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm_in.get_paraV_pointer(), PARAM.inp.nspin, this->exx_spacegroup_symmetry); + if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.exx_symmetry_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm_in.get_paraV_pointer(), &this->symrot_); } + else { this->exx_ptr->cal_exx_elec(Ds, *dm_in.get_paraV_pointer()); } + }; + if(istep > 0 && flag_restart) + cal(*dm_last_step); + else + cal(dm); } } } @@ -121,6 +139,10 @@ void Exx_LRI_Interface::exx_hamilt2density(elecstate::ElecState& elec, // Peize Lin add 2020.04.04 if (XC_Functional::get_func_type() == 4 || XC_Functional::get_func_type() == 5) { + const double coeff = (GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Cam + || GlobalC::exx_info.info_global.ccp_type == Conv_Coulomb_Pot_K::Ccp_Type::Ccp) + ? 1.0 + : GlobalC::exx_info.info_global.hybrid_alpha; // add exx // Peize Lin add 2016-12-03 if (GlobalC::restart.info_load.load_H_finish && !GlobalC::restart.info_load.restart_exx @@ -129,7 +151,7 @@ void Exx_LRI_Interface::exx_hamilt2density(elecstate::ElecState& elec, if (GlobalV::MY_RANK == 0) {GlobalC::restart.load_disk("Eexx", 0, 1, &this->exx_ptr->Eexx); } Parallel_Common::bcast_double(this->exx_ptr->Eexx); - this->exx_ptr->Eexx /= GlobalC::exx_info.info_global.hybrid_alpha; + this->exx_ptr->Eexx /= coeff; } elec.set_exx(this->get_Eexx()); } @@ -139,6 +161,65 @@ void Exx_LRI_Interface::exx_hamilt2density(elecstate::ElecState& elec, } } +template +void Exx_LRI_Interface::exx_iter_finish(const K_Vectors& kv, const UnitCell& ucell, + hamilt::Hamilt& hamilt, elecstate::ElecState& elec, Charge_Mixing& chgmix, + const double& scf_ene_thr, int& iter, const int istep, bool& conv_esolver) +{ + if (GlobalC::restart.info_save.save_H && (this->two_level_step > 0 || istep > 0) + && (!GlobalC::exx_info.info_global.separate_loop || iter == 1)) // to avoid saving the same value repeatedly + { + ////////// for Add_Hexx_Type::k + /* + hamilt::HS_Matrix_K Hexxk_save(&this->pv, 1); + for (int ik = 0; ik < this->kv.get_nks(); ++ik) { + Hexxk_save.set_zero_hk(); + + hamilt::OperatorEXX> opexx_save(&Hexxk_save, + nullptr, + this->kv); + + opexx_save.contributeHk(ik); + + GlobalC::restart.save_disk("Hexx", + ik, + this->pv.get_local_size(), + Hexxk_save.get_hk()); + }*/ + ////////// for Add_Hexx_Type:R + const std::string& restart_HR_path = GlobalC::restart.folder + "HexxR" + std::to_string(GlobalV::MY_RANK); + ModuleIO::write_Hexxs_csr(restart_HR_path, GlobalC::ucell, this->get_Hexxs()); + + if (GlobalV::MY_RANK == 0) + { + GlobalC::restart.save_disk("Eexx", 0, 1, &elec.f_en.exx); + } + } + + if (GlobalC::exx_info.info_global.cal_exx && conv_esolver) + { + // Kerker mixing does not work for the density matrix. + // In the separate loop case, it can still work in the subsequent inner loops where Hexx(DM) is fixed. + // In the non-separate loop case where Hexx(DM) is updated in every iteration of the 2nd loop, it should be + // closed. + if (!GlobalC::exx_info.info_global.separate_loop) + { + chgmix.close_kerker_gg0(); + } + this->dm_last_step = dynamic_cast*>(&elec)->get_DM(); + conv_esolver = this->exx_after_converge( + hamilt, + *dynamic_cast*>(&elec)->get_DM(), + kv, + PARAM.inp.nspin, + iter, + istep, + elec.f_en.etot, + scf_ene_thr); + } + //else if ( PARAM.inp.rdmft && two_level_step ) { conv_esolver = true; } // for RDMFT in the future to quit after the first iter of the exx-loop +} + template bool Exx_LRI_Interface::exx_after_converge( hamilt::Hamilt& hamilt, @@ -146,6 +227,7 @@ bool Exx_LRI_Interface::exx_after_converge( const K_Vectors& kv, const int& nspin, int& iter, + const int& istep, const double& etot, const double& scf_ene_thr) { // only called if (GlobalC::exx_info.info_global.cal_exx) @@ -154,7 +236,7 @@ bool Exx_LRI_Interface::exx_after_converge( GlobalC::restart.info_load.restart_exx = true; this->exx_ptr->Eexx = 0; }; - + // no separate_loop case if (!GlobalC::exx_info.info_global.separate_loop) { @@ -164,7 +246,7 @@ bool Exx_LRI_Interface::exx_after_converge( // in first scf loop, exx updated once in beginning, // in second scf loop, exx updated every iter - if (this->two_level_step) + if (this->two_level_step || istep > 0) { restart_reset(); return true; diff --git a/source/module_ri/Faddeeva.cc b/source/module_ri/Faddeeva.cc new file mode 100644 index 00000000000..786ba2c063b --- /dev/null +++ b/source/module_ri/Faddeeva.cc @@ -0,0 +1,2517 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; -*- + +/* Copyright (c) 2012 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* (Note that this file can be compiled with either C++, in which + case it uses C++ std::complex, or C, in which case it + uses C99 double complex.) */ + +/* Available at: http://ab-initio.mit.edu/Faddeeva + + Computes various error functions (erf, erfc, erfi, erfcx), + including the Dawson integral, in the complex plane, based + on algorithms for the computation of the Faddeeva function + w(z) = exp(-z^2) * erfc(-i*z). + Given w(z), the error functions are mostly straightforward + to compute, except for certain regions where we have to + switch to Taylor expansions to avoid cancellation errors + [e.g. near the origin for erf(z)]. + + To compute the Faddeeva function, we use a combination of two + algorithms: + + For sufficiently large |z|, we use a continued-fraction expansion + for w(z) similar to those described in: + + Walter Gautschi, "Efficient computation of the complex error + function," SIAM J. Numer. Anal. 7(1), pp. 187-198 (1970) + + G. P. M. Poppe and C. M. J. Wijers, "More efficient computation + of the complex error function," ACM Trans. Math. Soft. 16(1), + pp. 38-46 (1990). + + Unlike those papers, however, we switch to a completely different + algorithm for smaller |z|: + + Mofreh R. Zaghloul and Ahmed N. Ali, "Algorithm 916: Computing the + Faddeyeva and Voigt Functions," ACM Trans. Math. Soft. 38(2), 15 + (2011). + + (I initially used this algorithm for all z, but it turned out to be + significantly slower than the continued-fraction expansion for + larger |z|. On the other hand, it is competitive for smaller |z|, + and is significantly more accurate than the Poppe & Wijers code + in some regions, e.g. in the vicinity of z=1+1i.) + + Note that this is an INDEPENDENT RE-IMPLEMENTATION of these algorithms, + based on the description in the papers ONLY. In particular, I did + not refer to the authors' Fortran or Matlab implementations, respectively, + (which are under restrictive ACM copyright terms and therefore unusable + in free/open-source software). + + Steven G. Johnson, Massachusetts Institute of Technology + http://math.mit.edu/~stevenj + October 2012. + + -- Note that Algorithm 916 assumes that the erfc(x) function, + or rather the scaled function erfcx(x) = exp(x*x)*erfc(x), + is supplied for REAL arguments x. I originally used an + erfcx routine derived from DERFC in SLATEC, but I have + since replaced it with a much faster routine written by + me which uses a combination of continued-fraction expansions + and a lookup table of Chebyshev polynomials. For speed, + I implemented a similar algorithm for Im[w(x)] of real x, + since this comes up frequently in the other error functions. + + A small test program is included the end, which checks + the w(z) etc. results against several known values. To compile + the test function, compile with -DTEST_FADDEEVA (that is, + #define TEST_FADDEEVA). + + If HAVE_CONFIG_H is #defined (e.g. by compiling with -DHAVE_CONFIG_H), + then we #include "config.h", which is assumed to be a GNU autoconf-style + header defining HAVE_* macros to indicate the presence of features. In + particular, if HAVE_ISNAN and HAVE_ISINF are #defined, we use those + functions in math.h instead of defining our own, and if HAVE_ERF and/or + HAVE_ERFC are defined we use those functions from for erf and + erfc of real arguments, respectively, instead of defining our own. + + REVISION HISTORY: + 4 October 2012: Initial public release (SGJ) + 5 October 2012: Revised (SGJ) to fix spelling error, + start summation for large x at round(x/a) (> 1) + rather than ceil(x/a) as in the original + paper, which should slightly improve performance + (and, apparently, slightly improves accuracy) + 19 October 2012: Revised (SGJ) to fix bugs for large x, large -y, + and 15 1e154. + Set relerr argument to min(relerr,0.1). + 27 October 2012: Enhance accuracy in Re[w(z)] taken by itself, + by switching to Alg. 916 in a region near + the real-z axis where continued fractions + have poor relative accuracy in Re[w(z)]. Thanks + to M. Zaghloul for the tip. + 29 October 2012: Replace SLATEC-derived erfcx routine with + completely rewritten code by me, using a very + different algorithm which is much faster. + 30 October 2012: Implemented special-case code for real z + (where real part is exp(-x^2) and imag part is + Dawson integral), using algorithm similar to erfx. + Export ImFaddeeva_w function to make Dawson's + integral directly accessible. + 3 November 2012: Provide implementations of erf, erfc, erfcx, + and Dawson functions in Faddeeva:: namespace, + in addition to Faddeeva::w. Provide header + file Faddeeva.hh. + 4 November 2012: Slightly faster erf for real arguments. + Updated MATLAB and Octave plugins. + 27 November 2012: Support compilation with either C++ or + plain C (using C99 complex numbers). + For real x, use standard-library erf(x) + and erfc(x) if available (for C99 or C++11). + #include "config.h" if HAVE_CONFIG_H is #defined. + 15 December 2012: Portability fixes (copysign, Inf/NaN creation), + use CMPLX/__builtin_complex if available in C, + slight accuracy improvements to erf and dawson + functions near the origin. Use gnulib functions + if GNULIB_NAMESPACE is defined. + 18 December 2012: Slight tweaks (remove recomputation of x*x in Dawson) + 12 May 2015: Bugfix for systems lacking copysign function. +*/ + +///////////////////////////////////////////////////////////////////////// +/* If this file is compiled as a part of a larger project, + support using an autoconf-style config.h header file + (with various "HAVE_*" #defines to indicate features) + if HAVE_CONFIG_H is #defined (in GNU autotools style). */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +///////////////////////////////////////////////////////////////////////// +// macros to allow us to use either C++ or C (with C99 features) + +#ifdef __cplusplus + +# include "Faddeeva.hh" + +# include +# include +# include +using namespace std; + +// use std::numeric_limits, since 1./0. and 0./0. fail with some compilers (MS) +# define Inf numeric_limits::infinity() +# define NaN numeric_limits::quiet_NaN() + +typedef complex cmplx; + +// Use C-like complex syntax, since the C syntax is more restrictive +# define cexp(z) exp(z) +# define creal(z) real(z) +# define cimag(z) imag(z) +# define cpolar(r,t) polar(r,t) + +# define C(a,b) cmplx(a,b) + +# define FADDEEVA(name) Faddeeva::name +# define FADDEEVA_RE(name) Faddeeva::name + +// isnan/isinf were introduced in C++11 +# if (__cplusplus < 201103L) && (!defined(HAVE_ISNAN) || !defined(HAVE_ISINF)) +static inline bool my_isnan(double x) { return x != x; } +# define isnan my_isnan +static inline bool my_isinf(double x) { return 1/x == 0.; } +# define isinf my_isinf +# elif (__cplusplus >= 201103L) +// g++ gets confused between the C and C++ isnan/isinf functions +# define isnan std::isnan +# define isinf std::isinf +# endif + +// copysign was introduced in C++11 (and is also in POSIX and C99) +# if defined(_WIN32) || defined(__WIN32__) +# define copysign _copysign // of course MS had to be different +# elif defined(GNULIB_NAMESPACE) // we are using using gnulib +# define copysign GNULIB_NAMESPACE::copysign +# elif (__cplusplus < 201103L) && !defined(HAVE_COPYSIGN) && !defined(__linux__) && !(defined(__APPLE__) && defined(__MACH__)) && !defined(_AIX) +static inline double my_copysign(double x, double y) { return x<0 != y<0 ? -x : x; } +# define copysign my_copysign +# endif + +// If we are using the gnulib (e.g. in the GNU Octave sources), +// gnulib generates a link warning if we use ::floor instead of gnulib::floor. +// This warning is completely innocuous because the only difference between +// gnulib::floor and the system ::floor (and only on ancient OSF systems) +// has to do with floor(-0), which doesn't occur in the usage below, but +// the Octave developers prefer that we silence the warning. +# ifdef GNULIB_NAMESPACE +# define floor GNULIB_NAMESPACE::floor +# endif + +#else // !__cplusplus, i.e. pure C (requires C99 features) + +# include "Faddeeva.h" + +# define _GNU_SOURCE // enable GNU libc NAN extension if possible + +# include +# include + +typedef double complex cmplx; + +# define FADDEEVA(name) Faddeeva_ ## name +# define FADDEEVA_RE(name) Faddeeva_ ## name ## _re + +/* Constructing complex numbers like 0+i*NaN is problematic in C99 + without the C11 CMPLX macro, because 0.+I*NAN may give NaN+i*NAN if + I is a complex (rather than imaginary) constant. For some reason, + however, it works fine in (pre-4.7) gcc if I define Inf and NaN as + 1/0 and 0/0 (and only if I compile with optimization -O1 or more), + but not if I use the INFINITY or NAN macros. */ + +/* __builtin_complex was introduced in gcc 4.7, but the C11 CMPLX macro + may not be defined unless we are using a recent (2012) version of + glibc and compile with -std=c11... note that icc lies about being + gcc and probably doesn't have this builtin(?), so exclude icc explicitly */ +# if !defined(CMPLX) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +# define CMPLX(a,b) __builtin_complex((double) (a), (double) (b)) +# endif + +# ifdef CMPLX // C11 +# define C(a,b) CMPLX(a,b) +# define Inf INFINITY // C99 infinity +# ifdef NAN // GNU libc extension +# define NaN NAN +# else +# define NaN (0./0.) // NaN +# endif +# else +# define C(a,b) ((a) + I*(b)) +# define Inf (1./0.) +# define NaN (0./0.) +# endif + +static inline cmplx cpolar(double r, double t) +{ + if (r == 0.0 && !isnan(t)) + return 0.0; + else + return C(r * cos(t), r * sin(t)); +} + +#endif // !__cplusplus, i.e. pure C (requires C99 features) + +///////////////////////////////////////////////////////////////////////// +// Auxiliary routines to compute other special functions based on w(z) + +// compute erfcx(z) = exp(z^2) erfz(z) +cmplx FADDEEVA(erfcx)(cmplx z, double relerr) +{ + return FADDEEVA(w)(C(-cimag(z), creal(z)), relerr); +} + +// compute the error function erf(x) +double FADDEEVA_RE(erf)(double x) +{ +#if !defined(__cplusplus) + return erf(x); // C99 supplies erf in math.h +#elif (__cplusplus >= 201103L) || defined(HAVE_ERF) + return ::erf(x); // C++11 supplies std::erf in cmath +#else + double mx2 = -x*x; + if (mx2 < -750) // underflow + return (x >= 0 ? 1.0 : -1.0); + + if (x >= 0) { + if (x < 8e-2) goto taylor; + return 1.0 - exp(mx2) * FADDEEVA_RE(erfcx)(x); + } + else { // x < 0 + if (x > -8e-2) goto taylor; + return exp(mx2) * FADDEEVA_RE(erfcx)(-x) - 1.0; + } + + // Use Taylor series for small |x|, to avoid cancellation inaccuracy + // erf(x) = 2/sqrt(pi) * x * (1 - x^2/3 + x^4/10 - x^6/42 + x^8/216 + ...) + taylor: + return x * (1.1283791670955125739 + + mx2 * (0.37612638903183752464 + + mx2 * (0.11283791670955125739 + + mx2 * (0.026866170645131251760 + + mx2 * 0.0052239776254421878422)))); +#endif +} + +// compute the error function erf(z) +cmplx FADDEEVA(erf)(cmplx z, double relerr) +{ + double x = creal(z), y = cimag(z); + + if (y == 0) + return C(FADDEEVA_RE(erf)(x), + y); // preserve sign of 0 + if (x == 0) // handle separately for speed & handling of y = Inf or NaN + return C(x, // preserve sign of 0 + /* handle y -> Inf limit manually, since + exp(y^2) -> Inf but Im[w(y)] -> 0, so + IEEE will give us a NaN when it should be Inf */ + y*y > 720 ? (y > 0 ? Inf : -Inf) + : exp(y*y) * FADDEEVA(w_im)(y)); + + double mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow + double mIm_z2 = -2*x*y; // Im(-z^2) + if (mRe_z2 < -750) // underflow + return (x >= 0 ? 1.0 : -1.0); + + /* Handle positive and negative x via different formulas, + using the mirror symmetries of w, to avoid overflow/underflow + problems from multiplying exponentially large and small quantities. */ + if (x >= 0) { + if (x < 8e-2) { + if (fabs(y) < 1e-2) + goto taylor; + else if (fabs(mIm_z2) < 5e-3 && x < 5e-3) + goto taylor_erfi; + } + /* don't use complex exp function, since that will produce spurious NaN + values when multiplying w in an overflow situation. */ + return 1.0 - exp(mRe_z2) * + (C(cos(mIm_z2), sin(mIm_z2)) + * FADDEEVA(w)(C(-y,x), relerr)); + } + else { // x < 0 + if (x > -8e-2) { // duplicate from above to avoid fabs(x) call + if (fabs(y) < 1e-2) + goto taylor; + else if (fabs(mIm_z2) < 5e-3 && x > -5e-3) + goto taylor_erfi; + } + else if (isnan(x)) + return C(NaN, y == 0 ? 0 : NaN); + /* don't use complex exp function, since that will produce spurious NaN + values when multiplying w in an overflow situation. */ + return exp(mRe_z2) * + (C(cos(mIm_z2), sin(mIm_z2)) + * FADDEEVA(w)(C(y,-x), relerr)) - 1.0; + } + + // Use Taylor series for small |z|, to avoid cancellation inaccuracy + // erf(z) = 2/sqrt(pi) * z * (1 - z^2/3 + z^4/10 - z^6/42 + z^8/216 + ...) + taylor: + { + cmplx mz2 = C(mRe_z2, mIm_z2); // -z^2 + return z * (1.1283791670955125739 + + mz2 * (0.37612638903183752464 + + mz2 * (0.11283791670955125739 + + mz2 * (0.026866170645131251760 + + mz2 * 0.0052239776254421878422)))); + } + + /* for small |x| and small |xy|, + use Taylor series to avoid cancellation inaccuracy: + erf(x+iy) = erf(iy) + + 2*exp(y^2)/sqrt(pi) * + [ x * (1 - x^2 * (1+2y^2)/3 + x^4 * (3+12y^2+4y^4)/30 + ... + - i * x^2 * y * (1 - x^2 * (3+2y^2)/6 + ...) ] + where: + erf(iy) = exp(y^2) * Im[w(y)] + */ + taylor_erfi: + { + double x2 = x*x, y2 = y*y; + double expy2 = exp(y2); + return C + (expy2 * x * (1.1283791670955125739 + - x2 * (0.37612638903183752464 + + 0.75225277806367504925*y2) + + x2*x2 * (0.11283791670955125739 + + y2 * (0.45135166683820502956 + + 0.15045055561273500986*y2))), + expy2 * (FADDEEVA(w_im)(y) + - x2*y * (1.1283791670955125739 + - x2 * (0.56418958354775628695 + + 0.37612638903183752464*y2)))); + } +} + +// erfi(z) = -i erf(iz) +cmplx FADDEEVA(erfi)(cmplx z, double relerr) +{ + cmplx e = FADDEEVA(erf)(C(-cimag(z),creal(z)), relerr); + return C(cimag(e), -creal(e)); +} + +// erfi(x) = -i erf(ix) +double FADDEEVA_RE(erfi)(double x) +{ + return x*x > 720 ? (x > 0 ? Inf : -Inf) + : exp(x*x) * FADDEEVA(w_im)(x); +} + +// erfc(x) = 1 - erf(x) +double FADDEEVA_RE(erfc)(double x) +{ +#if !defined(__cplusplus) + return erfc(x); // C99 supplies erfc in math.h +#elif (__cplusplus >= 201103L) || defined(HAVE_ERFC) + return ::erfc(x); // C++11 supplies std::erfc in cmath +#else + if (x*x > 750) // underflow + return (x >= 0 ? 0.0 : 2.0); + return x >= 0 ? exp(-x*x) * FADDEEVA_RE(erfcx)(x) + : 2. - exp(-x*x) * FADDEEVA_RE(erfcx)(-x); +#endif +} + +// erfc(z) = 1 - erf(z) +cmplx FADDEEVA(erfc)(cmplx z, double relerr) +{ + double x = creal(z), y = cimag(z); + + if (x == 0.) + return C(1, + /* handle y -> Inf limit manually, since + exp(y^2) -> Inf but Im[w(y)] -> 0, so + IEEE will give us a NaN when it should be Inf */ + y*y > 720 ? (y > 0 ? -Inf : Inf) + : -exp(y*y) * FADDEEVA(w_im)(y)); + if (y == 0.) { + if (x*x > 750) // underflow + return C(x >= 0 ? 0.0 : 2.0, + -y); // preserve sign of 0 + return C(x >= 0 ? exp(-x*x) * FADDEEVA_RE(erfcx)(x) + : 2. - exp(-x*x) * FADDEEVA_RE(erfcx)(-x), + -y); // preserve sign of zero + } + + double mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow + double mIm_z2 = -2*x*y; // Im(-z^2) + if (mRe_z2 < -750) // underflow + return (x >= 0 ? 0.0 : 2.0); + + if (x >= 0) + return cexp(C(mRe_z2, mIm_z2)) + * FADDEEVA(w)(C(-y,x), relerr); + else + return 2.0 - cexp(C(mRe_z2, mIm_z2)) + * FADDEEVA(w)(C(y,-x), relerr); +} + +// compute Dawson(x) = sqrt(pi)/2 * exp(-x^2) * erfi(x) +double FADDEEVA_RE(Dawson)(double x) +{ + const double spi2 = 0.8862269254527580136490837416705725913990; // sqrt(pi)/2 + return spi2 * FADDEEVA(w_im)(x); +} + +// compute Dawson(z) = sqrt(pi)/2 * exp(-z^2) * erfi(z) +cmplx FADDEEVA(Dawson)(cmplx z, double relerr) +{ + const double spi2 = 0.8862269254527580136490837416705725913990; // sqrt(pi)/2 + double x = creal(z), y = cimag(z); + + // handle axes separately for speed & proper handling of x or y = Inf or NaN + if (y == 0) + return C(spi2 * FADDEEVA(w_im)(x), + -y); // preserve sign of 0 + if (x == 0) { + double y2 = y*y; + if (y2 < 2.5e-5) { // Taylor expansion + return C(x, // preserve sign of 0 + y * (1. + + y2 * (0.6666666666666666666666666666666666666667 + + y2 * 0.26666666666666666666666666666666666667))); + } + return C(x, // preserve sign of 0 + spi2 * (y >= 0 + ? exp(y2) - FADDEEVA_RE(erfcx)(y) + : FADDEEVA_RE(erfcx)(-y) - exp(y2))); + } + + double mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow + double mIm_z2 = -2*x*y; // Im(-z^2) + cmplx mz2 = C(mRe_z2, mIm_z2); // -z^2 + + /* Handle positive and negative x via different formulas, + using the mirror symmetries of w, to avoid overflow/underflow + problems from multiplying exponentially large and small quantities. */ + if (y >= 0) { + if (y < 5e-3) { + if (fabs(x) < 5e-3) + goto taylor; + else if (fabs(mIm_z2) < 5e-3) + goto taylor_realaxis; + } + cmplx res = cexp(mz2) - FADDEEVA(w)(z, relerr); + return spi2 * C(-cimag(res), creal(res)); + } + else { // y < 0 + if (y > -5e-3) { // duplicate from above to avoid fabs(x) call + if (fabs(x) < 5e-3) + goto taylor; + else if (fabs(mIm_z2) < 5e-3) + goto taylor_realaxis; + } + else if (isnan(y)) + return C(x == 0 ? 0 : NaN, NaN); + cmplx res = FADDEEVA(w)(-z, relerr) - cexp(mz2); + return spi2 * C(-cimag(res), creal(res)); + } + + // Use Taylor series for small |z|, to avoid cancellation inaccuracy + // dawson(z) = z - 2/3 z^3 + 4/15 z^5 + ... + taylor: + return z * (1. + + mz2 * (0.6666666666666666666666666666666666666667 + + mz2 * 0.2666666666666666666666666666666666666667)); + + /* for small |y| and small |xy|, + use Taylor series to avoid cancellation inaccuracy: + dawson(x + iy) + = D + y^2 (D + x - 2Dx^2) + + y^4 (D/2 + 5x/6 - 2Dx^2 - x^3/3 + 2Dx^4/3) + + iy [ (1-2Dx) + 2/3 y^2 (1 - 3Dx - x^2 + 2Dx^3) + + y^4/15 (4 - 15Dx - 9x^2 + 20Dx^3 + 2x^4 - 4Dx^5) ] + ... + where D = dawson(x) + + However, for large |x|, 2Dx -> 1 which gives cancellation problems in + this series (many of the leading terms cancel). So, for large |x|, + we need to substitute a continued-fraction expansion for D. + + dawson(x) = 0.5 / (x-0.5/(x-1/(x-1.5/(x-2/(x-2.5/(x...)))))) + + The 6 terms shown here seems to be the minimum needed to be + accurate as soon as the simpler Taylor expansion above starts + breaking down. Using this 6-term expansion, factoring out the + denominator, and simplifying with Maple, we obtain: + + Re dawson(x + iy) * (-15 + 90x^2 - 60x^4 + 8x^6) / x + = 33 - 28x^2 + 4x^4 + y^2 (18 - 4x^2) + 4 y^4 + Im dawson(x + iy) * (-15 + 90x^2 - 60x^4 + 8x^6) / y + = -15 + 24x^2 - 4x^4 + 2/3 y^2 (6x^2 - 15) - 4 y^4 + + Finally, for |x| > 5e7, we can use a simpler 1-term continued-fraction + expansion for the real part, and a 2-term expansion for the imaginary + part. (This avoids overflow problems for huge |x|.) This yields: + + Re dawson(x + iy) = [1 + y^2 (1 + y^2/2 - (xy)^2/3)] / (2x) + Im dawson(x + iy) = y [ -1 - 2/3 y^2 + y^4/15 (2x^2 - 4) ] / (2x^2 - 1) + + */ + taylor_realaxis: + { + double x2 = x*x; + if (x2 > 1600) { // |x| > 40 + double y2 = y*y; + if (x2 > 25e14) {// |x| > 5e7 + double xy2 = (x*y)*(x*y); + return C((0.5 + y2 * (0.5 + 0.25*y2 + - 0.16666666666666666667*xy2)) / x, + y * (-1 + y2 * (-0.66666666666666666667 + + 0.13333333333333333333*xy2 + - 0.26666666666666666667*y2)) + / (2*x2 - 1)); + } + return (1. / (-15 + x2*(90 + x2*(-60 + 8*x2)))) * + C(x * (33 + x2 * (-28 + 4*x2) + + y2 * (18 - 4*x2 + 4*y2)), + y * (-15 + x2 * (24 - 4*x2) + + y2 * (4*x2 - 10 - 4*y2))); + } + else { + double D = spi2 * FADDEEVA(w_im)(x); + double y2 = y*y; + return C + (D + y2 * (D + x - 2*D*x2) + + y2*y2 * (D * (0.5 - x2 * (2 - 0.66666666666666666667*x2)) + + x * (0.83333333333333333333 + - 0.33333333333333333333 * x2)), + y * (1 - 2*D*x + + y2 * 0.66666666666666666667 * (1 - x2 - D*x * (3 - 2*x2)) + + y2*y2 * (0.26666666666666666667 - + x2 * (0.6 - 0.13333333333333333333 * x2) + - D*x * (1 - x2 * (1.3333333333333333333 + - 0.26666666666666666667 * x2))))); + } + } +} + +///////////////////////////////////////////////////////////////////////// + +// return sinc(x) = sin(x)/x, given both x and sin(x) +// [since we only use this in cases where sin(x) has already been computed] +static inline double sinc(double x, double sinx) { + return fabs(x) < 1e-4 ? 1 - (0.1666666666666666666667)*x*x : sinx / x; +} + +// sinh(x) via Taylor series, accurate to machine precision for |x| < 1e-2 +static inline double sinh_taylor(double x) { + return x * (1 + (x*x) * (0.1666666666666666666667 + + 0.00833333333333333333333 * (x*x))); +} + +static inline double sqr(double x) { return x*x; } + +// precomputed table of expa2n2[n-1] = exp(-a2*n*n) +// for double-precision a2 = 0.26865... in FADDEEVA(w), below. +static const double expa2n2[] = { + 7.64405281671221563e-01, + 3.41424527166548425e-01, + 8.91072646929412548e-02, + 1.35887299055460086e-02, + 1.21085455253437481e-03, + 6.30452613933449404e-05, + 1.91805156577114683e-06, + 3.40969447714832381e-08, + 3.54175089099469393e-10, + 2.14965079583260682e-12, + 7.62368911833724354e-15, + 1.57982797110681093e-17, + 1.91294189103582677e-20, + 1.35344656764205340e-23, + 5.59535712428588720e-27, + 1.35164257972401769e-30, + 1.90784582843501167e-34, + 1.57351920291442930e-38, + 7.58312432328032845e-43, + 2.13536275438697082e-47, + 3.51352063787195769e-52, + 3.37800830266396920e-57, + 1.89769439468301000e-62, + 6.22929926072668851e-68, + 1.19481172006938722e-73, + 1.33908181133005953e-79, + 8.76924303483223939e-86, + 3.35555576166254986e-92, + 7.50264110688173024e-99, + 9.80192200745410268e-106, + 7.48265412822268959e-113, + 3.33770122566809425e-120, + 8.69934598159861140e-128, + 1.32486951484088852e-135, + 1.17898144201315253e-143, + 6.13039120236180012e-152, + 1.86258785950822098e-160, + 3.30668408201432783e-169, + 3.43017280887946235e-178, + 2.07915397775808219e-187, + 7.36384545323984966e-197, + 1.52394760394085741e-206, + 1.84281935046532100e-216, + 1.30209553802992923e-226, + 5.37588903521080531e-237, + 1.29689584599763145e-247, + 1.82813078022866562e-258, + 1.50576355348684241e-269, + 7.24692320799294194e-281, + 2.03797051314726829e-292, + 3.34880215927873807e-304, + 0.0 // underflow (also prevents reads past array end, below) +}; + +///////////////////////////////////////////////////////////////////////// + +cmplx FADDEEVA(w)(cmplx z, double relerr) +{ + if (creal(z) == 0.0) + return C(FADDEEVA_RE(erfcx)(cimag(z)), + creal(z)); // give correct sign of 0 in cimag(w) + else if (cimag(z) == 0) + return C(exp(-sqr(creal(z))), + FADDEEVA(w_im)(creal(z))); + + double a, a2, c; + if (relerr <= DBL_EPSILON) { + relerr = DBL_EPSILON; + a = 0.518321480430085929872; // pi / sqrt(-log(eps*0.5)) + c = 0.329973702884629072537; // (2/pi) * a; + a2 = 0.268657157075235951582; // a^2 + } + else { + const double pi = 3.14159265358979323846264338327950288419716939937510582; + if (relerr > 0.1) relerr = 0.1; // not sensible to compute < 1 digit + a = pi / sqrt(-log(relerr*0.5)); + c = (2/pi)*a; + a2 = a*a; + } + const double x = fabs(creal(z)); + const double y = cimag(z), ya = fabs(y); + + cmplx ret = 0.; // return value + + double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0; + +#define USE_CONTINUED_FRACTION 1 // 1 to use continued fraction for large |z| + +#if USE_CONTINUED_FRACTION + if (ya > 7 || (x > 6 // continued fraction is faster + /* As pointed out by M. Zaghloul, the continued + fraction seems to give a large relative error in + Re w(z) for |x| ~ 6 and small |y|, so use + algorithm 816 in this region: */ + && (ya > 0.1 || (x > 8 && ya > 1e-10) || x > 28))) { + + /* Poppe & Wijers suggest using a number of terms + nu = 3 + 1442 / (26*rho + 77) + where rho = sqrt((x/x0)^2 + (y/y0)^2) where x0=6.3, y0=4.4. + (They only use this expansion for rho >= 1, but rho a little less + than 1 seems okay too.) + Instead, I did my own fit to a slightly different function + that avoids the hypotenuse calculation, using NLopt to minimize + the sum of the squares of the errors in nu with the constraint + that the estimated nu be >= minimum nu to attain machine precision. + I also separate the regions where nu == 2 and nu == 1. */ + const double ispi = 0.56418958354775628694807945156; // 1 / sqrt(pi) + double xs = y < 0 ? -creal(z) : creal(z); // compute for -z if y < 0 + if (x + ya > 4000) { // nu <= 2 + if (x + ya > 1e7) { // nu == 1, w(z) = i/sqrt(pi) / z + // scale to avoid overflow + if (x > ya) { + double yax = ya / xs; + double denom = ispi / (xs + yax*ya); + ret = C(denom*yax, denom); + } + else if (isinf(ya)) + return ((isnan(x) || y < 0) + ? C(NaN,NaN) : C(0,0)); + else { + double xya = xs / ya; + double denom = ispi / (xya*xs + ya); + ret = C(denom, denom*xya); + } + } + else { // nu == 2, w(z) = i/sqrt(pi) * z / (z*z - 0.5) + double dr = xs*xs - ya*ya - 0.5, di = 2*xs*ya; + double denom = ispi / (dr*dr + di*di); + ret = C(denom * (xs*di-ya*dr), denom * (xs*dr+ya*di)); + } + } + else { // compute nu(z) estimate and do general continued fraction + const double c0=3.9, c1=11.398, c2=0.08254, c3=0.1421, c4=0.2023; // fit + double nu = floor(c0 + c1 / (c2*x + c3*ya + c4)); + double wr = xs, wi = ya; + for (nu = 0.5 * (nu - 1); nu > 0.4; nu -= 0.5) { + // w <- z - nu/w: + double denom = nu / (wr*wr + wi*wi); + wr = xs - wr * denom; + wi = ya + wi * denom; + } + { // w(z) = i/sqrt(pi) / w: + double denom = ispi / (wr*wr + wi*wi); + ret = C(denom*wi, denom*wr); + } + } + if (y < 0) { + // use w(z) = 2.0*exp(-z*z) - w(-z), + // but be careful of overflow in exp(-z*z) + // = exp(-(xs*xs-ya*ya) -2*i*xs*ya) + return 2.0*cexp(C((ya-xs)*(xs+ya), 2*xs*y)) - ret; + } + else + return ret; + } +#else // !USE_CONTINUED_FRACTION + if (x + ya > 1e7) { // w(z) = i/sqrt(pi) / z, to machine precision + const double ispi = 0.56418958354775628694807945156; // 1 / sqrt(pi) + double xs = y < 0 ? -creal(z) : creal(z); // compute for -z if y < 0 + // scale to avoid overflow + if (x > ya) { + double yax = ya / xs; + double denom = ispi / (xs + yax*ya); + ret = C(denom*yax, denom); + } + else { + double xya = xs / ya; + double denom = ispi / (xya*xs + ya); + ret = C(denom, denom*xya); + } + if (y < 0) { + // use w(z) = 2.0*exp(-z*z) - w(-z), + // but be careful of overflow in exp(-z*z) + // = exp(-(xs*xs-ya*ya) -2*i*xs*ya) + return 2.0*cexp(C((ya-xs)*(xs+ya), 2*xs*y)) - ret; + } + else + return ret; + } +#endif // !USE_CONTINUED_FRACTION + + /* Note: The test that seems to be suggested in the paper is x < + sqrt(-log(DBL_MIN)), about 26.6, since otherwise exp(-x^2) + underflows to zero and sum1,sum2,sum4 are zero. However, long + before this occurs, the sum1,sum2,sum4 contributions are + negligible in double precision; I find that this happens for x > + about 6, for all y. On the other hand, I find that the case + where we compute all of the sums is faster (at least with the + precomputed expa2n2 table) until about x=10. Furthermore, if we + try to compute all of the sums for x > 20, I find that we + sometimes run into numerical problems because underflow/overflow + problems start to appear in the various coefficients of the sums, + below. Therefore, we use x < 10 here. */ + else if (x < 10) { + double prod2ax = 1, prodm2ax = 1; + double expx2; + + if (isnan(y)) + return C(y,y); + + /* Somewhat ugly copy-and-paste duplication here, but I see significant + speedups from using the special-case code with the precomputed + exponential, and the x < 5e-4 special case is needed for accuracy. */ + + if (relerr == DBL_EPSILON) { // use precomputed exp(-a2*(n*n)) table + if (x < 5e-4) { // compute sum4 and sum5 together as sum5-sum4 + const double x2 = x*x; + expx2 = 1 - x2 * (1 - 0.5*x2); // exp(-x*x) via Taylor + // compute exp(2*a*x) and exp(-2*a*x) via Taylor, to double precision + const double ax2 = 1.036642960860171859744*x; // 2*a*x + const double exp2ax = + 1 + ax2 * (1 + ax2 * (0.5 + 0.166666666666666666667*ax2)); + const double expm2ax = + 1 - ax2 * (1 - ax2 * (0.5 - 0.166666666666666666667*ax2)); + for (int n = 1; 1; ++n) { + const double coef = expa2n2[n-1] * expx2 / (a2*(n*n) + y*y); + prod2ax *= exp2ax; + prodm2ax *= expm2ax; + sum1 += coef; + sum2 += coef * prodm2ax; + sum3 += coef * prod2ax; + + // really = sum5 - sum4 + sum5 += coef * (2*a) * n * sinh_taylor((2*a)*n*x); + + // test convergence via sum3 + if (coef * prod2ax < relerr * sum3) break; + } + } + else { // x > 5e-4, compute sum4 and sum5 separately + expx2 = exp(-x*x); + const double exp2ax = exp((2*a)*x), expm2ax = 1 / exp2ax; + for (int n = 1; 1; ++n) { + const double coef = expa2n2[n-1] * expx2 / (a2*(n*n) + y*y); + prod2ax *= exp2ax; + prodm2ax *= expm2ax; + sum1 += coef; + sum2 += coef * prodm2ax; + sum4 += (coef * prodm2ax) * (a*n); + sum3 += coef * prod2ax; + sum5 += (coef * prod2ax) * (a*n); + // test convergence via sum5, since this sum has the slowest decay + if ((coef * prod2ax) * (a*n) < relerr * sum5) break; + } + } + } + else { // relerr != DBL_EPSILON, compute exp(-a2*(n*n)) on the fly + const double exp2ax = exp((2*a)*x), expm2ax = 1 / exp2ax; + if (x < 5e-4) { // compute sum4 and sum5 together as sum5-sum4 + const double x2 = x*x; + expx2 = 1 - x2 * (1 - 0.5*x2); // exp(-x*x) via Taylor + for (int n = 1; 1; ++n) { + const double coef = exp(-a2*(n*n)) * expx2 / (a2*(n*n) + y*y); + prod2ax *= exp2ax; + prodm2ax *= expm2ax; + sum1 += coef; + sum2 += coef * prodm2ax; + sum3 += coef * prod2ax; + + // really = sum5 - sum4 + sum5 += coef * (2*a) * n * sinh_taylor((2*a)*n*x); + + // test convergence via sum3 + if (coef * prod2ax < relerr * sum3) break; + } + } + else { // x > 5e-4, compute sum4 and sum5 separately + expx2 = exp(-x*x); + for (int n = 1; 1; ++n) { + const double coef = exp(-a2*(n*n)) * expx2 / (a2*(n*n) + y*y); + prod2ax *= exp2ax; + prodm2ax *= expm2ax; + sum1 += coef; + sum2 += coef * prodm2ax; + sum4 += (coef * prodm2ax) * (a*n); + sum3 += coef * prod2ax; + sum5 += (coef * prod2ax) * (a*n); + // test convergence via sum5, since this sum has the slowest decay + if ((coef * prod2ax) * (a*n) < relerr * sum5) break; + } + } + } + const double expx2erfcxy = // avoid spurious overflow for large negative y + y > -6 // for y < -6, erfcx(y) = 2*exp(y*y) to double precision + ? expx2*FADDEEVA_RE(erfcx)(y) : 2*exp(y*y-x*x); + if (y > 5) { // imaginary terms cancel + const double sinxy = sin(x*y); + ret = (expx2erfcxy - c*y*sum1) * cos(2*x*y) + + (c*x*expx2) * sinxy * sinc(x*y, sinxy); + } + else { + double xs = creal(z); + const double sinxy = sin(xs*y); + const double sin2xy = sin(2*xs*y), cos2xy = cos(2*xs*y); + const double coef1 = expx2erfcxy - c*y*sum1; + const double coef2 = c*xs*expx2; + ret = C(coef1 * cos2xy + coef2 * sinxy * sinc(xs*y, sinxy), + coef2 * sinc(2*xs*y, sin2xy) - coef1 * sin2xy); + } + } + else { // x large: only sum3 & sum5 contribute (see above note) + if (isnan(x)) + return C(x,x); + if (isnan(y)) + return C(y,y); + +#if USE_CONTINUED_FRACTION + ret = exp(-x*x); // |y| < 1e-10, so we only need exp(-x*x) term +#else + if (y < 0) { + /* erfcx(y) ~ 2*exp(y*y) + (< 1) if y < 0, so + erfcx(y)*exp(-x*x) ~ 2*exp(y*y-x*x) term may not be negligible + if y*y - x*x > -36 or so. So, compute this term just in case. + We also need the -exp(-x*x) term to compute Re[w] accurately + in the case where y is very small. */ + ret = cpolar(2*exp(y*y-x*x) - exp(-x*x), -2*creal(z)*y); + } + else + ret = exp(-x*x); // not negligible in real part if y very small +#endif + // (round instead of ceil as in original paper; note that x/a > 1 here) + double n0 = floor(x/a + 0.5); // sum in both directions, starting at n0 + double dx = a*n0 - x; + sum3 = exp(-dx*dx) / (a2*(n0*n0) + y*y); + sum5 = a*n0 * sum3; + double exp1 = exp(4*a*dx), exp1dn = 1; + int dn; + for (dn = 1; n0 - dn > 0; ++dn) { // loop over n0-dn and n0+dn terms + double np = n0 + dn, nm = n0 - dn; + double tp = exp(-sqr(a*dn+dx)); + double tm = tp * (exp1dn *= exp1); // trick to get tm from tp + tp /= (a2*(np*np) + y*y); + tm /= (a2*(nm*nm) + y*y); + sum3 += tp + tm; + sum5 += a * (np * tp + nm * tm); + if (a * (np * tp + nm * tm) < relerr * sum5) goto finish; + } + while (1) { // loop over n0+dn terms only (since n0-dn <= 0) + double np = n0 + dn++; + double tp = exp(-sqr(a*dn+dx)) / (a2*(np*np) + y*y); + sum3 += tp; + sum5 += a * np * tp; + if (a * np * tp < relerr * sum5) goto finish; + } + } + finish: + return ret + C((0.5*c)*y*(sum2+sum3), + (0.5*c)*copysign(sum5-sum4, creal(z))); +} + +///////////////////////////////////////////////////////////////////////// + +/* erfcx(x) = exp(x^2) erfc(x) function, for real x, written by + Steven G. Johnson, October 2012. + + This function combines a few different ideas. + + First, for x > 50, it uses a continued-fraction expansion (same as + for the Faddeeva function, but with algebraic simplifications for z=i*x). + + Second, for 0 <= x <= 50, it uses Chebyshev polynomial approximations, + but with two twists: + + a) It maps x to y = 4 / (4+x) in [0,1]. This simple transformation, + inspired by a similar transformation in the octave-forge/specfun + erfcx by Soren Hauberg, results in much faster Chebyshev convergence + than other simple transformations I have examined. + + b) Instead of using a single Chebyshev polynomial for the entire + [0,1] y interval, we break the interval up into 100 equal + subintervals, with a switch/lookup table, and use much lower + degree Chebyshev polynomials in each subinterval. This greatly + improves performance in my tests. + + For x < 0, we use the relationship erfcx(-x) = 2 exp(x^2) - erfc(x), + with the usual checks for overflow etcetera. + + Performance-wise, it seems to be substantially faster than either + the SLATEC DERFC function [or an erfcx function derived therefrom] + or Cody's CALERF function (from netlib.org/specfun), while + retaining near machine precision in accuracy. */ + +/* Given y100=100*y, where y = 4/(4+x) for x >= 0, compute erfc(x). + + Uses a look-up table of 100 different Chebyshev polynomials + for y intervals [0,0.01], [0.01,0.02], ...., [0.99,1], generated + with the help of Maple and a little shell script. This allows + the Chebyshev polynomials to be of significantly lower degree (about 1/4) + compared to fitting the whole [0,1] interval with a single polynomial. */ +static double erfcx_y100(double y100) +{ + switch ((int) y100) { +case 0: { +double t = 2*y100 - 1; +return 0.70878032454106438663e-3 + (0.71234091047026302958e-3 + (0.35779077297597742384e-5 + (0.17403143962587937815e-7 + (0.81710660047307788845e-10 + (0.36885022360434957634e-12 + 0.15917038551111111111e-14 * t) * t) * t) * t) * t) * t; +} +case 1: { +double t = 2*y100 - 3; +return 0.21479143208285144230e-2 + (0.72686402367379996033e-3 + (0.36843175430938995552e-5 + (0.18071841272149201685e-7 + (0.85496449296040325555e-10 + (0.38852037518534291510e-12 + 0.16868473576888888889e-14 * t) * t) * t) * t) * t) * t; +} +case 2: { +double t = 2*y100 - 5; +return 0.36165255935630175090e-2 + (0.74182092323555510862e-3 + (0.37948319957528242260e-5 + (0.18771627021793087350e-7 + (0.89484715122415089123e-10 + (0.40935858517772440862e-12 + 0.17872061464888888889e-14 * t) * t) * t) * t) * t) * t; +} +case 3: { +double t = 2*y100 - 7; +return 0.51154983860031979264e-2 + (0.75722840734791660540e-3 + (0.39096425726735703941e-5 + (0.19504168704300468210e-7 + (0.93687503063178993915e-10 + (0.43143925959079664747e-12 + 0.18939926435555555556e-14 * t) * t) * t) * t) * t) * t; +} +case 4: { +double t = 2*y100 - 9; +return 0.66457513172673049824e-2 + (0.77310406054447454920e-3 + (0.40289510589399439385e-5 + (0.20271233238288381092e-7 + (0.98117631321709100264e-10 + (0.45484207406017752971e-12 + 0.20076352213333333333e-14 * t) * t) * t) * t) * t) * t; +} +case 5: { +double t = 2*y100 - 11; +return 0.82082389970241207883e-2 + (0.78946629611881710721e-3 + (0.41529701552622656574e-5 + (0.21074693344544655714e-7 + (0.10278874108587317989e-9 + (0.47965201390613339638e-12 + 0.21285907413333333333e-14 * t) * t) * t) * t) * t) * t; +} +case 6: { +double t = 2*y100 - 13; +return 0.98039537275352193165e-2 + (0.80633440108342840956e-3 + (0.42819241329736982942e-5 + (0.21916534346907168612e-7 + (0.10771535136565470914e-9 + (0.50595972623692822410e-12 + 0.22573462684444444444e-14 * t) * t) * t) * t) * t) * t; +} +case 7: { +double t = 2*y100 - 15; +return 0.11433927298290302370e-1 + (0.82372858383196561209e-3 + (0.44160495311765438816e-5 + (0.22798861426211986056e-7 + (0.11291291745879239736e-9 + (0.53386189365816880454e-12 + 0.23944209546666666667e-14 * t) * t) * t) * t) * t) * t; +} +case 8: { +double t = 2*y100 - 17; +return 0.13099232878814653979e-1 + (0.84167002467906968214e-3 + (0.45555958988457506002e-5 + (0.23723907357214175198e-7 + (0.11839789326602695603e-9 + (0.56346163067550237877e-12 + 0.25403679644444444444e-14 * t) * t) * t) * t) * t) * t; +} +case 9: { +double t = 2*y100 - 19; +return 0.14800987015587535621e-1 + (0.86018092946345943214e-3 + (0.47008265848816866105e-5 + (0.24694040760197315333e-7 + (0.12418779768752299093e-9 + (0.59486890370320261949e-12 + 0.26957764568888888889e-14 * t) * t) * t) * t) * t) * t; +} +case 10: { +double t = 2*y100 - 21; +return 0.16540351739394069380e-1 + (0.87928458641241463952e-3 + (0.48520195793001753903e-5 + (0.25711774900881709176e-7 + (0.13030128534230822419e-9 + (0.62820097586874779402e-12 + 0.28612737351111111111e-14 * t) * t) * t) * t) * t) * t; +} +case 11: { +double t = 2*y100 - 23; +return 0.18318536789842392647e-1 + (0.89900542647891721692e-3 + (0.50094684089553365810e-5 + (0.26779777074218070482e-7 + (0.13675822186304615566e-9 + (0.66358287745352705725e-12 + 0.30375273884444444444e-14 * t) * t) * t) * t) * t) * t; +} +case 12: { +double t = 2*y100 - 25; +return 0.20136801964214276775e-1 + (0.91936908737673676012e-3 + (0.51734830914104276820e-5 + (0.27900878609710432673e-7 + (0.14357976402809042257e-9 + (0.70114790311043728387e-12 + 0.32252476000000000000e-14 * t) * t) * t) * t) * t) * t; +} +case 13: { +double t = 2*y100 - 27; +return 0.21996459598282740954e-1 + (0.94040248155366777784e-3 + (0.53443911508041164739e-5 + (0.29078085538049374673e-7 + (0.15078844500329731137e-9 + (0.74103813647499204269e-12 + 0.34251892320000000000e-14 * t) * t) * t) * t) * t) * t; +} +case 14: { +double t = 2*y100 - 29; +return 0.23898877187226319502e-1 + (0.96213386835900177540e-3 + (0.55225386998049012752e-5 + (0.30314589961047687059e-7 + (0.15840826497296335264e-9 + (0.78340500472414454395e-12 + 0.36381553564444444445e-14 * t) * t) * t) * t) * t) * t; +} +case 15: { +double t = 2*y100 - 31; +return 0.25845480155298518485e-1 + (0.98459293067820123389e-3 + (0.57082915920051843672e-5 + (0.31613782169164830118e-7 + (0.16646478745529630813e-9 + (0.82840985928785407942e-12 + 0.38649975768888888890e-14 * t) * t) * t) * t) * t) * t; +} +case 16: { +double t = 2*y100 - 33; +return 0.27837754783474696598e-1 + (0.10078108563256892757e-2 + (0.59020366493792212221e-5 + (0.32979263553246520417e-7 + (0.17498524159268458073e-9 + (0.87622459124842525110e-12 + 0.41066206488888888890e-14 * t) * t) * t) * t) * t) * t; +} +case 17: { +double t = 2*y100 - 35; +return 0.29877251304899307550e-1 + (0.10318204245057349310e-2 + (0.61041829697162055093e-5 + (0.34414860359542720579e-7 + (0.18399863072934089607e-9 + (0.92703227366365046533e-12 + 0.43639844053333333334e-14 * t) * t) * t) * t) * t) * t; +} +case 18: { +double t = 2*y100 - 37; +return 0.31965587178596443475e-1 + (0.10566560976716574401e-2 + (0.63151633192414586770e-5 + (0.35924638339521924242e-7 + (0.19353584758781174038e-9 + (0.98102783859889264382e-12 + 0.46381060817777777779e-14 * t) * t) * t) * t) * t) * t; +} +case 19: { +double t = 2*y100 - 39; +return 0.34104450552588334840e-1 + (0.10823541191350532574e-2 + (0.65354356159553934436e-5 + (0.37512918348533521149e-7 + (0.20362979635817883229e-9 + (0.10384187833037282363e-11 + 0.49300625262222222221e-14 * t) * t) * t) * t) * t) * t; +} +case 20: { +double t = 2*y100 - 41; +return 0.36295603928292425716e-1 + (0.11089526167995268200e-2 + (0.67654845095518363577e-5 + (0.39184292949913591646e-7 + (0.21431552202133775150e-9 + (0.10994259106646731797e-11 + 0.52409949102222222221e-14 * t) * t) * t) * t) * t) * t; +} +case 21: { +double t = 2*y100 - 43; +return 0.38540888038840509795e-1 + (0.11364917134175420009e-2 + (0.70058230641246312003e-5 + (0.40943644083718586939e-7 + (0.22563034723692881631e-9 + (0.11642841011361992885e-11 + 0.55721092871111111110e-14 * t) * t) * t) * t) * t) * t; +} +case 22: { +double t = 2*y100 - 45; +return 0.40842225954785960651e-1 + (0.11650136437945673891e-2 + (0.72569945502343006619e-5 + (0.42796161861855042273e-7 + (0.23761401711005024162e-9 + (0.12332431172381557035e-11 + 0.59246802364444444445e-14 * t) * t) * t) * t) * t) * t; +} +case 23: { +double t = 2*y100 - 47; +return 0.43201627431540222422e-1 + (0.11945628793917272199e-2 + (0.75195743532849206263e-5 + (0.44747364553960993492e-7 + (0.25030885216472953674e-9 + (0.13065684400300476484e-11 + 0.63000532853333333334e-14 * t) * t) * t) * t) * t) * t; +} +case 24: { +double t = 2*y100 - 49; +return 0.45621193513810471438e-1 + (0.12251862608067529503e-2 + (0.77941720055551920319e-5 + (0.46803119830954460212e-7 + (0.26375990983978426273e-9 + (0.13845421370977119765e-11 + 0.66996477404444444445e-14 * t) * t) * t) * t) * t) * t; +} +case 25: { +double t = 2*y100 - 51; +return 0.48103121413299865517e-1 + (0.12569331386432195113e-2 + (0.80814333496367673980e-5 + (0.48969667335682018324e-7 + (0.27801515481905748484e-9 + (0.14674637611609884208e-11 + 0.71249589351111111110e-14 * t) * t) * t) * t) * t) * t; +} +case 26: { +double t = 2*y100 - 53; +return 0.50649709676983338501e-1 + (0.12898555233099055810e-2 + (0.83820428414568799654e-5 + (0.51253642652551838659e-7 + (0.29312563849675507232e-9 + (0.15556512782814827846e-11 + 0.75775607822222222221e-14 * t) * t) * t) * t) * t) * t; +} +case 27: { +double t = 2*y100 - 55; +return 0.53263363664388864181e-1 + (0.13240082443256975769e-2 + (0.86967260015007658418e-5 + (0.53662102750396795566e-7 + (0.30914568786634796807e-9 + (0.16494420240828493176e-11 + 0.80591079644444444445e-14 * t) * t) * t) * t) * t) * t; +} +case 28: { +double t = 2*y100 - 57; +return 0.55946601353500013794e-1 + (0.13594491197408190706e-2 + (0.90262520233016380987e-5 + (0.56202552975056695376e-7 + (0.32613310410503135996e-9 + (0.17491936862246367398e-11 + 0.85713381688888888890e-14 * t) * t) * t) * t) * t) * t; +} +case 29: { +double t = 2*y100 - 59; +return 0.58702059496154081813e-1 + (0.13962391363223647892e-2 + (0.93714365487312784270e-5 + (0.58882975670265286526e-7 + (0.34414937110591753387e-9 + (0.18552853109751857859e-11 + 0.91160736711111111110e-14 * t) * t) * t) * t) * t) * t; +} +case 30: { +double t = 2*y100 - 61; +return 0.61532500145144778048e-1 + (0.14344426411912015247e-2 + (0.97331446201016809696e-5 + (0.61711860507347175097e-7 + (0.36325987418295300221e-9 + (0.19681183310134518232e-11 + 0.96952238400000000000e-14 * t) * t) * t) * t) * t) * t; +} +case 31: { +double t = 2*y100 - 63; +return 0.64440817576653297993e-1 + (0.14741275456383131151e-2 + (0.10112293819576437838e-4 + (0.64698236605933246196e-7 + (0.38353412915303665586e-9 + (0.20881176114385120186e-11 + 0.10310784480000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 32: { +double t = 2*y100 - 65; +return 0.67430045633130393282e-1 + (0.15153655418916540370e-2 + (0.10509857606888328667e-4 + (0.67851706529363332855e-7 + (0.40504602194811140006e-9 + (0.22157325110542534469e-11 + 0.10964842115555555556e-13 * t) * t) * t) * t) * t) * t; +} +case 33: { +double t = 2*y100 - 67; +return 0.70503365513338850709e-1 + (0.15582323336495709827e-2 + (0.10926868866865231089e-4 + (0.71182482239613507542e-7 + (0.42787405890153386710e-9 + (0.23514379522274416437e-11 + 0.11659571751111111111e-13 * t) * t) * t) * t) * t) * t; +} +case 34: { +double t = 2*y100 - 69; +return 0.73664114037944596353e-1 + (0.16028078812438820413e-2 + (0.11364423678778207991e-4 + (0.74701423097423182009e-7 + (0.45210162777476488324e-9 + (0.24957355004088569134e-11 + 0.12397238257777777778e-13 * t) * t) * t) * t) * t) * t; +} +case 35: { +double t = 2*y100 - 71; +return 0.76915792420819562379e-1 + (0.16491766623447889354e-2 + (0.11823685320041302169e-4 + (0.78420075993781544386e-7 + (0.47781726956916478925e-9 + (0.26491544403815724749e-11 + 0.13180196462222222222e-13 * t) * t) * t) * t) * t) * t; +} +case 36: { +double t = 2*y100 - 73; +return 0.80262075578094612819e-1 + (0.16974279491709504117e-2 + (0.12305888517309891674e-4 + (0.82350717698979042290e-7 + (0.50511496109857113929e-9 + (0.28122528497626897696e-11 + 0.14010889635555555556e-13 * t) * t) * t) * t) * t) * t; +} +case 37: { +double t = 2*y100 - 75; +return 0.83706822008980357446e-1 + (0.17476561032212656962e-2 + (0.12812343958540763368e-4 + (0.86506399515036435592e-7 + (0.53409440823869467453e-9 + (0.29856186620887555043e-11 + 0.14891851591111111111e-13 * t) * t) * t) * t) * t) * t; +} +case 38: { +double t = 2*y100 - 77; +return 0.87254084284461718231e-1 + (0.17999608886001962327e-2 + (0.13344443080089492218e-4 + (0.90900994316429008631e-7 + (0.56486134972616465316e-9 + (0.31698707080033956934e-11 + 0.15825697795555555556e-13 * t) * t) * t) * t) * t) * t; +} +case 39: { +double t = 2*y100 - 79; +return 0.90908120182172748487e-1 + (0.18544478050657699758e-2 + (0.13903663143426120077e-4 + (0.95549246062549906177e-7 + (0.59752787125242054315e-9 + (0.33656597366099099413e-11 + 0.16815130613333333333e-13 * t) * t) * t) * t) * t) * t; +} +case 40: { +double t = 2*y100 - 81; +return 0.94673404508075481121e-1 + (0.19112284419887303347e-2 + (0.14491572616545004930e-4 + (0.10046682186333613697e-6 + (0.63221272959791000515e-9 + (0.35736693975589130818e-11 + 0.17862931591111111111e-13 * t) * t) * t) * t) * t) * t; +} +case 41: { +double t = 2*y100 - 83; +return 0.98554641648004456555e-1 + (0.19704208544725622126e-2 + (0.15109836875625443935e-4 + (0.10567036667675984067e-6 + (0.66904168640019354565e-9 + (0.37946171850824333014e-11 + 0.18971959040000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 42: { +double t = 2*y100 - 85; +return 0.10255677889470089531e0 + (0.20321499629472857418e-2 + (0.15760224242962179564e-4 + (0.11117756071353507391e-6 + (0.70814785110097658502e-9 + (0.40292553276632563925e-11 + 0.20145143075555555556e-13 * t) * t) * t) * t) * t) * t; +} +case 43: { +double t = 2*y100 - 87; +return 0.10668502059865093318e0 + (0.20965479776148731610e-2 + (0.16444612377624983565e-4 + (0.11700717962026152749e-6 + (0.74967203250938418991e-9 + (0.42783716186085922176e-11 + 0.21385479360000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 44: { +double t = 2*y100 - 89; +return 0.11094484319386444474e0 + (0.21637548491908170841e-2 + (0.17164995035719657111e-4 + (0.12317915750735938089e-6 + (0.79376309831499633734e-9 + (0.45427901763106353914e-11 + 0.22696025653333333333e-13 * t) * t) * t) * t) * t) * t; +} +case 45: { +double t = 2*y100 - 91; +return 0.11534201115268804714e0 + (0.22339187474546420375e-2 + (0.17923489217504226813e-4 + (0.12971465288245997681e-6 + (0.84057834180389073587e-9 + (0.48233721206418027227e-11 + 0.24079890062222222222e-13 * t) * t) * t) * t) * t) * t; +} +case 46: { +double t = 2*y100 - 93; +return 0.11988259392684094740e0 + (0.23071965691918689601e-2 + (0.18722342718958935446e-4 + (0.13663611754337957520e-6 + (0.89028385488493287005e-9 + (0.51210161569225846701e-11 + 0.25540227111111111111e-13 * t) * t) * t) * t) * t) * t; +} +case 47: { +double t = 2*y100 - 95; +return 0.12457298393509812907e0 + (0.23837544771809575380e-2 + (0.19563942105711612475e-4 + (0.14396736847739470782e-6 + (0.94305490646459247016e-9 + (0.54366590583134218096e-11 + 0.27080225920000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 48: { +double t = 2*y100 - 97; +return 0.12941991566142438816e0 + (0.24637684719508859484e-2 + (0.20450821127475879816e-4 + (0.15173366280523906622e-6 + (0.99907632506389027739e-9 + (0.57712760311351625221e-11 + 0.28703099555555555556e-13 * t) * t) * t) * t) * t) * t; +} +case 49: { +double t = 2*y100 - 99; +return 0.13443048593088696613e0 + (0.25474249981080823877e-2 + (0.21385669591362915223e-4 + (0.15996177579900443030e-6 + (0.10585428844575134013e-8 + (0.61258809536787882989e-11 + 0.30412080142222222222e-13 * t) * t) * t) * t) * t) * t; +} +case 50: { +double t = 2*y100 - 101; +return 0.13961217543434561353e0 + (0.26349215871051761416e-2 + (0.22371342712572567744e-4 + (0.16868008199296822247e-6 + (0.11216596910444996246e-8 + (0.65015264753090890662e-11 + 0.32210394506666666666e-13 * t) * t) * t) * t) * t) * t; +} +case 51: { +double t = 2*y100 - 103; +return 0.14497287157673800690e0 + (0.27264675383982439814e-2 + (0.23410870961050950197e-4 + (0.17791863939526376477e-6 + (0.11886425714330958106e-8 + (0.68993039665054288034e-11 + 0.34101266222222222221e-13 * t) * t) * t) * t) * t) * t; +} +case 52: { +double t = 2*y100 - 105; +return 0.15052089272774618151e0 + (0.28222846410136238008e-2 + (0.24507470422713397006e-4 + (0.18770927679626136909e-6 + (0.12597184587583370712e-8 + (0.73203433049229821618e-11 + 0.36087889048888888890e-13 * t) * t) * t) * t) * t) * t; +} +case 53: { +double t = 2*y100 - 107; +return 0.15626501395774612325e0 + (0.29226079376196624949e-2 + (0.25664553693768450545e-4 + (0.19808568415654461964e-6 + (0.13351257759815557897e-8 + (0.77658124891046760667e-11 + 0.38173420035555555555e-13 * t) * t) * t) * t) * t) * t; +} +case 54: { +double t = 2*y100 - 109; +return 0.16221449434620737567e0 + (0.30276865332726475672e-2 + (0.26885741326534564336e-4 + (0.20908350604346384143e-6 + (0.14151148144240728728e-8 + (0.82369170665974313027e-11 + 0.40360957457777777779e-13 * t) * t) * t) * t) * t) * t; +} +case 55: { +double t = 2*y100 - 111; +return 0.16837910595412130659e0 + (0.31377844510793082301e-2 + (0.28174873844911175026e-4 + (0.22074043807045782387e-6 + (0.14999481055996090039e-8 + (0.87348993661930809254e-11 + 0.42653528977777777779e-13 * t) * t) * t) * t) * t) * t; +} +case 56: { +double t = 2*y100 - 113; +return 0.17476916455659369953e0 + (0.32531815370903068316e-2 + (0.29536024347344364074e-4 + (0.23309632627767074202e-6 + (0.15899007843582444846e-8 + (0.92610375235427359475e-11 + 0.45054073102222222221e-13 * t) * t) * t) * t) * t) * t; +} +case 57: { +double t = 2*y100 - 115; +return 0.18139556223643701364e0 + (0.33741744168096996041e-2 + (0.30973511714709500836e-4 + (0.24619326937592290996e-6 + (0.16852609412267750744e-8 + (0.98166442942854895573e-11 + 0.47565418097777777779e-13 * t) * t) * t) * t) * t) * t; +} +case 58: { +double t = 2*y100 - 117; +return 0.18826980194443664549e0 + (0.35010775057740317997e-2 + (0.32491914440014267480e-4 + (0.26007572375886319028e-6 + (0.17863299617388376116e-8 + (0.10403065638343878679e-10 + 0.50190265831111111110e-13 * t) * t) * t) * t) * t) * t; +} +case 59: { +double t = 2*y100 - 119; +return 0.19540403413693967350e0 + (0.36342240767211326315e-2 + (0.34096085096200907289e-4 + (0.27479061117017637474e-6 + (0.18934228504790032826e-8 + (0.11021679075323598664e-10 + 0.52931171733333333334e-13 * t) * t) * t) * t) * t) * t; +} +case 60: { +double t = 2*y100 - 121; +return 0.20281109560651886959e0 + (0.37739673859323597060e-2 + (0.35791165457592409054e-4 + (0.29038742889416172404e-6 + (0.20068685374849001770e-8 + (0.11673891799578381999e-10 + 0.55790523093333333334e-13 * t) * t) * t) * t) * t) * t; +} +case 61: { +double t = 2*y100 - 123; +return 0.21050455062669334978e0 + (0.39206818613925652425e-2 + (0.37582602289680101704e-4 + (0.30691836231886877385e-6 + (0.21270101645763677824e-8 + (0.12361138551062899455e-10 + 0.58770520160000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 62: { +double t = 2*y100 - 125; +return 0.21849873453703332479e0 + (0.40747643554689586041e-2 + (0.39476163820986711501e-4 + (0.32443839970139918836e-6 + (0.22542053491518680200e-8 + (0.13084879235290858490e-10 + 0.61873153262222222221e-13 * t) * t) * t) * t) * t) * t; +} +case 63: { +double t = 2*y100 - 127; +return 0.22680879990043229327e0 + (0.42366354648628516935e-2 + (0.41477956909656896779e-4 + (0.34300544894502810002e-6 + (0.23888264229264067658e-8 + (0.13846596292818514601e-10 + 0.65100183751111111110e-13 * t) * t) * t) * t) * t) * t; +} +case 64: { +double t = 2*y100 - 129; +return 0.23545076536988703937e0 + (0.44067409206365170888e-2 + (0.43594444916224700881e-4 + (0.36268045617760415178e-6 + (0.25312606430853202748e-8 + (0.14647791812837903061e-10 + 0.68453122631111111110e-13 * t) * t) * t) * t) * t) * t; +} +case 65: { +double t = 2*y100 - 131; +return 0.24444156740777432838e0 + (0.45855530511605787178e-2 + (0.45832466292683085475e-4 + (0.38352752590033030472e-6 + (0.26819103733055603460e-8 + (0.15489984390884756993e-10 + 0.71933206364444444445e-13 * t) * t) * t) * t) * t) * t; +} +case 66: { +double t = 2*y100 - 133; +return 0.25379911500634264643e0 + (0.47735723208650032167e-2 + (0.48199253896534185372e-4 + (0.40561404245564732314e-6 + (0.28411932320871165585e-8 + (0.16374705736458320149e-10 + 0.75541379822222222221e-13 * t) * t) * t) * t) * t) * t; +} +case 67: { +double t = 2*y100 - 135; +return 0.26354234756393613032e0 + (0.49713289477083781266e-2 + (0.50702455036930367504e-4 + (0.42901079254268185722e-6 + (0.30095422058900481753e-8 + (0.17303497025347342498e-10 + 0.79278273368888888890e-13 * t) * t) * t) * t) * t) * t; +} +case 68: { +double t = 2*y100 - 137; +return 0.27369129607732343398e0 + (0.51793846023052643767e-2 + (0.53350152258326602629e-4 + (0.45379208848865015485e-6 + (0.31874057245814381257e-8 + (0.18277905010245111046e-10 + 0.83144182364444444445e-13 * t) * t) * t) * t) * t) * t; +} +case 69: { +double t = 2*y100 - 139; +return 0.28426714781640316172e0 + (0.53983341916695141966e-2 + (0.56150884865255810638e-4 + (0.48003589196494734238e-6 + (0.33752476967570796349e-8 + (0.19299477888083469086e-10 + 0.87139049137777777779e-13 * t) * t) * t) * t) * t) * t; +} +case 70: { +double t = 2*y100 - 141; +return 0.29529231465348519920e0 + (0.56288077305420795663e-2 + (0.59113671189913307427e-4 + (0.50782393781744840482e-6 + (0.35735475025851713168e-8 + (0.20369760937017070382e-10 + 0.91262442613333333334e-13 * t) * t) * t) * t) * t) * t; +} +case 71: { +double t = 2*y100 - 143; +return 0.30679050522528838613e0 + (0.58714723032745403331e-2 + (0.62248031602197686791e-4 + (0.53724185766200945789e-6 + (0.37827999418960232678e-8 + (0.21490291930444538307e-10 + 0.95513539182222222221e-13 * t) * t) * t) * t) * t) * t; +} +case 72: { +double t = 2*y100 - 145; +return 0.31878680111173319425e0 + (0.61270341192339103514e-2 + (0.65564012259707640976e-4 + (0.56837930287837738996e-6 + (0.40035151353392378882e-8 + (0.22662596341239294792e-10 + 0.99891109760000000000e-13 * t) * t) * t) * t) * t) * t; +} +case 73: { +double t = 2*y100 - 147; +return 0.33130773722152622027e0 + (0.63962406646798080903e-2 + (0.69072209592942396666e-4 + (0.60133006661885941812e-6 + (0.42362183765883466691e-8 + (0.23888182347073698382e-10 + 0.10439349811555555556e-12 * t) * t) * t) * t) * t) * t; +} +case 74: { +double t = 2*y100 - 149; +return 0.34438138658041336523e0 + (0.66798829540414007258e-2 + (0.72783795518603561144e-4 + (0.63619220443228800680e-6 + (0.44814499336514453364e-8 + (0.25168535651285475274e-10 + 0.10901861383111111111e-12 * t) * t) * t) * t) * t) * t; +} +case 75: { +double t = 2*y100 - 151; +return 0.35803744972380175583e0 + (0.69787978834882685031e-2 + (0.76710543371454822497e-4 + (0.67306815308917386747e-6 + (0.47397647975845228205e-8 + (0.26505114141143050509e-10 + 0.11376390933333333333e-12 * t) * t) * t) * t) * t) * t; +} +case 76: { +double t = 2*y100 - 153; +return 0.37230734890119724188e0 + (0.72938706896461381003e-2 + (0.80864854542670714092e-4 + (0.71206484718062688779e-6 + (0.50117323769745883805e-8 + (0.27899342394100074165e-10 + 0.11862637614222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 77: { +double t = 2*y100 - 155; +return 0.38722432730555448223e0 + (0.76260375162549802745e-2 + (0.85259785810004603848e-4 + (0.75329383305171327677e-6 + (0.52979361368388119355e-8 + (0.29352606054164086709e-10 + 0.12360253370666666667e-12 * t) * t) * t) * t) * t) * t; +} +case 78: { +double t = 2*y100 - 157; +return 0.40282355354616940667e0 + (0.79762880915029728079e-2 + (0.89909077342438246452e-4 + (0.79687137961956194579e-6 + (0.55989731807360403195e-8 + (0.30866246101464869050e-10 + 0.12868841946666666667e-12 * t) * t) * t) * t) * t) * t; +} +case 79: { +double t = 2*y100 - 159; +return 0.41914223158913787649e0 + (0.83456685186950463538e-2 + (0.94827181359250161335e-4 + (0.84291858561783141014e-6 + (0.59154537751083485684e-8 + (0.32441553034347469291e-10 + 0.13387957943111111111e-12 * t) * t) * t) * t) * t) * t; +} +case 80: { +double t = 2*y100 - 161; +return 0.43621971639463786896e0 + (0.87352841828289495773e-2 + (0.10002929142066799966e-3 + (0.89156148280219880024e-6 + (0.62480008150788597147e-8 + (0.34079760983458878910e-10 + 0.13917107176888888889e-12 * t) * t) * t) * t) * t) * t; +} +case 81: { +double t = 2*y100 - 163; +return 0.45409763548534330981e0 + (0.91463027755548240654e-2 + (0.10553137232446167258e-3 + (0.94293113464638623798e-6 + (0.65972492312219959885e-8 + (0.35782041795476563662e-10 + 0.14455745872000000000e-12 * t) * t) * t) * t) * t) * t; +} +case 82: { +double t = 2*y100 - 165; +return 0.47282001668512331468e0 + (0.95799574408860463394e-2 + (0.11135019058000067469e-3 + (0.99716373005509038080e-6 + (0.69638453369956970347e-8 + (0.37549499088161345850e-10 + 0.15003280712888888889e-12 * t) * t) * t) * t) * t) * t; +} +case 83: { +double t = 2*y100 - 167; +return 0.49243342227179841649e0 + (0.10037550043909497071e-1 + (0.11750334542845234952e-3 + (0.10544006716188967172e-5 + (0.73484461168242224872e-8 + (0.39383162326435752965e-10 + 0.15559069118222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 84: { +double t = 2*y100 - 169; +return 0.51298708979209258326e0 + (0.10520454564612427224e-1 + (0.12400930037494996655e-3 + (0.11147886579371265246e-5 + (0.77517184550568711454e-8 + (0.41283980931872622611e-10 + 0.16122419680000000000e-12 * t) * t) * t) * t) * t) * t; +} +case 85: { +double t = 2*y100 - 171; +return 0.53453307979101369843e0 + (0.11030120618800726938e-1 + (0.13088741519572269581e-3 + (0.11784797595374515432e-5 + (0.81743383063044825400e-8 + (0.43252818449517081051e-10 + 0.16692592640000000000e-12 * t) * t) * t) * t) * t) * t; +} +case 86: { +double t = 2*y100 - 173; +return 0.55712643071169299478e0 + (0.11568077107929735233e-1 + (0.13815797838036651289e-3 + (0.12456314879260904558e-5 + (0.86169898078969313597e-8 + (0.45290446811539652525e-10 + 0.17268801084444444444e-12 * t) * t) * t) * t) * t) * t; +} +case 87: { +double t = 2*y100 - 175; +return 0.58082532122519320968e0 + (0.12135935999503877077e-1 + (0.14584223996665838559e-3 + (0.13164068573095710742e-5 + (0.90803643355106020163e-8 + (0.47397540713124619155e-10 + 0.17850211608888888889e-12 * t) * t) * t) * t) * t) * t; +} +case 88: { +double t = 2*y100 - 177; +return 0.60569124025293375554e0 + (0.12735396239525550361e-1 + (0.15396244472258863344e-3 + (0.13909744385382818253e-5 + (0.95651595032306228245e-8 + (0.49574672127669041550e-10 + 0.18435945564444444444e-12 * t) * t) * t) * t) * t) * t; +} +case 89: { +double t = 2*y100 - 179; +return 0.63178916494715716894e0 + (0.13368247798287030927e-1 + (0.16254186562762076141e-3 + (0.14695084048334056083e-5 + (0.10072078109604152350e-7 + (0.51822304995680707483e-10 + 0.19025081422222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 90: { +double t = 2*y100 - 181; +return 0.65918774689725319200e0 + (0.14036375850601992063e-1 + (0.17160483760259706354e-3 + (0.15521885688723188371e-5 + (0.10601827031535280590e-7 + (0.54140790105837520499e-10 + 0.19616655146666666667e-12 * t) * t) * t) * t) * t) * t; +} +case 91: { +double t = 2*y100 - 183; +return 0.68795950683174433822e0 + (0.14741765091365869084e-1 + (0.18117679143520433835e-3 + (0.16392004108230585213e-5 + (0.11155116068018043001e-7 + (0.56530360194925690374e-10 + 0.20209663662222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 92: { +double t = 2*y100 - 185; +return 0.71818103808729967036e0 + (0.15486504187117112279e-1 + (0.19128428784550923217e-3 + (0.17307350969359975848e-5 + (0.11732656736113607751e-7 + (0.58991125287563833603e-10 + 0.20803065333333333333e-12 * t) * t) * t) * t) * t) * t; +} +case 93: { +double t = 2*y100 - 187; +return 0.74993321911726254661e0 + (0.16272790364044783382e-1 + (0.20195505163377912645e-3 + (0.18269894883203346953e-5 + (0.12335161021630225535e-7 + (0.61523068312169087227e-10 + 0.21395783431111111111e-12 * t) * t) * t) * t) * t) * t; +} +case 94: { +double t = 2*y100 - 189; +return 0.78330143531283492729e0 + (0.17102934132652429240e-1 + (0.21321800585063327041e-3 + (0.19281661395543913713e-5 + (0.12963340087354341574e-7 + (0.64126040998066348872e-10 + 0.21986708942222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 95: { +double t = 2*y100 - 191; +return 0.81837581041023811832e0 + (0.17979364149044223802e-1 + (0.22510330592753129006e-3 + (0.20344732868018175389e-5 + (0.13617902941839949718e-7 + (0.66799760083972474642e-10 + 0.22574701262222222222e-12 * t) * t) * t) * t) * t) * t; +} +case 96: { +double t = 2*y100 - 193; +return 0.85525144775685126237e0 + (0.18904632212547561026e-1 + (0.23764237370371255638e-3 + (0.21461248251306387979e-5 + (0.14299555071870523786e-7 + (0.69543803864694171934e-10 + 0.23158593688888888889e-12 * t) * t) * t) * t) * t) * t; +} +case 97: { +double t = 2*y100 - 195; +return 0.89402868170849933734e0 + (0.19881418399127202569e-1 + (0.25086793128395995798e-3 + (0.22633402747585233180e-5 + (0.15008997042116532283e-7 + (0.72357609075043941261e-10 + 0.23737194737777777778e-12 * t) * t) * t) * t) * t) * t; +} +case 98: { +double t = 2*y100 - 197; +return 0.93481333942870796363e0 + (0.20912536329780368893e-1 + (0.26481403465998477969e-3 + (0.23863447359754921676e-5 + (0.15746923065472184451e-7 + (0.75240468141720143653e-10 + 0.24309291271111111111e-12 * t) * t) * t) * t) * t) * t; +} +case 99: { +double t = 2*y100 - 199; +return 0.97771701335885035464e0 + (0.22000938572830479551e-1 + (0.27951610702682383001e-3 + (0.25153688325245314530e-5 + (0.16514019547822821453e-7 + (0.78191526829368231251e-10 + 0.24873652355555555556e-12 * t) * t) * t) * t) * t) * t; +} + } + // we only get here if y = 1, i.e. |x| < 4*eps, in which case + // erfcx is within 1e-15 of 1.. + return 1.0; +} + +double FADDEEVA_RE(erfcx)(double x) +{ + if (x >= 0) { + if (x > 50) { // continued-fraction expansion is faster + const double ispi = 0.56418958354775628694807945156; // 1 / sqrt(pi) + if (x > 5e7) // 1-term expansion, important to avoid overflow + return ispi / x; + /* 5-term expansion (rely on compiler for CSE), simplified from: + ispi / (x+0.5/(x+1/(x+1.5/(x+2/x)))) */ + return ispi*((x*x) * (x*x+4.5) + 2) / (x * ((x*x) * (x*x+5) + 3.75)); + } + return erfcx_y100(400/(4+x)); + } + else + return x < -26.7 ? HUGE_VAL : (x < -6.1 ? 2*exp(x*x) + : 2*exp(x*x) - erfcx_y100(400/(4-x))); +} + +///////////////////////////////////////////////////////////////////////// +/* Compute a scaled Dawson integral + FADDEEVA(w_im)(x) = 2*Dawson(x)/sqrt(pi) + equivalent to the imaginary part w(x) for real x. + + Uses methods similar to the erfcx calculation above: continued fractions + for large |x|, a lookup table of Chebyshev polynomials for smaller |x|, + and finally a Taylor expansion for |x|<0.01. + + Steven G. Johnson, October 2012. */ + +/* Given y100=100*y, where y = 1/(1+x) for x >= 0, compute w_im(x). + + Uses a look-up table of 100 different Chebyshev polynomials + for y intervals [0,0.01], [0.01,0.02], ...., [0.99,1], generated + with the help of Maple and a little shell script. This allows + the Chebyshev polynomials to be of significantly lower degree (about 1/30) + compared to fitting the whole [0,1] interval with a single polynomial. */ +static double w_im_y100(double y100, double x) { + switch ((int) y100) { + case 0: { + double t = 2*y100 - 1; + return 0.28351593328822191546e-2 + (0.28494783221378400759e-2 + (0.14427470563276734183e-4 + (0.10939723080231588129e-6 + (0.92474307943275042045e-9 + (0.89128907666450075245e-11 + 0.92974121935111111110e-13 * t) * t) * t) * t) * t) * t; + } + case 1: { + double t = 2*y100 - 3; + return 0.85927161243940350562e-2 + (0.29085312941641339862e-2 + (0.15106783707725582090e-4 + (0.11716709978531327367e-6 + (0.10197387816021040024e-8 + (0.10122678863073360769e-10 + 0.10917479678400000000e-12 * t) * t) * t) * t) * t) * t; + } + case 2: { + double t = 2*y100 - 5; + return 0.14471159831187703054e-1 + (0.29703978970263836210e-2 + (0.15835096760173030976e-4 + (0.12574803383199211596e-6 + (0.11278672159518415848e-8 + (0.11547462300333495797e-10 + 0.12894535335111111111e-12 * t) * t) * t) * t) * t) * t; + } + case 3: { + double t = 2*y100 - 7; + return 0.20476320420324610618e-1 + (0.30352843012898665856e-2 + (0.16617609387003727409e-4 + (0.13525429711163116103e-6 + (0.12515095552507169013e-8 + (0.13235687543603382345e-10 + 0.15326595042666666667e-12 * t) * t) * t) * t) * t) * t; + } + case 4: { + double t = 2*y100 - 9; + return 0.26614461952489004566e-1 + (0.31034189276234947088e-2 + (0.17460268109986214274e-4 + (0.14582130824485709573e-6 + (0.13935959083809746345e-8 + (0.15249438072998932900e-10 + 0.18344741882133333333e-12 * t) * t) * t) * t) * t) * t; + } + case 5: { + double t = 2*y100 - 11; + return 0.32892330248093586215e-1 + (0.31750557067975068584e-2 + (0.18369907582308672632e-4 + (0.15761063702089457882e-6 + (0.15577638230480894382e-8 + (0.17663868462699097951e-10 + (0.22126732680711111111e-12 + 0.30273474177737853668e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 6: { + double t = 2*y100 - 13; + return 0.39317207681134336024e-1 + (0.32504779701937539333e-2 + (0.19354426046513400534e-4 + (0.17081646971321290539e-6 + (0.17485733959327106250e-8 + (0.20593687304921961410e-10 + (0.26917401949155555556e-12 + 0.38562123837725712270e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 7: { + double t = 2*y100 - 15; + return 0.45896976511367738235e-1 + (0.33300031273110976165e-2 + (0.20423005398039037313e-4 + (0.18567412470376467303e-6 + (0.19718038363586588213e-8 + (0.24175006536781219807e-10 + (0.33059982791466666666e-12 + 0.49756574284439426165e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 8: { + double t = 2*y100 - 17; + return 0.52640192524848962855e-1 + (0.34139883358846720806e-2 + (0.21586390240603337337e-4 + (0.20247136501568904646e-6 + (0.22348696948197102935e-8 + (0.28597516301950162548e-10 + (0.41045502119111111110e-12 + 0.65151614515238361946e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 9: { + double t = 2*y100 - 19; + return 0.59556171228656770456e-1 + (0.35028374386648914444e-2 + (0.22857246150998562824e-4 + (0.22156372146525190679e-6 + (0.25474171590893813583e-8 + (0.34122390890697400584e-10 + (0.51593189879111111110e-12 + 0.86775076853908006938e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 10: { + double t = 2*y100 - 21; + return 0.66655089485108212551e-1 + (0.35970095381271285568e-2 + (0.24250626164318672928e-4 + (0.24339561521785040536e-6 + (0.29221990406518411415e-8 + (0.41117013527967776467e-10 + (0.65786450716444444445e-12 + 0.11791885745450623331e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 11: { + double t = 2*y100 - 23; + return 0.73948106345519174661e-1 + (0.36970297216569341748e-2 + (0.25784588137312868792e-4 + (0.26853012002366752770e-6 + (0.33763958861206729592e-8 + (0.50111549981376976397e-10 + (0.85313857496888888890e-12 + 0.16417079927706899860e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 12: { + double t = 2*y100 - 25; + return 0.81447508065002963203e-1 + (0.38035026606492705117e-2 + (0.27481027572231851896e-4 + (0.29769200731832331364e-6 + (0.39336816287457655076e-8 + (0.61895471132038157624e-10 + (0.11292303213511111111e-11 + 0.23558532213703884304e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 13: { + double t = 2*y100 - 27; + return 0.89166884027582716628e-1 + (0.39171301322438946014e-2 + (0.29366827260422311668e-4 + (0.33183204390350724895e-6 + (0.46276006281647330524e-8 + (0.77692631378169813324e-10 + (0.15335153258844444444e-11 + 0.35183103415916026911e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 14: { + double t = 2*y100 - 29; + return 0.97121342888032322019e-1 + (0.40387340353207909514e-2 + (0.31475490395950776930e-4 + (0.37222714227125135042e-6 + (0.55074373178613809996e-8 + (0.99509175283990337944e-10 + (0.21552645758222222222e-11 + 0.55728651431872687605e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 15: { + double t = 2*y100 - 31; + return 0.10532778218603311137e0 + (0.41692873614065380607e-2 + (0.33849549774889456984e-4 + (0.42064596193692630143e-6 + (0.66494579697622432987e-8 + (0.13094103581931802337e-9 + (0.31896187409777777778e-11 + 0.97271974184476560742e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 16: { + double t = 2*y100 - 33; + return 0.11380523107427108222e0 + (0.43099572287871821013e-2 + (0.36544324341565929930e-4 + (0.47965044028581857764e-6 + (0.81819034238463698796e-8 + (0.17934133239549647357e-9 + (0.50956666166186293627e-11 + (0.18850487318190638010e-12 + 0.79697813173519853340e-14 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 17: { + double t = 2*y100 - 35; + return 0.12257529703447467345e0 + (0.44621675710026986366e-2 + (0.39634304721292440285e-4 + (0.55321553769873381819e-6 + (0.10343619428848520870e-7 + (0.26033830170470368088e-9 + (0.87743837749108025357e-11 + (0.34427092430230063401e-12 + 0.10205506615709843189e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 18: { + double t = 2*y100 - 37; + return 0.13166276955656699478e0 + (0.46276970481783001803e-2 + (0.43225026380496399310e-4 + (0.64799164020016902656e-6 + (0.13580082794704641782e-7 + (0.39839800853954313927e-9 + (0.14431142411840000000e-10 + 0.42193457308830027541e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 19: { + double t = 2*y100 - 39; + return 0.14109647869803356475e0 + (0.48088424418545347758e-2 + (0.47474504753352150205e-4 + (0.77509866468724360352e-6 + (0.18536851570794291724e-7 + (0.60146623257887570439e-9 + (0.18533978397305276318e-10 + (0.41033845938901048380e-13 - 0.46160680279304825485e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 20: { + double t = 2*y100 - 41; + return 0.15091057940548936603e0 + (0.50086864672004685703e-2 + (0.52622482832192230762e-4 + (0.95034664722040355212e-6 + (0.25614261331144718769e-7 + (0.80183196716888606252e-9 + (0.12282524750534352272e-10 + (-0.10531774117332273617e-11 - 0.86157181395039646412e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 21: { + double t = 2*y100 - 43; + return 0.16114648116017010770e0 + (0.52314661581655369795e-2 + (0.59005534545908331315e-4 + (0.11885518333915387760e-5 + (0.33975801443239949256e-7 + (0.82111547144080388610e-9 + (-0.12357674017312854138e-10 + (-0.24355112256914479176e-11 - 0.75155506863572930844e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 22: { + double t = 2*y100 - 45; + return 0.17185551279680451144e0 + (0.54829002967599420860e-2 + (0.67013226658738082118e-4 + (0.14897400671425088807e-5 + (0.40690283917126153701e-7 + (0.44060872913473778318e-9 + (-0.52641873433280000000e-10 - 0.30940587864543343124e-11 * t) * t) * t) * t) * t) * t) * t; + } + case 23: { + double t = 2*y100 - 47; + return 0.18310194559815257381e0 + (0.57701559375966953174e-2 + (0.76948789401735193483e-4 + (0.18227569842290822512e-5 + (0.41092208344387212276e-7 + (-0.44009499965694442143e-9 + (-0.92195414685628803451e-10 + (-0.22657389705721753299e-11 + 0.10004784908106839254e-12 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 24: { + double t = 2*y100 - 49; + return 0.19496527191546630345e0 + (0.61010853144364724856e-2 + (0.88812881056342004864e-4 + (0.21180686746360261031e-5 + (0.30652145555130049203e-7 + (-0.16841328574105890409e-8 + (-0.11008129460612823934e-9 + (-0.12180794204544515779e-12 + 0.15703325634590334097e-12 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 25: { + double t = 2*y100 - 51; + return 0.20754006813966575720e0 + (0.64825787724922073908e-2 + (0.10209599627522311893e-3 + (0.22785233392557600468e-5 + (0.73495224449907568402e-8 + (-0.29442705974150112783e-8 + (-0.94082603434315016546e-10 + (0.23609990400179321267e-11 + 0.14141908654269023788e-12 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 26: { + double t = 2*y100 - 53; + return 0.22093185554845172146e0 + (0.69182878150187964499e-2 + (0.11568723331156335712e-3 + (0.22060577946323627739e-5 + (-0.26929730679360840096e-7 + (-0.38176506152362058013e-8 + (-0.47399503861054459243e-10 + (0.40953700187172127264e-11 + 0.69157730376118511127e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 27: { + double t = 2*y100 - 55; + return 0.23524827304057813918e0 + (0.74063350762008734520e-2 + (0.12796333874615790348e-3 + (0.18327267316171054273e-5 + (-0.66742910737957100098e-7 + (-0.40204740975496797870e-8 + (0.14515984139495745330e-10 + (0.44921608954536047975e-11 - 0.18583341338983776219e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 28: { + double t = 2*y100 - 57; + return 0.25058626331812744775e0 + (0.79377285151602061328e-2 + (0.13704268650417478346e-3 + (0.11427511739544695861e-5 + (-0.10485442447768377485e-6 + (-0.34850364756499369763e-8 + (0.72656453829502179208e-10 + (0.36195460197779299406e-11 - 0.84882136022200714710e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 29: { + double t = 2*y100 - 59; + return 0.26701724900280689785e0 + (0.84959936119625864274e-2 + (0.14112359443938883232e-3 + (0.17800427288596909634e-6 + (-0.13443492107643109071e-6 + (-0.23512456315677680293e-8 + (0.11245846264695936769e-9 + (0.19850501334649565404e-11 - 0.11284666134635050832e-12 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 30: { + double t = 2*y100 - 61; + return 0.28457293586253654144e0 + (0.90581563892650431899e-2 + (0.13880520331140646738e-3 + (-0.97262302362522896157e-6 + (-0.15077100040254187366e-6 + (-0.88574317464577116689e-9 + (0.12760311125637474581e-9 + (0.20155151018282695055e-12 - 0.10514169375181734921e-12 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 31: { + double t = 2*y100 - 63; + return 0.30323425595617385705e0 + (0.95968346790597422934e-2 + (0.12931067776725883939e-3 + (-0.21938741702795543986e-5 + (-0.15202888584907373963e-6 + (0.61788350541116331411e-9 + (0.11957835742791248256e-9 + (-0.12598179834007710908e-11 - 0.75151817129574614194e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 32: { + double t = 2*y100 - 65; + return 0.32292521181517384379e0 + (0.10082957727001199408e-1 + (0.11257589426154962226e-3 + (-0.33670890319327881129e-5 + (-0.13910529040004008158e-6 + (0.19170714373047512945e-8 + (0.94840222377720494290e-10 + (-0.21650018351795353201e-11 - 0.37875211678024922689e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 33: { + double t = 2*y100 - 67; + return 0.34351233557911753862e0 + (0.10488575435572745309e-1 + (0.89209444197248726614e-4 + (-0.43893459576483345364e-5 + (-0.11488595830450424419e-6 + (0.28599494117122464806e-8 + (0.61537542799857777779e-10 - 0.24935749227658002212e-11 * t) * t) * t) * t) * t) * t) * t; + } + case 34: { + double t = 2*y100 - 69; + return 0.36480946642143669093e0 + (0.10789304203431861366e-1 + (0.60357993745283076834e-4 + (-0.51855862174130669389e-5 + (-0.83291664087289801313e-7 + (0.33898011178582671546e-8 + (0.27082948188277716482e-10 + (-0.23603379397408694974e-11 + 0.19328087692252869842e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 35: { + double t = 2*y100 - 71; + return 0.38658679935694939199e0 + (0.10966119158288804999e-1 + (0.27521612041849561426e-4 + (-0.57132774537670953638e-5 + (-0.48404772799207914899e-7 + (0.35268354132474570493e-8 + (-0.32383477652514618094e-11 + (-0.19334202915190442501e-11 + 0.32333189861286460270e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 36: { + double t = 2*y100 - 73; + return 0.40858275583808707870e0 + (0.11006378016848466550e-1 + (-0.76396376685213286033e-5 + (-0.59609835484245791439e-5 + (-0.13834610033859313213e-7 + (0.33406952974861448790e-8 + (-0.26474915974296612559e-10 + (-0.13750229270354351983e-11 + 0.36169366979417390637e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 37: { + double t = 2*y100 - 75; + return 0.43051714914006682977e0 + (0.10904106549500816155e-1 + (-0.43477527256787216909e-4 + (-0.59429739547798343948e-5 + (0.17639200194091885949e-7 + (0.29235991689639918688e-8 + (-0.41718791216277812879e-10 + (-0.81023337739508049606e-12 + 0.33618915934461994428e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 38: { + double t = 2*y100 - 77; + return 0.45210428135559607406e0 + (0.10659670756384400554e-1 + (-0.78488639913256978087e-4 + (-0.56919860886214735936e-5 + (0.44181850467477733407e-7 + (0.23694306174312688151e-8 + (-0.49492621596685443247e-10 + (-0.31827275712126287222e-12 + 0.27494438742721623654e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 39: { + double t = 2*y100 - 79; + return 0.47306491195005224077e0 + (0.10279006119745977570e-1 + (-0.11140268171830478306e-3 + (-0.52518035247451432069e-5 + (0.64846898158889479518e-7 + (0.17603624837787337662e-8 + (-0.51129481592926104316e-10 + (0.62674584974141049511e-13 + 0.20055478560829935356e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 40: { + double t = 2*y100 - 81; + return 0.49313638965719857647e0 + (0.97725799114772017662e-2 + (-0.14122854267291533334e-3 + (-0.46707252568834951907e-5 + (0.79421347979319449524e-7 + (0.11603027184324708643e-8 + (-0.48269605844397175946e-10 + (0.32477251431748571219e-12 + 0.12831052634143527985e-13 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 41: { + double t = 2*y100 - 83; + return 0.51208057433416004042e0 + (0.91542422354009224951e-2 + (-0.16726530230228647275e-3 + (-0.39964621752527649409e-5 + (0.88232252903213171454e-7 + (0.61343113364949928501e-9 + (-0.42516755603130443051e-10 + (0.47910437172240209262e-12 + 0.66784341874437478953e-14 * t) * t) * t) * t) * t) * t) * t) * t; + } + case 42: { + double t = 2*y100 - 85; + return 0.52968945458607484524e0 + (0.84400880445116786088e-2 + (-0.18908729783854258774e-3 + (-0.32725905467782951931e-5 + (0.91956190588652090659e-7 + (0.14593989152420122909e-9 + (-0.35239490687644444445e-10 + 0.54613829888448694898e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 43: { + double t = 2*y100 - 87; + return 0.54578857454330070965e0 + (0.76474155195880295311e-2 + (-0.20651230590808213884e-3 + (-0.25364339140543131706e-5 + (0.91455367999510681979e-7 + (-0.23061359005297528898e-9 + (-0.27512928625244444444e-10 + 0.54895806008493285579e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 44: { + double t = 2*y100 - 89; + return 0.56023851910298493910e0 + (0.67938321739997196804e-2 + (-0.21956066613331411760e-3 + (-0.18181127670443266395e-5 + (0.87650335075416845987e-7 + (-0.51548062050366615977e-9 + (-0.20068462174044444444e-10 + 0.50912654909758187264e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 45: { + double t = 2*y100 - 91; + return 0.57293478057455721150e0 + (0.58965321010394044087e-2 + (-0.22841145229276575597e-3 + (-0.11404605562013443659e-5 + (0.81430290992322326296e-7 + (-0.71512447242755357629e-9 + (-0.13372664928000000000e-10 + 0.44461498336689298148e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 46: { + double t = 2*y100 - 93; + return 0.58380635448407827360e0 + (0.49717469530842831182e-2 + (-0.23336001540009645365e-3 + (-0.51952064448608850822e-6 + (0.73596577815411080511e-7 + (-0.84020916763091566035e-9 + (-0.76700972702222222221e-11 + 0.36914462807972467044e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 47: { + double t = 2*y100 - 95; + return 0.59281340237769489597e0 + (0.40343592069379730568e-2 + (-0.23477963738658326185e-3 + (0.34615944987790224234e-7 + (0.64832803248395814574e-7 + (-0.90329163587627007971e-9 + (-0.30421940400000000000e-11 + 0.29237386653743536669e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 48: { + double t = 2*y100 - 97; + return 0.59994428743114271918e0 + (0.30976579788271744329e-2 + (-0.23308875765700082835e-3 + (0.51681681023846925160e-6 + (0.55694594264948268169e-7 + (-0.91719117313243464652e-9 + (0.53982743680000000000e-12 + 0.22050829296187771142e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 49: { + double t = 2*y100 - 99; + return 0.60521224471819875444e0 + (0.21732138012345456060e-2 + (-0.22872428969625997456e-3 + (0.92588959922653404233e-6 + (0.46612665806531930684e-7 + (-0.89393722514414153351e-9 + (0.31718550353777777778e-11 + 0.15705458816080549117e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 50: { + double t = 2*y100 - 101; + return 0.60865189969791123620e0 + (0.12708480848877451719e-2 + (-0.22212090111534847166e-3 + (0.12636236031532793467e-5 + (0.37904037100232937574e-7 + (-0.84417089968101223519e-9 + (0.49843180828444444445e-11 + 0.10355439441049048273e-12 * t) * t) * t) * t) * t) * t) * t; + } + case 51: { + double t = 2*y100 - 103; + return 0.61031580103499200191e0 + (0.39867436055861038223e-3 + (-0.21369573439579869291e-3 + (0.15339402129026183670e-5 + (0.29787479206646594442e-7 + (-0.77687792914228632974e-9 + (0.61192452741333333334e-11 + 0.60216691829459295780e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 52: { + double t = 2*y100 - 105; + return 0.61027109047879835868e0 + (-0.43680904508059878254e-3 + (-0.20383783788303894442e-3 + (0.17421743090883439959e-5 + (0.22400425572175715576e-7 + (-0.69934719320045128997e-9 + (0.67152759655111111110e-11 + 0.26419960042578359995e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 53: { + double t = 2*y100 - 107; + return 0.60859639489217430521e0 + (-0.12305921390962936873e-2 + (-0.19290150253894682629e-3 + (0.18944904654478310128e-5 + (0.15815530398618149110e-7 + (-0.61726850580964876070e-9 + 0.68987888999111111110e-11 * t) * t) * t) * t) * t) * t; + } + case 54: { + double t = 2*y100 - 109; + return 0.60537899426486075181e0 + (-0.19790062241395705751e-2 + (-0.18120271393047062253e-3 + (0.19974264162313241405e-5 + (0.10055795094298172492e-7 + (-0.53491997919318263593e-9 + (0.67794550295111111110e-11 - 0.17059208095741511603e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 55: { + double t = 2*y100 - 111; + return 0.60071229457904110537e0 + (-0.26795676776166354354e-2 + (-0.16901799553627508781e-3 + (0.20575498324332621581e-5 + (0.51077165074461745053e-8 + (-0.45536079828057221858e-9 + (0.64488005516444444445e-11 - 0.29311677573152766338e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 56: { + double t = 2*y100 - 113; + return 0.59469361520112714738e0 + (-0.33308208190600993470e-2 + (-0.15658501295912405679e-3 + (0.20812116912895417272e-5 + (0.93227468760614182021e-9 + (-0.38066673740116080415e-9 + (0.59806790359111111110e-11 - 0.36887077278950440597e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 57: { + double t = 2*y100 - 115; + return 0.58742228631775388268e0 + (-0.39321858196059227251e-2 + (-0.14410441141450122535e-3 + (0.20743790018404020716e-5 + (-0.25261903811221913762e-8 + (-0.31212416519526924318e-9 + (0.54328422462222222221e-11 - 0.40864152484979815972e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 58: { + double t = 2*y100 - 117; + return 0.57899804200033018447e0 + (-0.44838157005618913447e-2 + (-0.13174245966501437965e-3 + (0.20425306888294362674e-5 + (-0.53330296023875447782e-8 + (-0.25041289435539821014e-9 + (0.48490437205333333334e-11 - 0.42162206939169045177e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 59: { + double t = 2*y100 - 119; + return 0.56951968796931245974e0 + (-0.49864649488074868952e-2 + (-0.11963416583477567125e-3 + (0.19906021780991036425e-5 + (-0.75580140299436494248e-8 + (-0.19576060961919820491e-9 + (0.42613011928888888890e-11 - 0.41539443304115604377e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 60: { + double t = 2*y100 - 121; + return 0.55908401930063918964e0 + (-0.54413711036826877753e-2 + (-0.10788661102511914628e-3 + (0.19229663322982839331e-5 + (-0.92714731195118129616e-8 + (-0.14807038677197394186e-9 + (0.36920870298666666666e-11 - 0.39603726688419162617e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 61: { + double t = 2*y100 - 123; + return 0.54778496152925675315e0 + (-0.58501497933213396670e-2 + (-0.96582314317855227421e-4 + (0.18434405235069270228e-5 + (-0.10541580254317078711e-7 + (-0.10702303407788943498e-9 + (0.31563175582222222222e-11 - 0.36829748079110481422e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 62: { + double t = 2*y100 - 125; + return 0.53571290831682823999e0 + (-0.62147030670760791791e-2 + (-0.85782497917111760790e-4 + (0.17553116363443470478e-5 + (-0.11432547349815541084e-7 + (-0.72157091369041330520e-10 + (0.26630811607111111111e-11 - 0.33578660425893164084e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 63: { + double t = 2*y100 - 127; + return 0.52295422962048434978e0 + (-0.65371404367776320720e-2 + (-0.75530164941473343780e-4 + (0.16613725797181276790e-5 + (-0.12003521296598910761e-7 + (-0.42929753689181106171e-10 + (0.22170894940444444444e-11 - 0.30117697501065110505e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 64: { + double t = 2*y100 - 129; + return 0.50959092577577886140e0 + (-0.68197117603118591766e-2 + (-0.65852936198953623307e-4 + (0.15639654113906716939e-5 + (-0.12308007991056524902e-7 + (-0.18761997536910939570e-10 + (0.18198628922666666667e-11 - 0.26638355362285200932e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 65: { + double t = 2*y100 - 131; + return 0.49570040481823167970e0 + (-0.70647509397614398066e-2 + (-0.56765617728962588218e-4 + (0.14650274449141448497e-5 + (-0.12393681471984051132e-7 + (0.92904351801168955424e-12 + (0.14706755960177777778e-11 - 0.23272455351266325318e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 66: { + double t = 2*y100 - 133; + return 0.48135536250935238066e0 + (-0.72746293327402359783e-2 + (-0.48272489495730030780e-4 + (0.13661377309113939689e-5 + (-0.12302464447599382189e-7 + (0.16707760028737074907e-10 + (0.11672928324444444444e-11 - 0.20105801424709924499e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 67: { + double t = 2*y100 - 135; + return 0.46662374675511439448e0 + (-0.74517177649528487002e-2 + (-0.40369318744279128718e-4 + (0.12685621118898535407e-5 + (-0.12070791463315156250e-7 + (0.29105507892605823871e-10 + (0.90653314645333333334e-12 - 0.17189503312102982646e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 68: { + double t = 2*y100 - 137; + return 0.45156879030168268778e0 + (-0.75983560650033817497e-2 + (-0.33045110380705139759e-4 + (0.11732956732035040896e-5 + (-0.11729986947158201869e-7 + (0.38611905704166441308e-10 + (0.68468768305777777779e-12 - 0.14549134330396754575e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 69: { + double t = 2*y100 - 139; + return 0.43624909769330896904e0 + (-0.77168291040309554679e-2 + (-0.26283612321339907756e-4 + (0.10811018836893550820e-5 + (-0.11306707563739851552e-7 + (0.45670446788529607380e-10 + (0.49782492549333333334e-12 - 0.12191983967561779442e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 70: { + double t = 2*y100 - 141; + return 0.42071877443548481181e0 + (-0.78093484015052730097e-2 + (-0.20064596897224934705e-4 + (0.99254806680671890766e-6 + (-0.10823412088884741451e-7 + (0.50677203326904716247e-10 + (0.34200547594666666666e-12 - 0.10112698698356194618e-13 * t) * t) * t) * t) * t) * t) * t; + } + case 71: { + double t = 2*y100 - 143; + return 0.40502758809710844280e0 + (-0.78780384460872937555e-2 + (-0.14364940764532853112e-4 + (0.90803709228265217384e-6 + (-0.10298832847014466907e-7 + (0.53981671221969478551e-10 + (0.21342751381333333333e-12 - 0.82975901848387729274e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 72: { + double t = 2*y100 - 145; + return 0.38922115269731446690e0 + (-0.79249269708242064120e-2 + (-0.91595258799106970453e-5 + (0.82783535102217576495e-6 + (-0.97484311059617744437e-8 + (0.55889029041660225629e-10 + (0.10851981336888888889e-12 - 0.67278553237853459757e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 73: { + double t = 2*y100 - 147; + return 0.37334112915460307335e0 + (-0.79519385109223148791e-2 + (-0.44219833548840469752e-5 + (0.75209719038240314732e-6 + (-0.91848251458553190451e-8 + (0.56663266668051433844e-10 + (0.23995894257777777778e-13 - 0.53819475285389344313e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 74: { + double t = 2*y100 - 149; + return 0.35742543583374223085e0 + (-0.79608906571527956177e-2 + (-0.12530071050975781198e-6 + (0.68088605744900552505e-6 + (-0.86181844090844164075e-8 + (0.56530784203816176153e-10 + (-0.43120012248888888890e-13 - 0.42372603392496813810e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 75: { + double t = 2*y100 - 151; + return 0.34150846431979618536e0 + (-0.79534924968773806029e-2 + (0.37576885610891515813e-5 + (0.61419263633090524326e-6 + (-0.80565865409945960125e-8 + (0.55684175248749269411e-10 + (-0.95486860764444444445e-13 - 0.32712946432984510595e-14 * t) * t) * t) * t) * t) * t) * t; + } + case 76: { + double t = 2*y100 - 153; + return 0.32562129649136346824e0 + (-0.79313448067948884309e-2 + (0.72539159933545300034e-5 + (0.55195028297415503083e-6 + (-0.75063365335570475258e-8 + (0.54281686749699595941e-10 - 0.13545424295111111111e-12 * t) * t) * t) * t) * t) * t; + } + case 77: { + double t = 2*y100 - 155; + return 0.30979191977078391864e0 + (-0.78959416264207333695e-2 + (0.10389774377677210794e-4 + (0.49404804463196316464e-6 + (-0.69722488229411164685e-8 + (0.52469254655951393842e-10 - 0.16507860650666666667e-12 * t) * t) * t) * t) * t) * t; + } + case 78: { + double t = 2*y100 - 157; + return 0.29404543811214459904e0 + (-0.78486728990364155356e-2 + (0.13190885683106990459e-4 + (0.44034158861387909694e-6 + (-0.64578942561562616481e-8 + (0.50354306498006928984e-10 - 0.18614473550222222222e-12 * t) * t) * t) * t) * t) * t; + } + case 79: { + double t = 2*y100 - 159; + return 0.27840427686253660515e0 + (-0.77908279176252742013e-2 + (0.15681928798708548349e-4 + (0.39066226205099807573e-6 + (-0.59658144820660420814e-8 + (0.48030086420373141763e-10 - 0.20018995173333333333e-12 * t) * t) * t) * t) * t) * t; + } + case 80: { + double t = 2*y100 - 161; + return 0.26288838011163800908e0 + (-0.77235993576119469018e-2 + (0.17886516796198660969e-4 + (0.34482457073472497720e-6 + (-0.54977066551955420066e-8 + (0.45572749379147269213e-10 - 0.20852924954666666667e-12 * t) * t) * t) * t) * t) * t; + } + case 81: { + double t = 2*y100 - 163; + return 0.24751539954181029717e0 + (-0.76480877165290370975e-2 + (0.19827114835033977049e-4 + (0.30263228619976332110e-6 + (-0.50545814570120129947e-8 + (0.43043879374212005966e-10 - 0.21228012028444444444e-12 * t) * t) * t) * t) * t) * t; + } + case 82: { + double t = 2*y100 - 165; + return 0.23230087411688914593e0 + (-0.75653060136384041587e-2 + (0.21524991113020016415e-4 + (0.26388338542539382413e-6 + (-0.46368974069671446622e-8 + (0.40492715758206515307e-10 - 0.21238627815111111111e-12 * t) * t) * t) * t) * t) * t; + } + case 83: { + double t = 2*y100 - 167; + return 0.21725840021297341931e0 + (-0.74761846305979730439e-2 + (0.23000194404129495243e-4 + (0.22837400135642906796e-6 + (-0.42446743058417541277e-8 + (0.37958104071765923728e-10 - 0.20963978568888888889e-12 * t) * t) * t) * t) * t) * t; + } + case 84: { + double t = 2*y100 - 169; + return 0.20239979200788191491e0 + (-0.73815761980493466516e-2 + (0.24271552727631854013e-4 + (0.19590154043390012843e-6 + (-0.38775884642456551753e-8 + (0.35470192372162901168e-10 - 0.20470131678222222222e-12 * t) * t) * t) * t) * t) * t; + } + case 85: { + double t = 2*y100 - 171; + return 0.18773523211558098962e0 + (-0.72822604530339834448e-2 + (0.25356688567841293697e-4 + (0.16626710297744290016e-6 + (-0.35350521468015310830e-8 + (0.33051896213898864306e-10 - 0.19811844544000000000e-12 * t) * t) * t) * t) * t) * t; + } + case 86: { + double t = 2*y100 - 173; + return 0.17327341258479649442e0 + (-0.71789490089142761950e-2 + (0.26272046822383820476e-4 + (0.13927732375657362345e-6 + (-0.32162794266956859603e-8 + (0.30720156036105652035e-10 - 0.19034196304000000000e-12 * t) * t) * t) * t) * t) * t; + } + case 87: { + double t = 2*y100 - 175; + return 0.15902166648328672043e0 + (-0.70722899934245504034e-2 + (0.27032932310132226025e-4 + (0.11474573347816568279e-6 + (-0.29203404091754665063e-8 + (0.28487010262547971859e-10 - 0.18174029063111111111e-12 * t) * t) * t) * t) * t) * t; + } + case 88: { + double t = 2*y100 - 177; + return 0.14498609036610283865e0 + (-0.69628725220045029273e-2 + (0.27653554229160596221e-4 + (0.92493727167393036470e-7 + (-0.26462055548683583849e-8 + (0.26360506250989943739e-10 - 0.17261211260444444444e-12 * t) * t) * t) * t) * t) * t; + } + case 89: { + double t = 2*y100 - 179; + return 0.13117165798208050667e0 + (-0.68512309830281084723e-2 + (0.28147075431133863774e-4 + (0.72351212437979583441e-7 + (-0.23927816200314358570e-8 + (0.24345469651209833155e-10 - 0.16319736960000000000e-12 * t) * t) * t) * t) * t) * t; + } + case 90: { + double t = 2*y100 - 181; + return 0.11758232561160626306e0 + (-0.67378491192463392927e-2 + (0.28525664781722907847e-4 + (0.54156999310046790024e-7 + (-0.21589405340123827823e-8 + (0.22444150951727334619e-10 - 0.15368675584000000000e-12 * t) * t) * t) * t) * t) * t; + } + case 91: { + double t = 2*y100 - 183; + return 0.10422112945361673560e0 + (-0.66231638959845581564e-2 + (0.28800551216363918088e-4 + (0.37758983397952149613e-7 + (-0.19435423557038933431e-8 + (0.20656766125421362458e-10 - 0.14422990012444444444e-12 * t) * t) * t) * t) * t) * t; + } + case 92: { + double t = 2*y100 - 185; + return 0.91090275493541084785e-1 + (-0.65075691516115160062e-2 + (0.28982078385527224867e-4 + (0.23014165807643012781e-7 + (-0.17454532910249875958e-8 + (0.18981946442680092373e-10 - 0.13494234691555555556e-12 * t) * t) * t) * t) * t) * t; + } + case 93: { + double t = 2*y100 - 187; + return 0.78191222288771379358e-1 + (-0.63914190297303976434e-2 + (0.29079759021299682675e-4 + (0.97885458059415717014e-8 + (-0.15635596116134296819e-8 + (0.17417110744051331974e-10 - 0.12591151763555555556e-12 * t) * t) * t) * t) * t) * t; + } + case 94: { + double t = 2*y100 - 189; + return 0.65524757106147402224e-1 + (-0.62750311956082444159e-2 + (0.29102328354323449795e-4 + (-0.20430838882727954582e-8 + (-0.13967781903855367270e-8 + (0.15958771833747057569e-10 - 0.11720175765333333333e-12 * t) * t) * t) * t) * t) * t; + } + case 95: { + double t = 2*y100 - 191; + return 0.53091065838453612773e-1 + (-0.61586898417077043662e-2 + (0.29057796072960100710e-4 + (-0.12597414620517987536e-7 + (-0.12440642607426861943e-8 + (0.14602787128447932137e-10 - 0.10885859114666666667e-12 * t) * t) * t) * t) * t) * t; + } + case 96: { + double t = 2*y100 - 193; + return 0.40889797115352738582e-1 + (-0.60426484889413678200e-2 + (0.28953496450191694606e-4 + (-0.21982952021823718400e-7 + (-0.11044169117553026211e-8 + (0.13344562332430552171e-10 - 0.10091231402844444444e-12 * t) * t) * t) * t) * t) * t; + } + case 97: case 98: + case 99: case 100: { // use Taylor expansion for small x (|x| <= 0.0309...) + // (2/sqrt(pi)) * (x - 2/3 x^3 + 4/15 x^5 - 8/105 x^7 + 16/945 x^9) + double x2 = x*x; + return x * (1.1283791670955125739 + - x2 * (0.75225277806367504925 + - x2 * (0.30090111122547001970 + - x2 * (0.085971746064420005629 + - x2 * 0.016931216931216931217)))); + } + } + /* Since 0 <= y100 < 101, this is only reached if x is NaN, + in which case we should return NaN. */ + return NaN; +} + +double FADDEEVA(w_im)(double x) +{ + if (x >= 0) { + if (x > 45) { // continued-fraction expansion is faster + const double ispi = 0.56418958354775628694807945156; // 1 / sqrt(pi) + if (x > 5e7) // 1-term expansion, important to avoid overflow + return ispi / x; + /* 5-term expansion (rely on compiler for CSE), simplified from: + ispi / (x-0.5/(x-1/(x-1.5/(x-2/x)))) */ + return ispi*((x*x) * (x*x-4.5) + 2) / (x * ((x*x) * (x*x-5) + 3.75)); + } + return w_im_y100(100/(1+x), x); + } + else { // = -FADDEEVA(w_im)(-x) + if (x < -45) { // continued-fraction expansion is faster + const double ispi = 0.56418958354775628694807945156; // 1 / sqrt(pi) + if (x < -5e7) // 1-term expansion, important to avoid overflow + return ispi / x; + /* 5-term expansion (rely on compiler for CSE), simplified from: + ispi / (x-0.5/(x-1/(x-1.5/(x-2/x)))) */ + return ispi*((x*x) * (x*x-4.5) + 2) / (x * ((x*x) * (x*x-5) + 3.75)); + } + return -w_im_y100(100/(1-x), -x); + } +} + +///////////////////////////////////////////////////////////////////////// + +// Compile with -DTEST_FADDEEVA to compile a little test program +#ifdef TEST_FADDEEVA + +#ifdef __cplusplus +# include +#else +# include +#endif + +// compute relative error |b-a|/|a|, handling case of NaN and Inf, +static double relerr(double a, double b) { + if (isnan(a) || isnan(b) || isinf(a) || isinf(b)) { + if ((isnan(a) && !isnan(b)) || (!isnan(a) && isnan(b)) || + (isinf(a) && !isinf(b)) || (!isinf(a) && isinf(b)) || + (isinf(a) && isinf(b) && a*b < 0)) + return Inf; // "infinite" error + return 0; // matching infinity/nan results counted as zero error + } + if (a == 0) + return b == 0 ? 0 : Inf; + else + return fabs((b-a) / a); +} + +int main(void) { + double errmax_all = 0; + { + printf("############# w(z) tests #############\n"); +#define NTST 57 // define instead of const for C compatibility + cmplx z[NTST] = { + C(624.2,-0.26123), + C(-0.4,3.), + C(0.6,2.), + C(-1.,1.), + C(-1.,-9.), + C(-1.,9.), + C(-0.0000000234545,1.1234), + C(-3.,5.1), + C(-53,30.1), + C(0.0,0.12345), + C(11,1), + C(-22,-2), + C(9,-28), + C(21,-33), + C(1e5,1e5), + C(1e14,1e14), + C(-3001,-1000), + C(1e160,-1e159), + C(-6.01,0.01), + C(-0.7,-0.7), + C(2.611780000000000e+01, 4.540909610972489e+03), + C(0.8e7,0.3e7), + C(-20,-19.8081), + C(1e-16,-1.1e-16), + C(2.3e-8,1.3e-8), + C(6.3,-1e-13), + C(6.3,1e-20), + C(1e-20,6.3), + C(1e-20,16.3), + C(9,1e-300), + C(6.01,0.11), + C(8.01,1.01e-10), + C(28.01,1e-300), + C(10.01,1e-200), + C(10.01,-1e-200), + C(10.01,0.99e-10), + C(10.01,-0.99e-10), + C(1e-20,7.01), + C(-1,7.01), + C(5.99,7.01), + C(1,0), + C(55,0), + C(-0.1,0), + C(1e-20,0), + C(0,5e-14), + C(0,51), + C(Inf,0), + C(-Inf,0), + C(0,Inf), + C(0,-Inf), + C(Inf,Inf), + C(Inf,-Inf), + C(NaN,NaN), + C(NaN,0), + C(0,NaN), + C(NaN,Inf), + C(Inf,NaN) + }; + cmplx w[NTST] = { /* w(z), computed with WolframAlpha + ... note that WolframAlpha is problematic + some of the above inputs, so I had to + use the continued-fraction expansion + in WolframAlpha in some cases, or switch + to Maple */ + C(-3.78270245518980507452677445620103199303131110e-7, + 0.000903861276433172057331093754199933411710053155), + C(0.1764906227004816847297495349730234591778719532788, + -0.02146550539468457616788719893991501311573031095617), + C(0.2410250715772692146133539023007113781272362309451, + 0.06087579663428089745895459735240964093522265589350), + C(0.30474420525691259245713884106959496013413834051768, + -0.20821893820283162728743734725471561394145872072738), + C(7.317131068972378096865595229600561710140617977e34, + 8.321873499714402777186848353320412813066170427e34), + C(0.0615698507236323685519612934241429530190806818395, + -0.00676005783716575013073036218018565206070072304635), + C(0.3960793007699874918961319170187598400134746631, + -5.593152259116644920546186222529802777409274656e-9), + C(0.08217199226739447943295069917990417630675021771804, + -0.04701291087643609891018366143118110965272615832184), + C(0.00457246000350281640952328010227885008541748668738, + -0.00804900791411691821818731763401840373998654987934), + C(0.8746342859608052666092782112565360755791467973338452, + 0.), + C(0.00468190164965444174367477874864366058339647648741, + 0.0510735563901306197993676329845149741675029197050), + C(-0.0023193175200187620902125853834909543869428763219, + -0.025460054739731556004902057663500272721780776336), + C(9.11463368405637174660562096516414499772662584e304, + 3.97101807145263333769664875189354358563218932e305), + C(-4.4927207857715598976165541011143706155432296e281, + -2.8019591213423077494444700357168707775769028e281), + C(2.820947917809305132678577516325951485807107151e-6, + 2.820947917668257736791638444590253942253354058e-6), + C(2.82094791773878143474039725787438662716372268e-15, + 2.82094791773878143474039725773333923127678361e-15), + C(-0.0000563851289696244350147899376081488003110150498, + -0.000169211755126812174631861529808288295454992688), + C(-5.586035480670854326218608431294778077663867e-162, + 5.586035480670854326218608431294778077663867e-161), + C(0.00016318325137140451888255634399123461580248456, + -0.095232456573009287370728788146686162555021209999), + C(0.69504753678406939989115375989939096800793577783885, + -1.8916411171103639136680830887017670616339912024317), + C(0.0001242418269653279656612334210746733213167234822, + 7.145975826320186888508563111992099992116786763e-7), + C(2.318587329648353318615800865959225429377529825e-8, + 6.182899545728857485721417893323317843200933380e-8), + C(-0.0133426877243506022053521927604277115767311800303, + -0.0148087097143220769493341484176979826888871576145), + C(1.00000000000000012412170838050638522857747934, + 1.12837916709551279389615890312156495593616433e-16), + C(0.9999999853310704677583504063775310832036830015, + 2.595272024519678881897196435157270184030360773e-8), + C(-1.4731421795638279504242963027196663601154624e-15, + 0.090727659684127365236479098488823462473074709), + C(5.79246077884410284575834156425396800754409308e-18, + 0.0907276596841273652364790985059772809093822374), + C(0.0884658993528521953466533278764830881245144368, + 1.37088352495749125283269718778582613192166760e-22), + C(0.0345480845419190424370085249304184266813447878, + 2.11161102895179044968099038990446187626075258e-23), + C(6.63967719958073440070225527042829242391918213e-36, + 0.0630820900592582863713653132559743161572639353), + C(0.00179435233208702644891092397579091030658500743634, + 0.0951983814805270647939647438459699953990788064762), + C(9.09760377102097999924241322094863528771095448e-13, + 0.0709979210725138550986782242355007611074966717), + C(7.2049510279742166460047102593255688682910274423e-304, + 0.0201552956479526953866611812593266285000876784321), + C(3.04543604652250734193622967873276113872279682e-44, + 0.0566481651760675042930042117726713294607499165), + C(3.04543604652250734193622967873276113872279682e-44, + 0.0566481651760675042930042117726713294607499165), + C(0.5659928732065273429286988428080855057102069081e-12, + 0.056648165176067504292998527162143030538756683302), + C(-0.56599287320652734292869884280802459698927645e-12, + 0.0566481651760675042929985271621430305387566833029), + C(0.0796884251721652215687859778119964009569455462, + 1.11474461817561675017794941973556302717225126e-22), + C(0.07817195821247357458545539935996687005781943386550, + -0.01093913670103576690766705513142246633056714279654), + C(0.04670032980990449912809326141164730850466208439937, + 0.03944038961933534137558064191650437353429669886545), + C(0.36787944117144232159552377016146086744581113103176, + 0.60715770584139372911503823580074492116122092866515), + C(0, + 0.010259688805536830986089913987516716056946786526145), + C(0.99004983374916805357390597718003655777207908125383, + -0.11208866436449538036721343053869621153527769495574), + C(0.99999999999999999999999999999999999999990000, + 1.12837916709551257389615890312154517168802603e-20), + C(0.999999999999943581041645226871305192054749891144158, + 0), + C(0.0110604154853277201542582159216317923453996211744250, + 0), + C(0,0), + C(0,0), + C(0,0), + C(Inf,0), + C(0,0), + C(NaN,NaN), + C(NaN,NaN), + C(NaN,NaN), + C(NaN,0), + C(NaN,NaN), + C(NaN,NaN) + }; + double errmax = 0; + for (int i = 0; i < NTST; ++i) { + cmplx fw = FADDEEVA(w)(z[i],0.); + double re_err = relerr(creal(w[i]), creal(fw)); + double im_err = relerr(cimag(w[i]), cimag(fw)); + printf("w(%g%+gi) = %g%+gi (vs. %g%+gi), re/im rel. err. = %0.2g/%0.2g)\n", + creal(z[i]),cimag(z[i]), creal(fw),cimag(fw), creal(w[i]),cimag(w[i]), + re_err, im_err); + if (re_err > errmax) errmax = re_err; + if (im_err > errmax) errmax = im_err; + } + if (errmax > 1e-13) { + printf("FAILURE -- relative error %g too large!\n", errmax); + return 1; + } + printf("SUCCESS (max relative error = %g)\n", errmax); + if (errmax > errmax_all) errmax_all = errmax; + } + { +#undef NTST +#define NTST 41 // define instead of const for C compatibility + cmplx z[NTST] = { + C(1,2), + C(-1,2), + C(1,-2), + C(-1,-2), + C(9,-28), + C(21,-33), + C(1e3,1e3), + C(-3001,-1000), + C(1e160,-1e159), + C(5.1e-3, 1e-8), + C(-4.9e-3, 4.95e-3), + C(4.9e-3, 0.5), + C(4.9e-4, -0.5e1), + C(-4.9e-5, -0.5e2), + C(5.1e-3, 0.5), + C(5.1e-4, -0.5e1), + C(-5.1e-5, -0.5e2), + C(1e-6,2e-6), + C(0,2e-6), + C(0,2), + C(0,20), + C(0,200), + C(Inf,0), + C(-Inf,0), + C(0,Inf), + C(0,-Inf), + C(Inf,Inf), + C(Inf,-Inf), + C(NaN,NaN), + C(NaN,0), + C(0,NaN), + C(NaN,Inf), + C(Inf,NaN), + C(1e-3,NaN), + C(7e-2,7e-2), + C(7e-2,-7e-4), + C(-9e-2,7e-4), + C(-9e-2,9e-2), + C(-7e-4,9e-2), + C(7e-2,0.9e-2), + C(7e-2,1.1e-2) + }; + cmplx w[NTST] = { // erf(z[i]), evaluated with Maple + C(-0.5366435657785650339917955593141927494421, + -5.049143703447034669543036958614140565553), + C(0.5366435657785650339917955593141927494421, + -5.049143703447034669543036958614140565553), + C(-0.5366435657785650339917955593141927494421, + 5.049143703447034669543036958614140565553), + C(0.5366435657785650339917955593141927494421, + 5.049143703447034669543036958614140565553), + C(0.3359473673830576996788000505817956637777e304, + -0.1999896139679880888755589794455069208455e304), + C(0.3584459971462946066523939204836760283645e278, + 0.3818954885257184373734213077678011282505e280), + C(0.9996020422657148639102150147542224526887, + 0.00002801044116908227889681753993542916894856), + C(-1, 0), + C(1, 0), + C(0.005754683859034800134412990541076554934877, + 0.1128349818335058741511924929801267822634e-7), + C(-0.005529149142341821193633460286828381876955, + 0.005585388387864706679609092447916333443570), + C(0.007099365669981359632319829148438283865814, + 0.6149347012854211635026981277569074001219), + C(0.3981176338702323417718189922039863062440e8, + -0.8298176341665249121085423917575122140650e10), + C(-Inf, + -Inf), + C(0.007389128308257135427153919483147229573895, + 0.6149332524601658796226417164791221815139), + C(0.4143671923267934479245651547534414976991e8, + -0.8298168216818314211557046346850921446950e10), + C(-Inf, + -Inf), + C(0.1128379167099649964175513742247082845155e-5, + 0.2256758334191777400570377193451519478895e-5), + C(0, + 0.2256758334194034158904576117253481476197e-5), + C(0, + 18.56480241457555259870429191324101719886), + C(0, + 0.1474797539628786202447733153131835124599e173), + C(0, + Inf), + C(1,0), + C(-1,0), + C(0,Inf), + C(0,-Inf), + C(NaN,NaN), + C(NaN,NaN), + C(NaN,NaN), + C(NaN,0), + C(0,NaN), + C(NaN,NaN), + C(NaN,NaN), + C(NaN,NaN), + C(0.07924380404615782687930591956705225541145, + 0.07872776218046681145537914954027729115247), + C(0.07885775828512276968931773651224684454495, + -0.0007860046704118224342390725280161272277506), + C(-0.1012806432747198859687963080684978759881, + 0.0007834934747022035607566216654982820299469), + C(-0.1020998418798097910247132140051062512527, + 0.1010030778892310851309082083238896270340), + C(-0.0007962891763147907785684591823889484764272, + 0.1018289385936278171741809237435404896152), + C(0.07886408666470478681566329888615410479530, + 0.01010604288780868961492224347707949372245), + C(0.07886723099940260286824654364807981336591, + 0.01235199327873258197931147306290916629654) + }; +#define TST(f,isc) \ + printf("############# " #f "(z) tests #############\n"); \ + double errmax = 0; \ + for (int i = 0; i < NTST; ++i) { \ + cmplx fw = FADDEEVA(f)(z[i],0.); \ + double re_err = relerr(creal(w[i]), creal(fw)); \ + double im_err = relerr(cimag(w[i]), cimag(fw)); \ + printf(#f "(%g%+gi) = %g%+gi (vs. %g%+gi), re/im rel. err. = %0.2g/%0.2g)\n", \ + creal(z[i]),cimag(z[i]), creal(fw),cimag(fw), creal(w[i]),cimag(w[i]), \ + re_err, im_err); \ + if (re_err > errmax) errmax = re_err; \ + if (im_err > errmax) errmax = im_err; \ + } \ + if (errmax > 1e-13) { \ + printf("FAILURE -- relative error %g too large!\n", errmax); \ + return 1; \ + } \ + printf("Checking " #f "(x) special case...\n"); \ + for (int i = 0; i < 10000; ++i) { \ + double x = pow(10., -300. + i * 600. / (10000 - 1)); \ + double re_err = relerr(FADDEEVA_RE(f)(x), \ + creal(FADDEEVA(f)(C(x,x*isc),0.))); \ + if (re_err > errmax) errmax = re_err; \ + re_err = relerr(FADDEEVA_RE(f)(-x), \ + creal(FADDEEVA(f)(C(-x,x*isc),0.))); \ + if (re_err > errmax) errmax = re_err; \ + } \ + { \ + double re_err = relerr(FADDEEVA_RE(f)(Inf), \ + creal(FADDEEVA(f)(C(Inf,0.),0.))); \ + if (re_err > errmax) errmax = re_err; \ + re_err = relerr(FADDEEVA_RE(f)(-Inf), \ + creal(FADDEEVA(f)(C(-Inf,0.),0.))); \ + if (re_err > errmax) errmax = re_err; \ + re_err = relerr(FADDEEVA_RE(f)(NaN), \ + creal(FADDEEVA(f)(C(NaN,0.),0.))); \ + if (re_err > errmax) errmax = re_err; \ + } \ + if (errmax > 1e-13) { \ + printf("FAILURE -- relative error %g too large!\n", errmax); \ + return 1; \ + } \ + printf("SUCCESS (max relative error = %g)\n", errmax); \ + if (errmax > errmax_all) errmax_all = errmax + + TST(erf, 1e-20); + } + { + // since erfi just calls through to erf, just one test should + // be sufficient to make sure I didn't screw up the signs or something +#undef NTST +#define NTST 1 // define instead of const for C compatibility + cmplx z[NTST] = { C(1.234,0.5678) }; + cmplx w[NTST] = { // erfi(z[i]), computed with Maple + C(1.081032284405373149432716643834106923212, + 1.926775520840916645838949402886591180834) + }; + TST(erfi, 0); + } + { + // since erfcx just calls through to w, just one test should + // be sufficient to make sure I didn't screw up the signs or something +#undef NTST +#define NTST 1 // define instead of const for C compatibility + cmplx z[NTST] = { C(1.234,0.5678) }; + cmplx w[NTST] = { // erfcx(z[i]), computed with Maple + C(0.3382187479799972294747793561190487832579, + -0.1116077470811648467464927471872945833154) + }; + TST(erfcx, 0); + } + { +#undef NTST +#define NTST 30 // define instead of const for C compatibility + cmplx z[NTST] = { + C(1,2), + C(-1,2), + C(1,-2), + C(-1,-2), + C(9,-28), + C(21,-33), + C(1e3,1e3), + C(-3001,-1000), + C(1e160,-1e159), + C(5.1e-3, 1e-8), + C(0,2e-6), + C(0,2), + C(0,20), + C(0,200), + C(2e-6,0), + C(2,0), + C(20,0), + C(200,0), + C(Inf,0), + C(-Inf,0), + C(0,Inf), + C(0,-Inf), + C(Inf,Inf), + C(Inf,-Inf), + C(NaN,NaN), + C(NaN,0), + C(0,NaN), + C(NaN,Inf), + C(Inf,NaN), + C(88,0) + }; + cmplx w[NTST] = { // erfc(z[i]), evaluated with Maple + C(1.536643565778565033991795559314192749442, + 5.049143703447034669543036958614140565553), + C(0.4633564342214349660082044406858072505579, + 5.049143703447034669543036958614140565553), + C(1.536643565778565033991795559314192749442, + -5.049143703447034669543036958614140565553), + C(0.4633564342214349660082044406858072505579, + -5.049143703447034669543036958614140565553), + C(-0.3359473673830576996788000505817956637777e304, + 0.1999896139679880888755589794455069208455e304), + C(-0.3584459971462946066523939204836760283645e278, + -0.3818954885257184373734213077678011282505e280), + C(0.0003979577342851360897849852457775473112748, + -0.00002801044116908227889681753993542916894856), + C(2, 0), + C(0, 0), + C(0.9942453161409651998655870094589234450651, + -0.1128349818335058741511924929801267822634e-7), + C(1, + -0.2256758334194034158904576117253481476197e-5), + C(1, + -18.56480241457555259870429191324101719886), + C(1, + -0.1474797539628786202447733153131835124599e173), + C(1, -Inf), + C(0.9999977432416658119838633199332831406314, + 0), + C(0.004677734981047265837930743632747071389108, + 0), + C(0.5395865611607900928934999167905345604088e-175, + 0), + C(0, 0), + C(0, 0), + C(2, 0), + C(1, -Inf), + C(1, Inf), + C(NaN, NaN), + C(NaN, NaN), + C(NaN, NaN), + C(NaN, 0), + C(1, NaN), + C(NaN, NaN), + C(NaN, NaN), + C(0,0) + }; + TST(erfc, 1e-20); + } + { +#undef NTST +#define NTST 48 // define instead of const for C compatibility + cmplx z[NTST] = { + C(2,1), + C(-2,1), + C(2,-1), + C(-2,-1), + C(-28,9), + C(33,-21), + C(1e3,1e3), + C(-1000,-3001), + C(1e-8, 5.1e-3), + C(4.95e-3, -4.9e-3), + C(5.1e-3, 5.1e-3), + C(0.5, 4.9e-3), + C(-0.5e1, 4.9e-4), + C(-0.5e2, -4.9e-5), + C(0.5e3, 4.9e-6), + C(0.5, 5.1e-3), + C(-0.5e1, 5.1e-4), + C(-0.5e2, -5.1e-5), + C(1e-6,2e-6), + C(2e-6,0), + C(2,0), + C(20,0), + C(200,0), + C(0,4.9e-3), + C(0,-5.1e-3), + C(0,2e-6), + C(0,-2), + C(0,20), + C(0,-200), + C(Inf,0), + C(-Inf,0), + C(0,Inf), + C(0,-Inf), + C(Inf,Inf), + C(Inf,-Inf), + C(NaN,NaN), + C(NaN,0), + C(0,NaN), + C(NaN,Inf), + C(Inf,NaN), + C(39, 6.4e-5), + C(41, 6.09e-5), + C(4.9e7, 5e-11), + C(5.1e7, 4.8e-11), + C(1e9, 2.4e-12), + C(1e11, 2.4e-14), + C(1e13, 2.4e-16), + C(1e300, 2.4e-303) + }; + cmplx w[NTST] = { // dawson(z[i]), evaluated with Maple + C(0.1635394094345355614904345232875688576839, + -0.1531245755371229803585918112683241066853), + C(-0.1635394094345355614904345232875688576839, + -0.1531245755371229803585918112683241066853), + C(0.1635394094345355614904345232875688576839, + 0.1531245755371229803585918112683241066853), + C(-0.1635394094345355614904345232875688576839, + 0.1531245755371229803585918112683241066853), + C(-0.01619082256681596362895875232699626384420, + -0.005210224203359059109181555401330902819419), + C(0.01078377080978103125464543240346760257008, + 0.006866888783433775382193630944275682670599), + C(-0.5808616819196736225612296471081337245459, + 0.6688593905505562263387760667171706325749), + C(Inf, + -Inf), + C(0.1000052020902036118082966385855563526705e-7, + 0.005100088434920073153418834680320146441685), + C(0.004950156837581592745389973960217444687524, + -0.004899838305155226382584756154100963570500), + C(0.005100176864319675957314822982399286703798, + 0.005099823128319785355949825238269336481254), + C(0.4244534840871830045021143490355372016428, + 0.002820278933186814021399602648373095266538), + C(-0.1021340733271046543881236523269967674156, + -0.00001045696456072005761498961861088944159916), + C(-0.01000200120119206748855061636187197886859, + 0.9805885888237419500266621041508714123763e-8), + C(0.001000002000012000023960527532953151819595, + -0.9800058800588007290937355024646722133204e-11), + C(0.4244549085628511778373438768121222815752, + 0.002935393851311701428647152230552122898291), + C(-0.1021340732357117208743299813648493928105, + -0.00001088377943049851799938998805451564893540), + C(-0.01000200120119126652710792390331206563616, + 0.1020612612857282306892368985525393707486e-7), + C(0.1000000000007333333333344266666666664457e-5, + 0.2000000000001333333333323199999999978819e-5), + C(0.1999999999994666666666675199999999990248e-5, + 0), + C(0.3013403889237919660346644392864226952119, + 0), + C(0.02503136792640367194699495234782353186858, + 0), + C(0.002500031251171948248596912483183760683918, + 0), + C(0,0.004900078433419939164774792850907128053308), + C(0,-0.005100088434920074173454208832365950009419), + C(0,0.2000000000005333333333341866666666676419e-5), + C(0,-48.16001211429122974789822893525016528191), + C(0,0.4627407029504443513654142715903005954668e174), + C(0,-Inf), + C(0,0), + C(-0,0), + C(0, Inf), + C(0, -Inf), + C(NaN, NaN), + C(NaN, NaN), + C(NaN, NaN), + C(NaN, 0), + C(0, NaN), + C(NaN, NaN), + C(NaN, NaN), + C(0.01282473148489433743567240624939698290584, + -0.2105957276516618621447832572909153498104e-7), + C(0.01219875253423634378984109995893708152885, + -0.1813040560401824664088425926165834355953e-7), + C(0.1020408163265306334945473399689037886997e-7, + -0.1041232819658476285651490827866174985330e-25), + C(0.9803921568627452865036825956835185367356e-8, + -0.9227220299884665067601095648451913375754e-26), + C(0.5000000000000000002500000000000000003750e-9, + -0.1200000000000000001800000188712838420241e-29), + C(5.00000000000000000000025000000000000000000003e-12, + -1.20000000000000000000018000000000000000000004e-36), + C(5.00000000000000000000000002500000000000000000e-14, + -1.20000000000000000000000001800000000000000000e-42), + C(5e-301, 0) + }; + TST(Dawson, 1e-20); + } + printf("#####################################\n"); + printf("SUCCESS (max relative error = %g)\n", errmax_all); +} + +#endif diff --git a/source/module_ri/Faddeeva.hh b/source/module_ri/Faddeeva.hh new file mode 100644 index 00000000000..c4a2e9717fd --- /dev/null +++ b/source/module_ri/Faddeeva.hh @@ -0,0 +1,62 @@ +/* Copyright (c) 2012 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* Available at: http://ab-initio.mit.edu/Faddeeva + + Header file for Faddeeva.cc; see that file for more information. */ + +#ifndef FADDEEVA_HH +#define FADDEEVA_HH 1 + +#include + +namespace Faddeeva { + +// compute w(z) = exp(-z^2) erfc(-iz) [ Faddeeva / scaled complex error func ] +extern std::complex w(std::complex z,double relerr=0); +extern double w_im(double x); // special-case code for Im[w(x)] of real x + +// Various functions that we can compute with the help of w(z) + +// compute erfcx(z) = exp(z^2) erfc(z) +extern std::complex erfcx(std::complex z, double relerr=0); +extern double erfcx(double x); // special case for real x + +// compute erf(z), the error function of complex arguments +extern std::complex erf(std::complex z, double relerr=0); +extern double erf(double x); // special case for real x + +// compute erfi(z) = -i erf(iz), the imaginary error function +extern std::complex erfi(std::complex z, double relerr=0); +extern double erfi(double x); // special case for real x + +// compute erfc(z) = 1 - erf(z), the complementary error function +extern std::complex erfc(std::complex z, double relerr=0); +extern double erfc(double x); // special case for real x + +// compute Dawson(z) = sqrt(pi)/2 * exp(-z^2) * erfi(z) +extern std::complex Dawson(std::complex z, double relerr=0); +extern double Dawson(double x); // special case for real x + +} // namespace Faddeeva + +#endif // FADDEEVA_HH diff --git a/source/module_ri/LRI_CV.h b/source/module_ri/LRI_CV.h index 252259c1196..d8c7de95b16 100644 --- a/source/module_ri/LRI_CV.h +++ b/source/module_ri/LRI_CV.h @@ -6,125 +6,125 @@ #ifndef LRI_CV_H #define LRI_CV_H +#include +#include +#include + +#include +#include +#include + #include "Matrix_Orbs11.h" #include "Matrix_Orbs21.h" -#include "module_basis/module_ao/ORB_atomic_lm.h" #include "module_base/abfs-vector3_order.h" #include "module_base/element_basis_index.h" +#include "module_basis/module_ao/ORB_atomic_lm.h" -#include -#include - -#include -#include -#include -#include - -template +template class LRI_CV { -private: - using TA = int; - using TC = std::array; - using TAC = std::pair; - using Tdata_real = RI::Global_Func::To_Real_t; - -public: - LRI_CV(); - ~LRI_CV(); - - void set_orbitals( - const LCAO_Orbitals& orb, - const std::vector>> &lcaos_in, - const std::vector>> &abfs_in, - const std::vector>> &abfs_ccp_in, - const double &kmesh_times, - const double &ccp_rmesh_times_in); - inline std::map>> - cal_Vs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags); // "writable_Vws" - inline std::array>>,3> - cal_dVs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags); // "writable_dVws" - std::pair>>, - std::array>>,3>> - cal_Cs_dCs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags); // "cal_dC", "writable_Cws", "writable_dCws", "writable_Vws", "writable_dVws" - - size_t get_index_abfs_size(const size_t &iat){return this->index_abfs[iat].count_size; } - -private: + private: + using TA = int; + using TC = std::array; + using TAC = std::pair; + using Tdata_real = RI::Global_Func::To_Real_t; + + public: + LRI_CV(); + ~LRI_CV(); + + void set_orbitals(const LCAO_Orbitals& orb, + const std::vector>>& lcaos_in, + const std::vector>>& abfs_in, + const std::vector>>& abfs_ccp_in, + const double& kmesh_times, + ORB_gaunt_table& MGT, + const bool& init_MGT, + const bool& init_C); + + inline std::map>> cal_Vs( + const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags); // "writable_Vws" + inline std::map, 3>>> cal_dVs( + const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags); // "writable_dVws" + std::pair>>, + std::map, 3>>>> + cal_Cs_dCs(const std::vector& list_A0, + const std::vector& list_A1, + const std::map& + flags); // "cal_dC", "writable_Cws", "writable_dCws", "writable_Vws", "writable_dVws" + + size_t get_index_abfs_size(const size_t& iat) + { + return this->index_abfs[iat].count_size; + } + + private: std::vector orb_cutoff_; - std::vector>> lcaos; - std::vector>> abfs; - std::vector>> abfs_ccp; - ModuleBase::Element_Basis_Index::IndexLNM index_lcaos; - ModuleBase::Element_Basis_Index::IndexLNM index_abfs; - double ccp_rmesh_times; - -public: - std::map,RI::Tensor>>> Vws; - std::map,RI::Tensor>>> Cws; - std::map,std::array,3>>>> dVws; - std::map,std::array,3>>>> dCws; -private: - pthread_rwlock_t rwlock_Vw; - pthread_rwlock_t rwlock_Cw; - pthread_rwlock_t rwlock_dVw; - pthread_rwlock_t rwlock_dCw; - - Matrix_Orbs11 m_abfs_abfs; - Matrix_Orbs21 m_abfslcaos_lcaos; - - template - using T_func_DPcal_data = std::function &R, - const std::map &flags)>; - template - std::map> - cal_datas( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags, - const double &rmesh_times, - const T_func_DPcal_data &func_DPcal_data); - - inline RI::Tensor - DPcal_V( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags); // "writable_Vws" - inline std::array,3> - DPcal_dV( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags); // "writable_dVws" - std::pair, std::array,3>> - DPcal_C_dC( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags); // "cal_dC", "writable_Cws", "writable_dCws", "writable_Vws", "writable_dVws" - - template - To11 DPcal_o11( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const bool &flag_writable_o11ws, - pthread_rwlock_t &rwlock_o11, - std::map,To11>>> &o11ws, - const Tfunc &func_cal_o11); + std::vector>> lcaos; + std::vector>> abfs; + std::vector>> abfs_ccp; + ModuleBase::Element_Basis_Index::IndexLNM index_lcaos; + ModuleBase::Element_Basis_Index::IndexLNM index_abfs; + std::vector abfs_ccp_rcut; + + public: + std::map, RI::Tensor>>> Vws; + std::map, RI::Tensor>>> Cws; + std::map, std::array, 3>>>> dVws; + std::map, std::array, 3>>>> dCws; + + private: + pthread_rwlock_t rwlock_Vw; + pthread_rwlock_t rwlock_Cw; + pthread_rwlock_t rwlock_dVw; + pthread_rwlock_t rwlock_dCw; + + Matrix_Orbs11 m_abfs_abfs; + Matrix_Orbs21 m_abfslcaos_lcaos; + + template + using T_func_DPcal_data = std::function& R, + const std::map& flags)>; + using T_func_cal_Rcut = std::function; + template + std::map> cal_datas(const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags, + const T_func_cal_Rcut& func_cal_Rcut, + const T_func_DPcal_data& func_DPcal_data); + + inline double cal_V_Rcut(const int it0, const int it1); + inline double cal_C_Rcut(const int it0, const int it1); + + inline RI::Tensor DPcal_V(const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& flags); // "writable_Vws" + inline std::array, 3> DPcal_dV(const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& flags); // "writable_dVws" + std::pair, std::array, 3>> DPcal_C_dC( + const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& + flags); // "cal_dC", "writable_Cws", "writable_dCws", "writable_Vws", "writable_dVws" + + template + To11 DPcal_o11(const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const bool& flag_writable_o11ws, + pthread_rwlock_t& rwlock_o11, + std::map, To11>>>& o11ws, + const Tfunc& func_cal_o11); }; #include "LRI_CV.hpp" diff --git a/source/module_ri/LRI_CV.hpp b/source/module_ri/LRI_CV.hpp index 8640088130c..12307f80e9e 100644 --- a/source/module_ri/LRI_CV.hpp +++ b/source/module_ri/LRI_CV.hpp @@ -8,413 +8,533 @@ #include "LRI_CV.h" #include "LRI_CV_Tools.h" -#include "exx_abfs-abfs_index.h" #include "RI_Util.h" -#include "../module_base/tool_title.h" +#include "../module_ri/exx_abfs-construct_orbs.h" #include "../module_base/timer.h" +#include "../module_base/tool_title.h" +#include "../module_ri/exx_abfs-abfs_index.h" + #include "../module_hamilt_pw/hamilt_pwdft/global.h" #include -#include - -template -LRI_CV::LRI_CV() -{ - pthread_rwlock_init(&rwlock_Vw,NULL); - pthread_rwlock_init(&rwlock_Cw,NULL); - pthread_rwlock_init(&rwlock_dVw,NULL); - pthread_rwlock_init(&rwlock_dCw,NULL); +#include + +template +LRI_CV::LRI_CV() { + pthread_rwlock_init(&rwlock_Vw, NULL); + pthread_rwlock_init(&rwlock_Cw, NULL); + pthread_rwlock_init(&rwlock_dVw, NULL); + pthread_rwlock_init(&rwlock_dCw, NULL); } -template -LRI_CV::~LRI_CV() -{ - pthread_rwlock_destroy(&rwlock_Vw); - pthread_rwlock_destroy(&rwlock_Cw); - pthread_rwlock_destroy(&rwlock_dVw); - pthread_rwlock_destroy(&rwlock_dCw); +template +LRI_CV::~LRI_CV() { + pthread_rwlock_destroy(&rwlock_Vw); + pthread_rwlock_destroy(&rwlock_Cw); + pthread_rwlock_destroy(&rwlock_dVw); + pthread_rwlock_destroy(&rwlock_dCw); } - -template +template void LRI_CV::set_orbitals( const LCAO_Orbitals& orb, - const std::vector>> &lcaos_in, - const std::vector>> &abfs_in, - const std::vector>> &abfs_ccp_in, - const double &kmesh_times, - const double &ccp_rmesh_times_in) -{ - ModuleBase::TITLE("LRI_CV", "set_orbitals"); - ModuleBase::timer::tick("LRI_CV", "set_orbitals"); + const std::vector>>& lcaos_in, + const std::vector>>& abfs_in, + const std::vector>>& + abfs_ccp_in, + const double& kmesh_times, + ORB_gaunt_table& MGT, + const bool& init_MGT, + const bool& init_C) { + ModuleBase::TITLE("LRI_CV", "set_orbitals"); + ModuleBase::timer::tick("LRI_CV", "set_orbitals"); this->orb_cutoff_ = orb.cutoffs(); - this->lcaos = lcaos_in; - this->abfs = abfs_in; - this->abfs_ccp = abfs_ccp_in; - this->ccp_rmesh_times = ccp_rmesh_times_in; - - const ModuleBase::Element_Basis_Index::Range - range_lcaos = Exx_Abfs::Abfs_Index::construct_range( lcaos ); - this->index_lcaos = ModuleBase::Element_Basis_Index::construct_index( range_lcaos ); - - const ModuleBase::Element_Basis_Index::Range - range_abfs = Exx_Abfs::Abfs_Index::construct_range( abfs ); - this->index_abfs = ModuleBase::Element_Basis_Index::construct_index( range_abfs ); - - this->m_abfs_abfs.init( 2, orb, kmesh_times, (1+this->ccp_rmesh_times)/2.0 ); - this->m_abfs_abfs.init_radial( this->abfs_ccp, this->abfs ); - this->m_abfs_abfs.init_radial_table(); - - this->m_abfslcaos_lcaos.init( 1, orb, kmesh_times, 1 ); - this->m_abfslcaos_lcaos.init_radial( this->abfs_ccp, this->lcaos, this->lcaos ); - this->m_abfslcaos_lcaos.init_radial_table(); - - ModuleBase::timer::tick("LRI_CV", "set_orbitals"); + this->lcaos = lcaos_in; + this->abfs = abfs_in; + this->abfs_ccp = abfs_ccp_in; + + this->abfs_ccp_rcut = Exx_Abfs::Construct_Orbs::get_Rcut(this->abfs_ccp); + const double lcaos_rmax = Exx_Abfs::Construct_Orbs::get_Rmax(this->lcaos); + const double abfs_ccp_rmax + = Exx_Abfs::Construct_Orbs::get_Rmax(this->abfs_ccp); + + const ModuleBase::Element_Basis_Index::Range range_lcaos + = Exx_Abfs::Abfs_Index::construct_range(lcaos); + this->index_lcaos + = ModuleBase::Element_Basis_Index::construct_index(range_lcaos); + + const ModuleBase::Element_Basis_Index::Range range_abfs + = Exx_Abfs::Abfs_Index::construct_range(abfs); + this->index_abfs + = ModuleBase::Element_Basis_Index::construct_index(range_abfs); + + // this->m_abfs_abfs.init( 2, kmesh_times, (1+this->ccp_rmesh_times)/2.0 ); + int Lmax_v = std::numeric_limits::min(); + this->m_abfs_abfs.init(2, orb, kmesh_times, lcaos_rmax + abfs_ccp_rmax, Lmax_v); + // this->m_abfslcaos_lcaos.init( 1, kmesh_times, 1 ); + int Lmax_c = std::numeric_limits::min(); + if (init_C) + this->m_abfslcaos_lcaos.init(1, orb, kmesh_times, lcaos_rmax, Lmax_c); + int Lmax = std::max(Lmax_v, Lmax_c); + + if (init_MGT) { + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + } + + this->m_abfs_abfs.init_radial(this->abfs_ccp, this->abfs, MGT); + this->m_abfs_abfs.init_radial_table(); + if (init_C) { + this->m_abfslcaos_lcaos.init_radial(this->abfs_ccp, + this->lcaos, + this->lcaos, + MGT); + this->m_abfslcaos_lcaos.init_radial_table(); + } + + ModuleBase::timer::tick("LRI_CV", "set_orbitals"); } +template +double LRI_CV::cal_V_Rcut(const int it0, const int it1) { + return this->abfs_ccp_rcut[it0] + this->orb_cutoff_[it1]; +} - -template template -auto LRI_CV::cal_datas( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags, - const double &rmesh_times, - const T_func_DPcal_data &func_DPcal_data) --> std::map> -{ - ModuleBase::TITLE("LRI_CV","cal_datas"); - ModuleBase::timer::tick("LRI_CV", "cal_datas"); - - std::map> Datas; - #pragma omp parallel - for(size_t i0=0; i0 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; - const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; - const double Rcut = std::min( - orb_cutoff_[it0] * rmesh_times + orb_cutoff_[it1], - orb_cutoff_[it1] * rmesh_times + orb_cutoff_[it0]); - const Abfs::Vector3_Order R_delta = -tau0+tau1+(RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec); - if( R_delta.norm()*GlobalC::ucell.lat0 < Rcut ) - { - const Tresult Data = func_DPcal_data(it0, it1, R_delta, flags); -// if(Data.norm(std::numeric_limits::max()) > threshold) -// { - #pragma omp critical(LRI_CV_cal_datas) - Datas[list_A0[i0]][list_A1[i1]] = Data; -// } - } - } - } - ModuleBase::timer::tick("LRI_CV", "cal_datas"); - return Datas; +template +double LRI_CV::cal_C_Rcut(const int it0, const int it1) { + return std::min(this->abfs_ccp_rcut[it0], this->orb_cutoff_[it0]) + + this->orb_cutoff_[it1]; } +template +template +auto LRI_CV::cal_datas(const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags, + const T_func_cal_Rcut& func_cal_Rcut, + const T_func_DPcal_data& func_DPcal_data) + -> std::map> { + ModuleBase::TITLE("LRI_CV", "cal_datas"); + ModuleBase::timer::tick("LRI_CV", "cal_datas"); + + std::map> Datas; +#pragma omp parallel + for (size_t i0 = 0; i0 < list_A0.size(); ++i0) { +#pragma omp for schedule(dynamic) nowait + for (size_t i1 = 0; i1 < list_A1.size(); ++i1) { + const TA iat0 = list_A0[i0]; + const TA iat1 = list_A1[i1].first; + const TC& cell1 = list_A1[i1].second; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const ModuleBase::Vector3 tau0 + = GlobalC::ucell.atoms[it0].tau[ia0]; + const ModuleBase::Vector3 tau1 + = GlobalC::ucell.atoms[it1].tau[ia1]; + // const double Rcut = std::min( + // GlobalC::ORB.Phi[it0].getRcut() * rmesh_times + + // GlobalC::ORB.Phi[it1].getRcut(), + // GlobalC::ORB.Phi[it1].getRcut() + // * rmesh_times + GlobalC::ORB.Phi[it0].getRcut()); + const double Rcut + = std::min(func_cal_Rcut(it0, it1), func_cal_Rcut(it1, it0)); + const Abfs::Vector3_Order R_delta + = -tau0 + tau1 + + (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec); + if (R_delta.norm() * GlobalC::ucell.lat0 < Rcut) { + const Tresult Data = func_DPcal_data(it0, it1, R_delta, flags); + // if(Data.norm(std::numeric_limits::max()) + //> threshold) + // { +#pragma omp critical(LRI_CV_cal_datas) + Datas[list_A0[i0]][list_A1[i1]] = Data; + // } + } + } + } + ModuleBase::timer::tick("LRI_CV", "cal_datas"); + return Datas; +} -template +template auto LRI_CV::cal_Vs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags) // + "writable_Vws" --> std::map>> -{ - ModuleBase::TITLE("LRI_CV","cal_Vs"); - const T_func_DPcal_data> - func_DPcal_V = std::bind( - &LRI_CV::DPcal_V, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - return this->cal_datas(list_A0, list_A1, flags, this->ccp_rmesh_times, func_DPcal_V); + const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags) // + "writable_Vws" + -> std::map>> { + ModuleBase::TITLE("LRI_CV", "cal_Vs"); + + const T_func_DPcal_data> func_DPcal_V + = std::bind(&LRI_CV::DPcal_V, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4); + const T_func_cal_Rcut func_cal_Rcut = std::bind(&LRI_CV::cal_V_Rcut, + this, + std::placeholders::_1, + std::placeholders::_2); + return this->cal_datas(list_A0, + list_A1, + flags, + func_cal_Rcut, + func_DPcal_V); } -template +template auto LRI_CV::cal_dVs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags) // + "writable_dVws" --> std::array>>,3> -{ - ModuleBase::TITLE("LRI_CV","cal_dVs"); - const T_func_DPcal_data,3>> - func_DPcal_dV = std::bind( - &LRI_CV::DPcal_dV, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - return LRI_CV_Tools::change_order( - this->cal_datas(list_A0, list_A1, flags, this->ccp_rmesh_times, func_DPcal_dV)); + const std::vector& list_A0, + const std::vector& list_A1, + const std::map& flags) // + "writable_dVws" + -> std::map, 3>>> { + ModuleBase::TITLE("LRI_CV", "cal_dVs"); + const T_func_DPcal_data, 3>> func_DPcal_dV + = std::bind(&LRI_CV::DPcal_dV, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4); + const T_func_cal_Rcut func_cal_Rcut = std::bind(&LRI_CV::cal_V_Rcut, + this, + std::placeholders::_1, + std::placeholders::_2); + return this->cal_datas(list_A0, + list_A1, + flags, + func_cal_Rcut, + func_DPcal_dV); } -template +template auto LRI_CV::cal_Cs_dCs( - const std::vector &list_A0, - const std::vector &list_A1, - const std::map &flags) // "cal_dC" + "writable_Cws", "writable_dCws", "writable_Vws", "writable_dVws" --> std::pair>>, std::array>>,3>> -{ - ModuleBase::TITLE("LRI_CV","cal_Cs_dCs"); - const T_func_DPcal_data, std::array,3>>> - func_DPcal_C_dC = std::bind( - &LRI_CV::DPcal_C_dC, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - std::map, std::array,3>>>> - Cs_dCs_tmp = this->cal_datas(list_A0, list_A1, flags, std::min(1.0,this->ccp_rmesh_times), func_DPcal_C_dC); - - std::map>> Cs; - std::array>>,3> dCs; - for(auto &Cs_dCs_A : Cs_dCs_tmp) - for(auto &Cs_dCs_B : Cs_dCs_A.second) - { - Cs[Cs_dCs_A.first][Cs_dCs_B.first] = std::move(std::get<0>(Cs_dCs_B.second)); - if(flags.at("cal_dC")) - for(int ix=0; ix<3; ++ix) - dCs[ix][Cs_dCs_A.first][Cs_dCs_B.first] = std::move(std::get<1>(Cs_dCs_B.second)[ix]); - } - return std::make_pair(Cs, dCs); + const std::vector& list_A0, + const std::vector& list_A1, + const std::map& + flags) // "cal_dC" + "writable_Cws", "writable_dCws", "writable_Vws", + // "writable_dVws" + -> std::pair< + std::map>>, + std::map, 3>>>> { + ModuleBase::TITLE("LRI_CV", "cal_Cs_dCs"); + const T_func_DPcal_data< + std::pair, std::array, 3>>> + func_DPcal_C_dC = std::bind(&LRI_CV::DPcal_C_dC, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4); + const T_func_cal_Rcut func_cal_Rcut = std::bind(&LRI_CV::cal_C_Rcut, + this, + std::placeholders::_1, + std::placeholders::_2); + std::map, + std::array, 3>>>> + Cs_dCs_tmp = this->cal_datas(list_A0, + list_A1, + flags, + func_cal_Rcut, + func_DPcal_C_dC); + + std::map>> Cs; + std::map, 3>>> dCs; + for (auto& Cs_dCs_A: Cs_dCs_tmp) + for (auto& Cs_dCs_B: Cs_dCs_A.second) { + Cs[Cs_dCs_A.first][Cs_dCs_B.first] + = std::move(std::get<0>(Cs_dCs_B.second)); + if (flags.at("cal_dC")) + dCs[Cs_dCs_A.first][Cs_dCs_B.first] + = std::move(std::get<1>(Cs_dCs_B.second)); + } + return std::make_pair(Cs, dCs); } - -template template +template +template To11 LRI_CV::DPcal_o11( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const bool &flag_writable_o11ws, - pthread_rwlock_t &rwlock_o11, - std::map,To11>>> &o11ws, - const Tfunc &func_cal_o11) -{ - const Abfs::Vector3_Order Rm = -R; - pthread_rwlock_rdlock(&rwlock_o11); - const To11 o11_read = RI::Global_Func::find(o11ws, it0, it1, R); - pthread_rwlock_unlock(&rwlock_o11); - - if(LRI_CV_Tools::exist(o11_read)) - { - return o11_read; - } - else - { - pthread_rwlock_rdlock(&rwlock_o11); - const To11 o11_transform_read = RI::Global_Func::find(o11ws, it1, it0, Rm); - pthread_rwlock_unlock(&rwlock_o11); - - if(LRI_CV_Tools::exist(o11_transform_read)) - { - const To11 o11 = LRI_CV_Tools::transform_Rm(o11_transform_read); - if(flag_writable_o11ws) // such write may be deleted for memory saving with transform_Rm() every time - { - pthread_rwlock_wrlock(&rwlock_o11); - o11ws[it0][it1][R] = o11; - pthread_rwlock_unlock(&rwlock_o11); - } - return o11; - } - else - { - const To11 o11 = func_cal_o11( - it0, it1, ModuleBase::Vector3{0,0,0}, R, - this->index_abfs, this->index_abfs, - Matrix_Orbs11::Matrix_Order::AB); - if(flag_writable_o11ws) - { - pthread_rwlock_wrlock(&rwlock_o11); - o11ws[it0][it1][R] = o11; - pthread_rwlock_unlock(&rwlock_o11); - } - return o11; - } // end else (!exist(o11_transform_read)) - } // end else (!exist(o11_read)) + const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const bool& flag_writable_o11ws, + pthread_rwlock_t& rwlock_o11, + std::map, To11>>>& + o11ws, + const Tfunc& func_cal_o11) { + const Abfs::Vector3_Order Rm = -R; + pthread_rwlock_rdlock(&rwlock_o11); + const To11 o11_read = RI::Global_Func::find(o11ws, it0, it1, R); + pthread_rwlock_unlock(&rwlock_o11); + + if (LRI_CV_Tools::exist(o11_read)) { + return o11_read; + } else { + pthread_rwlock_rdlock(&rwlock_o11); + const To11 o11_transform_read + = RI::Global_Func::find(o11ws, it1, it0, Rm); + pthread_rwlock_unlock(&rwlock_o11); + + if (LRI_CV_Tools::exist(o11_transform_read)) { + const To11 o11 = LRI_CV_Tools::transform_Rm(o11_transform_read); + if (flag_writable_o11ws) // such write may be deleted for memory + // saving with transform_Rm() every time + { + pthread_rwlock_wrlock(&rwlock_o11); + o11ws[it0][it1][R] = o11; + pthread_rwlock_unlock(&rwlock_o11); + } + return o11; + } else { + const To11 o11 = func_cal_o11(it0, + it1, + ModuleBase::Vector3{0, 0, 0}, + R, + this->index_abfs, + this->index_abfs, + Matrix_Orbs11::Matrix_Order::AB); + if (flag_writable_o11ws) { + pthread_rwlock_wrlock(&rwlock_o11); + o11ws[it0][it1][R] = o11; + pthread_rwlock_unlock(&rwlock_o11); + } + return o11; + } // end else (!exist(o11_transform_read)) + } // end else (!exist(o11_read)) } -template -RI::Tensor -LRI_CV::DPcal_V( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags) // "writable_Vws" +template +RI::Tensor LRI_CV::DPcal_V( + const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& flags) // "writable_Vws" { - const auto cal_overlap_matrix = std::bind( - &Matrix_Orbs11::cal_overlap_matrix, - &this->m_abfs_abfs, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7); - return this->DPcal_o11(it0, it1, R, flags.at("writable_Vws"), this->rwlock_Vw, this->Vws, cal_overlap_matrix); + const auto cal_overlap_matrix + = std::bind(&Matrix_Orbs11::cal_overlap_matrix, + &this->m_abfs_abfs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6, + std::placeholders::_7); + return this->DPcal_o11(it0, + it1, + R, + flags.at("writable_Vws"), + this->rwlock_Vw, + this->Vws, + cal_overlap_matrix); } -template -std::array, 3> -LRI_CV::DPcal_dV( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags) // "writable_dVws" +template +std::array, 3> LRI_CV::DPcal_dV( + const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& flags) // "writable_dVws" { - if(ModuleBase::Vector3(0,0,0)==R) - { - assert(it0==it1); - const size_t size = this->index_abfs[it0].count_size; - const std::array, 3> dV = { RI::Tensor({size,size}), RI::Tensor({size,size}), RI::Tensor({size,size}) }; - if(flags.at("writable_dVws")) - { - pthread_rwlock_wrlock(&this->rwlock_dVw); - this->dVws[it0][it1][R] = dV; - pthread_rwlock_unlock(&this->rwlock_dVw); - } - return dV; - } - - const auto cal_grad_overlap_matrix = std::bind( - &Matrix_Orbs11::cal_grad_overlap_matrix, - &this->m_abfs_abfs, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7); - return this->DPcal_o11(it0, it1, R, flags.at("writable_dVws"), this->rwlock_dVw, this->dVws, cal_grad_overlap_matrix); + if (ModuleBase::Vector3(0, 0, 0) == R) { + assert(it0 == it1); + const size_t size = this->index_abfs[it0].count_size; + const std::array, 3> dV + = {RI::Tensor({size, size}), + RI::Tensor({size, size}), + RI::Tensor({size, size})}; + if (flags.at("writable_dVws")) { + pthread_rwlock_wrlock(&this->rwlock_dVw); + this->dVws[it0][it1][R] = dV; + pthread_rwlock_unlock(&this->rwlock_dVw); + } + return dV; + } + + const auto cal_grad_overlap_matrix + = std::bind(&Matrix_Orbs11::cal_grad_overlap_matrix, + &this->m_abfs_abfs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6, + std::placeholders::_7); + return this->DPcal_o11(it0, + it1, + R, + flags.at("writable_dVws"), + this->rwlock_dVw, + this->dVws, + cal_grad_overlap_matrix); } - -template -std::pair, std::array,3>> -LRI_CV::DPcal_C_dC( - const int it0, - const int it1, - const Abfs::Vector3_Order &R, - const std::map &flags) // "cal_dC", "writable_Cws", "writable_dCws" + "writable_Vws", "writable_dVws" +template +std::pair, std::array, 3>> + LRI_CV::DPcal_C_dC( + const int it0, + const int it1, + const Abfs::Vector3_Order& R, + const std::map& + flags) // "cal_dC", "writable_Cws", "writable_dCws" + + // "writable_Vws", "writable_dVws" { - using namespace LRI_CV_Tools; - - const Abfs::Vector3_Order Rm = -R; - pthread_rwlock_rdlock(&this->rwlock_Cw); - const RI::Tensor C_read = RI::Global_Func::find(this->Cws, it0, it1, R); - pthread_rwlock_unlock(&this->rwlock_Cw); - pthread_rwlock_rdlock(&this->rwlock_dCw); - const std::array,3> dC_read = RI::Global_Func::find(this->dCws, it0, it1, R); - pthread_rwlock_unlock(&this->rwlock_dCw); - const bool flag_finish_dC = (!flags.at("cal_dC")) || LRI_CV_Tools::exist(dC_read); - - if(!C_read.empty() && flag_finish_dC) - { - return std::make_pair(C_read, dC_read); - } - else - { - if( (ModuleBase::Vector3(0,0,0)==R) && (it0==it1) ) - { - const RI::Tensor - A = this->m_abfslcaos_lcaos.template cal_overlap_matrix( - it0, it1, {0,0,0}, {0,0,0}, - this->index_abfs, this->index_lcaos, this->index_lcaos, - Matrix_Orbs21::Matrix_Order::A1A2B); - const RI::Tensor V = this->DPcal_V( it0, it0, {0,0,0}, {{"writable_Vws",true}}); - const RI::Tensor L = LRI_CV_Tools::cal_I(V); - - const RI::Tensor C = RI::Global_Func::convert(0.5) * LRI_CV_Tools::mul1(L,A); // Attention 0.5! - if(flags.at("writable_Cws")) - { - pthread_rwlock_wrlock(&this->rwlock_Cw); - this->Cws[it0][it1][{0,0,0}] = C; - pthread_rwlock_unlock(&this->rwlock_Cw); - } - - if(flag_finish_dC) - { - return std::make_pair(C, dC_read); - } - else - { - const RI::Shape_Vector sizes = {this->index_abfs[it0].count_size, - this->index_lcaos[it0].count_size, - this->index_lcaos[it0].count_size}; - const std::array,3> - dC({RI::Tensor({sizes}), RI::Tensor({sizes}), RI::Tensor({sizes})}); - if(flags.at("writable_dCws")) - { - pthread_rwlock_wrlock(&this->rwlock_dCw); - this->dCws[it0][it1][{0,0,0}] = dC; - pthread_rwlock_unlock(&this->rwlock_dCw); - } - return std::make_pair(C, dC); - } - } // end if( (ModuleBase::Vector3(0,0,0)==R) && (it0==it1) ) - else - { - const std::vector> - A = {this->m_abfslcaos_lcaos.template cal_overlap_matrix( - it0, it1, {0,0,0}, R, - this->index_abfs, this->index_lcaos, this->index_lcaos, - Matrix_Orbs21::Matrix_Order::A1A2B), - this->m_abfslcaos_lcaos.template cal_overlap_matrix( - it1, it0, {0,0,0}, Rm, - this->index_abfs, this->index_lcaos, this->index_lcaos, - Matrix_Orbs21::Matrix_Order::A1BA2)}; - - const std::vector>> - V = {{DPcal_V(it0, it0, {0,0,0}, {{"writable_Vws",true}}), - DPcal_V(it0, it1, R, flags)}, - {DPcal_V(it1, it0, Rm, flags), - DPcal_V(it1, it1, {0,0,0}, {{"writable_Vws",true}})}}; - - const std::vector>> - L = LRI_CV_Tools::cal_I(V); - - const std::vector> C = LRI_CV_Tools::mul2(L,A); - if(flags.at("writable_Cws")) - { - pthread_rwlock_wrlock(&this->rwlock_Cw); - this->Cws[it0][it1][R] = C[0]; - this->Cws[it1][it0][Rm] = LRI_CV_Tools::transpose12(C[1]); - pthread_rwlock_unlock(&this->rwlock_Cw); - } - - if(flag_finish_dC) - { - return std::make_pair(C[0], dC_read); - } - else - { - const std::vector,3>> - dA = {this->m_abfslcaos_lcaos.template cal_grad_overlap_matrix( - it0, it1, {0,0,0}, R, - this->index_abfs, this->index_lcaos, this->index_lcaos, - Matrix_Orbs21::Matrix_Order::A1A2B), - LRI_CV_Tools::negative( - this->m_abfslcaos_lcaos.template cal_grad_overlap_matrix( - it1, it0, {0,0,0}, Rm, - this->index_abfs, this->index_lcaos, this->index_lcaos, - Matrix_Orbs21::Matrix_Order::A1BA2))}; - - const std::array,3> dV_01 = DPcal_dV(it0, it1, R, flags); - const std::array,3> dV_10 = LRI_CV_Tools::negative(DPcal_dV(it1, it0, Rm, flags)); - - std::array>,3> // dC = L*(dA-dV*C) - dC_tmp = LRI_CV_Tools::mul2( - L, - LRI_CV_Tools::change_order( LRI_CV_Tools::minus( - dA, - std::vector,3>>{ - LRI_CV_Tools::mul1(dV_01, C[1]), - LRI_CV_Tools::mul1(dV_10, C[0])}))); - const std::vector,3>> - dC = LRI_CV_Tools::change_order(std::move(dC_tmp)); - if(flags.at("writable_dCws")) - { - pthread_rwlock_wrlock(&this->rwlock_dCw); - this->dCws[it0][it1][R] = dC[0]; - this->dCws[it1][it0][Rm] = LRI_CV_Tools::negative(LRI_CV_Tools::transpose12(dC[1])); - pthread_rwlock_unlock(&this->rwlock_dCw); - } - return std::make_pair(C[0], dC[0]); - } // end else (!flag_finish_dC) - } // end else ( (ModuleBase::Vector3(0,0,0)!=R) || (it0!=it1) ) - } // end else (!(C_read && flag_finish_dC)) + using namespace LRI_CV_Tools; + + const Abfs::Vector3_Order Rm = -R; + pthread_rwlock_rdlock(&this->rwlock_Cw); + const RI::Tensor C_read + = RI::Global_Func::find(this->Cws, it0, it1, R); + pthread_rwlock_unlock(&this->rwlock_Cw); + pthread_rwlock_rdlock(&this->rwlock_dCw); + const std::array, 3> dC_read + = RI::Global_Func::find(this->dCws, it0, it1, R); + pthread_rwlock_unlock(&this->rwlock_dCw); + const bool flag_finish_dC + = (!flags.at("cal_dC")) || LRI_CV_Tools::exist(dC_read); + + if (!C_read.empty() && flag_finish_dC) { + return std::make_pair(C_read, dC_read); + } else { + if ((ModuleBase::Vector3(0, 0, 0) == R) && (it0 == it1)) { + const RI::Tensor A + = this->m_abfslcaos_lcaos.template cal_overlap_matrix( + it0, + it1, + {0, 0, 0}, + {0, 0, 0}, + this->index_abfs, + this->index_lcaos, + this->index_lcaos, + Matrix_Orbs21::Matrix_Order::A1A2B); + const RI::Tensor V + = this->DPcal_V(it0, it0, {0, 0, 0}, {{"writable_Vws", true}}); + const RI::Tensor L = LRI_CV_Tools::cal_I(V); + + const RI::Tensor C + = RI::Global_Func::convert(0.5) + * LRI_CV_Tools::mul1(L, A); // Attention 0.5! + if (flags.at("writable_Cws")) { + pthread_rwlock_wrlock(&this->rwlock_Cw); + this->Cws[it0][it1][{0, 0, 0}] = C; + pthread_rwlock_unlock(&this->rwlock_Cw); + } + + if (flag_finish_dC) { + return std::make_pair(C, dC_read); + } else { + const RI::Shape_Vector sizes + = {this->index_abfs[it0].count_size, + this->index_lcaos[it0].count_size, + this->index_lcaos[it0].count_size}; + const std::array, 3> dC( + {RI::Tensor({sizes}), + RI::Tensor({sizes}), + RI::Tensor({sizes})}); + if (flags.at("writable_dCws")) { + pthread_rwlock_wrlock(&this->rwlock_dCw); + this->dCws[it0][it1][{0, 0, 0}] = dC; + pthread_rwlock_unlock(&this->rwlock_dCw); + } + return std::make_pair(C, dC); + } + } // end if( (ModuleBase::Vector3(0,0,0)==R) && (it0==it1) ) + else { + const std::vector> A + = {this->m_abfslcaos_lcaos.template cal_overlap_matrix( + it0, + it1, + {0, 0, 0}, + R, + this->index_abfs, + this->index_lcaos, + this->index_lcaos, + Matrix_Orbs21::Matrix_Order::A1A2B), + this->m_abfslcaos_lcaos.template cal_overlap_matrix( + it1, + it0, + {0, 0, 0}, + Rm, + this->index_abfs, + this->index_lcaos, + this->index_lcaos, + Matrix_Orbs21::Matrix_Order::A1BA2)}; + + const std::vector>> V + = {{DPcal_V(it0, it0, {0, 0, 0}, {{"writable_Vws", true}}), + DPcal_V(it0, it1, R, flags)}, + {DPcal_V(it1, it0, Rm, flags), + DPcal_V(it1, it1, {0, 0, 0}, {{"writable_Vws", true}})}}; + + const std::vector>> L + = LRI_CV_Tools::cal_I(V); + + const std::vector> C = LRI_CV_Tools::mul2(L, A); + if (flags.at("writable_Cws")) { + pthread_rwlock_wrlock(&this->rwlock_Cw); + this->Cws[it0][it1][R] = C[0]; + this->Cws[it1][it0][Rm] = LRI_CV_Tools::transpose12(C[1]); + pthread_rwlock_unlock(&this->rwlock_Cw); + } + + if (flag_finish_dC) { + return std::make_pair(C[0], dC_read); + } else { + const std::vector, 3>> dA + = {this->m_abfslcaos_lcaos + .template cal_grad_overlap_matrix( + it0, + it1, + {0, 0, 0}, + R, + this->index_abfs, + this->index_lcaos, + this->index_lcaos, + Matrix_Orbs21::Matrix_Order::A1A2B), + LRI_CV_Tools::negative( + this->m_abfslcaos_lcaos + .template cal_grad_overlap_matrix( + it1, + it0, + {0, 0, 0}, + Rm, + this->index_abfs, + this->index_lcaos, + this->index_lcaos, + Matrix_Orbs21::Matrix_Order::A1BA2))}; + + const std::array, 3> dV_01 + = DPcal_dV(it0, it1, R, flags); + const std::array, 3> dV_10 + = LRI_CV_Tools::negative(DPcal_dV(it1, it0, Rm, flags)); + + std::array>, + 3> // dC = L*(dA-dV*C) + dC_tmp = LRI_CV_Tools::mul2( + L, + LRI_CV_Tools::change_order(LRI_CV_Tools::minus( + dA, + std::vector, 3>>{ + LRI_CV_Tools::mul1(dV_01, C[1]), + LRI_CV_Tools::mul1(dV_10, C[0])}))); + const std::vector, 3>> dC + = LRI_CV_Tools::change_order(std::move(dC_tmp)); + if (flags.at("writable_dCws")) { + pthread_rwlock_wrlock(&this->rwlock_dCw); + this->dCws[it0][it1][R] = dC[0]; + this->dCws[it1][it0][Rm] = LRI_CV_Tools::negative( + LRI_CV_Tools::transpose12(dC[1])); + pthread_rwlock_unlock(&this->rwlock_dCw); + } + return std::make_pair(C[0], dC[0]); + } // end else (!flag_finish_dC) + } // end else ( (ModuleBase::Vector3(0,0,0)!=R) || (it0!=it1) ) + } // end else (!(C_read && flag_finish_dC)) } - #endif diff --git a/source/module_ri/LRI_CV_Tools.h b/source/module_ri/LRI_CV_Tools.h index 52085f6bc3f..812b97bbc5d 100644 --- a/source/module_ri/LRI_CV_Tools.h +++ b/source/module_ri/LRI_CV_Tools.h @@ -8,10 +8,15 @@ #include "module_base/abfs-vector3_order.h" -#include +#include "abfs.h" +#include "module_base/abfs-vector3_order.h" +#include "module_ri/abfs.h" -#include +#include +#include #include +#include +#include #include #include @@ -19,96 +24,231 @@ namespace LRI_CV_Tools { - template extern RI::Tensor cal_I( const RI::Tensor &m ); - template extern std::vector>> cal_I( const std::vector>> &ms ); - - template inline RI::Tensor transform_Rm(const RI::Tensor &V ); - template inline std::array,3> transform_Rm(const std::array,3> &dV); - - //template inline bool exist(const T &V); - - //template - //extern Treturn mul1(const T1 &t1, const T2 &t2); - //template - //extern Treturn mul2(const T1 &mat, const T2 &vec); - - template inline bool exist(const RI::Tensor &V); - template inline bool exist(const std::array &dV); - - template - extern RI::Tensor mul1(const RI::Tensor &t1, const RI::Tensor &t2); - template - extern std::array mul1(const std::array &t1, const T &t2); - - template - extern std::vector> mul2(const std::vector>> &mat, - const std::vector> &vec); - template - extern std::array mul2(const T1 &t1, const std::array &t2); - - //template - //std::array operator-(const std::array &v1, const std::array &v2); - //template - //std::vector operator-(const std::vector &v1, const std::vector &v2); - template - extern std::vector> minus( - const std::vector> &v1, - const std::vector> &v2); - - template - extern std::array negative(const std::array &v_in); - - //template T transpose12(const T &c_in); - template RI::Tensor transpose12(const RI::Tensor &c_in); - template std::array transpose12(const std::array &c_in); - - template - extern std::array,N> - change_order( - std::vector> &&ds_in); - template - std::vector> - change_order( - std::array,N> &&ds_in); - template - extern std::array>,N> - change_order( - std::vector>> &&ds_in); - template - extern std::array>,N> - change_order( - std::map>> && ds_in); - - template - extern std::array cal_latvec_range(const double &rcut_times, const std::vector& orb_cutoff); - - template - extern std::map,RI::Tensor>>> - get_CVws( - const std::map>,RI::Tensor>> &CVs); - template - extern std::map,std::array,3>>>> - get_dCVws( - const std::array>,RI::Tensor>>,3> &dCVs); - - template - extern std::array,RI::Tensor>>,3>,3> - cal_dMRs( - const std::array,RI::Tensor>>,3> &dMs); - - using TC = std::array; - using TAC = std::pair; - template - using TLRI = std::map>>; - template - TLRI read_Cs_ao(const std::string& file_path, const double& threshold = 1e-10); - template - void write_Cs_ao(const TLRI& Vs, const std::string& file_path); - template - TLRI read_Vs_abf(const std::string& file_path, const double& threshold = 1e-10); - template - void write_Vs_abf(const TLRI& Vs, const std::string& file_path); -} +template +extern RI::Tensor cal_I(const RI::Tensor& m); +template +extern std::vector>> cal_I(const std::vector>>& ms); + +template +inline RI::Tensor transform_Rm(const RI::Tensor& V); +template +inline std::array, 3> transform_Rm(const std::array, 3>& dV); + +// template inline bool exist(const T &V); + +// template +// extern Treturn mul1(const T1 &t1, const T2 &t2); +// template +// extern Treturn mul2(const T1 &mat, const T2 &vec); + +template +inline bool exist(const RI::Tensor& V); +template +inline bool exist(const std::array& dV); + +template +extern RI::Tensor mul1(const RI::Tensor& t1, const RI::Tensor& t2); +template +extern std::array mul1(const std::array& t1, const T& t2); + +template +extern std::vector> mul2(const std::vector>>& mat, + const std::vector>& vec); +template +extern std::array mul2(const T1& t1, const std::array& t2); +template +extern RI::Tensor mul2(const T& t1, const RI::Tensor& t2); +template +extern std::map> mul2(const T& t1, const std::map>& t2); + +// template +// std::array operator-(const std::array &v1, const std::array +// &v2); template std::vector operator-(const std::vector &v1, +// const std::vector &v2); +template +extern std::vector> minus(const std::vector>& v1, + const std::vector>& v2); +template +extern std::array>, N> minus( + std::array>, N>& v1, + std::array>, N>& v2); +template +inline std::map>> minus( + std::map>>& v1, + std::map>>& v2); +template +extern std::map> minus(std::map>& v1, + std::map>& v2); + +template +extern std::array negative(const std::array& v_in); + +// template T transpose12(const T &c_in); +template +RI::Tensor transpose12(const RI::Tensor& c_in); +template +std::array transpose12(const std::array& c_in); + +template +extern std::array, N> change_order(std::vector>&& ds_in); +template +std::vector> change_order(std::array, N>&& ds_in); +template +extern std::array>, N> change_order(std::vector>>&& ds_in); +template +extern std::array>, N> change_order( + std::map>>&& ds_in); +template +extern std::map>> change_order( + std::array>, N>&& ds_in); + +template +extern std::array cal_latvec_range(const double& rcut_times, const std::vector& orb_cutoff); + +template +extern std::map, RI::Tensor>>> get_CVws( + const std::map>, RI::Tensor>>& CVs); +template +extern std::map, std::array, 3>>>> get_dCVws( + const std::map>, std::array, 3>>>& dCVs); +template +extern std::array, RI::Tensor>>, 3>, 3> cal_dMRs( + const std::array, RI::Tensor>>, 3>& dMs); + +using TC = std::array; +using TAC = std::pair; +template +using TLRI = std::map>>; +template +TLRI read_Cs_ao(const std::string& file_path, const double& threshold = 1e-10); +template +void write_Cs_ao(const TLRI& Vs, const std::string& file_path); +template +TLRI read_Vs_abf(const std::string& file_path, const double& threshold = 1e-10); +template +void write_Vs_abf(const TLRI& Vs, const std::string& file_path); + +template +struct is_std_array : std::false_type +{ +}; +template +struct is_std_array> : std::true_type +{ +}; +template +struct is_tensor : std::false_type +{ +}; +template +struct is_tensor> : std::true_type +{ +}; + +template +struct TinType; + +template +struct TinType> +{ + using type = T; +}; + +template +struct TinType, N>> +{ + using type = T; +}; + +template ::value>> +inline void init_elem(Tdata& data, const size_t ndim0, const size_t ndim1) +{ + data = Tdata({ndim0, ndim1}); +}; +template +extern void init_elem(std::array, N>& data, const size_t ndim0, const size_t ndim1); + +template ::value && !is_tensor::value>> +inline void add_elem(Tdata& data, const Tdata& val, const Tdata& frac) +{ + data += frac * val; +}; +template +extern void add_elem(std::array& data, const T& val, const T& frac); +template ::value>> +inline void add_elem(const Tdata& data, + const int lmp, + const int lmq, + const typename TinType::type& val, + const typename TinType::type& frac) +{ + data(lmp, lmq) += frac * val; +}; +template +extern void add_elem(std::array, N>& data, + const int lmp, + const int lmq, + const std::array& val, + const T& frac); +template ::value>> +inline void add_elem(Tdata& data, + const int lmp0, + const int lmq0, + const Tdata& val, + const int lmp1, + const int lmq1, + const typename TinType::type& frac) +{ + data(lmp0, lmq0) += frac * val(lmp1, lmq1); +}; +template +extern void add_elem(std::array, N>& data, + const int lmp0, + const int lmq0, + const std::array, N>& val, + const int lmp1, + const int lmq1, + const T& frac); + +template +inline RI::Tensor convert(RI::Tensor&& data); +template +extern std::array, N> convert(std::array, N>&& data); + +// template +// typename std::enable_if::value, T>::type +// inline check_zero(T value) { +// return (std::abs(value) < 1e-8) ? static_cast(0) : value; +// } + +// template +// typename std::enable_if::value, T>::type +// inline check_zero(const T& value) { +// using RealType = typename T::value_type; +// RealType real_part = std::real(value); +// RealType imag_part = std::imag(value); + +// real_part = (std::abs(real_part) < 1e-8) ? 0 : real_part; +// imag_part = (std::abs(imag_part) < 1e-8) ? 0 : imag_part; + +// return std::complex(real_part, imag_part); +// } + +// template +// extern RI::Tensor check_zero(RI::Tensor&& data); +// template +// extern std::array, N> check_zero(std::array, N>&& data); + +template +struct plus +{ + T operator()(const T& lhs, const T& rhs) const + { + using namespace RI::Array_Operator; + return lhs + rhs; + } +}; +} // namespace LRI_CV_Tools #include "LRI_CV_Tools.hpp" #include "write_ri_cv.hpp" diff --git a/source/module_ri/LRI_CV_Tools.hpp b/source/module_ri/LRI_CV_Tools.hpp index 3e720ba9f4c..519e5ad850b 100644 --- a/source/module_ri/LRI_CV_Tools.hpp +++ b/source/module_ri/LRI_CV_Tools.hpp @@ -6,315 +6,477 @@ #ifndef LRI_CV_TOOLS_HPP #define LRI_CV_TOOLS_HPP -#include "LRI_CV_Tools.h" -#include "Inverse_Matrix.h" #include "../module_base/mathzone.h" +#include "Inverse_Matrix.h" +#include "LRI_CV_Tools.h" +#include "RI_Util.h" + +#include +#include #include "../module_hamilt_pw/hamilt_pwdft/global.h" -template -RI::Tensor -LRI_CV_Tools::cal_I( const RI::Tensor &m ) -{ - Inverse_Matrix I; - I.input(m); - I.cal_inverse( Inverse_Matrix::Method::potrf ); - return I.output(); +template +RI::Tensor LRI_CV_Tools::cal_I(const RI::Tensor& m) { + Inverse_Matrix I; + I.input(m); + I.cal_inverse(Inverse_Matrix::Method::potrf); + return I.output(); } -template +template std::vector>> -LRI_CV_Tools::cal_I( const std::vector>> &ms ) -{ - Inverse_Matrix I; - I.input(ms); - I.cal_inverse( Inverse_Matrix::Method::potrf ); - return I.output({ms[0][0].shape[0], ms[1][0].shape[0]}, {ms[0][0].shape[1], ms[0][1].shape[1]}); + LRI_CV_Tools::cal_I(const std::vector>>& ms) { + Inverse_Matrix I; + I.input(ms); + I.cal_inverse(Inverse_Matrix::Method::potrf); + return I.output({ms[0][0].shape[0], ms[1][0].shape[0]}, + {ms[0][0].shape[1], ms[0][1].shape[1]}); } - - -template -RI::Tensor LRI_CV_Tools::transform_Rm(const RI::Tensor &V) -{ - return V.transpose(); +template +RI::Tensor LRI_CV_Tools::transform_Rm(const RI::Tensor& V) { + return V.transpose(); } -template -std::array,3> LRI_CV_Tools::transform_Rm(const std::array,3> &dV) -{ - return std::array,3>{-dV[0].transpose(), -dV[1].transpose(), -dV[2].transpose()}; +template +std::array, 3> + LRI_CV_Tools::transform_Rm(const std::array, 3>& dV) { + return std::array, 3>{-dV[0].transpose(), + -dV[1].transpose(), + -dV[2].transpose()}; } -template -bool LRI_CV_Tools::exist(const RI::Tensor &V) -{ - return !V.empty(); +template +bool LRI_CV_Tools::exist(const RI::Tensor& V) { + return !V.empty(); } -template -bool LRI_CV_Tools::exist(const std::array &dV) -{ - for(size_t i=0; i<3; ++i) - { - if(!dV[i].empty()) - return true; - } - return false; +template +bool LRI_CV_Tools::exist(const std::array& dV) { + for (size_t i = 0; i < 3; ++i) + if (!dV[i].empty()) + return true; + return false; } - -template -RI::Tensor LRI_CV_Tools::mul1( - const RI::Tensor &t1, - const RI::Tensor &t2) -{ - const size_t sa0=t1.shape[0], sa1=t2.shape[0], sl0=t2.shape[1], sl1=t2.shape[2]; - return (t1 * t2.reshape({sa1,sl0*sl1})).reshape({sa0,sl0,sl1}); +template +RI::Tensor LRI_CV_Tools::mul1(const RI::Tensor& t1, + const RI::Tensor& t2) { + const size_t sa0 = t1.shape[0], sa1 = t2.shape[0], sl0 = t2.shape[1], + sl1 = t2.shape[2]; + return (t1 * t2.reshape({sa1, sl0 * sl1})).reshape({sa0, sl0, sl1}); } -template -std::array LRI_CV_Tools::mul1( - const std::array &t1, - const T &t2) -{ - return std::array{ - mul1(t1[0],t2), mul1(t1[1],t2), mul1(t1[2],t2) }; +template +std::array LRI_CV_Tools::mul1(const std::array& t1, const T& t2) { + return std::array{mul1(t1[0], t2), mul1(t1[1], t2), mul1(t1[2], t2)}; } /* template std::array LRI_CV_Tools::mul1( - const T &t1, - const std::array &t2) + const T &t1, + const std::array &t2) { - return std::array{ - mul1(t1,t2[0]), mul1(t1,t2[1]), mul1(t1,t2[2]) }; + return std::array{ + mul1(t1,t2[0]), mul1(t1,t2[1]), mul1(t1,t2[2]) }; } */ -template -std::vector> LRI_CV_Tools::mul2( - const std::vector>> &mat, - const std::vector> &vec) -{ - const size_t sa0=vec[0].shape[0], sa1=vec[1].shape[0], sl0=vec[0].shape[1], sl1=vec[0].shape[2]; - const RI::Tensor vec0=vec[0].reshape({sa0,sl0*sl1}), vec1=vec[1].reshape({sa1,sl0*sl1}); - return std::vector> - {( mat[0][0]*vec0 + mat[0][1]*vec1 ).reshape({sa0,sl0,sl1}), - ( mat[1][0]*vec0 + mat[1][1]*vec1 ).reshape({sa1,sl0,sl1})}; +template +std::vector> + LRI_CV_Tools::mul2(const std::vector>>& mat, + const std::vector>& vec) { + const size_t sa0 = vec[0].shape[0], sa1 = vec[1].shape[0], + sl0 = vec[0].shape[1], sl1 = vec[0].shape[2]; + const RI::Tensor vec0 = vec[0].reshape({sa0, sl0 * sl1}), + vec1 = vec[1].reshape({sa1, sl0 * sl1}); + return std::vector>{ + (mat[0][0] * vec0 + mat[0][1] * vec1).reshape({sa0, sl0, sl1}), + (mat[1][0] * vec0 + mat[1][1] * vec1).reshape({sa1, sl0, sl1})}; } /* template std::array LRI_CV_Tools::mul2( - const std::array &t1, - const T2 &t2) + const std::array &t1, + const T2 &t2) { - return std::array{ - mul2(t1[0],t2), mul2(t1[1],t2), mul2(t1[2],t2) }; + return std::array{ + mul2(t1[0],t2), mul2(t1[1],t2), mul2(t1[2],t2) }; } */ -template -std::array LRI_CV_Tools::mul2( - const T1 &t1, - const std::array &t2) -{ - return std::array{ - mul2(t1,t2[0]), mul2(t1,t2[1]), mul2(t1,t2[2]) }; +template +std::array LRI_CV_Tools::mul2(const T1& t1, + const std::array& t2) { + return std::array{mul2(t1, t2[0]), mul2(t1, t2[1]), mul2(t1, t2[2])}; +} + +template +RI::Tensor LRI_CV_Tools::mul2(const T& t1, const RI::Tensor& t2) { + return t1 * t2; +} + +template +std::map> + LRI_CV_Tools::mul2(const T& t1, + const std::map>& t2) { + std::map> res; + for (const auto& outerPair: t2) { + const TkeyA keyA = outerPair.first; + const std::map& innerMap = outerPair.second; + std::map newInnerMap; + + for (const auto& innerPair: innerMap) { + const TkeyB keyB = innerPair.first; + const Tvalue value = innerPair.second; + newInnerMap[keyB] = mul2(t1, value); + } + + res[keyA] = newInnerMap; + } + + return res; } /* template -std::array LRI_CV_Tools::operator-(const std::array &v1, const std::array &v2) +std::array LRI_CV_Tools::operator-(const std::array &v1, const +std::array &v2) { - std::array v; - for(std::size_t i=0; i v; + for(std::size_t i=0; i -std::vector LRI_CV_Tools::operator-(const std::vector &v1, const std::vector &v2) +std::vector LRI_CV_Tools::operator-(const std::vector &v1, const +std::vector &v2) { - assert(v1.size()==v2.size()); - std::vector v(v1.size()); - for(std::size_t i=0; i v(v1.size()); + for(std::size_t i=0; i -std::vector> LRI_CV_Tools::minus( - const std::vector> &v1, - const std::vector> &v2) -{ - assert(v1.size()==v2.size()); - std::vector> v(v1.size()); - for(std::size_t i=0; i +std::vector> + LRI_CV_Tools::minus(const std::vector>& v1, + const std::vector>& v2) { + assert(v1.size() == v2.size()); + std::vector> v(v1.size()); + for (std::size_t i = 0; i < v.size(); ++i) + for (std::size_t j = 0; j < N; ++j) + v[i][j] = v1[i][j] - v2[i][j]; + return v; } +template +std::map>> LRI_CV_Tools::minus( + std::map>>& v1, + std::map>>& v2) { + std::array>, N> v1_order + = change_order(std::move(v1)); + std::array>, N> v2_order + = change_order(std::move(v2)); + auto dv = minus(v1_order, v2_order); + return change_order(std::move(dv)); +} -template -std::array LRI_CV_Tools::negative(const std::array &v_in) -{ - std::array v_out; - for(std::size_t i=0; i +std::array>, N> LRI_CV_Tools::minus( + std::array>, N>& v1, + std::array>, N>& v2) { + std::array>, N> dv; + for (size_t i = 0; i != N; ++i) + dv[i] = minus(v1[i], v2[i]); + return dv; } +template +std::map> + LRI_CV_Tools::minus(std::map>& v1, + std::map>& v2) { + assert(v1.size() == v2.size()); + using namespace RI::Map_Operator; + using namespace RI::Array_Operator; -template -RI::Tensor LRI_CV_Tools::transpose12(const RI::Tensor &c_in) -{ - RI::Tensor c_out({c_in.shape[0], c_in.shape[2], c_in.shape[1]}); - for(size_t i0=0; i0> dv; + auto it1 = v1.begin(); + auto it2 = v2.begin(); + while (it1 != v1.end() && it2 != v2.end()) { + assert(it1->first == it2->first); + const TkeyA& keyA = it1->first; + const std::map& map1 = it1->second; + const std::map& map2 = it2->second; + dv[keyA] = map1 - map2; + ++it1; + ++it2; + } + return dv; } -template -std::array LRI_CV_Tools::transpose12(const std::array &c_in) -{ - std::array c_out; - for(size_t i=0; i +std::array LRI_CV_Tools::negative(const std::array& v_in) { + std::array v_out; + for (std::size_t i = 0; i < N; ++i) + v_out[i] = -v_in[i]; + return v_out; } +template +RI::Tensor LRI_CV_Tools::transpose12(const RI::Tensor& c_in) { + RI::Tensor c_out({c_in.shape[0], c_in.shape[2], c_in.shape[1]}); + for (size_t i0 = 0; i0 < c_in.shape[0]; ++i0) + for (size_t i1 = 0; i1 < c_in.shape[1]; ++i1) + for (size_t i2 = 0; i2 < c_in.shape[2]; ++i2) + c_out(i0, i2, i1) = c_in(i0, i1, i2); + return c_out; +} -template -std::array,N> -LRI_CV_Tools::change_order(std::vector> &&ds_in) -{ - std::array,N> ds; - for(int ix=0; ix +std::array LRI_CV_Tools::transpose12(const std::array& c_in) { + std::array c_out; + for (size_t i = 0; i < N; ++i) + c_out[i] = transpose12(c_in[i]); + return c_out; } -template -std::vector> -LRI_CV_Tools::change_order(std::array,N> &&ds_in) -{ - std::vector> ds(ds_in[0].size()); - for(int ix=0; ix +std::array, N> + LRI_CV_Tools::change_order(std::vector>&& ds_in) { + std::array, N> ds; + for (int ix = 0; ix < N; ++ix) { + ds[ix].resize(ds_in.size()); + for (int iv = 0; iv < ds_in.size(); ++iv) + ds[ix][iv] = std::move(ds_in[iv][ix]); + } + return ds; } -template -std::array>,N> -LRI_CV_Tools::change_order(std::vector>> &&ds_in) -{ - std::array>,N> ds; - for(int ix=0; ix +std::vector> + LRI_CV_Tools::change_order(std::array, N>&& ds_in) { + std::vector> ds(ds_in[0].size()); + for (int ix = 0; ix < N; ++ix) { + assert(ds.size() == ds_in[ix].size()); + for (int iv = 0; iv < ds.size(); ++iv) + ds[iv][ix] = std::move(ds_in[ix][iv]); + } + return ds; } -template -std::array>,N> -LRI_CV_Tools::change_order(std::map>> && ds_in) -{ - std::array>,N> ds; - for(auto &ds_A : ds_in) - for(auto &ds_B : ds_A.second) - for(int ix=0; ix +std::array>, N> LRI_CV_Tools::change_order( + std::vector>>&& ds_in) { + std::array>, N> ds; + for (int ix = 0; ix < N; ++ix) { + ds[ix].resize(ds_in.size()); + for (int i0 = 0; i0 < ds_in.size(); ++i0) { + ds[ix][i0].resize(ds_in[i0].size()); + for (int i1 = 0; i1 < ds_in[i0].size(); ++i1) + ds[ix][i0][i1] = std::move(ds_in[i0][i1][ix]); + } + } + return ds; } +template +std::array>, N> + LRI_CV_Tools::change_order( + std::map>>&& ds_in) { + std::array>, N> ds; + for (auto& ds_A: ds_in) + for (auto& ds_B: ds_A.second) + for (int ix = 0; ix < N; ++ix) + ds[ix][ds_A.first][ds_B.first] = std::move(ds_B.second[ix]); + return ds; +} -template -std::array -LRI_CV_Tools::cal_latvec_range(const double &rcut_times, const std::vector& orb_cutoff) -{ - double Rcut_max = 0; - for(int T=0; T +std::map>> + LRI_CV_Tools::change_order( + std::array>, N>&& ds_in) { + std::map>> ds; + for (int ix = 0; ix < N; ++ix) + for (auto& ds_A: ds_in[ix]) + for (auto& ds_B: ds_A.second) + ds[ds_A.first][ds_B.first][ix] = std::move(ds_B.second); + return ds; +} + +template +std::array LRI_CV_Tools::cal_latvec_range(const double& rcut_times, + const std::vector& orb_cutoff) { + double Rcut_max = 0; + for(int T=0; T proj = ModuleBase::Mathzone::latvec_projection( - std::array,3>{GlobalC::ucell.a1, GlobalC::ucell.a2, GlobalC::ucell.a3}); - const ModuleBase::Vector3 latvec_times = Rcut_max * rcut_times / (proj * GlobalC::ucell.lat0); - const ModuleBase::Vector3 latvec_times_ceil = {static_cast(std::ceil(latvec_times.x)), - static_cast(std::ceil(latvec_times.y)), - static_cast(std::ceil(latvec_times.z))}; - const ModuleBase::Vector3 period = 2 * latvec_times_ceil + ModuleBase::Vector3{1,1,1}; - return std::array{period.x, period.y, period.z}; -} - -template -std::map,RI::Tensor>>> -LRI_CV_Tools::get_CVws( - const std::map>,RI::Tensor>> &CVs) -{ - std::map,RI::Tensor>>> CVws; - for(const auto &CVs_A : CVs) - { - const TA iat0 = CVs_A.first; - const int it0 = GlobalC::ucell.iat2it[iat0]; - const int ia0 = GlobalC::ucell.iat2ia[iat0]; - const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; - for(const auto &CVs_B : CVs_A.second) - { - const TA iat1 = CVs_B.first.first; - const int it1 = GlobalC::ucell.iat2it[iat1]; - const int ia1 = GlobalC::ucell.iat2ia[iat1]; - const std::array &cell1 = CVs_B.first.second; - const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; - const Abfs::Vector3_Order R_delta = -tau0+tau1+(RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec); - CVws[it0][it1][R_delta] = CVs_B.second; - } - } - return CVws; + const ModuleBase::Vector3 proj + = ModuleBase::Mathzone::latvec_projection( + std::array, 3>{GlobalC::ucell.a1, + GlobalC::ucell.a2, + GlobalC::ucell.a3}); + const ModuleBase::Vector3 latvec_times + = Rcut_max * rcut_times / (proj * GlobalC::ucell.lat0); + const ModuleBase::Vector3 latvec_times_ceil + = {static_cast(std::ceil(latvec_times.x)), + static_cast(std::ceil(latvec_times.y)), + static_cast(std::ceil(latvec_times.z))}; + const ModuleBase::Vector3 period + = 2 * latvec_times_ceil + ModuleBase::Vector3{1, 1, 1}; + return std::array{period.x, period.y, period.z}; } -template -std::map,std::array,3>>>> -LRI_CV_Tools::get_dCVws( - const std::array>,RI::Tensor>>,3> &dCVs) -{ - std::map,std::array,3>>>> dCVws; - for(int ix=0; ix<3; ++ix) - { - for(const auto &dCVs_A : dCVs[ix]) - { - const TA iat0 = dCVs_A.first; - const int it0 = GlobalC::ucell.iat2it[iat0]; - const int ia0 = GlobalC::ucell.iat2ia[iat0]; - const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; - for(const auto &dCVs_B : dCVs_A.second) - { - const TA iat1 = dCVs_B.first.first; - const int it1 = GlobalC::ucell.iat2it[iat1]; - const int ia1 = GlobalC::ucell.iat2ia[iat1]; - const std::array &cell1 = dCVs_B.first.second; - const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; - const Abfs::Vector3_Order R_delta = -tau0+tau1+(RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec); - dCVws[it0][it1][R_delta][ix] = dCVs_B.second; - } - } - } - return dCVws; +template +std::map< + int, + std::map, RI::Tensor>>> + LRI_CV_Tools::get_CVws( + const std::map>, + RI::Tensor>>& CVs) { + std::map< + int, + std::map, RI::Tensor>>> + CVws; + for (const auto& CVs_A: CVs) { + const TA iat0 = CVs_A.first; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const ModuleBase::Vector3 tau0 + = GlobalC::ucell.atoms[it0].tau[ia0]; + for (const auto& CVs_B: CVs_A.second) { + const TA iat1 = CVs_B.first.first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const std::array& cell1 = CVs_B.first.second; + const ModuleBase::Vector3 tau1 + = GlobalC::ucell.atoms[it1].tau[ia1]; + const Abfs::Vector3_Order R_delta + = -tau0 + tau1 + + (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec); + CVws[it0][it1][R_delta] = CVs_B.second; + } + } + return CVws; +} + +template +std::map, + std::array, 3>>>> + LRI_CV_Tools::get_dCVws( + const std::map>, + std::array, 3>>>& dCVs) { + std::map, + std::array, 3>>>> + dCVws; + for (const auto& dCVs_A: dCVs) { + const TA iat0 = dCVs_A.first; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const ModuleBase::Vector3 tau0 + = GlobalC::ucell.atoms[it0].tau[ia0]; + for (const auto& dCVs_B: dCVs_A.second) { + const TA iat1 = dCVs_B.first.first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const std::array& cell1 = dCVs_B.first.second; + const ModuleBase::Vector3 tau1 + = GlobalC::ucell.atoms[it1].tau[ia1]; + const Abfs::Vector3_Order R_delta + = -tau0 + tau1 + + (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec); + dCVws[it0][it1][R_delta] = dCVs_B.second; + } + } + return dCVws; +} + +template +void LRI_CV_Tools::init_elem(std::array, N>& data, + const size_t ndim0, + const size_t ndim1) { + for (size_t i = 0; i < N; ++i) { + data[i] = RI::Tensor({ndim0, ndim1}); + } +} + +template +void LRI_CV_Tools::add_elem(std::array& data, + const T& val, + const T& frac) { + for (size_t i = 0; i < N; ++i) + data[i] += frac * val; +} + +template +void LRI_CV_Tools::add_elem(std::array, N>& data, + const int lmp, + const int lmq, + const std::array& val, + const T& frac) { + for (size_t i = 0; i < N; ++i) { + data[i](lmp, lmq) += frac * val[i]; + } +} + +template +void LRI_CV_Tools::add_elem(std::array, N>& data, + const int lmp0, + const int lmq0, + const std::array, N>& val, + const int lmp1, + const int lmq1, + const T& frac) { + for (size_t i = 0; i < N; ++i) { + data[i](lmp0, lmq0) += frac * val[i](lmp1, lmq1); + } } +template +RI::Tensor LRI_CV_Tools::convert(RI::Tensor&& data) { + return RI::Global_Func::convert(data); +} + +template +std::array, N> + LRI_CV_Tools::convert(std::array, N>&& data) { + std::array, N> out; + for (size_t i = 0; i != N; ++i) + out[i] = RI::Global_Func::convert(data[i]); + return out; +} + +// template +// RI::Tensor LRI_CV_Tools::check_zero(RI::Tensor&& data) { +// RI::Tensor result(data.shape); + +// const std::size_t rows = data.shape[0]; +// const std::size_t cols = data.shape[1]; + +// for (std::size_t i = 0; i < rows; ++i) { +// for (std::size_t j = 0; j < cols; ++j) { +// result(i, j) = LRI_CV_Tools::check_zero(data(i, j)); +// } +// } + +// return result; +// } + +// template +// std::array, N> +// LRI_CV_Tools::check_zero(std::array, N>&& data) { +// std::array, N> result; + +// for (size_t i = 0; i != N; ++i) +// result[i] = LRI_CV_Tools::check_zero(std::move(data[i])); + +// return result; +// } + // dMRs[ipos0][ipos1] = \nabla_{ipos0} M R_{ipos1} template @@ -356,4 +518,5 @@ LRI_CV_Tools::cal_dMRs( } return dMRs; } + #endif diff --git a/source/module_ri/Matrix_Orbs11.cpp b/source/module_ri/Matrix_Orbs11.cpp index 76aab8a6e40..dda18be74cf 100644 --- a/source/module_ri/Matrix_Orbs11.cpp +++ b/source/module_ri/Matrix_Orbs11.cpp @@ -9,12 +9,12 @@ #include "module_base/tool_title.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" -void Matrix_Orbs11::init(const int mode, const LCAO_Orbitals& orb, const double kmesh_times, const double rmesh_times) +void Matrix_Orbs11::init(const int mode, const LCAO_Orbitals& orb, const double kmesh_times, const double rmax, int Lmax) { ModuleBase::TITLE("Matrix_Orbs11", "init"); ModuleBase::timer::tick("Matrix_Orbs11", "init"); - int Lmax_used, Lmax; + int Lmax_used; const int ntype = orb.get_ntype(); int lmax_orb = -1, lmax_beta = -1; @@ -26,7 +26,7 @@ void Matrix_Orbs11::init(const int mode, const LCAO_Orbitals& orb, const double const double dr = orb.get_dR(); const double dk = orb.get_dk(); const int kmesh = orb.get_kmesh() * kmesh_times + 1; - int Rmesh = static_cast(orb.get_Rmax() * rmesh_times / dr) + 4; + int Rmesh = static_cast(rmax / dr) + 4; Rmesh += 1 - Rmesh % 2; Center2_Orb::init_Table_Spherical_Bessel(2, @@ -42,17 +42,18 @@ void Matrix_Orbs11::init(const int mode, const LCAO_Orbitals& orb, const double Rmesh, psb_); - //========================================= - // (3) make Gaunt coefficients table - //========================================= - this->MGT.init_Gaunt_CH(Lmax); - this->MGT.init_Gaunt(Lmax); + // //========================================= + // // (3) make Gaunt coefficients table + // //========================================= + // this->MGT.init_Gaunt_CH(Lmax); + // this->MGT.init_Gaunt(Lmax); ModuleBase::timer::tick("Matrix_Orbs11", "init"); } void Matrix_Orbs11::init_radial(const std::vector>>& orb_A, - const std::vector>>& orb_B) + const std::vector>>& orb_B, + const ORB_gaunt_table& MGT) { ModuleBase::TITLE("Matrix_Orbs11", "init_radial"); ModuleBase::timer::tick("Matrix_Orbs11", "init_radial"); @@ -64,17 +65,17 @@ void Matrix_Orbs11::init_radial(const std::vectorMGT))); -} -} -} -} -} + Center2_Orb::Orb11(orb_A[TA][LA][NA], orb_B[TB][LB][NB], psb_, MGT))); +} +} +} +} +} } ModuleBase::timer::tick("Matrix_Orbs11", "init_radial"); } -void Matrix_Orbs11::init_radial(const LCAO_Orbitals& orb_A, const LCAO_Orbitals& orb_B) +void Matrix_Orbs11::init_radial(const LCAO_Orbitals& orb_A, const LCAO_Orbitals& orb_B, const ORB_gaunt_table& MGT) { ModuleBase::TITLE("Matrix_Orbs11", "init_radial"); ModuleBase::timer::tick("Matrix_Orbs11", "init_radial"); @@ -89,12 +90,12 @@ void Matrix_Orbs11::init_radial(const LCAO_Orbitals& orb_A, const LCAO_Orbitals& Center2_Orb::Orb11(orb_A.Phi[TA].PhiLN(LA, NA), orb_B.Phi[TB].PhiLN(LB, NB), psb_, - this->MGT))); -} -} -} -} -} + MGT))); +} +} +} +} +} } ModuleBase::timer::tick("Matrix_Orbs11", "init_radial"); } @@ -109,12 +110,12 @@ void Matrix_Orbs11::init_radial_table() for (auto& coD: coC.second) { for (auto& coE: coD.second) { for (auto& coF: coE.second) { - coF.second.init_radial_table(); -} -} -} -} -} + coF.second.init_radial_table(); +} +} +} +} +} } ModuleBase::timer::tick("Matrix_Orbs11", "init_radial_table"); } @@ -136,20 +137,20 @@ void Matrix_Orbs11::init_radial_table(const std::map(position); for (size_t i = 0; i != 4; ++i) { - radials.insert(iq + i); + radials.insert(iq + i); } } for (auto& coC: *center2_orb11_sAB) { for (auto& coD: coC.second) { for (auto& coE: coD.second) { for (auto& coF: coE.second) { - coF.second.init_radial_table(radials); -} -} -} + coF.second.init_radial_table(radials); +} +} +} } } - } + } } ModuleBase::timer::tick("Matrix_Orbs11", "init_radial_table"); } diff --git a/source/module_ri/Matrix_Orbs11.h b/source/module_ri/Matrix_Orbs11.h index 8861198029f..b0f93754765 100644 --- a/source/module_ri/Matrix_Orbs11.h +++ b/source/module_ri/Matrix_Orbs11.h @@ -20,18 +20,21 @@ class Matrix_Orbs11 { - public: - // mode: - // 1: - // 2: - void init(const int mode, - const LCAO_Orbitals& orb, - const double kmesh_times, // extend Kcut, keep dK - const double rmesh_times); // extend Rcut, keep dR +public: + // mode: + // 1: + // 2: + void init( + const int mode, + const LCAO_Orbitals& orb, + const double kmesh_times, // extend Kcut, keep dK + const double rmax, + int Lmax); // extend Rcut, keep dR void init_radial(const std::vector>>& orb_A, - const std::vector>>& orb_B); - void init_radial(const LCAO_Orbitals& orb_A, const LCAO_Orbitals& orb_B); + const std::vector>>& orb_B, + const ORB_gaunt_table& MGT); + void init_radial(const LCAO_Orbitals& orb_A, const LCAO_Orbitals& orb_B, const ORB_gaunt_table& MGT); void init_radial_table(); void init_radial_table(const std::map>>& Rs); // unit: ucell.lat0 @@ -67,7 +70,6 @@ class Matrix_Orbs11 private: ModuleBase::Sph_Bessel_Recursive::D2* psb_ = nullptr; - ORB_gaunt_table MGT; const double lcao_dr_ = 0.01; std::map(orb.get_Rmax() * rmesh_times / dr) + 4; + int Rmesh = static_cast(rmax / dr) + 4; Rmesh += 1 - Rmesh % 2; Center2_Orb::init_Table_Spherical_Bessel(3, @@ -40,19 +44,22 @@ void Matrix_Orbs21::init(const int mode, const LCAO_Orbitals& orb, const double kmesh, Rmesh, psb_); + + Lmax = 2 * Lmax + 1; - //========================================= - // (3) make Gaunt coefficients table - //========================================= - this->MGT.init_Gaunt_CH(2 * Lmax + 1); // why +1 - this->MGT.init_Gaunt(2 * Lmax + 1); + // //========================================= + // // (3) make Gaunt coefficients table + // //========================================= + // this->MGT.init_Gaunt_CH(2 * Lmax + 1); // why +1 + // this->MGT.init_Gaunt(2 * Lmax + 1); ModuleBase::timer::tick("Matrix_Orbs21", "init"); } void Matrix_Orbs21::init_radial(const std::vector>>& orb_A1, const std::vector>>& orb_A2, - const std::vector>>& orb_B) + const std::vector>>& orb_B, + const ORB_gaunt_table& MGT) { ModuleBase::TITLE("Matrix_Orbs21", "init_radial"); ModuleBase::timer::tick("Matrix_Orbs21", "init_radial"); @@ -71,13 +78,14 @@ void Matrix_Orbs21::init_radial(const std::vectorMGT))); + MGT))); ModuleBase::timer::tick("Matrix_Orbs21", "init_radial"); } void Matrix_Orbs21::init_radial(const std::vector>>& orb_A1, const LCAO_Orbitals& orb_A2, - const LCAO_Orbitals& orb_B) + const LCAO_Orbitals& orb_B, + const ORB_gaunt_table& MGT) { ModuleBase::TITLE("Matrix_Orbs21", "init_radial"); ModuleBase::timer::tick("Matrix_Orbs21", "init_radial"); @@ -96,13 +104,13 @@ void Matrix_Orbs21::init_radial(const std::vectorMGT))); + MGT))); ModuleBase::timer::tick("Matrix_Orbs21", "init_radial"); } void Matrix_Orbs21::init_radial_table() { - ModuleBase::TITLE("Matrix_Orbs21", "init_radial"); + ModuleBase::TITLE("Matrix_Orbs21", "init_radial_table"); ModuleBase::timer::tick("Matrix_Orbs21", "init_radial_table"); for (auto& coA: center2_orb21_s) for (auto& coB: coA.second) diff --git a/source/module_ri/Matrix_Orbs21.h b/source/module_ri/Matrix_Orbs21.h index 680b11b0daf..17a1ad8003d 100644 --- a/source/module_ri/Matrix_Orbs21.h +++ b/source/module_ri/Matrix_Orbs21.h @@ -25,14 +25,17 @@ class Matrix_Orbs21 void init(const int mode, const LCAO_Orbitals& orb, const double kmesh_times, // extend Kcut, keep dK - const double rmesh_times); // extend Rcut, keep dR + const double rmax, + int& Lmax); // extend Rcut, keep dR void init_radial(const std::vector>>& orb_A1, const std::vector>>& orb_A2, - const std::vector>>& orb_B); + const std::vector>>& orb_B, + const ORB_gaunt_table& MGT); void init_radial(const std::vector>>& orb_A1, const LCAO_Orbitals& orb_A2, - const LCAO_Orbitals& orb_B); + const LCAO_Orbitals& orb_B, + const ORB_gaunt_table& MGT); void init_radial_table(); void init_radial_table(const std::map>>& Rs); // unit: ucell.lat0 @@ -75,7 +78,6 @@ class Matrix_Orbs21 private: ModuleBase::Sph_Bessel_Recursive::D2* psb_ = nullptr; - ORB_gaunt_table MGT; const double lcao_dr_ = 0.01; std::map(orb.get_Rmax() * rmesh_times / dr) + 4; + int Rmesh = static_cast(rmax / dr) + 4; Rmesh += 1 - Rmesh % 2; Center2_Orb::init_Table_Spherical_Bessel(4, @@ -41,11 +45,13 @@ void Matrix_Orbs22::init(const int mode, const LCAO_Orbitals& orb, const double Rmesh, psb_); - //========================================= - // (3) make Gaunt coefficients table - //========================================= - this->MGT.init_Gaunt_CH(2 * Lmax + 1); // why +1 - this->MGT.init_Gaunt(2 * Lmax + 1); + Lmax = 2 * Lmax + 1; + + // //========================================= + // // (3) make Gaunt coefficients table + // //========================================= + // this->MGT.init_Gaunt_CH(2 * Lmax + 1); // why +1 + // this->MGT.init_Gaunt(2 * Lmax + 1); ModuleBase::timer::tick("Matrix_Orbs22", "init"); std::cout << "Matrix_Orbs22::init()::done" << std::endl; @@ -54,7 +60,8 @@ void Matrix_Orbs22::init(const int mode, const LCAO_Orbitals& orb, const double void Matrix_Orbs22::init_radial(const std::vector>>& orb_A1, const std::vector>>& orb_A2, const std::vector>>& orb_B1, - const std::vector>>& orb_B2) + const std::vector>>& orb_B2, + const ORB_gaunt_table& MGT) { ModuleBase::TITLE("Matrix_Orbs22", "init_radial"); ModuleBase::timer::tick("Matrix_Orbs22", "init_radial"); @@ -84,7 +91,8 @@ void Matrix_Orbs22::init_radial(const std::vector - void init(const int mode, +public: + // mode: + // 1: + void init( + const int mode, const LCAO_Orbitals& orb, - const double kmesh_times, // extend Kcut, keep dK - const double rmesh_times); // extend Rcut, keep dR + const double kmesh_times, // extend Kcut, keep dK + const double rmax, + int& Lmax); // extend Rcut, keep dR void init_radial(const std::vector>>& orb_A1, const std::vector>>& orb_A2, const std::vector>>& orb_B1, - const std::vector>>& orb_B2); + const std::vector>>& orb_B2, + const ORB_gaunt_table& MGT); void init_radial(const LCAO_Orbitals& orb_A1, const LCAO_Orbitals& orb_A2, const LCAO_Orbitals& orb_B1, - const LCAO_Orbitals& orb_B2); + const LCAO_Orbitals& orb_B2, + const ORB_gaunt_table& MGT); void init_radial_table(); void init_radial_table(const std::map>>& Rs); // unit: ucell.lat0 diff --git a/source/module_ri/RI_2D_Comm.h b/source/module_ri/RI_2D_Comm.h index 56e49914727..1b41cb8c782 100644 --- a/source/module_ri/RI_2D_Comm.h +++ b/source/module_ri/RI_2D_Comm.h @@ -7,76 +7,96 @@ #define RI_2D_COMM_H #include "module_basis/module_ao/parallel_orbitals.h" -#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" #include "module_cell/klist.h" +#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" #include - +#include #include -#include -#include +#include #include +#include #include -#include -#include +#include +#include namespace RI_2D_Comm { - using TA = int; - using Tcell = int; - static const size_t Ndim = 3; - using TC = std::array; - using TAC = std::pair; +using TA = int; +using Tcell = int; +static const size_t Ndim = 3; +using TC = std::array; +using TAC = std::pair; -//public: - template - extern std::vector>>> - split_m2D_ktoR(const K_Vectors& kv, const std::vector& mks_2D, const Parallel_2D& pv, const int nspin, const bool spgsym = false); +// public: +template +extern std::vector>>> split_m2D_ktoR( + const K_Vectors& kv, + const std::vector& mks_2D, + const Parallel_2D& pv, + const int nspin, + const bool spgsym = false); - // judge[is] = {s0, s1} - extern std::vector, std::set>> - get_2D_judge(const Parallel_2D& pv); +// judge[is] = {s0, s1} +extern std::vector, std::set>> get_2D_judge(const Parallel_2D& pv); - template - extern void add_Hexx( - const K_Vectors& kv, - const int ik, - const double alpha, - const std::vector>>>& Hs, - const Parallel_Orbitals& pv, - TK* hk); +template +extern void add_Hexx(const K_Vectors& kv, + const int ik, + const double alpha, + const std::vector>>>& Hs, + const Parallel_Orbitals& pv, + TK* hk); - template - extern void add_HexxR( - const int current_spin, - const double alpha, - const std::vector>>>& Hs, - const Parallel_Orbitals& pv, - const int npol, - hamilt::HContainer& HlocR, - const RI::Cell_Nearest* const cell_nearest = nullptr); +template +extern void add_HexxR(const int current_spin, + const double alpha, + const std::vector>>>& Hs, + const Parallel_Orbitals& pv, + const int npol, + hamilt::HContainer& HlocR, + const RI::Cell_Nearest* const cell_nearest = nullptr); - template - extern std::vector> Hexxs_to_Hk( - const K_Vectors &kv, - const Parallel_Orbitals &pv, - const std::vector< std::map>>> &Hexxs, - const int ik); - template - std::vector> pulay_mixing( - const Parallel_Orbitals &pv, - std::deque>> &Hk_seq, - const std::vector> &Hk_new, - const double mixing_beta, - const std::string mixing_mode); - -//private: - extern std::vector get_ik_list(const K_Vectors &kv, const int is_k); - extern inline std::tuple get_iat_iw_is_block(const int iwt); - extern inline int get_is_block(const int is_k, const int is_row_b, const int is_col_b); - extern inline std::tuple split_is_block(const int is_b); - extern inline int get_iwt(const int iat, const int iw_b, const int is_b); +inline RI::Tensor tensor_real(const RI::Tensor& t) +{ + return t; } +inline RI::Tensor> tensor_real(const RI::Tensor>& t) +{ + RI::Tensor> r(t.shape); + for (int i = 0; i < t.data->size(); ++i) + (*r.data)[i] = ((*t.data)[i]).real(); + return r; +} + +// private: +extern std::vector get_ik_list(const K_Vectors& kv, const int is_k); +extern inline std::tuple get_iat_iw_is_block(const int iwt); +extern inline int get_is_block(const int is_k, const int is_row_b, const int is_col_b); +extern inline std::tuple split_is_block(const int is_b); +extern inline int get_iwt(const int iat, const int iw_b, const int is_b); + +template +extern std::map> comm_map2_first(const MPI_Comm& mpi_comm, + const std::map>& Ds_in, + const std::set& s0, + const std::set& s1); +template +extern std::map> comm_map2(const MPI_Comm& mpi_comm, + const std::map>& Ds_in, + const Tjudge& judge); +template +extern void set_value_add(Tkey&& key, Tvalue&& value, std::map& data); +template +extern void set_value_add(std::tuple&& key, + Tvalue&& value, + std::map>& data); +template +extern void add_datas(std::map&& data_local, std::map& data_recv); +template +extern void add_datas(std::map>&& data_local, + std::map>& data_recv); +} // namespace RI_2D_Comm #include "RI_2D_Comm.hpp" diff --git a/source/module_ri/RI_2D_Comm.hpp b/source/module_ri/RI_2D_Comm.hpp index a168764340a..f9eef46505b 100644 --- a/source/module_ri/RI_2D_Comm.hpp +++ b/source/module_ri/RI_2D_Comm.hpp @@ -1,284 +1,411 @@ -//======================= -// AUTHOR : Peize Lin -// DATE : 2022-08-17 -//======================= - -#ifndef RI_2D_COMM_HPP -#define RI_2D_COMM_HPP - -#include "RI_2D_Comm.h" -#include "RI_Util.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" -#include "module_base/tool_title.h" -#include "module_base/timer.h" -#include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" -#include "module_parameter/parameter.h" -#include - -#include -#include -#include - -inline RI::Tensor tensor_conj(const RI::Tensor& t) { return t; } -inline RI::Tensor> tensor_conj(const RI::Tensor>& t) -{ - RI::Tensor> r(t.shape); - for (int i = 0; i < t.data->size(); ++i) { - (*r.data)[i] = std::conj((*t.data)[i]); - } - return r; -} -template -auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors & kv, const std::vector&mks_2D, const Parallel_2D & pv, const int nspin, const bool spgsym) --> std::vector>>> -{ - ModuleBase::TITLE("RI_2D_Comm","split_m2D_ktoR"); - ModuleBase::timer::tick("RI_2D_Comm", "split_m2D_ktoR"); - - const TC period = RI_Util::get_Born_vonKarmen_period(kv); - const std::map nspin_k = {{1,1}, {2,2}, {4,1}}; - const double SPIN_multiple = std::map{ {1,0.5}, {2,1}, {4,1} }.at(nspin); // why? - - std::vector>>> mRs_a2D(nspin); - for (int is_k = 0; is_k < nspin_k.at(nspin); ++is_k) - { - const std::vector ik_list = RI_2D_Comm::get_ik_list(kv, is_k); - for(const TC &cell : RI_Util::get_Born_von_Karmen_cells(period)) - { - RI::Tensor mR_2D; - int ik_full = 0; - for (const int ik : ik_list) - { - auto set_mR_2D = [&mR_2D](auto&& mk_frac) { - if (mR_2D.empty()) { - mR_2D = RI::Global_Func::convert(mk_frac); - } else { - mR_2D - = mR_2D + RI::Global_Func::convert(mk_frac); - } - }; - using Tdata_m = typename Tmatrix::value_type; - if (!spgsym) - { - RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik], pv.get_col_size(), pv.get_row_size()); - const Tdata_m frac = SPIN_multiple - * RI::Global_Func::convert(std::exp( - -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); - if (static_cast(std::round(SPIN_multiple * kv.wk[ik] * kv.get_nkstot_full())) == 2) - { set_mR_2D(mk_2D * (frac * 0.5) + tensor_conj(mk_2D * (frac * 0.5))); } - else { set_mR_2D(mk_2D * frac); } - } - else - { // traverse kstar, ik means ik_ibz - for (auto& isym_kvd : kv.kstars[ik % ik_list.size()]) - { - RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik_full + is_k * kv.get_nkstot_full()], pv.get_col_size(), pv.get_row_size()); - const Tdata_m frac = SPIN_multiple - * RI::Global_Func::convert(std::exp( - -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * ((isym_kvd.second * GlobalC::ucell.G) * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); - set_mR_2D(mk_2D * frac); - ++ik_full; - } - } - } - for(int iwt0_2D=0; iwt0_2D!=mR_2D.shape[0]; ++iwt0_2D) - { - const int iwt0 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) - ? pv.local2global_col(iwt0_2D) - : pv.local2global_row(iwt0_2D); - int iat0, iw0_b, is0_b; - std::tie(iat0,iw0_b,is0_b) = RI_2D_Comm::get_iat_iw_is_block(iwt0); - const int it0 = GlobalC::ucell.iat2it[iat0]; - for(int iwt1_2D=0; iwt1_2D!=mR_2D.shape[1]; ++iwt1_2D) - { - const int iwt1 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) - ? pv.local2global_row(iwt1_2D) - : pv.local2global_col(iwt1_2D); - int iat1, iw1_b, is1_b; - std::tie(iat1,iw1_b,is1_b) = RI_2D_Comm::get_iat_iw_is_block(iwt1); - const int it1 = GlobalC::ucell.iat2it[iat1]; - - const int is_b = RI_2D_Comm::get_is_block(is_k, is0_b, is1_b); - RI::Tensor &mR_a2D = mRs_a2D[is_b][iat0][{iat1,cell}]; - if (mR_a2D.empty()) { - mR_a2D = RI::Tensor( - {static_cast(GlobalC::ucell.atoms[it0].nw), - static_cast( - GlobalC::ucell.atoms[it1].nw)}); - } - mR_a2D(iw0_b,iw1_b) = mR_2D(iwt0_2D, iwt1_2D); - } - } - } - } - ModuleBase::timer::tick("RI_2D_Comm", "split_m2D_ktoR"); - return mRs_a2D; -} - - -template -void RI_2D_Comm::add_Hexx( - const K_Vectors &kv, - const int ik, - const double alpha, - const std::vector>>> &Hs, - const Parallel_Orbitals& pv, - TK* hk) -{ - ModuleBase::TITLE("RI_2D_Comm","add_Hexx"); - ModuleBase::timer::tick("RI_2D_Comm", "add_Hexx"); - - const std::map> is_list = {{1,{0}}, {2,{kv.isk[ik]}}, {4,{0,1,2,3}}}; - for(const int is_b : is_list.at(PARAM.inp.nspin)) - { - int is0_b, is1_b; - std::tie(is0_b,is1_b) = RI_2D_Comm::split_is_block(is_b); - for(const auto &Hs_tmpA : Hs[is_b]) - { - const TA &iat0 = Hs_tmpA.first; - for(const auto &Hs_tmpB : Hs_tmpA.second) - { - const TA &iat1 = Hs_tmpB.first.first; - const TC &cell1 = Hs_tmpB.first.second; - const std::complex frac = alpha - * std::exp( ModuleBase::TWO_PI*ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec)) ); - const RI::Tensor &H = Hs_tmpB.second; - for(size_t iw0_b=0; iw0_b(H(iw0_b, iw1_b)) * RI::Global_Func::convert(frac), pv, hk); - } - } - } - } - } - ModuleBase::timer::tick("RI_2D_Comm", "add_Hexx"); -} - -std::tuple -RI_2D_Comm::get_iat_iw_is_block(const int iwt) -{ - const int iat = GlobalC::ucell.iwt2iat[iwt]; - const int iw = GlobalC::ucell.iwt2iw[iwt]; - switch(PARAM.inp.nspin) - { - case 1: case 2: - return std::make_tuple(iat, iw, 0); - case 4: - return std::make_tuple(iat, iw/2, iw%2); - default: - throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); - } -} - -int RI_2D_Comm::get_is_block(const int is_k, const int is_row_b, const int is_col_b) -{ - switch(PARAM.inp.nspin) - { - case 1: return 0; - case 2: return is_k; - case 4: return is_row_b*2+is_col_b; - default: throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); - } -} - -std::tuple -RI_2D_Comm::split_is_block(const int is_b) -{ - switch(PARAM.inp.nspin) - { - case 1: case 2: - return std::make_tuple(0, 0); - case 4: - return std::make_tuple(is_b/2, is_b%2); - default: - throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); - } -} - - - -int RI_2D_Comm::get_iwt(const int iat, const int iw_b, const int is_b) -{ - const int it = GlobalC::ucell.iat2it[iat]; - const int ia = GlobalC::ucell.iat2ia[iat]; - int iw=-1; - switch(PARAM.inp.nspin) - { - case 1: case 2: - iw = iw_b; break; - case 4: - iw = iw_b*2+is_b; break; - default: - throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); - } - const int iwt = GlobalC::ucell.itiaiw2iwt(it,ia,iw); - return iwt; -} - -template -void RI_2D_Comm::add_HexxR( - const int current_spin, - const double alpha, - const std::vector>>>& Hs, - const Parallel_Orbitals& pv, - const int npol, - hamilt::HContainer& hR, - const RI::Cell_Nearest* const cell_nearest) -{ - ModuleBase::TITLE("RI_2D_Comm", "add_HexxR"); - ModuleBase::timer::tick("RI_2D_Comm", "add_HexxR"); - const std::map> is_list = { {1,{0}}, {2,{current_spin}}, {4,{0,1,2,3}} }; - for (const int is_hs : is_list.at(PARAM.inp.nspin)) - { - int is0_b = 0, is1_b = 0; - std::tie(is0_b, is1_b) = RI_2D_Comm::split_is_block(is_hs); - for (const auto& Hs_tmpA : Hs[is_hs]) - { - const TA& iat0 = Hs_tmpA.first; - for (const auto& Hs_tmpB : Hs_tmpA.second) - { - const TA& iat1 = Hs_tmpB.first.first; - const TC& cell = Hs_tmpB.first.second; - const Abfs::Vector3_Order R = RI_Util::array3_to_Vector3( - (cell_nearest ? - cell_nearest->get_cell_nearest_discrete(iat0, iat1, cell) - : cell)); - hamilt::BaseMatrix* HlocR = hR.find_matrix(iat0, iat1, R.x, R.y, R.z); - if (HlocR == nullptr) - { // add R to HContainer - hamilt::AtomPair tmp(iat0, iat1, R.x, R.y, R.z, &pv); - hR.insert_pair(tmp); - HlocR = hR.find_matrix(iat0, iat1, R.x, R.y, R.z); - } - auto row_indexes = pv.get_indexes_row(iat0); - auto col_indexes = pv.get_indexes_col(iat1); - const RI::Tensor& HexxR = (Tdata)alpha * Hs_tmpB.second; - for (int lw0_b = 0;lw0_b < row_indexes.size();lw0_b += npol) // block - { - const int& gw0 = row_indexes[lw0_b] / npol; - const int& lw0 = (npol == 2) ? (lw0_b + is0_b) : lw0_b; - for (int lw1_b = 0;lw1_b < col_indexes.size();lw1_b += npol) - { - const int& gw1 = col_indexes[lw1_b] / npol; - const int& lw1 = (npol == 2) ? (lw1_b + is1_b) : lw1_b; - HlocR->add_element(lw0, lw1, RI::Global_Func::convert(HexxR(gw0, gw1))); - } - } - } - } - } - - ModuleBase::timer::tick("RI_2D_Comm", "add_HexxR"); -} - +//======================= +// AUTHOR : Peize Lin +// DATE : 2022-08-17 +//======================= + +#ifndef RI_2D_COMM_HPP +#define RI_2D_COMM_HPP + +#include +#include +#include +#include +#include +#include "module_hamilt_lcao/hamilt_lcaodft/LCAO_domain.h" +#include "module_parameter/parameter.h" +#include + +#include +#include +#include + +#include "RI_2D_Comm.h" +#include "RI_Util.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" + +// inline RI::Tensor tensor_conj(const RI::Tensor& t) { return t; } +// inline RI::Tensor> tensor_conj(const RI::Tensor>& t) +// { +// RI::Tensor> r(t.shape); +// for (int i = 0;i < t.data->size();++i)(*r.data)[i] = std::conj((*t.data)[i]); +// return r; +// } +// inline RI::Tensor tensor_real(const RI::Tensor& t) { return t; } +// inline RI::Tensor> tensor_real(const RI::Tensor>& t) +// { +// RI::Tensor> r(t.shape); +// for (int i = 0;i < t.data->size();++i)(*r.data)[i] = ((*t.data)[i]).real(); +// return r; +// } + +template +auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors& kv, + const std::vector& mks_2D, + const Parallel_2D& pv, + const int nspin, + const bool spgsym) + -> std::vector>>> +{ + ModuleBase::TITLE("RI_2D_Comm", "split_m2D_ktoR"); + ModuleBase::timer::tick("RI_2D_Comm", "split_m2D_ktoR"); + + const TC period = RI_Util::get_Born_vonKarmen_period(kv); + const std::map nspin_k = {{1,1}, {2,2}, {4,1}}; + const double SPIN_multiple = std::map{ {1,0.5}, {2,1}, {4,1} }.at(nspin); // why? + + std::vector>>> mRs_a2D(nspin); + for (int is_k = 0; is_k < nspin_k.at(nspin); ++is_k) + { + const std::vector ik_list = RI_2D_Comm::get_ik_list(kv, is_k); + for(const TC &cell : RI_Util::get_Born_von_Karmen_cells(period)) + { + RI::Tensor mR_2D; + int ik_full = 0; + for (const int ik : ik_list) + { + auto set_mR_2D = [&mR_2D](auto&& mk_frac) { + if (mR_2D.empty()) { + mR_2D = RI::Global_Func::convert(mk_frac); + } else { + mR_2D + = mR_2D + RI::Global_Func::convert(mk_frac); + } + }; + using Tdata_m = typename Tmatrix::value_type; + if (!spgsym) + { + RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik], pv.get_col_size(), pv.get_row_size()); + const Tdata_m frac = SPIN_multiple + * RI::Global_Func::convert(std::exp( + -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); + if (static_cast(std::round(SPIN_multiple * kv.wk[ik] * kv.get_nkstot_full())) == 2) + { set_mR_2D(tensor_real(mk_2D * frac)); } + else { set_mR_2D(mk_2D * frac); } + } + else + { // traverse kstar, ik means ik_ibz + for (auto& isym_kvd : kv.kstars[ik % ik_list.size()]) + { + RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik_full + is_k * kv.get_nkstot_full()], pv.get_col_size(), pv.get_row_size()); + const Tdata_m frac = SPIN_multiple + * RI::Global_Func::convert(std::exp( + -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * ((isym_kvd.second * GlobalC::ucell.G) * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); + set_mR_2D(mk_2D * frac); + ++ik_full; + } + } + } + for(int iwt0_2D=0; iwt0_2D!=mR_2D.shape[0]; ++iwt0_2D) + { + const int iwt0 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) + ? pv.local2global_col(iwt0_2D) + : pv.local2global_row(iwt0_2D); + int iat0, iw0_b, is0_b; + std::tie(iat0,iw0_b,is0_b) = RI_2D_Comm::get_iat_iw_is_block(iwt0); + const int it0 = GlobalC::ucell.iat2it[iat0]; + for(int iwt1_2D=0; iwt1_2D!=mR_2D.shape[1]; ++iwt1_2D) + { + const int iwt1 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver) + ? pv.local2global_row(iwt1_2D) + : pv.local2global_col(iwt1_2D); + int iat1, iw1_b, is1_b; + std::tie(iat1,iw1_b,is1_b) = RI_2D_Comm::get_iat_iw_is_block(iwt1); + const int it1 = GlobalC::ucell.iat2it[iat1]; + + const int is_b = RI_2D_Comm::get_is_block(is_k, is0_b, is1_b); + RI::Tensor &mR_a2D = mRs_a2D[is_b][iat0][{iat1,cell}]; + if (mR_a2D.empty()) { + mR_a2D = RI::Tensor( + {static_cast(GlobalC::ucell.atoms[it0].nw), + static_cast( + GlobalC::ucell.atoms[it1].nw)}); + } + mR_a2D(iw0_b,iw1_b) = mR_2D(iwt0_2D, iwt1_2D); + } + } + } + } + ModuleBase::timer::tick("RI_2D_Comm", "split_m2D_ktoR"); + return mRs_a2D; +} + + +template +void RI_2D_Comm::add_Hexx( + const K_Vectors &kv, + const int ik, + const double alpha, + const std::vector>>> &Hs, + const Parallel_Orbitals& pv, + TK* hk) +{ + ModuleBase::TITLE("RI_2D_Comm","add_Hexx"); + ModuleBase::timer::tick("RI_2D_Comm", "add_Hexx"); + + const std::map> is_list = {{1,{0}}, {2,{kv.isk[ik]}}, {4,{0,1,2,3}}}; + for(const int is_b : is_list.at(PARAM.inp.nspin)) + { + int is0_b, is1_b; + std::tie(is0_b,is1_b) = RI_2D_Comm::split_is_block(is_b); + for(const auto &Hs_tmpA : Hs[is_b]) + { + const TA &iat0 = Hs_tmpA.first; + for(const auto &Hs_tmpB : Hs_tmpA.second) + { + const TA &iat1 = Hs_tmpB.first.first; + const TC &cell1 = Hs_tmpB.first.second; + const std::complex frac = alpha + * std::exp( ModuleBase::TWO_PI*ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec)) ); + const RI::Tensor &H = Hs_tmpB.second; + for(size_t iw0_b=0; iw0_b(H(iw0_b, iw1_b)) * RI::Global_Func::convert(frac), pv, hk); + } + } + } + } + } + ModuleBase::timer::tick("RI_2D_Comm", "add_Hexx"); +} + +std::tuple RI_2D_Comm::get_iat_iw_is_block(const int iwt) +{ + const int iat = GlobalC::ucell.iwt2iat[iwt]; + const int iw = GlobalC::ucell.iwt2iw[iwt]; + switch(PARAM.inp.nspin) + { + case 1: case 2: + return std::make_tuple(iat, iw, 0); + case 4: + return std::make_tuple(iat, iw/2, iw%2); + default: + throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); + } +} + +int RI_2D_Comm::get_is_block(const int is_k, const int is_row_b, const int is_col_b) +{ + switch(PARAM.inp.nspin) + { + case 1: return 0; + case 2: return is_k; + case 4: return is_row_b*2+is_col_b; + default: throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); + } +} + +std::tuple RI_2D_Comm::split_is_block(const int is_b) +{ + switch(PARAM.inp.nspin) + { + case 1: case 2: + return std::make_tuple(0, 0); + case 4: + return std::make_tuple(is_b/2, is_b%2); + default: + throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); + } +} + +int RI_2D_Comm::get_iwt(const int iat, const int iw_b, const int is_b) +{ + const int it = GlobalC::ucell.iat2it[iat]; + const int ia = GlobalC::ucell.iat2ia[iat]; + int iw=-1; + switch(PARAM.inp.nspin) + { + case 1: case 2: + iw = iw_b; break; + case 4: + iw = iw_b*2+is_b; break; + default: + throw std::invalid_argument(std::string(__FILE__)+" line "+std::to_string(__LINE__)); + } + const int iwt = GlobalC::ucell.itiaiw2iwt(it,ia,iw); + return iwt; +} + +template +void RI_2D_Comm::add_HexxR( + const int current_spin, + const double alpha, + const std::vector>>>& Hs, + const Parallel_Orbitals& pv, + const int npol, + hamilt::HContainer& hR, + const RI::Cell_Nearest* const cell_nearest) +{ + ModuleBase::TITLE("RI_2D_Comm", "add_HexxR"); + ModuleBase::timer::tick("RI_2D_Comm", "add_HexxR"); + const std::map> is_list = { {1,{0}}, {2,{current_spin}}, {4,{0,1,2,3}} }; + for (const int is_hs : is_list.at(PARAM.inp.nspin)) + { + int is0_b = 0, is1_b = 0; + std::tie(is0_b, is1_b) = RI_2D_Comm::split_is_block(is_hs); + for (const auto& Hs_tmpA : Hs[is_hs]) + { + const TA& iat0 = Hs_tmpA.first; + for (const auto& Hs_tmpB : Hs_tmpA.second) + { + const TA& iat1 = Hs_tmpB.first.first; + const TC& cell = Hs_tmpB.first.second; + const Abfs::Vector3_Order R = RI_Util::array3_to_Vector3( + (cell_nearest ? + cell_nearest->get_cell_nearest_discrete(iat0, iat1, cell) + : cell)); + hamilt::BaseMatrix* HlocR = hR.find_matrix(iat0, iat1, R.x, R.y, R.z); + if (HlocR == nullptr) + { // add R to HContainer + hamilt::AtomPair tmp(iat0, iat1, R.x, R.y, R.z, &pv); + hR.insert_pair(tmp); + HlocR = hR.find_matrix(iat0, iat1, R.x, R.y, R.z); + } + auto row_indexes = pv.get_indexes_row(iat0); + auto col_indexes = pv.get_indexes_col(iat1); + const RI::Tensor& HexxR = (Tdata)alpha * Hs_tmpB.second; + for (int lw0_b = 0;lw0_b < row_indexes.size();lw0_b += npol) // block + { + const int& gw0 = row_indexes[lw0_b] / npol; + const int& lw0 = (npol == 2) ? (lw0_b + is0_b) : lw0_b; + for (int lw1_b = 0;lw1_b < col_indexes.size();lw1_b += npol) + { + const int& gw1 = col_indexes[lw1_b] / npol; + const int& lw1 = (npol == 2) ? (lw1_b + is1_b) : lw1_b; + HlocR->add_element(lw0, lw1, RI::Global_Func::convert(HexxR(gw0, gw1))); + } + } + } + } + } + + ModuleBase::timer::tick("RI_2D_Comm", "add_HexxR"); +} + +template +std::map> RI_2D_Comm::comm_map2_first(const MPI_Comm& mpi_comm, + const std::map>& Ds_in, + const std::set& s0, + const std::set& s1) +{ + RI::Communicate_Map_Period::Judge_Map2_First judge; + judge.s0 = s0; + judge.s1 = s1; + return comm_map2(mpi_comm, Ds_in, judge); +} + +template +std::map> RI_2D_Comm::comm_map2(const MPI_Comm& mpi_comm, + const std::map>& Ds_in, + const Tjudge& judge) +{ + Comm::Comm_Assemble, T, std::map>, Tjudge, std::map>> + com(mpi_comm); + + com.traverse_keys_provide = Comm::Communicate_Map::traverse_keys; + com.get_value_provide = Comm::Communicate_Map::get_value; + com.set_value_require = set_value_add; + com.flag_lock_set_value = Comm::Comm_Tools::Lock_Type::Copy_merge; + com.init_datas_local = Comm::Communicate_Map::init_datas_local; + com.add_datas = add_datas; + + std::map> Ds_out; + com.communicate(Ds_in, judge, Ds_out); + return Ds_out; +} + +template +void RI_2D_Comm::set_value_add(Tkey&& key, Tvalue&& value, std::map& data) +{ + using namespace RI::Array_Operator; + auto ptr = data.find(key); + if (ptr == data.end()) + data[key] = std::move(value); + else + ptr->second = ptr->second + std::move(value); +} + +template +void RI_2D_Comm::set_value_add(std::tuple&& key, + Tvalue&& value, + std::map>& data) +{ + set_value_add(std::move(std::get<1>(key)), std::move(value), data[std::get<0>(key)]); +} + +template +void RI_2D_Comm::add_datas(std::map&& data_local, std::map& data_recv) +{ + using namespace RI::Array_Operator; + auto ptr_local = data_local.begin(); + auto ptr_recv = data_recv.begin(); + for (; ptr_local != data_local.end() && ptr_recv != data_recv.end();) + { + const Tkey& key_local = ptr_local->first; + const Tkey& key_recv = ptr_recv->first; + if (key_local == key_recv) + { + ptr_recv->second = ptr_recv->second + std::move(ptr_local->second); + ++ptr_local; + ++ptr_recv; + } + else if (key_local < key_recv) + { + ptr_recv = data_recv.emplace_hint(ptr_recv, key_local, std::move(ptr_local->second)); + ++ptr_local; + } + else + { + ++ptr_recv; + } + } + for (; ptr_local != data_local.end(); ++ptr_local) + { + ptr_recv = data_recv.emplace_hint(ptr_recv, ptr_local->first, std::move(ptr_local->second)); + } +} + +template +void RI_2D_Comm::add_datas(std::map>&& data_local, + std::map>& data_recv) +{ + auto ptr_local = data_local.begin(); + auto ptr_recv = data_recv.begin(); + for (; ptr_local != data_local.end() && ptr_recv != data_recv.end();) + { + const Tkey0& key_local = ptr_local->first; + const Tkey0& key_recv = ptr_recv->first; + if (key_local == key_recv) + { + add_datas(std::move(ptr_local->second), ptr_recv->second); + ++ptr_local; + ++ptr_recv; + } + else if (key_local < key_recv) + { + ptr_recv = data_recv.emplace_hint(ptr_recv, key_local, std::move(ptr_local->second)); + ++ptr_local; + } + else + { + ++ptr_recv; + } + } + for (; ptr_local != data_local.end(); ++ptr_local) + { + ptr_recv = data_recv.emplace_hint(ptr_recv, ptr_local->first, std::move(ptr_local->second)); + } +} + #endif \ No newline at end of file diff --git a/source/module_ri/RI_Util.h b/source/module_ri/RI_Util.h index 63726733b7b..20ca04a3a9f 100644 --- a/source/module_ri/RI_Util.h +++ b/source/module_ri/RI_Util.h @@ -9,13 +9,15 @@ #include #include +#include "module_cell/klist.h" + #include #include namespace RI_Util { inline extern std::array - get_Born_vonKarmen_period(); + get_Born_vonKarmen_period(const K_Vectors &kv); template extern std::vector> diff --git a/source/module_ri/RI_Util.hpp b/source/module_ri/RI_Util.hpp index a7fd64c6612..5124458d141 100644 --- a/source/module_ri/RI_Util.hpp +++ b/source/module_ri/RI_Util.hpp @@ -7,7 +7,6 @@ #define RI_UTIL_HPP #include "RI_Util.h" -#include "module_hamilt_pw/hamilt_pwdft/global.h" namespace RI_Util { diff --git a/source/module_ri/RPA_LRI.h b/source/module_ri/RPA_LRI.h index b169b0884b9..5a8cc1f256c 100644 --- a/source/module_ri/RPA_LRI.h +++ b/source/module_ri/RPA_LRI.h @@ -33,9 +33,8 @@ template class RPA_LRI using TatomR = std::array; // tmp public: - RPA_LRI(const Exx_Info::Exx_Info_RI &info_in) : info(info_in) - { - } + RPA_LRI(const Exx_Info::Exx_Info_RI &info_in, const Exx_Info::Exx_Info_Ewald &info_ewald_in) + :info(info_in), info_ewald(info_ewald_in){}; ~RPA_LRI(){}; void init(const MPI_Comm &mpi_comm_in, const K_Vectors &kv_in, const std::vector& orb_cutoff); void cal_rpa_cv(); @@ -61,6 +60,7 @@ template class RPA_LRI private: const Exx_Info::Exx_Info_RI &info; + const Exx_Info::Exx_Info_Ewald &info_ewald; const K_Vectors *p_kv=nullptr; MPI_Comm mpi_comm; std::vector orb_cutoff_; @@ -77,7 +77,7 @@ template class RPA_LRI // Tdata post_process_Erpa( const Tdata &Erpa_in ) const; }; -Exx_LRI exx_lri_rpa(GlobalC::exx_info.info_ri); +Exx_LRI exx_lri_rpa(GlobalC::exx_info.info_ri, GlobalC::exx_info.info_ewald); #include "RPA_LRI.hpp" #endif diff --git a/source/module_ri/RPA_LRI.hpp b/source/module_ri/RPA_LRI.hpp index d60bc87f1d0..19d0ec69cdf 100644 --- a/source/module_ri/RPA_LRI.hpp +++ b/source/module_ri/RPA_LRI.hpp @@ -56,7 +56,7 @@ void RPA_LRI::cal_rpa_cv() = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, atoms, period_Cs, 2, false); std::pair>>, - std::array>>, 3>> + std::map, 3>>>> Cs_dCs = exx_lri_rpa.cv.cal_Cs_dCs(list_As_Cs.first, list_As_Cs.second[0], { @@ -108,7 +108,7 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix exx_lri_rpa.init(mpi_comm_in, kv, orb); exx_lri_rpa.cal_exx_ions(PARAM.inp.out_ri_cv); - if (exx_spacegroup_symmetry) { + if (exx_spacegroup_symmetry && PARAM.inp.exx_symmetry_realspace) { exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer(), &symrot); } else { exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer()); @@ -164,10 +164,10 @@ void RPA_LRI::out_eigen_vector(const Parallel_Orbitals& parav, const p std::vector is_wfc_ib_iw(npsin_tmp); for (int is = 0; is < npsin_tmp; is++) { - is_wfc_ib_iw[is].create(GlobalV::NBANDS, GlobalV::NLOCAL); - for (int ib_global = 0; ib_global < GlobalV::NBANDS; ++ib_global) + is_wfc_ib_iw[is].create(PARAM.inp.nbands, PARAM.globalv.nlocal); + for (int ib_global = 0; ib_global < PARAM.inp.nbands; ++ib_global) { - std::vector> wfc_iks(GlobalV::NLOCAL, zero); + std::vector> wfc_iks(PARAM.globalv.nlocal, zero); const int ib_local = parav.global2local_col(ib_global); @@ -181,18 +181,18 @@ void RPA_LRI::out_eigen_vector(const Parallel_Orbitals& parav, const p std::vector> tmp = wfc_iks; #ifdef __MPI - MPI_Allreduce(&tmp[0], &wfc_iks[0], GlobalV::NLOCAL, MPI_DOUBLE_COMPLEX, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&tmp[0], &wfc_iks[0], PARAM.globalv.nlocal, MPI_DOUBLE_COMPLEX, MPI_SUM, MPI_COMM_WORLD); #endif - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { is_wfc_ib_iw[is](ib_global, iw) = wfc_iks[iw]; } } // ib } // is ofs << ik + 1 << std::endl; - for (int iw = 0; iw < GlobalV::NLOCAL; iw++) + for (int iw = 0; iw < PARAM.globalv.nlocal; iw++) { - for (int ib = 0; ib < GlobalV::NBANDS; ib++) + for (int ib = 0; ib < PARAM.inp.nbands; ib++) { for (int is = 0; is < npsin_tmp; is++) { @@ -259,8 +259,8 @@ void RPA_LRI::out_bands(const elecstate::ElecState* pelec) ofs.open(ss.str().c_str(), std::ios::out); ofs << nks_tot << std::endl; ofs << PARAM.inp.nspin << std::endl; - ofs << GlobalV::NBANDS << std::endl; - ofs << GlobalV::NLOCAL << std::endl; + ofs << PARAM.inp.nbands << std::endl; + ofs << PARAM.globalv.nlocal << std::endl; ofs << (pelec->eferm.ef / 2.0) << std::endl; for (int ik = 0; ik != nks_tot; ik++) @@ -268,7 +268,7 @@ void RPA_LRI::out_bands(const elecstate::ElecState* pelec) for (int is = 0; is != nspin_tmp; is++) { ofs << std::setw(6) << ik + 1 << std::setw(6) << is + 1 << std::endl; - for (int ib = 0; ib != GlobalV::NBANDS; ib++) + for (int ib = 0; ib != PARAM.inp.nbands; ib++) { ofs << std::setw(5) << ib + 1 << " " << std::setw(8) << pelec->wg(ik + is * nks_tot, ib) * nks_tot << std::setw(18) << std::fixed << std::setprecision(8) << pelec->ekb(ik + is * nks_tot, ib) / 2.0 diff --git a/source/module_ri/conv_coulomb_pot_k.cpp b/source/module_ri/conv_coulomb_pot_k.cpp index 14870a4f721..c353655968b 100644 --- a/source/module_ri/conv_coulomb_pot_k.cpp +++ b/source/module_ri/conv_coulomb_pot_k.cpp @@ -1,80 +1,148 @@ #include "conv_coulomb_pot_k.h" + #include "../module_base/constants.h" #include "module_parameter/parameter.h" #include "../module_basis/module_ao/ORB_atomic_lm.h" #include "../module_hamilt_pw/hamilt_pwdft/global.h" +#include "Faddeeva.hh" +namespace Conv_Coulomb_Pot_K { -namespace Conv_Coulomb_Pot_K -{ - - std::vector cal_psi_ccp( - const std::vector & psif) - { - std::vector psik2_ccp(psif.size()); - for( size_t ik=0; ik cal_psi_hf( - const std::vector &psif, - const std::vector &k_radial, - const double hf_Rcut) - { - std::vector psik2_ccp(psif.size()); - for (size_t ik = 0; ik < psif.size(); ++ik) - psik2_ccp[ik] = ModuleBase::FOUR_PI * psif[ik] * (1 - std::cos(k_radial[ik] * hf_Rcut)); - return psik2_ccp; - } +std::vector cal_psi_ccp(const std::vector& psif) { + std::vector psik2_ccp(psif.size()); + for (size_t ik = 0; ik < psif.size(); ++ik) + psik2_ccp[ik] = ModuleBase::FOUR_PI * psif[ik]; + return psik2_ccp; +} +std::vector cal_psi_ccp_cam(const std::vector& psif, + const std::vector& k_radial, + const double omega, + const double cam_alpha, + const double cam_beta) { + std::vector psik2_ccp(psif.size()); + for (size_t ik = 0; ik < psif.size(); ++ik) { + double fock_part + = 1 + - std::exp(-(k_radial[ik] * k_radial[ik]) / (4 * omega * omega)); + psik2_ccp[ik] = ModuleBase::FOUR_PI * psif[ik] + * (cam_alpha + cam_beta * fock_part); + } + return psik2_ccp; +} - std::vector cal_psi_hse( - const std::vector & psif, - const std::vector & k_radial, - const double hse_omega) - { - std::vector psik2_ccp(psif.size()); - for( size_t ik=0; ik cal_psi_hf(const std::vector& psif, + const std::vector& k_radial, + const double hf_Rcut) { + std::vector psik2_ccp(psif.size()); + for (size_t ik = 0; ik < psif.size(); ++ik) + psik2_ccp[ik] = ModuleBase::FOUR_PI * psif[ik] + * (1 - std::cos(k_radial[ik] * hf_Rcut)); + return psik2_ccp; +} +std::vector cal_psi_hse(const std::vector& psif, + const std::vector& k_radial, + const double hse_omega) { + std::vector psik2_ccp(psif.size()); + for (size_t ik = 0; ik < psif.size(); ++ik) + psik2_ccp[ik] = ModuleBase::FOUR_PI * psif[ik] + * (1 + - std::exp(-(k_radial[ik] * k_radial[ik]) + / (4 * hse_omega * hse_omega))); + return psik2_ccp; +} +std::vector cal_psi_cam( + const std::vector& psif, + const std::vector& k_radial, + const double omega, + const double cam_alpha, + const double cam_beta, + const double Rc) { + double eps = 1e-14; + std::vector psik2_ccp(psif.size()); + for (size_t ik = 0; ik < psif.size(); ++ik) { + double coulomb_part = 1 - std::cos(k_radial[ik] * Rc); + double temp0 = std::cos(k_radial[ik] * Rc) * Faddeeva::erfc(omega * Rc); + double temp1 + = std::exp(-(k_radial[ik] * k_radial[ik]) / (4 * omega * omega)); + std::complex temp2 = std::complex(0, 0); + std::complex temp3 = std::complex(0, 0); + if (temp1 >= eps) { + temp2 = Faddeeva::erf(0.5 + * (ModuleBase::IMAG_UNIT * k_radial[ik] + + 2 * omega * omega * Rc) + / omega); + temp3 = ModuleBase::NEG_IMAG_UNIT + * Faddeeva::erfi(0.5 * k_radial[ik] / omega + + ModuleBase::IMAG_UNIT * omega * Rc); + } + std::complex fock_part + = -0.5 * (-2 + 2 * temp0 + temp1 * (temp2 + temp3)); + psik2_ccp[ik] + = ModuleBase::FOUR_PI * psif[ik] + * (cam_alpha * coulomb_part + cam_beta * fock_part.real()); + } + return psik2_ccp; +} - template<> - Numerical_Orbital_Lm cal_orbs_ccp( - const Numerical_Orbital_Lm &orbs, - const Ccp_Type &ccp_type, - const std::map ¶meter, - const double rmesh_times) - { - std::vector psik2_ccp; - switch(ccp_type) - { - case Ccp_Type::Ccp: - psik2_ccp = cal_psi_ccp( orbs.get_psif() ); break; - case Ccp_Type::Hf: - psik2_ccp = cal_psi_hf( orbs.get_psif(), orbs.get_k_radial(), parameter.at("hf_Rcut")); break; - case Ccp_Type::Hse: - psik2_ccp = cal_psi_hse( orbs.get_psif(), orbs.get_k_radial(), parameter.at("hse_omega") ); break; - default: - throw( ModuleBase::GlobalFunc::TO_STRING(__FILE__)+" line "+ModuleBase::GlobalFunc::TO_STRING(__LINE__) ); break; - } +template <> +Numerical_Orbital_Lm cal_orbs_ccp( + const Numerical_Orbital_Lm& orbs, + const Ccp_Type& ccp_type, + const std::map& parameter, + const double rmesh_times) { + std::vector psik2_ccp; + switch (ccp_type) { + case Ccp_Type::Ccp: + psik2_ccp = cal_psi_ccp(orbs.get_psif()); + break; + case Ccp_Type::Hf: + psik2_ccp = cal_psi_hf(orbs.get_psif(), + orbs.get_k_radial(), + parameter.at("hf_Rcut")); + break; + case Ccp_Type::Hse: + psik2_ccp = cal_psi_hse(orbs.get_psif(), + orbs.get_k_radial(), + parameter.at("hse_omega")); + break; + case Ccp_Type::Cam: + psik2_ccp = cal_psi_cam(orbs.get_psif(), + orbs.get_k_radial(), + parameter.at("hse_omega"), + parameter.at("cam_alpha"), + parameter.at("cam_beta"), + parameter.at("hf_Rcut")); + break; + case Ccp_Type::Ccp_Cam: + psik2_ccp = cal_psi_ccp_cam(orbs.get_psif(), + orbs.get_k_radial(), + parameter.at("hse_omega"), + parameter.at("cam_alpha"), + parameter.at("cam_beta")); + break; + default: + throw(ModuleBase::GlobalFunc::TO_STRING(__FILE__) + " line " + + ModuleBase::GlobalFunc::TO_STRING(__LINE__)); + break; + } - const double dr = orbs.get_rab().back(); - const int Nr = (static_cast(orbs.getNr()*rmesh_times)) | 1; - std::vector rab(Nr); - for( size_t ir=0; ir r_radial(Nr); - for( size_t ir=0; ir(orbs.getNr() * rmesh_times)) | 1; + std::vector rab(Nr); + for (size_t ir = 0; ir < std::min(orbs.getNr(), Nr); ++ir) + rab[ir] = orbs.getRab(ir); + for (size_t ir = orbs.getNr(); ir < Nr; ++ir) + rab[ir] = dr; + std::vector r_radial(Nr); + for (size_t ir = 0; ir < std::min(orbs.getNr(), Nr); ++ir) + r_radial[ir] = orbs.getRadial(ir); + for (size_t ir = orbs.getNr(); ir < Nr; ++ir) + r_radial[ir] + = orbs.get_r_radial().back() + (ir - orbs.getNr() + 1) * dr; Numerical_Orbital_Lm orbs_ccp; orbs_ccp.set_orbital_info( @@ -95,17 +163,14 @@ namespace Conv_Coulomb_Pot_K return orbs_ccp; } - template<> - double get_rmesh_proportion( - const Numerical_Orbital_Lm &orbs, - const double psi_threshold) - { - for(int ir=orbs.getNr()-1; ir>=0; --ir) - { - if(std::abs(orbs.getPsi(ir))>=psi_threshold) - return static_cast(ir)/orbs.getNr(); - } - return 0.0; - } - +template <> +double get_rmesh_proportion(const Numerical_Orbital_Lm& orbs, + const double psi_threshold) { + for (int ir = orbs.getNr() - 1; ir >= 0; --ir) { + if (std::abs(orbs.getPsi(ir)) >= psi_threshold) + return static_cast(ir) / orbs.getNr(); + } + return 0.0; } + +} // namespace Conv_Coulomb_Pot_K diff --git a/source/module_ri/conv_coulomb_pot_k.h b/source/module_ri/conv_coulomb_pot_k.h index d464a53f91d..e32ee8512a8 100644 --- a/source/module_ri/conv_coulomb_pot_k.h +++ b/source/module_ri/conv_coulomb_pot_k.h @@ -1,16 +1,21 @@ #ifndef CONV_COULOMB_POT_K_H #define CONV_COULOMB_POT_K_H -#include #include #include +#include + +#include "module_cell/klist.h" namespace Conv_Coulomb_Pot_K { enum class Ccp_Type{ // parameter: Ccp, // Hf, // "hf_Rcut" - Hse}; // "hse_omega" + Hse, // "hse_omega" + Cam, // "hse_omega", "cam_alpha", "cam_beta", "hf_Rcut" + Ccp_Cam // "hse_omega", "cam_alpha", "cam_beta" + }; template T cal_orbs_ccp( const T &orbs, @@ -34,6 +39,19 @@ namespace Conv_Coulomb_Pot_K const std::vector & psif, const std::vector & k_radial, const double hse_omega); + std::vector cal_psi_cam( + const std::vector& psif, + const std::vector& k_radial, + const double omega, + const double cam_alpha, + const double cam_beta, + const double Rc); + + std::vector cal_psi_ccp_cam(const std::vector& psif, + const std::vector& k_radial, + const double omega, + const double cam_alpha, + const double cam_beta); } #include "conv_coulomb_pot_k.hpp" diff --git a/source/module_ri/ewald_Vq.h b/source/module_ri/ewald_Vq.h new file mode 100644 index 00000000000..3fcd1f49f42 --- /dev/null +++ b/source/module_ri/ewald_Vq.h @@ -0,0 +1,202 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-03-08 +//======================= + +#ifndef EWALD_VQ_H +#define EWALD_VQ_H + +#include "LRI_CV.h" +#include "gaussian_abfs.h" +#include "module_base/element_basis_index.h" +#include "module_cell/klist.h" +#include "module_hamilt_general/module_xc/exx_info.h" +#include "module_parameter/parameter.h" + +#include +#include +#include +#include + +template +class Ewald_Vq +{ + private: + using TA = int; + using Tcell = int; + static constexpr std::size_t Ndim = 3; + using TC = std::array; + using TAC = std::pair; + + using TK = std::array; + using TAK = std::pair; + + public: + Ewald_Vq(const Exx_Info::Exx_Info_RI& info_in, const Exx_Info::Exx_Info_Ewald& info_ewald_in) + : info(info_in), info_ewald(info_ewald_in) + { + } + + void init(const LCAO_Orbitals& orb, + const MPI_Comm& mpi_comm_in, + const K_Vectors* kv_in, + std::vector>>& lcaos_in, + std::vector>>& abfs_in, + const std::map& parameter, + ORB_gaunt_table& MGT_in); + + void init_ions(const std::array& period_Vs_NAO); + + double get_singular_chi(const Singular_Value::Fq_type& fq_type, const double& qdiv); + + inline std::map>>> cal_Vq( + const double& chi, + std::map>>& Vs_in); // return Vq [0, Nk) + inline std::map>, Ndim>>> cal_dVq( + const double& chi, + std::map, Ndim>>>& dVs_in); // return Vq [0, Nk) + + inline std::map>> cal_Vs(const double& chi, + std::map>>& Vs_in); + inline std::map, Ndim>>> cal_dVs( + const double& chi, + std::map, Ndim>>>& dVs_in); + + private: + const Exx_Info::Exx_Info_RI& info; + const Exx_Info::Exx_Info_Ewald& info_ewald; + LRI_CV cv; + Gaussian_Abfs gaussian_abfs; + const K_Vectors* p_kv; + std::vector> kvec_c; + // std::vector wk; + MPI_Comm mpi_comm; + ModuleBase::realArray gaunt; + std::array nmp; + const double ewald_lambda = 1.0; + + std::vector>> multipole; + ModuleBase::Element_Basis_Index::IndexLNM index_abfs; + + std::vector lcaos_rcut; + std::vector g_lcaos_rcut; + std::vector g_abfs_ccp_rcut; + + const int nspin0 = std::map{{1, 1}, {2, 2}, {4, 1}}.at(PARAM.inp.nspin); + int nks0; + std::vector atoms_vec; + std::set atoms; + std::map parameter; + + std::vector>> g_lcaos; + std::vector>> g_abfs; + std::vector>> g_abfs_ccp; + + /* + MPI distribute + distribute_atoms_periods: + - list_A0 / list_A1 : {ia0, {ia1, R}} ; range -> [-Rmax, Rmax) + - list_A0_k / list_A1_k : {ia0, {ia1, ik}} ; range -> [-Nk/2, Nk/2) + + distribute_atoms: + - list_A0_pair_R / list_A1_pair_R : {ia0, ia1} for R ; range -> [-Rmax, + Rmax) + - list_A0_pair_k / list_A1_pair_k : {ia0, ia1} for k ; range -> [-Nk/2, + Nk/2) + - list_A0_pair_R_period / list_A1_pair_R_period : {ia0, ia1} for R ; range + -> match with kmesh + */ + std::vector list_A0; + std::vector list_A1; + std::vector list_A0_k; + std::vector list_A1_k; + std::vector list_A0_pair_R; + std::vector list_A1_pair_R; + std::vector list_A0_pair_R_period; + std::vector list_A1_pair_R_period; + std::vector list_A0_pair_k; + std::vector list_A1_pair_k; + + private: + inline std::map>> cal_Vs_gauss(const std::vector& list_A0, + const std::vector& list_A1); + inline std::map, Ndim>>> cal_dVs_gauss( + const std::vector& list_A0, + const std::vector& list_A1); + + inline std::map>> cal_Vs_minus_gauss( + const std::vector& list_A0, + const std::vector& list_A1, + std::map>>& Vs_in); + inline std::map, Ndim>>> cal_dVs_minus_gauss( + const std::vector& list_A0, + const std::vector& list_A1, + std::map, Ndim>>>& dVs_in); + template + std::map> set_Vs_dVs_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>& Vs_dVs_in, + std::map>& Vs_dVs_gauss_in); + + template + using T_func_DPget_Vq_dVq + = std::function& tau)>; + inline std::map>>> cal_Vq_gauss( + const std::vector& list_A0_k, + const std::vector& list_A1_k, + const double& chi, + const int& shift_for_mpi); // return Vq [-Nk/2, Nk/2) + inline std::map>, Ndim>>> cal_dVq_gauss( + const std::vector& list_A0_k, + const std::vector& list_A1_k, + const double& chi, + const int& shift_for_mpi); // return dVq [-Nk/2, Nk/2) + template + std::map> set_Vq_dVq_gauss(const std::vector& list_A0_k, + const std::vector& list_A1_k, + const int& shift_for_mpi, + const T_func_DPget_Vq_dVq& func_DPget_Vq_dVq); + + inline std::map>>> cal_Vq_minus_gauss( + const std::vector& list_A0, + const std::vector& list_A1, + std::map>>& Vs_minus_gauss); // return Vq [0, Nk) + inline std::map>, Ndim>>> cal_dVq_minus_gauss( + const std::vector& list_A0, + const std::vector& list_A1, + std::map, Ndim>>>& dVs_minus_gauss); // return Vq [0, Nk) + template + std::map> set_Vq_dVq_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>& Vs_dVs_minus_gauss); + + template + using T_func_DPcal_Vq_dVq_minus_gauss + = std::function>(std::map>& Vs_dVs_minus_gauss)>; + template + using T_func_DPcal_Vq_dVq_gauss = std::function>(const int& shift_for_mpi)>; + template + std::map> set_Vq_dVq( + const std::vector& list_A0_pair_k, + const std::vector& list_A1_pair_k, + std::map>& Vs_dVs_minus_gauss_in, + const T_func_DPcal_Vq_dVq_minus_gauss& func_cal_Vq_dVq_minus_gauss, + const T_func_DPcal_Vq_dVq_gauss& func_cal_Vq_dVq_gauss); // return Vq [0, Nk) + + template + std::map> set_Vs_dVs(const std::vector& list_A0_pair_R, + const std::vector& list_A1_pair_R, + std::map>& Vq); + + std::vector>> init_gauss( + std::vector>>& orb_in); + + inline double cal_V_Rcut(const int it0, const int it1); + inline double get_Rcut_max(const int it0, const int it1); +}; +#include "ewald_Vq.hpp" + +#endif \ No newline at end of file diff --git a/source/module_ri/ewald_Vq.hpp b/source/module_ri/ewald_Vq.hpp new file mode 100644 index 00000000000..f4cd9a1ffe8 --- /dev/null +++ b/source/module_ri/ewald_Vq.hpp @@ -0,0 +1,847 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-03-08 +//======================= + +#ifndef EWALD_VQ_HPP +#define EWALD_VQ_HPP + +#include +#include +#include + +// #include +#include "RI_2D_Comm.h" +#include "RI_Util.h" +#include "conv_coulomb_pot_k.h" +#include "exx_abfs-abfs_index.h" +#include "exx_abfs-construct_orbs.h" +#include "gaussian_abfs.h" +#include "module_base/element_basis_index.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "singular_value.h" + +#include + +template +void Ewald_Vq::init(const LCAO_Orbitals& orb, + const MPI_Comm& mpi_comm_in, + const K_Vectors* kv_in, + std::vector>>& lcaos_in, + std::vector>>& abfs_in, + const std::map& parameter, + ORB_gaunt_table& MGT_in) +{ + ModuleBase::TITLE("Ewald_Vq", "init"); + ModuleBase::timer::tick("Ewald_Vq", "init"); + + this->mpi_comm = mpi_comm_in; + this->p_kv = kv_in; + this->nks0 = this->p_kv->get_nkstot_full() / this->nspin0; + this->kvec_c.resize(this->nks0); + + this->parameter = parameter; + this->g_lcaos = this->init_gauss(lcaos_in); + this->g_abfs = this->init_gauss(abfs_in); + this->g_abfs_ccp = Conv_Coulomb_Pot_K::cal_orbs_ccp(this->g_abfs, + this->info.ccp_type, + this->parameter, + this->info.ccp_rmesh_times); + this->multipole = Exx_Abfs::Construct_Orbs::get_multipole(abfs_in); + this->lcaos_rcut = Exx_Abfs::Construct_Orbs::get_Rcut(lcaos_in); + this->g_lcaos_rcut = Exx_Abfs::Construct_Orbs::get_Rcut(this->g_lcaos); + this->g_abfs_ccp_rcut = Exx_Abfs::Construct_Orbs::get_Rcut(this->g_abfs_ccp); + + const ModuleBase::Element_Basis_Index::Range range_abfs = Exx_Abfs::Abfs_Index::construct_range(abfs_in); + this->index_abfs = ModuleBase::Element_Basis_Index::construct_index(range_abfs); + + this->cv + .set_orbitals(orb, this->g_lcaos, this->g_abfs, this->g_abfs_ccp, this->info.kmesh_times, MGT_in, false, false); + this->gaunt.create(MGT_in.Gaunt_Coefficients.getBound1(), + MGT_in.Gaunt_Coefficients.getBound2(), + MGT_in.Gaunt_Coefficients.getBound3()); + this->gaunt = MGT_in.Gaunt_Coefficients; + + this->atoms_vec.resize(GlobalC::ucell.nat); + std::iota(this->atoms_vec.begin(), this->atoms_vec.end(), 0); + this->atoms.insert(this->atoms_vec.begin(), this->atoms_vec.end()); + this->nmp = {this->p_kv->nmp[0], this->p_kv->nmp[1], this->p_kv->nmp[2]}; + + ModuleBase::timer::tick("Ewald_Vq", "init"); +} + +template +void Ewald_Vq::init_ions(const std::array& period_Vs_NAO) +{ + ModuleBase::TITLE("Ewald_Vq", "init_ions"); + ModuleBase::timer::tick("Ewald_Vq", "init_ions"); + + const std::array period_Vs + = LRI_CV_Tools::cal_latvec_range(1 + this->info.ccp_rmesh_times, this->g_lcaos_rcut); + + const std::pair, std::vector>>>> list_As_Vs + = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, this->atoms_vec, period_Vs, 2, false); + + this->list_A0 = list_As_Vs.first; + this->list_A1 = list_As_Vs.second[0]; + + const std::array Nks = {this->nks0}; + const std::pair, std::vector>>> list_As_Vq + = RI::Distribute_Equally::distribute_atoms_periods(this->mpi_comm, this->atoms_vec, Nks, 2, false); + this->list_A0_k = list_As_Vq.first; + this->list_A1_k = list_As_Vq.second[0]; + + const std::pair, std::vector>>> list_As_Vs_atoms + = RI::Distribute_Equally::distribute_atoms(this->mpi_comm, this->atoms_vec, period_Vs_NAO, 2, false); + this->list_A0_pair_R = list_As_Vs_atoms.first; + this->list_A1_pair_R = list_As_Vs_atoms.second[0]; + + const std::pair, std::vector>>> list_As_Vs_atoms_period + = RI::Distribute_Equally::distribute_atoms(this->mpi_comm, this->atoms_vec, this->nmp, 2, false); + this->list_A0_pair_R_period = list_As_Vs_atoms_period.first; + this->list_A1_pair_R_period = list_As_Vs_atoms_period.second[0]; + + const std::pair, std::vector>>> list_As_Vq_atoms + = RI::Distribute_Equally::distribute_atoms(this->mpi_comm, this->atoms_vec, Nks, 2, false); + this->list_A0_pair_k = list_As_Vq_atoms.first; + this->list_A1_pair_k = list_As_Vq_atoms.second[0]; + + for (size_t ik = 0; ik != this->nks0; ++ik) + this->kvec_c[ik] = this->p_kv->kvec_c_full[ik]; + + std::vector> neg_kvec(this->nks0); + std::transform(this->kvec_c.begin(), + this->kvec_c.end(), + neg_kvec.begin(), + [](ModuleBase::Vector3& vec) -> ModuleBase::Vector3 { return -vec; }); + this->gaussian_abfs.init(2 * GlobalC::exx_info.info_ri.abfs_Lmax + 1, + neg_kvec, + GlobalC::ucell.G, + this->ewald_lambda); + + ModuleBase::timer::tick("Ewald_Vq", "init_ions"); +} + +template +double Ewald_Vq::get_singular_chi(const Singular_Value::Fq_type& fq_type, const double& qdiv) +{ + ModuleBase::TITLE("Ewald_Vq", "get_singular_chi"); + ModuleBase::timer::tick("Ewald_Vq", "get_singular_chi"); + + double chi = 0.0; + switch (fq_type) + { + case Singular_Value::Fq_type::Type_0: + chi = Singular_Value::cal_type_0(this->kvec_c, qdiv, 100, 30, 1e-6, 3); + break; + case Singular_Value::Fq_type::Type_1: + chi = Singular_Value::cal_type_1(this->nmp, qdiv, 1, 5, 1e-4); + break; + default: + throw std::domain_error(std::string(__FILE__) + " line " + std::to_string(__LINE__)); + break; + } + + ModuleBase::timer::tick("Ewald_Vq", "get_singular_chi"); + return chi; +} + +template +auto Ewald_Vq::cal_Vs_gauss(const std::vector& list_A0, + const std::vector& list_A1) -> std::map>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vs_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs_gauss"); + + std::map flags = {{"writable_Vws", true}}; + std::map>> Vs_gauss = this->cv.cal_Vs(list_A0, list_A1, flags); + this->cv.Vws = LRI_CV_Tools::get_CVws(Vs_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs_gauss"); + return Vs_gauss; +} + +template +auto Ewald_Vq::cal_dVs_gauss(const std::vector& list_A0, const std::vector& list_A1) + -> std::map, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVs_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs_gauss"); + + std::map flags = {{"writable_dVws", true}}; + + std::map, Ndim>>> dVs_gauss + = this->cv.cal_dVs(list_A0, list_A1, flags); + this->cv.dVws = LRI_CV_Tools::get_dCVws(dVs_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs_gauss"); + return dVs_gauss; +} + +template +auto Ewald_Vq::cal_Vs_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>>& Vs_in) + -> std::map>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vs_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs_minus_gauss"); + + std::map>> Vs_gauss = this->cal_Vs_gauss(list_A0, list_A1); + std::map>> Vs_minus_gauss + = this->set_Vs_dVs_minus_gauss(list_A0, list_A1, Vs_in, Vs_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs_minus_gauss"); + return Vs_minus_gauss; +} + +template +auto Ewald_Vq::cal_dVs_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map, Ndim>>>& dVs_in) + -> std::map, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVs_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs_minus_gauss"); + + std::map, Ndim>>> dVs_gauss = this->cal_dVs_gauss(list_A0, list_A1); + std::map, Ndim>>> dVs_minus_gauss + = this->set_Vs_dVs_minus_gauss(list_A0, list_A1, dVs_in, dVs_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs_minus_gauss"); + return dVs_minus_gauss; +} + +template +double Ewald_Vq::cal_V_Rcut(const int it0, const int it1) +{ + // return this->g_abfs_ccp_rcut[it0] + this->g_lcaos_rcut[it1]; + return this->g_lcaos_rcut[it0] + this->g_lcaos_rcut[it1]; +} + +template +double Ewald_Vq::get_Rcut_max(const int it0, const int it1) +{ + double lcaos_rmax = this->lcaos_rcut[it0] //* this->info.ccp_rmesh_times + + this->lcaos_rcut[it1]; + double g_lcaos_rmax = this->g_lcaos_rcut[it0] //* this->info.ccp_rmesh_times + + this->g_lcaos_rcut[it1]; + + return std::min(lcaos_rmax, g_lcaos_rmax); +} + +template +template +auto Ewald_Vq::set_Vs_dVs_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>& Vs_dVs_in, + std::map>& Vs_dVs_gauss_in) + -> std::map> +{ + ModuleBase::TITLE("Ewald_Vq", "set_Vs_dVs_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "set_Vs_dVs_minus_gauss"); + + using Tin_convert = typename LRI_CV_Tools::TinType::type; + std::map> pVs_dVs_gauss; +#pragma omp parallel + for (size_t i0 = 0; i0 < list_A0.size(); ++i0) + { +#pragma omp for schedule(dynamic) nowait + for (size_t i1 = 0; i1 < list_A1.size(); ++i1) + { + const TA iat0 = list_A0[i0]; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const TA iat1 = list_A1[i1].first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const TC& cell1 = list_A1[i1].second; + + const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; + const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; + + const double Rcut = std::min(this->cal_V_Rcut(it0, it1), this->cal_V_Rcut(it1, it0)); + const Abfs::Vector3_Order R_delta + = -tau0 + tau1 + (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec); + if (R_delta.norm() * GlobalC::ucell.lat0 < Rcut) + { + const size_t size0 = this->index_abfs[it0].count_size; + const size_t size1 = this->index_abfs[it1].count_size; + Tresult data; + LRI_CV_Tools::init_elem(data, size0, size1); + + // pA * pB * V(R)_gauss + for (int l0 = 0; l0 != this->g_abfs_ccp[it0].size(); ++l0) + { + for (int l1 = 0; l1 != this->g_abfs[it1].size(); ++l1) + { + for (size_t n0 = 0; n0 != this->g_abfs_ccp[it0][l0].size(); ++n0) + { + const double pA = this->multipole[it0][l0][n0]; + for (size_t n1 = 0; n1 != this->g_abfs[it1][l1].size(); ++n1) + { + const double pB = this->multipole[it1][l1][n1]; + Tin_convert pp = RI::Global_Func::convert(pA * pB); + for (size_t m0 = 0; m0 != 2 * l0 + 1; ++m0) + { + for (size_t m1 = 0; m1 != 2 * l1 + 1; ++m1) + { + const size_t index0 = this->index_abfs[it0][l0][n0][m0]; + const size_t index1 = this->index_abfs[it1][l1][n1][m1]; + + LRI_CV_Tools::add_elem(data, + index0, + index1, + Vs_dVs_gauss_in[list_A0[i0]][list_A1[i1]], + index0, + index1, + pp); + } + } + } + } + } + } +#pragma omp critical(Ewald_Vq_set_Vs_dVs_minus_gauss) + pVs_dVs_gauss[list_A0[i0]][list_A1[i1]] = data; + } + } + } + + std::map> Vs_dVs_minus_gauss = LRI_CV_Tools::minus(Vs_dVs_in, pVs_dVs_gauss); + ModuleBase::timer::tick("Ewald_Vq", "set_Vs_dVs_minus_gauss"); + return Vs_dVs_minus_gauss; +} + +template +auto Ewald_Vq::cal_Vq_gauss(const std::vector& list_A0_k, + const std::vector& list_A1_k, + const double& chi, + const int& shift_for_mpi) + -> std::map>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vq_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq_gauss"); + + const T_func_DPget_Vq_dVq>> func_DPget_Vq = std::bind(&Gaussian_Abfs::get_Vq, + &this->gaussian_abfs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + chi, + std::placeholders::_4, + this->gaunt); + auto Vq_gauss = this->set_Vq_dVq_gauss(list_A0_k, list_A1_k, shift_for_mpi, func_DPget_Vq); + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq_gauss"); + return Vq_gauss; +} + +template +auto Ewald_Vq::cal_dVq_gauss(const std::vector& list_A0_k, + const std::vector& list_A1_k, + const double& chi, + const int& shift_for_mpi) + -> std::map>, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVq_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq_gauss"); + + const T_func_DPget_Vq_dVq>, Ndim>> func_DPget_dVq + = std::bind(&Gaussian_Abfs::get_dVq, + &this->gaussian_abfs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + chi, + std::placeholders::_4, + this->gaunt); + + using namespace RI::Array_Operator; + std::map>, Ndim>>> dVq_gauss; + auto res = this->set_Vq_dVq_gauss(list_A0_k, list_A1_k, shift_for_mpi, func_DPget_dVq); + + for (size_t i0 = 0; i0 < list_A0_k.size(); ++i0) + { + const TA iat0 = list_A0_k[i0]; + const int it0 = GlobalC::ucell.iat2it[iat0]; + for (size_t i1 = 0; i1 < list_A1_k.size(); ++i1) + { + const TA iat1 = list_A1_k[i1].first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + if (iat0 != iat1) + { + const int ik = list_A1_k[i1].second[0]; + const TAK index0 = std::make_pair(iat1, TK{ik}); + dVq_gauss[iat0][index0] = -res[list_A0_k[i0]][list_A1_k[i1]]; + const TAK index1 = std::make_pair(iat0, TK{ik}); + dVq_gauss[iat1][index1] = res[list_A0_k[i0]][list_A1_k[i1]]; + } + else + dVq_gauss[list_A0_k[i0]][list_A1_k[i1]] = res[list_A0_k[i0]][list_A1_k[i1]]; + } + } + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq_gauss"); + return dVq_gauss; +} + +template +template +auto Ewald_Vq::set_Vq_dVq_gauss(const std::vector& list_A0_k, + const std::vector& list_A1_k, + const int& shift_for_mpi, + const T_func_DPget_Vq_dVq& func_DPget_Vq_dVq) + -> std::map> +{ + ModuleBase::TITLE("Ewald_Vq", "set_Vq_dVq_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq_gauss"); + + std::map> Vq_dVq_gauss_out; + +#pragma omp parallel + for (size_t i0 = 0; i0 < list_A0_k.size(); ++i0) + { +#pragma omp for schedule(dynamic) nowait + for (size_t i1 = 0; i1 < list_A1_k.size(); ++i1) + { + const TA iat0 = list_A0_k[i0]; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; + + const TA iat1 = list_A1_k[i1].first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; + const size_t ik = list_A1_k[i1].second[0] + shift_for_mpi; + + const ModuleBase::Vector3 tau = tau0 - tau1; + auto data = func_DPget_Vq_dVq(this->g_abfs_ccp[it0].size() - 1, this->g_abfs[it1].size() - 1, ik, tau); + +#pragma omp critical(Ewald_Vq_set_Vq_dVq_gauss) + Vq_dVq_gauss_out[list_A0_k[i0]][list_A1_k[i1]] = data; + } + } + + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq_gauss"); + return Vq_dVq_gauss_out; +} + +template +auto Ewald_Vq::cal_Vq_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>>& Vs_minus_gauss) + -> std::map>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vq_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq_minus_gauss"); + + auto Vq_minus_gauss + = this->set_Vq_dVq_minus_gauss>>(list_A0, list_A1, Vs_minus_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq_minus_gauss"); + return Vq_minus_gauss; +} + +template +auto Ewald_Vq::cal_dVq_minus_gauss( + const std::vector& list_A0, + const std::vector& list_A1, + std::map, Ndim>>>& dVs_minus_gauss) + -> std::map>, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVq_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq_minus_gauss"); + + auto dVq_minus_gauss + = this->set_Vq_dVq_minus_gauss>, Ndim>>(list_A0, + list_A1, + dVs_minus_gauss); + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq_minus_gauss"); + return dVq_minus_gauss; +} + +template +template +auto Ewald_Vq::set_Vq_dVq_minus_gauss(const std::vector& list_A0, + const std::vector& list_A1, + std::map>& Vs_dVs_minus_gauss) + -> std::map> +{ + ModuleBase::TITLE("Ewald_Vq", "set_Vq_dVq_minus_gauss"); + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq_minus_gauss"); + + using namespace RI::Array_Operator; + using Tin_convert = typename LRI_CV_Tools::TinType::type; + std::map> datas; + + // auto start = std::chrono::system_clock::now(); + +#pragma omp parallel + { + std::map> local_datas; + +#pragma omp for schedule(dynamic) nowait + for (size_t ik = 0; ik != this->nks0; ++ik) + { + for (size_t i0 = 0; i0 < list_A0.size(); ++i0) + { + for (size_t i1 = 0; i1 < list_A1.size(); ++i1) + { + const TA iat0 = list_A0[i0]; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const TA iat1 = list_A1[i1].first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const TC& cell1 = list_A1[i1].second; + + const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; + const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; + const double Rcut = std::min(this->get_Rcut_max(it0, it1), this->get_Rcut_max(it1, it0)); + const ModuleBase::Vector3 R_delta + = -tau0 + tau1 + (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec); + + if (R_delta.norm() * GlobalC::ucell.lat0 < Rcut) + { + const std::complex phase = std::exp( + ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT + * (this->kvec_c[ik] * (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec))); + + Tout Vs_dVs_tmp = LRI_CV_Tools::mul2( + phase, + LRI_CV_Tools::convert(std::move(Vs_dVs_minus_gauss[iat0][list_A1[i1]]))); + + const TAK index = std::make_pair(iat1, TK{static_cast(ik)}); + if (!LRI_CV_Tools::exist(local_datas[iat0][index])) + local_datas[iat0][index] = Vs_dVs_tmp; + else + local_datas[iat0][index] = local_datas[iat0][index] + Vs_dVs_tmp; + } + } + } + } + +#pragma omp critical(Ewald_Vq_set_Vq_dVq_minus_gauss) + { + for (auto it0 = local_datas.begin(); it0 != local_datas.end(); ++it0) + { + const TA& key0 = it0->first; + std::map& map1 = it0->second; + for (auto it1 = map1.begin(); it1 != map1.end(); ++it1) + { + const TAK& key1 = it1->first; + Tout& value = it1->second; + + if (!LRI_CV_Tools::exist(datas[key0][key1])) + datas[key0][key1] = value; + else + datas[key0][key1] = datas[key0][key1] + value; + } + } + } + } + + // auto end = std::chrono::system_clock::now(); + // auto duration = std::chrono::duration_cast(end + // - start); std::cout << "set_Vq_dVq_minus_gauss Time: " + // << double(duration.count()) * + // std::chrono::microseconds::period::num + // / std::chrono::microseconds::period::den + // << " s" << std::endl; + + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq_minus_gauss"); + return datas; +} + +template +auto Ewald_Vq::cal_Vq(const double& chi, std::map>>& Vs_in) + -> std::map>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vq"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq"); + + std::map>> Vs_minus_gauss = this->cal_Vs_minus_gauss(this->list_A0, + this->list_A1, + Vs_in); //{ia0, {ia1, R}} + const T_func_DPcal_Vq_dVq_minus_gauss>, RI::Tensor> func_cal_Vq_minus_gauss + = std::bind(&Ewald_Vq::cal_Vq_minus_gauss, + this, + this->list_A0_pair_R, + this->list_A1_pair_R, + std::placeholders::_1); + const T_func_DPcal_Vq_dVq_gauss>> func_cal_Vq_gauss + = std::bind(&Ewald_Vq::cal_Vq_gauss, this, this->list_A0_k, this->list_A1_k, chi, std::placeholders::_1); + + auto Vq = this->set_Vq_dVq(this->list_A0_pair_k, + this->list_A1_pair_k, + Vs_minus_gauss, + func_cal_Vq_minus_gauss, + func_cal_Vq_gauss); //{ia0, ia1} + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vq"); + return Vq; +} + +template +auto Ewald_Vq::cal_dVq(const double& chi, + std::map, Ndim>>>& dVs_in) + -> std::map>, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVq"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq"); + + std::map, Ndim>>> dVs_minus_gauss + = this->cal_dVs_minus_gauss(this->list_A0, + this->list_A1, + dVs_in); //{ia0, {ia1, R}} + const T_func_DPcal_Vq_dVq_minus_gauss>, Ndim>, + std::array, Ndim>> + func_cal_dVq_minus_gauss = std::bind(&Ewald_Vq::cal_dVq_minus_gauss, + this, + this->list_A0_pair_R, + this->list_A1_pair_R, + std::placeholders::_1); + const T_func_DPcal_Vq_dVq_gauss>, Ndim>> func_cal_dVq_gauss + = std::bind(&Ewald_Vq::cal_dVq_gauss, + this, + this->list_A0_k, + this->list_A1_k, + chi, + std::placeholders::_1); + + auto dVq = this->set_Vq_dVq(this->list_A0_pair_k, + this->list_A1_pair_k, + dVs_minus_gauss, + func_cal_dVq_minus_gauss, + func_cal_dVq_gauss); //{ia0, ia1} + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVq"); + return dVq; +} + +template +template +auto Ewald_Vq::set_Vq_dVq(const std::vector& list_A0_pair_k, + const std::vector& list_A1_pair_k, + std::map>& Vs_dVs_minus_gauss_in, + const T_func_DPcal_Vq_dVq_minus_gauss& func_cal_Vq_dVq_minus_gauss, + const T_func_DPcal_Vq_dVq_gauss& func_cal_Vq_dVq_gauss) + -> std::map> +{ + ModuleBase::TITLE("Ewald_Vq", "set_Vq_dVq"); + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq"); + + using namespace RI::Array_Operator; + using Tin_convert = typename LRI_CV_Tools::TinType::type; + std::map> Vq_dVq; + const int shift_for_mpi = std::floor(this->nks0 / 2.0); + + // MPI: {ia0, {ia1, R}} to {ia0, ia1} + std::map> Vs_dVs_minus_gauss + = RI_2D_Comm::comm_map2_first(this->mpi_comm, Vs_dVs_minus_gauss_in, this->atoms, this->atoms); + std::map> Vq_dVq_minus_gauss = func_cal_Vq_dVq_minus_gauss(Vs_dVs_minus_gauss); //{ia0, ia1} + + // MPI: {ia0, {ia1, k}} to {ia0, ia1} + std::map> Vq_dVq_gauss_out = func_cal_Vq_dVq_gauss(shift_for_mpi); //{ia0, {ia1, k}} + std::map> Vq_dVq_gauss = RI_2D_Comm::comm_map2_first(this->mpi_comm, + Vq_dVq_gauss_out, + this->atoms, + this->atoms); //{ia0, ia1} + +#pragma omp parallel + for (size_t i0 = 0; i0 < list_A0_pair_k.size(); ++i0) + { +#pragma omp for schedule(dynamic) nowait + for (size_t i1 = 0; i1 < list_A1_pair_k.size(); ++i1) + { + const TA iat0 = list_A0_pair_k[i0]; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const TA iat1 = list_A1_pair_k[i1].first; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ik = list_A1_pair_k[i1].second[0] + shift_for_mpi; + const TAK re_index = std::make_pair(iat1, std::array{ik}); + + const size_t size0 = this->index_abfs[it0].count_size; + const size_t size1 = this->index_abfs[it1].count_size; + Tout data; + LRI_CV_Tools::init_elem(data, size0, size1); + for (int l0 = 0; l0 != this->g_abfs_ccp[it0].size(); ++l0) + { + for (int l1 = 0; l1 != this->g_abfs[it1].size(); ++l1) + { + for (size_t n0 = 0; n0 != this->g_abfs_ccp[it0][l0].size(); ++n0) + { + const double pA = this->multipole[it0][l0][n0]; + for (size_t n1 = 0; n1 != this->g_abfs[it1][l1].size(); ++n1) + { + const double pB = this->multipole[it1][l1][n1]; + Tin_convert pp = RI::Global_Func::convert(pA * pB); + for (size_t m0 = 0; m0 != 2 * l0 + 1; ++m0) + { + const size_t index0 = this->index_abfs[it0][l0][n0][m0]; + const size_t lm0 = l0 * l0 + m0; + for (size_t m1 = 0; m1 != 2 * l1 + 1; ++m1) + { + const size_t index1 = this->index_abfs[it1][l1][n1][m1]; + const size_t lm1 = l1 * l1 + m1; + + LRI_CV_Tools::add_elem(data, + index0, + index1, + Vq_dVq_gauss[list_A0_pair_k[i0]][list_A1_pair_k[i1]], + lm0, + lm1, + pp); + } + } + } + } + } + } + +#pragma omp critical(Ewald_Vq_set_Vq_dVq) + Vq_dVq[list_A0_pair_k[i0]][re_index] = Vq_dVq_minus_gauss[list_A0_pair_k[i0]][re_index] + data; + } + } + + ModuleBase::timer::tick("Ewald_Vq", "set_Vq_dVq"); + return Vq_dVq; +} + +template +auto Ewald_Vq::cal_Vs(const double& chi, std::map>>& Vs_in) //{ia0, {ia1, R}} + -> std::map>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_Vs"); + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs"); + + std::map>>> Vq = this->cal_Vq(chi, Vs_in); + auto Vs = this->set_Vs_dVs>(this->list_A0_pair_R_period, + this->list_A1_pair_R_period, + Vq); //{ia0, ia1} + + ModuleBase::timer::tick("Ewald_Vq", "cal_Vs"); + return Vs; +} + +template +auto Ewald_Vq::cal_dVs( + const double& chi, + std::map, Ndim>>>& dVs_in) //{ia0, {ia1, R}} + -> std::map, Ndim>>> +{ + ModuleBase::TITLE("Ewald_Vq", "cal_dVs"); + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs"); + + std::map>, Ndim>>> dVq = this->cal_dVq(chi, dVs_in); + auto dVs = this->set_Vs_dVs, Ndim>>(this->list_A0_pair_R_period, + this->list_A1_pair_R_period, + dVq); //{ia0, ia1} + + ModuleBase::timer::tick("Ewald_Vq", "cal_dVs"); + return dVs; +} + +template +template +auto Ewald_Vq::set_Vs_dVs(const std::vector& list_A0_pair_R, + const std::vector& list_A1_pair_R, + std::map>& Vq) -> std::map> +{ + ModuleBase::TITLE("Ewald_Vq", "set_Vs_dVs"); + ModuleBase::timer::tick("Ewald_Vq", "set_Vs_dVs"); + + using namespace RI::Array_Operator; + using Tin_convert = typename LRI_CV_Tools::TinType::type; + + const double cfrac = 1.0 / this->nks0; + std::map> datas; + + // auto start = std::chrono::system_clock::now(); +#pragma omp parallel + { + std::map> local_datas; + +#pragma omp for schedule(dynamic) nowait + for (size_t ik = 0; ik != this->nks0; ++ik) + { + for (size_t i0 = 0; i0 < list_A0_pair_R.size(); ++i0) + { + for (size_t i1 = 0; i1 < list_A1_pair_R.size(); ++i1) + { + const TA iat0 = list_A0_pair_R[i0]; + const TA iat1 = list_A1_pair_R[i1].first; + const TC& cell1 = list_A1_pair_R[i1].second; + + const std::complex frac + = std::exp(-ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT + * (this->kvec_c[ik] * (RI_Util::array3_to_Vector3(cell1) * GlobalC::ucell.latvec))) + * cfrac; + + const TAK index = std::make_pair(iat1, std::array{static_cast(ik)}); + Tout Vq_tmp = LRI_CV_Tools::convert(LRI_CV_Tools::mul2(frac, Vq[iat0][index])); + + if (!LRI_CV_Tools::exist(local_datas[iat0][list_A1_pair_R[i1]])) + local_datas[iat0][list_A1_pair_R[i1]] = Vq_tmp; + else + local_datas[iat0][list_A1_pair_R[i1]] = local_datas[iat0][list_A1_pair_R[i1]] + Vq_tmp; + } + } + } +#pragma omp critical(Ewald_Vq_set_Vs_dVs) + { + for (auto& outer_pair: local_datas) + { + TA key0 = outer_pair.first; + for (auto& inner_pair: outer_pair.second) + { + TAC key1 = inner_pair.first; + Tout& value = inner_pair.second; + if (!LRI_CV_Tools::exist(datas[key0][key1])) + datas[key0][key1] = value; + else + datas[key0][key1] = datas[key0][key1] + value; + } + } + } + } + // auto end = std::chrono::system_clock::now(); + // auto duration + // = std::chrono::duration_cast(end - start); + // std::cout << "set_Vs_dVs Time: " + // << double(duration.count()) + // * std::chrono::microseconds::period::num + // / std::chrono::microseconds::period::den + // << " s" << std::endl; + + ModuleBase::timer::tick("Ewald_Vq", "set_Vs_dVs"); + return datas; +} + +template +std::vector>> Ewald_Vq::init_gauss( + std::vector>>& orb_in) +{ + std::vector>> gauss; + gauss.resize(orb_in.size()); + for (size_t T = 0; T != orb_in.size(); ++T) + { + gauss[T].resize(orb_in[T].size()); + for (size_t L = 0; L != orb_in[T].size(); ++L) + { + gauss[T][L].resize(orb_in[T][L].size()); + for (size_t N = 0; N != orb_in[T][L].size(); ++N) + { + gauss[T][L][N] = this->gaussian_abfs.Gauss(orb_in[T][L][N], this->ewald_lambda); + } + } + } + + return gauss; +} + +#endif diff --git a/source/module_ri/exx_abfs-construct_orbs.cpp b/source/module_ri/exx_abfs-construct_orbs.cpp index 55eed086641..f3cb558f4bc 100644 --- a/source/module_ri/exx_abfs-construct_orbs.cpp +++ b/source/module_ri/exx_abfs-construct_orbs.cpp @@ -8,11 +8,10 @@ #include "module_hamilt_pw/hamilt_pwdft/global.h" //for ucell #include "module_ri/test_code/exx_abfs-construct_orbs-test.h" // Peize Lin test -std::vector>> Exx_Abfs::Construct_Orbs::change_orbs( - const LCAO_Orbitals &orbs_in, - const double kmesh_times ) -{ - ModuleBase::TITLE("Exx_Abfs::Construct_Orbs::change_orbs"); +std::vector>> + Exx_Abfs::Construct_Orbs::change_orbs(const LCAO_Orbitals& orbs_in, + const double kmesh_times) { + ModuleBase::TITLE("Exx_Abfs::Construct_Orbs::change_orbs"); std::vector>> orbs; orbs.resize( orbs_in.get_ntype() ); @@ -44,34 +43,46 @@ std::vector>> Exx_Abfs::Construct_ } } } + + for (int T = 0; T < orbs.size() ; T++) + { + for (int L=orbs[T].size()-1; L >= 0 ; L--) + { + if (orbs[T][L].size()>0) + break; + else + orbs[T].resize(L); + } + } return orbs; } -std::vector>> Exx_Abfs::Construct_Orbs::change_orbs( - const std::vector>> &orbs_in, - const double kmesh_times ) -{ - ModuleBase::TITLE("Exx_Abfs::Construct_Orbs::change_orbs"); - return orbital( get_psi(orbs_in), orbs_in, kmesh_times ); +std::vector>> + Exx_Abfs::Construct_Orbs::change_orbs( + const std::vector>>& + orbs_in, + const double kmesh_times) { + ModuleBase::TITLE("Exx_Abfs::Construct_Orbs::change_orbs"); + return orbital(get_psi(orbs_in), orbs_in, kmesh_times); } // P = u/r * Y /* template -std::vector>> Exx_Abfs::Construct_Orbs::abfs_same_atom( - const Orbs_Type &orbs, - const double kmesh_times, - const double norm_threshold ) +std::vector>> +Exx_Abfs::Construct_Orbs::abfs_same_atom( const Orbs_Type &orbs, const double +kmesh_times, const double norm_threshold ) { - const std::vector>>> - abfs_same_atom_psir = psir_mult_psir( orbs ); - const std::vector>>> - abfs_same_atom_psir_orth = orth( abfs_same_atom_psir, orbs, norm_threshold ); - const std::vector>>> - abfs_same_atom_psi_orth = div_r( abfs_same_atom_psir_orth, orbs.get_r_radial ); - const std::vector>> - abfs_same_atom = orbital( abfs_same_atom_psi_orth, orbs, kmesh_times ); - return abfs_same_atom; + const std::vector>>> + abfs_same_atom_psir = psir_mult_psir( orbs ); + const std::vector>>> + abfs_same_atom_psir_orth = orth( abfs_same_atom_psir, orbs, +norm_threshold ); const +std::vector>>> + abfs_same_atom_psi_orth = div_r( abfs_same_atom_psir_orth, +orbs.get_r_radial ); const +std::vector>> abfs_same_atom = +orbital( abfs_same_atom_psi_orth, orbs, kmesh_times ); return abfs_same_atom; } */ @@ -84,175 +95,183 @@ std::vector>> Exx_Abfs::Construct_ { ModuleBase::TITLE("Exx_Abfs::Construct_Orbs::abfs_same_atom"); - const std::vector>>> - abfs_same_atom_psi = psi_mult_psi( orbs ); + const std::vector>>> + abfs_same_atom_psi = psi_mult_psi(orbs); - const std::vector>>> - abfs_same_atom_orth_psi = orth( abfs_same_atom_psi, orbs ); - const std::vector>> - abfs_same_atom = orbital( abfs_same_atom_orth_psi, orbs, 1 ); + const std::vector>>> + abfs_same_atom_orth_psi = orth(abfs_same_atom_psi, orbs); + const std::vector>> + abfs_same_atom = orbital(abfs_same_atom_orth_psi, orbs, 1); - #if TEST_EXX_LCAO==1 - print_orbs(abfs_same_atom_psi,"abfs_same_atom_psi.dat"); - print_orbs(abfs_same_atom_orth_psi,"abfs_same_atom_orth_psi.dat"); - #elif TEST_EXX_LCAO==-1 - #error "TEST_EXX_LCAO" - #endif +#if TEST_EXX_LCAO == 1 + print_orbs(abfs_same_atom_psi, "abfs_same_atom_psi.dat"); + print_orbs(abfs_same_atom_orth_psi, "abfs_same_atom_orth_psi.dat"); +#elif TEST_EXX_LCAO == -1 +#error "TEST_EXX_LCAO" +#endif const std::vector>>> abfs_same_atom_pca_psi = pca( orb, abfs_same_atom, orbs, kmesh_times_mot, times_threshold ); - #if TEST_EXX_LCAO==1 - print_orbs(abfs_same_atom_pca_psi,"abfs_same_atom_pca_psi.dat"); - #elif TEST_EXX_LCAO==-1 - #error "TEST_EXX_LCAO" - #endif +#if TEST_EXX_LCAO == 1 + print_orbs(abfs_same_atom_pca_psi, "abfs_same_atom_pca_psi.dat"); +#elif TEST_EXX_LCAO == -1 +#error "TEST_EXX_LCAO" +#endif - const std::vector>> - abfs_same_atom_pca = orbital( abfs_same_atom_pca_psi, orbs, 1 ); - return abfs_same_atom_pca; + const std::vector>> + abfs_same_atom_pca = orbital(abfs_same_atom_pca_psi, orbs, 1); + return abfs_same_atom_pca; } /* template<> -std::vector>>> Exx_Abfs::Construct_Orbs::psi_mult_psi( - const LCAO_Orbitals &orbs ) +std::vector>>> +Exx_Abfs::Construct_Orbs::psi_mult_psi( const LCAO_Orbitals &orbs ) { - std::vector>>> psi_mult_psi( orbs.get_ntype() ); - for( int T=0; T!=orbs.get_ntype(); ++T ) - { - psi_mult_psi[T].resize( 2*orbs.Phi[T].getLmax()+1 ); - for( int L1=0; L1<=orbs.Phi[T].getLmax(); ++L1 ) - { - for( int N1=0; N1!=orbs.Phi[T].getNchi(L1); ++N1 ) - { - for( int L2=L1; L2<=orbs.Phi[T].getLmax(); ++L2 ) - { - for( int N2=((L2==L1)?N1:0); N2!=orbs.Phi[T].getNchi(L2); ++N2 ) - { - assert( orbs.Phi[T].PhiLN(L1,N1).getNr()==orbs.Phi[T].PhiLN(L2,N2).getNr() ); - - std::vector mult_psir( orbs.Phi[T].PhiLN(L1,N1).getNr() ); - for( int ir=0; ir!=orbs.Phi[T].PhiLN(L1,N1).getNr(); ++ir) - { - mult_psir[ir] = orbs.Phi[T].PhiLN(L1,N1).getPsi(ir) * orbs.Phi[T].PhiLN(L2,N2).getPsi(ir) ; - } - for( int L_new=std::abs(L2-L1); L_new<=L1+L2; ++L_new ) - { - psi_mult_psi[T][L_new].push_back(mult_psir); - } - } - } - } - } - } - return psi_mult_psi; + std::vector>>> psi_mult_psi( +orbs.get_ntype() ); for( int T=0; T!=orbs.get_ntype(); ++T ) + { + psi_mult_psi[T].resize( 2*orbs.Phi[T].getLmax()+1 ); + for( int L1=0; L1<=orbs.Phi[T].getLmax(); ++L1 ) + { + for( int N1=0; N1!=orbs.Phi[T].getNchi(L1); ++N1 ) + { + for( int L2=L1; L2<=orbs.Phi[T].getLmax(); ++L2 ) + { + for( int N2=((L2==L1)?N1:0); N2!=orbs.Phi[T].getNchi(L2); +++N2 ) + { + assert( +orbs.Phi[T].PhiLN(L1,N1).getNr()==orbs.Phi[T].PhiLN(L2,N2).getNr() ); + + std::vector mult_psir( +orbs.Phi[T].PhiLN(L1,N1).getNr() ); for( int ir=0; +ir!=orbs.Phi[T].PhiLN(L1,N1).getNr(); ++ir) + { + mult_psir[ir] = orbs.Phi[T].PhiLN(L1,N1).getPsi(ir) +* orbs.Phi[T].PhiLN(L2,N2).getPsi(ir) ; + } + for( int L_new=std::abs(L2-L1); L_new<=L1+L2; ++L_new ) + { + psi_mult_psi[T][L_new].push_back(mult_psir); + } + } + } + } + } + } + return psi_mult_psi; } */ -std::vector>>> Exx_Abfs::Construct_Orbs::psi_mult_psi( - const std::vector>> &orbs ) -{ - std::vector>>> psi_mult_psi( orbs.size() ); - for( int T=0; T!=orbs.size(); ++T ) - { - psi_mult_psi[T].resize( 2*orbs[T].size()-1 ); - for( int L1=0; L1!=orbs[T].size(); ++L1 ) - { - for( int N1=0; N1!=orbs[T][L1].size(); ++N1 ) - { - for( int L2=L1; L2!=orbs[T].size(); ++L2 ) - { - for( int N2=((L2==L1)?N1:0); N2!=orbs[T][L2].size(); ++N2 ) - { - assert( orbs[T][L1][N1].getNr()==orbs[T][L2][N2].getNr() ); - - std::vector mult_psir( orbs[T][L1][N1].getNr() ); - for( int ir=0; ir!=orbs[T][L1][N1].getNr(); ++ir) - { - mult_psir[ir] = orbs[T][L1][N1].getPsi(ir) * orbs[T][L2][N2].getPsi(ir) ; - } - for( int L_new=std::abs(L1-L2); L_new<=L1+L2; ++L_new ) - { - psi_mult_psi[T][L_new].push_back(mult_psir); - } - } - } - } - } - } - return psi_mult_psi; +std::vector>>> + Exx_Abfs::Construct_Orbs::psi_mult_psi( + const std::vector>>& + orbs) { + std::vector>>> psi_mult_psi( + orbs.size()); + for (int T = 0; T != orbs.size(); ++T) { + psi_mult_psi[T].resize(2 * orbs[T].size() - 1); + for (int L1 = 0; L1 != orbs[T].size(); ++L1) { + for (int N1 = 0; N1 != orbs[T][L1].size(); ++N1) { + for (int L2 = L1; L2 != orbs[T].size(); ++L2) { + for (int N2 = ((L2 == L1) ? N1 : 0); + N2 != orbs[T][L2].size(); + ++N2) { + assert(orbs[T][L1][N1].getNr() + == orbs[T][L2][N2].getNr()); + + std::vector mult_psir(orbs[T][L1][N1].getNr()); + for (int ir = 0; ir != orbs[T][L1][N1].getNr(); ++ir) { + mult_psir[ir] = orbs[T][L1][N1].getPsi(ir) + * orbs[T][L2][N2].getPsi(ir); + } + for (int L_new = std::abs(L1 - L2); L_new <= L1 + L2; + ++L_new) { + psi_mult_psi[T][L_new].push_back(mult_psir); + } + } + } + } + } + } + return psi_mult_psi; } /* template<> -std::vector>>> Exx_Abfs::Construct_Orbs::psir_mult_psir( - const LCAO_Orbitals &orbs ) +std::vector>>> +Exx_Abfs::Construct_Orbs::psir_mult_psir( const LCAO_Orbitals &orbs ) { - std::vector>>> psir_mult_psir( orbs.get_ntype() ); - for( int T=0; T!=orbs.get_ntype(); ++T ) - { - psir_mult_psir[T].resize( 2*orbs.Phi[T].getLmax()+1 ); - for( int L1=0; L1<=orbs.Phi[T].getLmax(); ++L1 ) - { - for( int N1=0; N1!=orbs.Phi[T].getNchi(L1); ++N1 ) - { - for( int L2=L1; L2<=orbs.Phi[T].getLmax(); ++L2 ) - { - for( int N2=((L2==L1)?N1:0); N2!=orbs.Phi[T].getNchi(L2); ++N2 ) - { - assert( orbs.Phi[T].PhiLN(L1,N1).getNr()==orbs.Phi[T].PhiLN(L2,N2).getNr() ); - - std::vector mult_psir( orbs.Phi[T].PhiLN(L1,N1).getNr() ); - for( int ir=0; ir!=orbs.Phi[T].PhiLN(L1,N1).getNr(); ++ir) - { - mult_psir[ir] = orbs.Phi[T].PhiLN(L1,N1).getPsi_r(ir) * orbs.Phi[T].PhiLN(L2,N2).getPsi_r(ir) ; - } - for( int L_new=std::abs(L1-L2); L_new<=L1+L2; ++L_new ) - { - psir_mult_psir[T][L_new].push_back(mult_psir); - } - } - } - } - } - } - return psir_mult_psir; + std::vector>>> psir_mult_psir( +orbs.get_ntype() ); for( int T=0; T!=orbs.get_ntype(); ++T ) + { + psir_mult_psir[T].resize( 2*orbs.Phi[T].getLmax()+1 ); + for( int L1=0; L1<=orbs.Phi[T].getLmax(); ++L1 ) + { + for( int N1=0; N1!=orbs.Phi[T].getNchi(L1); ++N1 ) + { + for( int L2=L1; L2<=orbs.Phi[T].getLmax(); ++L2 ) + { + for( int N2=((L2==L1)?N1:0); N2!=orbs.Phi[T].getNchi(L2); +++N2 ) + { + assert( +orbs.Phi[T].PhiLN(L1,N1).getNr()==orbs.Phi[T].PhiLN(L2,N2).getNr() ); + + std::vector mult_psir( +orbs.Phi[T].PhiLN(L1,N1).getNr() ); for( int ir=0; +ir!=orbs.Phi[T].PhiLN(L1,N1).getNr(); ++ir) + { + mult_psir[ir] = +orbs.Phi[T].PhiLN(L1,N1).getPsi_r(ir) * orbs.Phi[T].PhiLN(L2,N2).getPsi_r(ir) ; + } + for( int L_new=std::abs(L1-L2); L_new<=L1+L2; ++L_new ) + { + psir_mult_psir[T][L_new].push_back(mult_psir); + } + } + } + } + } + } + return psir_mult_psir; } */ -std::vector>>> Exx_Abfs::Construct_Orbs::psir_mult_psir( - const std::vector>> &orbs ) -{ - std::vector>>> psir_mult_psir( orbs.size() ); - for( int T=0; T!=orbs.size(); ++T ) - { - psir_mult_psir[T].resize( 2*orbs[T].size()-1 ); - for( int L1=0; L1!=orbs[T].size(); ++L1 ) - { - for( int N1=0; N1!=orbs[T][L1].size(); ++N1 ) - { - for( int L2=L1; L2!=orbs[T].size(); ++L2 ) - { - for( int N2=((L2==L1)?N1:0); N2!=orbs[T][L2].size(); ++N2 ) - { - assert( orbs[T][L1][N1].getNr()==orbs[T][L2][N2].getNr() ); - - std::vector mult_psir( orbs[T][L1][N1].getNr() ); - for( int ir=0; ir!=orbs[T][L1][N1].getNr(); ++ir) - { - mult_psir[ir] = orbs[T][L1][N1].getPsi_r(ir) * orbs[T][L2][N2].getPsi_r(ir) ; - } - for( int L_new=std::abs(L1-L2); L_new<=L1+L2; ++L_new ) - { - psir_mult_psir[T][L_new].push_back(mult_psir); - } - } - } - } - } - } - return psir_mult_psir; +std::vector>>> + Exx_Abfs::Construct_Orbs::psir_mult_psir( + const std::vector>>& + orbs) { + std::vector>>> psir_mult_psir( + orbs.size()); + for (int T = 0; T != orbs.size(); ++T) { + psir_mult_psir[T].resize(2 * orbs[T].size() - 1); + for (int L1 = 0; L1 != orbs[T].size(); ++L1) { + for (int N1 = 0; N1 != orbs[T][L1].size(); ++N1) { + for (int L2 = L1; L2 != orbs[T].size(); ++L2) { + for (int N2 = ((L2 == L1) ? N1 : 0); + N2 != orbs[T][L2].size(); + ++N2) { + assert(orbs[T][L1][N1].getNr() + == orbs[T][L2][N2].getNr()); + + std::vector mult_psir(orbs[T][L1][N1].getNr()); + for (int ir = 0; ir != orbs[T][L1][N1].getNr(); ++ir) { + mult_psir[ir] = orbs[T][L1][N1].getPsi_r(ir) + * orbs[T][L2][N2].getPsi_r(ir); + } + for (int L_new = std::abs(L1 - L2); L_new <= L1 + L2; + ++L_new) { + psir_mult_psir[T][L_new].push_back(mult_psir); + } + } + } + } + } + } + return psir_mult_psir; } std::vector>>> Exx_Abfs::Construct_Orbs::pca( @@ -268,125 +287,120 @@ std::vector>>> Exx_Abfs::Construct_O const std::vector,RI::Tensor>>> eig = ABFs_Construct::PCA::cal_PCA( orb, orbs, abfs, kmesh_times_mot ); - const std::vector>>> psis = get_psi( abfs ); - std::vector>>> psis_new( psis.size() ); - - for( size_t T=0; T!=eig.size(); ++T ) - { - double eig_value_max = 0; - for( size_t L=0; L!=eig[T].size(); ++L ) - for( size_t M=0; M!=eig[T][L].first.size(); ++M ) - { -//ofs< &eig_value = eig[T][L].first; - const RI::Tensor &eig_vec = eig[T][L].second; - for( size_t M=0; M!=eig_value.size(); ++M ) - { - if( eig_value[M] > eig_value_threshold ) - { - std::vector psi_new( psis[T][L][0].size() ); - for( size_t N=0; N!=psis[T][L].size(); ++N ) - for( size_t ir=0; ir!=psi_new.size(); ++ir ) - psi_new[ir] += eig_vec(M,N) * psis[T][L][N][ir]; - psis_new[T][L].push_back( psi_new ); - } - } - } - } - else - { - ModuleBase::WARNING(ModuleBase::GlobalFunc::TO_STRING(__FILE__), - "Element "+ModuleBase::GlobalFunc::TO_STRING(T)+" , all training data (lcao[i]*lcao[j]) are all the same. So PCA randomly choose an abf as the result."); - psis_new[T].resize( psis[T].size() ); - for( size_t L=0; L!=psis[T].size(); ++L ) - if( !psis[T][L].empty() ) - { - psis_new[T][L].push_back(psis[T][L][0]); - break; - } - } - } -//ofs.close(); - return psis_new; + const std::vector>>> psis + = get_psi(abfs); + std::vector>>> psis_new( + psis.size()); + + for (size_t T = 0; T != eig.size(); ++T) { + double eig_value_max = 0; + for (size_t L = 0; L != eig[T].size(); ++L) + for (size_t M = 0; M != eig[T][L].first.size(); ++M) { + // ofs<& eig_value = eig[T][L].first; + const RI::Tensor& eig_vec = eig[T][L].second; + for (size_t M = 0; M != eig_value.size(); ++M) { + if (eig_value[M] > eig_value_threshold) { + std::vector psi_new(psis[T][L][0].size()); + for (size_t N = 0; N != psis[T][L].size(); ++N) + for (size_t ir = 0; ir != psi_new.size(); ++ir) + psi_new[ir] + += eig_vec(M, N) * psis[T][L][N][ir]; + psis_new[T][L].push_back(psi_new); + } + } + } + } else { + ModuleBase::WARNING( + ModuleBase::GlobalFunc::TO_STRING(__FILE__), + "Element " + ModuleBase::GlobalFunc::TO_STRING(T) + + " , all training data (lcao[i]*lcao[j]) are all the " + "same. So PCA randomly choose " + "an abf as the result."); + psis_new[T].resize(psis[T].size()); + for (size_t L = 0; L != psis[T].size(); ++L) + if (!psis[T][L].empty()) { + psis_new[T][L].push_back(psis[T][L][0]); + break; + } + } + } + // ofs.close(); + return psis_new; } - -std::vector>>> Exx_Abfs::Construct_Orbs::orth( - const std::vector>>> &psis, - const std::vector>> &orbs, - const double norm_threshold ) -{ - std::vector>>> psis_orth( psis.size() ); - for( int T=0; T!=psis.size(); ++T ) - { - const Numerical_Orbital_Lm &orb = orbs[T][0][0]; - ModuleBase::Gram_Schmidt_Orth gso( - orb.get_rab(), - ModuleBase::Gram_Schmidt_Orth::Coordinate::Sphere ); - psis_orth[T].resize( psis[T].size() ); - for( int L=0; L!=psis[T].size(); ++L ) - { - psis_orth[T][L] = gso.cal_orth( psis[T][L], norm_threshold ); // Peize Lin test 2016-10-08 -// psis_orth[T][L] = gso.cal_orth( psis[T][L] ); // Peize Lin test 2016-10-08 - } - } - return psis_orth; +std::vector>>> + Exx_Abfs::Construct_Orbs::orth( + const std::vector>>>& psis, + const std::vector>>& orbs, + const double norm_threshold) { + std::vector>>> psis_orth( + psis.size()); + for (int T = 0; T != psis.size(); ++T) { + const Numerical_Orbital_Lm& orb = orbs[T][0][0]; + ModuleBase::Gram_Schmidt_Orth gso( + orb.get_rab(), + ModuleBase::Gram_Schmidt_Orth::Coordinate::Sphere); + psis_orth[T].resize(psis[T].size()); + for (int L = 0; L != psis[T].size(); ++L) { + psis_orth[T][L] + = gso.cal_orth(psis[T][L], + norm_threshold); // Peize Lin test 2016-10-08 + // psis_orth[T][L] = gso.cal_orth( psis[T][L] ); // + //Peize Lin test 2016-10-08 + } + } + return psis_orth; } -std::vector>>> Exx_Abfs::Construct_Orbs::div_r( - const std::vector>>> &psirs, - const std::vector &r_radial ) -{ - std::vector>>> psis( psirs.size() ); - for( auto T=0; T!=psirs.size(); ++T ) - { - psis[T].resize( psirs[T].size() ); - for( auto L=0; L!=psirs[T].size(); ++L ) - { - psis[T][L].resize( psirs[T][L].size() ); - for( auto N=0; N!=psirs[T][L].size(); ++N ) - { - psis[T][L][N].resize( psirs[T][L][N].size() ); - psis[T][L][N][0] = 0; - for( auto ir=1; ir!=psirs[T][L][N].size(); ++ir ) - { - psis[T][L][N][ir] = psirs[T][L][N][ir] / r_radial[ir]; - } - } - } - } - return psis; +std::vector>>> + Exx_Abfs::Construct_Orbs::div_r( + const std::vector>>>& psirs, + const std::vector& r_radial) { + std::vector>>> psis( + psirs.size()); + for (auto T = 0; T != psirs.size(); ++T) { + psis[T].resize(psirs[T].size()); + for (auto L = 0; L != psirs[T].size(); ++L) { + psis[T][L].resize(psirs[T][L].size()); + for (auto N = 0; N != psirs[T][L].size(); ++N) { + psis[T][L][N].resize(psirs[T][L][N].size()); + psis[T][L][N][0] = 0; + for (auto ir = 1; ir != psirs[T][L][N].size(); ++ir) { + psis[T][L][N][ir] = psirs[T][L][N][ir] / r_radial[ir]; + } + } + } + } + return psis; } -std::vector>>> Exx_Abfs::Construct_Orbs::get_psi( - const std::vector>> &orbs ) -{ - std::vector>>> orbs_psi( orbs.size() ); - for( int T=0; T!=orbs.size(); ++T ) - { - orbs_psi[T].resize( orbs[T].size() ); - for( int L=0; L!=orbs[T].size(); ++L ) - { - orbs_psi[T][L].resize( orbs[T][L].size() ); - for( int N=0; N!=orbs[T][L].size(); ++N ) - { - orbs_psi[T][L][N] = orbs[T][L][N].get_psi(); - } - } - } - return orbs_psi; +std::vector>>> + Exx_Abfs::Construct_Orbs::get_psi( + const std::vector>>& + orbs) { + std::vector>>> orbs_psi( + orbs.size()); + for (int T = 0; T != orbs.size(); ++T) { + orbs_psi[T].resize(orbs[T].size()); + for (int L = 0; L != orbs[T].size(); ++L) { + orbs_psi[T][L].resize(orbs[T][L].size()); + for (int N = 0; N != orbs[T][L].size(); ++N) { + orbs_psi[T][L][N] = orbs[T][L][N].get_psi(); + } + } + } + return orbs_psi; } std::vector>> Exx_Abfs::Construct_Orbs::orbital( @@ -427,43 +441,43 @@ std::vector>> Exx_Abfs::Construct_ } /* -std::vector>>> Exx_Abfs::Construct_Orbs::get_psi( - const LCAO_Orbitals &orbs ) +std::vector>>> +Exx_Abfs::Construct_Orbs::get_psi( const LCAO_Orbitals &orbs ) { - std::vector>>> orbs_psi( orbs.get_ntype() ); - for( int T=0; T!=orbs.get_ntype(); ++T ) - { - orbs_psi[T].resize( orbs.Phi[T].getLmax()+1 ); - for( int L=0; L<=orbs.Phi[T].getLmax(); ++L ) - { - orbs_psi[T][L].resize( orbs.Phi[T].getNchi(L) ); - for( int N=0; N!=orbs.Phi[T].getNchi(L); ++N ) - { - orbs_psi[T][L][N] = orbs.Phi[T].PhiLN(L,N).get_psi(); - } - } - } - return orbs_psi; + std::vector>>> orbs_psi( +orbs.get_ntype() ); for( int T=0; T!=orbs.get_ntype(); ++T ) + { + orbs_psi[T].resize( orbs.Phi[T].getLmax()+1 ); + for( int L=0; L<=orbs.Phi[T].getLmax(); ++L ) + { + orbs_psi[T][L].resize( orbs.Phi[T].getNchi(L) ); + for( int N=0; N!=orbs.Phi[T].getNchi(L); ++N ) + { + orbs_psi[T][L][N] = orbs.Phi[T].PhiLN(L,N).get_psi(); + } + } + } + return orbs_psi; } */ /* template<> inline const Numerical_Orbital_Lm &Exx_Abfs::Construct_Orbs::get_orbital( - const LCAO_Orbitals &orbs, - const size_t T, const size_t L, const size_t N) + const LCAO_Orbitals &orbs, + const size_t T, const size_t L, const size_t N) { - return orbs.Phi[T].PhiLN(L,N); + return orbs.Phi[T].PhiLN(L,N); } */ /* template<> inline const Numerical_Orbital_Lm &Exx_Abfs::Construct_Orbs::get_orbital( - const std::vector>> &orbs, - const size_t T, const size_t L, const size_t N) + const std::vector>> &orbs, + const size_t T, const size_t L, const size_t N) { - return orbs[T][L][N]; + return orbs[T][L][N]; } */ @@ -487,3 +501,51 @@ void Exx_Abfs::Construct_Orbs::print_orbs_size( os<>> Exx_Abfs::Construct_Orbs::get_multipole( + const std::vector>>& orb_in) +{ + std::vector>> multipole; + multipole.resize(orb_in.size()); + for (size_t T = 0; T != orb_in.size(); ++T) + { + multipole[T].resize(orb_in[T].size()); + for (size_t L = 0; L != orb_in[T].size(); ++L) + { + multipole[T][L].resize(orb_in[T][L].size()); + for (size_t N = 0; N != orb_in[T][L].size(); ++N) + { + const Numerical_Orbital_Lm& orb_lm = orb_in[T][L][N]; + const int nr = orb_lm.getNr(); + double* integrated_func = new double[nr]; + for (size_t ir = 0; ir != nr; ++ir) + integrated_func[ir] = orb_lm.getPsi(ir) * std::pow(orb_lm.getRadial(ir), 2 + L) / (2 * L + 1); + + ModuleBase::Integral::Simpson_Integral(nr, integrated_func, orb_lm.getRab(), multipole[T][L][N]); + } + } + } + + return multipole; +} + +std::vector Exx_Abfs::Construct_Orbs::get_Rcut(const std::vector>>& orb_in) +{ + std::vector Rcut(orb_in.size()); + for (size_t T = 0; T != orb_in.size(); ++T) + { + double rmax = std::numeric_limits::min(); + for (size_t L = 0; L != orb_in[T].size(); ++L) + { + for (size_t N = 0; N != orb_in[T][L].size(); ++N) + { + const double rcut = orb_in[T][L][N].getRcut(); + if (rcut > rmax) + rmax = rcut; + } + } + Rcut[T] = rmax; + } + + return Rcut; +} \ No newline at end of file diff --git a/source/module_ri/exx_abfs-construct_orbs.h b/source/module_ri/exx_abfs-construct_orbs.h index be61fc7ff19..a2f1ac2fe33 100644 --- a/source/module_ri/exx_abfs-construct_orbs.h +++ b/source/module_ri/exx_abfs-construct_orbs.h @@ -1,44 +1,75 @@ #ifndef EXX_ABFS_CONSTRUCT_ORBS_H #define EXX_ABFS_CONSTRUCT_ORBS_H +#include "../module_basis/module_ao/ORB_atomic_lm.h" #include "exx_abfs.h" #include -#include "../module_basis/module_ao/ORB_atomic_lm.h" - class LCAO_Orbitals; +class LCAO_Orbitals; -class Exx_Abfs::Construct_Orbs -{ -public: - static std::vector>> change_orbs( - const LCAO_Orbitals &orb_in, - const double kmesh_times ); - static std::vector>> change_orbs( - const std::vector>> &orb_in, - const double kmesh_times ); +class Exx_Abfs::Construct_Orbs { + public: + static std::vector>> + change_orbs(const LCAO_Orbitals& orb_in, const double kmesh_times); + static std::vector>> + change_orbs(const std::vector< + std::vector>>& orb_in, + const double kmesh_times); - static std::vector>> abfs_same_atom( - const LCAO_Orbitals& orb, - const std::vector>> &lcaos, - const double kmesh_times_mot, - const double times_threshold=0); - - static void print_orbs_size( - const std::vector>> &orbs, - std::ostream &os); - -private: - static std::vector>>> psi_mult_psi( - const std::vector>> &lcaos ); - - static std::vector>>> psir_mult_psir( - const std::vector>> &lcaos ); - - static std::vector>>> orth( - const std::vector>>> &psis, - const std::vector>> &lcaos, - const double norm_threshold = std::numeric_limits::min() ); + static std::vector>> + abfs_same_atom( + const LCAO_Orbitals& orb, + const std::vector>>& + lcaos, + const double kmesh_times_mot, + const double times_threshold = 0); + + static void print_orbs_size( + const std::vector>>& orbs, + std::ostream& os); + + // get the max number of orbitals among all elements + // static int get_nmax_total(const + // std::vector>> &orb_in); get + // number of orbitals for each element static std::map + // get_nw(const std::vector>> + // &orb_in); + + // get multipole of orbitals for each element and angular moment + static std::vector>> get_multipole( + const std::vector>>& + orb_in); + + static std::vector get_Rcut( + const std::vector>>& + orb_in); + static inline double get_Rmax(const std::vector& rcut) { + return *std::max_element(rcut.begin(), rcut.end()); + } + static inline double get_Rmax( + const std::vector>>& + orb_in) { + std::vector rcut = get_Rcut(orb_in); + return get_Rmax(rcut); + } + + private: + static std::vector>>> + psi_mult_psi( + const std::vector>>& + lcaos); + + static std::vector>>> + psir_mult_psir( + const std::vector>>& + lcaos); + + static std::vector>>> orth( + const std::vector>>>& psis, + const std::vector>>& + lcaos, + const double norm_threshold = std::numeric_limits::min()); static std::vector>>> pca( const LCAO_Orbitals& orb, @@ -60,4 +91,4 @@ class Exx_Abfs::Construct_Orbs const std::vector>> &orbs ); }; -#endif // EXX_ABFS_IO_ASA_H +#endif // EXX_ABFS_IO_ASA_H diff --git a/source/module_ri/exx_lip.cpp b/source/module_ri/exx_lip.cpp index e3a6016e589..c97021aa15e 100644 --- a/source/module_ri/exx_lip.cpp +++ b/source/module_ri/exx_lip.cpp @@ -30,17 +30,17 @@ void Exx_Lip::cal_exx() //t_phi_cal += my_time(t); judge_singularity(ik); - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) { - for (int iw_r = 0; iw_r < GlobalV::NLOCAL; ++iw_r) { - sum1[iw_l * GlobalV::NLOCAL + iw_r] = T(0.0, 0.0); + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { + for (int iw_r = 0; iw_r < PARAM.globalv.nlocal; ++iw_r) { + sum1[iw_l * PARAM.globalv.nlocal + iw_r] = T(0.0, 0.0); } } if (Conv_Coulomb_Pot_K::Ccp_Type::Ccp == info.ccp_type || Conv_Coulomb_Pot_K::Ccp_Type::Hf == info.ccp_type) { sum2_factor = 0.0; if (gzero_rank_in_pool == GlobalV::RANK_IN_POOL) { - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) { - for (int iw_r = 0; iw_r < GlobalV::NLOCAL; ++iw_r) { + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { + for (int iw_r = 0; iw_r < PARAM.globalv.nlocal; ++iw_r) { sum3[iw_l][iw_r] = T(0.0, 0.0); } } @@ -54,7 +54,7 @@ void Exx_Lip::cal_exx() (iq_tmp % (q_pack->kv_ptr->get_nks() / PARAM.inp.nspin) + (q_pack->kv_ptr->get_nks() / PARAM.inp.nspin)); qkg2_exp(ik, iq); //t_qkg2_exp += my_time(t); - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { b_cal(ik, iq, ib); //t_b_cal += my_time(t); @@ -80,9 +80,9 @@ void Exx_Lip::cal_exx() { std::ofstream ofs("Hexxk_" + ModuleBase::GlobalFunc::TO_STRING(istep++) + "_" + ModuleBase::GlobalFunc::TO_STRING(ik) + "_" + ModuleBase::GlobalFunc::TO_STRING(GlobalV::MY_RANK)); - for (int i = 0; i != GlobalV::NLOCAL; ++i) + for (int i = 0; i != PARAM.globalv.nlocal; ++i) { - for (int j = 0; j != GlobalV::NLOCAL; ++j) { + for (int j = 0; j != PARAM.globalv.nlocal; ++j) { ofs << exx_matrix[ik][i][j] << "\t"; } ofs << std::endl; @@ -102,15 +102,15 @@ void Exx_Lip::cal_exx() phi_cal(k_pack, ik); judge_singularity(ik); - for( int iw_l=0; iw_l(0.0,0.0); + for( int iw_l=0; iw_l(0.0,0.0); if( Exx_Info::Hybrid_Type::HF==info.hybrid_type || Exx_Info::Hybrid_Type::PBE0==info.hybrid_type || Exx_Info::Hybrid_Type::SCAN0==info.hybrid_type ) { sum2_factor = 0.0; if(gzero_rank_in_pool==GlobalV::RANK_IN_POOL) - for( int iw_l=0; iw_l(0.0,0.0); } @@ -118,7 +118,7 @@ void Exx_Lip::cal_exx() { int iq = (ik<(k_pack->kv_ptr->get_nks()/PARAM.inp.nspin)) ? (iq_tmp%(q_pack->kv_ptr->get_nks()/PARAM.inp.nspin)) : (iq_tmp%(q_pack->kv_ptr->get_nks()/PARAM.inp.nspin)+(q_pack->kv_ptr->get_nks()/PARAM.inp.nspin)); qkg2_exp(ik, iq); - for( int ib=0; ib::Exx_Lip( #ifdef __MPI MPI_Allreduce(&gzero_judge, &gzero_rank_in_pool, 1, MPI_INT, MPI_MAX, POOL_WORLD); #endif - k_pack->wf_wg.create(k_pack->kv_ptr->get_nks(),GlobalV::NBANDS); + k_pack->wf_wg.create(k_pack->kv_ptr->get_nks(),PARAM.inp.nbands); - k_pack->hvec_array = new psi::Psi(k_pack->kv_ptr->get_nks(), GlobalV::NBANDS, GlobalV::NLOCAL); + k_pack->hvec_array = new psi::Psi(k_pack->kv_ptr->get_nks(), PARAM.inp.nbands, PARAM.globalv.nlocal); // k_pack->hvec_array = new ModuleBase::ComplexMatrix[k_pack->kv_ptr->get_nks()]; // for( int ik=0; ikkv_ptr->get_nks(); ++ik) // { - // k_pack->hvec_array[ik].create(GlobalV::NLOCAL,GlobalV::NBANDS); + // k_pack->hvec_array[ik].create(PARAM.globalv.nlocal,PARAM.inp.nbands); // } // if (PARAM.inp.init_chg=="atomic") @@ -184,36 +184,36 @@ Exx_Lip::Exx_Lip( // read_q_pack(symm, wfc_basis, sf); // } - phi.resize(GlobalV::NLOCAL); - for (int iw = 0; iw < GlobalV::NLOCAL; ++iw) { phi[iw].resize(rho_basis->nrxx); } + phi.resize(PARAM.globalv.nlocal); + for (int iw = 0; iw < PARAM.globalv.nlocal; ++iw) { phi[iw].resize(rho_basis->nrxx); } psi.resize(q_pack->kv_ptr->get_nks()); for (int iq = 0; iq < q_pack->kv_ptr->get_nks(); ++iq) { - psi[iq].resize(GlobalV::NBANDS); - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) { psi[iq][ib].resize(rho_basis->nrxx); } + psi[iq].resize(PARAM.inp.nbands); + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { psi[iq][ib].resize(rho_basis->nrxx); } } recip_qkg2.resize(rho_basis->npw); - b.resize(GlobalV::NLOCAL * rho_basis->npw); + b.resize(PARAM.globalv.nlocal * rho_basis->npw); - sum1.resize(GlobalV::NLOCAL * GlobalV::NLOCAL); + sum1.resize(PARAM.globalv.nlocal * PARAM.globalv.nlocal); if (Conv_Coulomb_Pot_K::Ccp_Type::Ccp == info.ccp_type || Conv_Coulomb_Pot_K::Ccp_Type::Hf == info.ccp_type) { if (gzero_rank_in_pool == GlobalV::RANK_IN_POOL) { - b0.resize(GlobalV::NLOCAL); - sum3.resize(GlobalV::NLOCAL); - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) { sum3[iw_l].resize(GlobalV::NLOCAL); } + b0.resize(PARAM.globalv.nlocal); + sum3.resize(PARAM.globalv.nlocal); + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { sum3[iw_l].resize(PARAM.globalv.nlocal); } } } exx_matrix.resize(k_pack->kv_ptr->get_nks()); for (int ik = 0; ik < k_pack->kv_ptr->get_nks(); ++ik) { - exx_matrix[ik].resize(GlobalV::NLOCAL); - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) { exx_matrix[ik][iw_l].resize(GlobalV::NLOCAL); } + exx_matrix[ik].resize(PARAM.globalv.nlocal); + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { exx_matrix[ik][iw_l].resize(PARAM.globalv.nlocal); } } } catch (const std::bad_alloc& ex) @@ -248,13 +248,13 @@ void Exx_Lip::wf_wg_cal() ModuleBase::TITLE("Exx_Lip", "wf_wg_cal"); if (PARAM.inp.nspin == 1) { for (int ik = 0; ik < k_pack->kv_ptr->get_nks(); ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) { + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { k_pack->wf_wg(ik, ib) = k_pack->pelec->wg(ik, ib) / 2; } } } else if (PARAM.inp.nspin == 2) { for (int ik = 0; ik < k_pack->kv_ptr->get_nks(); ++ik) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) { + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { k_pack->wf_wg(ik, ib) = k_pack->pelec->wg(ik, ib); } } @@ -265,7 +265,7 @@ template void Exx_Lip::phi_cal(k_package* kq_pack, int ikq) { T* porter = new T[wfc_basis->nrxx]; - for (int iw = 0; iw < GlobalV::NLOCAL; ++iw) + for (int iw = 0; iw < PARAM.globalv.nlocal; ++iw) { // wfc_basis->recip2real(&kq_pack->wf_ptr->wanf2[ikq](iw,0), porter, ikq); wfc_basis->recip2real(&(kq_pack->wf_ptr->get_psig().lock()->operator()(ikq, iw, 0)), porter, ikq); @@ -297,7 +297,7 @@ void Exx_Lip::psi_cal() T* porter = new T[wfc_basis->nrxx]; for (int iq = 0; iq < q_pack->kv_ptr->get_nks(); ++iq) { - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { wfc_basis->recip2real(&(q_pack->kspw_psi_ptr->operator()(iq, ib, 0)), porter, iq); @@ -326,10 +326,10 @@ void Exx_Lip::psi_cal() for (int iq = 0; iq < q_pack->kv_ptr->get_nks(); ++iq) { phi_cal(q_pack, iq); - for (int ib = 0; ib < GlobalV::NBANDS; ++ib) + for (int ib = 0; ib < PARAM.inp.nbands; ++ib) { ModuleBase::GlobalFunc::ZEROS(psi[iq][ib].data(), rho_basis->nrxx); - for (int iw = 0; iw < GlobalV::NLOCAL; ++iw) + for (int iw = 0; iw < PARAM.globalv.nlocal; ++iw) { for (int ir = 0; ir < rho_basis->nrxx; ++ir) { @@ -390,6 +390,10 @@ void Exx_Lip::qkg2_exp(int ik, int iq) recip_qkg2[ig] = sqrt((1 - exp(-qkg2 / (4 * info.hse_omega * info.hse_omega))) / qkg2); } } + else if( Conv_Coulomb_Pot_K::Ccp_Type::Cam==info.ccp_type || Conv_Coulomb_Pot_K::Ccp_Type::Ccp_Cam==info.ccp_type) + { + ModuleBase::WARNING_QUIT("INPUT", "lcao_in_pw is not supported for long-range corrected and CAM- hybrid functionals"); + } } } @@ -416,7 +420,7 @@ void Exx_Lip::b_cal(int ik, int iq, int ib) T* const porter = new T[rho_basis->nrxx]; - for(size_t iw=0; iw< GlobalV::NLOCAL; ++iw) + for(size_t iw=0; iw< PARAM.globalv.nlocal; ++iw) { auto& phi_w = phi[iw]; for( size_t ir=0; irnrxx; ++ir) @@ -443,8 +447,8 @@ template void Exx_Lip::sum3_cal(int iq, int ib) { if (gzero_rank_in_pool == GlobalV::RANK_IN_POOL) { - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) { - for (int iw_r = 0; iw_r < GlobalV::NLOCAL; ++iw_r) { + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { + for (int iw_r = 0; iw_r < PARAM.globalv.nlocal; ++iw_r) { sum3[iw_l][iw_r] += b0[iw_l] * conj(b0[iw_r]) * (Real)q_pack->wf_wg(iq, ib); } } @@ -457,13 +461,13 @@ void Exx_Lip::b_sum(int iq, int ib) // Peize Lin change 2019-04-14 // sum1[iw_l,iw_r] += \sum_{ig} b[iw_l,ig] * conj(b[iw_r,ig]) * q_pack->wf_wg(iq,ib) LapackConnector::herk( 'U','N', - GlobalV::NLOCAL, rho_basis->npw, + PARAM.globalv.nlocal, rho_basis->npw, (Real)q_pack->wf_wg(iq, ib), b.data(), rho_basis->npw, - 1.0, sum1.data(), GlobalV::NLOCAL); + 1.0, sum1.data(), PARAM.globalv.nlocal); // cblas_zherk( CblasRowMajor, CblasUpper, CblasNoTrans, -// GlobalV::NLOCAL, rho_basis->npw, +// PARAM.globalv.nlocal, rho_basis->npw, // q_pack->wf_wg(iq,ib), static_cast(b), rho_basis->npw, -// 1.0, static_cast(sum1), GlobalV::NLOCAL); +// 1.0, static_cast(sum1), PARAM.globalv.nlocal); } template @@ -477,17 +481,17 @@ void Exx_Lip::sum_all(int ik) MPI_Reduce(&sum2_factor, &sum2_factor_g, 1, MPI_DOUBLE, MPI_SUM, gzero_rank_in_pool, POOL_WORLD); } #endif - for (size_t iw_l = 1; iw_l < GlobalV::NLOCAL; ++iw_l) { + for (size_t iw_l = 1; iw_l < PARAM.globalv.nlocal; ++iw_l) { for (size_t iw_r = 0; iw_r < iw_l; ++iw_r) { - sum1[iw_l * GlobalV::NLOCAL + iw_r] = conj(sum1[iw_r * GlobalV::NLOCAL + iw_l]); // Peize Lin add conj 2019-04-14 + sum1[iw_l * PARAM.globalv.nlocal + iw_r] = conj(sum1[iw_r * PARAM.globalv.nlocal + iw_l]); // Peize Lin add conj 2019-04-14 } } - for (int iw_l = 0; iw_l < GlobalV::NLOCAL; ++iw_l) + for (int iw_l = 0; iw_l < PARAM.globalv.nlocal; ++iw_l) { - for( int iw_r=0; iw_r::exx_energy_cal() for( int ik=0; ikkv_ptr->get_nks(); ++ik) { - for( int iw_l=0; iw_lhvec_array)(ik, ib, iw_l)) * (*k_pack->hvec_array)(ik, ib, iw_r)).real() * k_pack->wf_wg(ik, ib); } @@ -533,9 +537,9 @@ void Exx_Lip::exx_energy_cal() for( int ik=0; ikkv_ptr->get_nks(); ++ik) { ofs<<"ik:\t"<::exx_energy_cal() for( int ik=0; ikkv_ptr->get_nks(); ++ik) { ofs<<"ik:\t"<hvec_array)(ik, ib, iw_l)) * (*k_pack->hvec_array)(ik, ib, iw_r) * k_pack->wf_wg(ik, ib); ofs<::write_q_pack() const std::ofstream ofs_wf_wg(ss_wf_wg.str().c_str()); for( int iq = 0; iq < q_pack->kv_ptr->get_nks(); ++iq) { - for( int ib=0; ibwf_wg(iq,ib)<<"\t"; } @@ -611,9 +615,9 @@ void Exx_Lip::write_q_pack() const std::ofstream ofs_hvec(ss_hvec.str().c_str()); for( int iq=0; iqkv_ptr->get_nks(); ++iq) { - for( int iw=0; iwhvec_array)(iq, ib, iw).real() << " " << (*q_pack->hvec_array)(iq, ib, iw).imag() << " "; } @@ -659,7 +663,7 @@ void Exx_Lip::write_q_pack() const // // q_pack->wf_ptr); // } // #endif -// q_pack->wf_wg.create(q_pack->kv_ptr->get_nks(),GlobalV::NBANDS); +// q_pack->wf_wg.create(q_pack->kv_ptr->get_nks(),PARAM.inp.nbands); // if(!GlobalV::RANK_IN_POOL) // { // std::stringstream ss_wf_wg; @@ -667,7 +671,7 @@ void Exx_Lip::write_q_pack() const // std::ifstream ifs_wf_wg(ss_wf_wg.str().c_str()); // for( int iq = 0; iq < q_pack->kv_ptr->get_nks(); ++iq) // { -// for( int ib=0; ib>q_pack->wf_wg(iq,ib); // } @@ -675,13 +679,13 @@ void Exx_Lip::write_q_pack() const // ifs_wf_wg.close(); // } // #ifdef __MPI -// MPI_Bcast( q_pack->wf_wg.c, q_pack->kv_ptr->get_nks()*GlobalV::NBANDS, MPI_DOUBLE, 0, POOL_WORLD); +// MPI_Bcast( q_pack->wf_wg.c, q_pack->kv_ptr->get_nks()*PARAM.inp.nbands, MPI_DOUBLE, 0, POOL_WORLD); // #endif // q_pack->hvec_array = new ModuleBase::ComplexMatrix [q_pack->kv_ptr->get_nks()]; // for( int iq=0; iqkv_ptr->get_nks(); ++iq) // { -// q_pack->hvec_array[iq].create(GlobalV::NLOCAL,GlobalV::NBANDS); +// q_pack->hvec_array[iq].create(PARAM.globalv.nlocal,PARAM.inp.nbands); // } // if(!GlobalV::RANK_IN_POOL) // { @@ -690,9 +694,9 @@ void Exx_Lip::write_q_pack() const // std::ifstream ifs_hvec(ss_hvec.str().c_str()); // for( int iq=0; iqkv_ptr->get_nks(); ++iq) // { -// for( int iw=0; iw>a>>b; @@ -705,7 +709,7 @@ void Exx_Lip::write_q_pack() const // #ifdef __MPI // for( int iq=0; iqkv_ptr->get_nks(); ++iq) // { -// MPI_Bcast( q_pack->hvec_array[iq].c, GlobalV::NLOCAL*GlobalV::NBANDS, MPI_DOUBLE_COMPLEX, 0, POOL_WORLD); +// MPI_Bcast( q_pack->hvec_array[iq].c, PARAM.globalv.nlocal*PARAM.inp.nbands, MPI_DOUBLE_COMPLEX, 0, POOL_WORLD); // } // #endif diff --git a/source/module_ri/exx_opt_orb.cpp b/source/module_ri/exx_opt_orb.cpp index d714de1a9d6..faf0919b836 100644 --- a/source/module_ri/exx_opt_orb.cpp +++ b/source/module_ri/exx_opt_orb.cpp @@ -73,8 +73,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_lcaoslcaos_lcaoslcaos = [&]() -> std::map>>>> { Matrix_Orbs22 m_lcaoslcaos_lcaoslcaos; - m_lcaoslcaos_lcaoslcaos.init( 1, orb, this->kmesh_times, 1 ); - m_lcaoslcaos_lcaoslcaos.init_radial( lcaos, lcaos, lcaos, lcaos ); + ORB_gaunt_table MGT; + int Lmax; + m_lcaoslcaos_lcaoslcaos.init( 1, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_lcaoslcaos_lcaoslcaos.init_radial( lcaos, lcaos, lcaos, lcaos, MGT ); #if TEST_EXX_RADIAL>=1 m_lcaoslcaos_lcaoslcaos.init_radial_table(radial_R); #else @@ -89,8 +93,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_lcaoslcaos_jys = [&]() -> std::map>>>>> { Matrix_Orbs21 m_jyslcaos_lcaos; - m_jyslcaos_lcaos.init( 1, orb, this->kmesh_times, 1 ); - m_jyslcaos_lcaos.init_radial( jle.jle, lcaos, lcaos ); + ORB_gaunt_table MGT; + int Lmax; + m_jyslcaos_lcaos.init( 1, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_jyslcaos_lcaos.init_radial( jle.jle, lcaos, lcaos, MGT); #if TEST_EXX_RADIAL>=1 m_jyslcaos_lcaos.init_radial_table(radial_R); #else @@ -105,8 +113,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_jys_jys = [&]() -> std::map>>>> { Matrix_Orbs11 m_jys_jys; - m_jys_jys.init( 2, orb, this->kmesh_times, 1 ); - m_jys_jys.init_radial( jle.jle, jle.jle ); + ORB_gaunt_table MGT; + int Lmax; + m_jys_jys.init( 2, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_jys_jys.init_radial( jle.jle, jle.jle, MGT ); #if TEST_EXX_RADIAL>=1 m_jys_jys.init_radial_table(radial_R); #else @@ -121,8 +133,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_abfs_abfs = [&]() -> std::map>>>> { Matrix_Orbs11 m_abfs_abfs; - m_abfs_abfs.init( 2, orb, this->kmesh_times, 1 ); - m_abfs_abfs.init_radial( abfs, abfs ); + ORB_gaunt_table MGT; + int Lmax; + m_abfs_abfs.init( 2, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_abfs_abfs.init_radial( abfs, abfs, MGT ); #if TEST_EXX_RADIAL>=1 m_abfs_abfs.init_radial_table(radial_R); #else @@ -137,8 +153,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_lcaoslcaos_abfs = [&]() -> std::map>>>>> { Matrix_Orbs21 m_abfslcaos_lcaos; - m_abfslcaos_lcaos.init( 1, orb, this->kmesh_times, 1 ); - m_abfslcaos_lcaos.init_radial( abfs, lcaos, lcaos ); + ORB_gaunt_table MGT; + int Lmax; + m_abfslcaos_lcaos.init( 1, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_abfslcaos_lcaos.init_radial( abfs, lcaos, lcaos, MGT ); #if TEST_EXX_RADIAL>=1 m_abfslcaos_lcaos.init_radial_table(radial_R); #else @@ -153,8 +173,12 @@ void Exx_Opt_Orb::generate_matrix(const K_Vectors &kv, const LCAO_Orbitals& orb) const auto ms_jys_abfs = [&]() -> std::map>>>> { Matrix_Orbs11 m_jys_abfs; - m_jys_abfs.init( 2, orb, this->kmesh_times, 1 ); - m_jys_abfs.init_radial( jle.jle, abfs ); + ORB_gaunt_table MGT; + int Lmax; + m_jys_abfs.init( 2, orb, this->kmesh_times, orb.get_Rmax(), Lmax ); + MGT.init_Gaunt_CH(Lmax); + MGT.init_Gaunt(Lmax); + m_jys_abfs.init_radial( jle.jle, abfs, MGT ); #if TEST_EXX_RADIAL>=1 m_jys_abfs.init_radial_table(radial_R); #else diff --git a/source/module_ri/gaussian_abfs.cpp b/source/module_ri/gaussian_abfs.cpp new file mode 100644 index 00000000000..ed44237963d --- /dev/null +++ b/source/module_ri/gaussian_abfs.cpp @@ -0,0 +1,476 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-02-27 +//======================= + +#ifndef GAUSSIAN_ABFS_CPP +#define GAUSSIAN_ABFS_CPP + +#include "gaussian_abfs.h" + +#include +// #include + +#include "LRI_CV_Tools.h" +#include "module_base/global_variable.h" +#include "module_base/math_ylmreal.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" + +#include + +void Gaussian_Abfs::init(const int& Lmax, + const std::vector>& kvec_c, + const ModuleBase::Matrix3& G, + const double& lambda) { + ModuleBase::TITLE("Gaussian_Abfs", "init"); + ModuleBase::timer::tick("Gaussian_Abfs", "init"); + + this->kvec_c = kvec_c; + const int nks0 = kvec_c.size(); + + this->lambda = lambda; + const double eta = 35; + std::vector> Gvec; + Gvec.resize(3); + Gvec[0].x = G.e11; + Gvec[0].y = G.e12; + Gvec[0].z = G.e13; + + Gvec[1].x = G.e21; + Gvec[1].y = G.e22; + Gvec[1].z = G.e23; + + Gvec[2].x = G.e31; + Gvec[2].y = G.e32; + Gvec[2].z = G.e33; + + this->n_cells.resize(nks0); + this->qGvecs.resize(nks0); + this->check_gamma.resize(nks0); + this->ylm.resize(nks0); + const int total_lm = (Lmax + 1) * (Lmax + 1); + +#pragma omp parallel for schedule(dynamic) + for (size_t ik = 0; ik != nks0; ++ik) { + ModuleBase::Vector3 qvec = this->kvec_c[ik]; + const double Gmax = std::sqrt(eta * this->lambda) + + qvec.norm() * GlobalC::ucell.tpiba; + std::vector n_supercells = get_n_supercells(G, Gmax); + int total_cells + = std::accumulate(n_supercells.begin(), + n_supercells.end(), + 1, + [](int a, int b) { return a * (2 * b + 1); }); + + std::vector> qGvec_ik(total_cells); + std::vector check_gamma_ik(total_cells); + for (int idx = 0; idx < total_cells; ++idx) { + int G0 = (idx + / ((2 * n_supercells[1] + 1) * (2 * n_supercells[2] + 1))) + - n_supercells[0]; + int G1 = ((idx / (2 * n_supercells[2] + 1)) + % (2 * n_supercells[1] + 1)) + - n_supercells[1]; + int G2 = (idx % (2 * n_supercells[2] + 1)) - n_supercells[2]; + ModuleBase::Vector3 qGvec + = -(qvec + Gvec[0] * static_cast(G0) + + Gvec[1] * static_cast(G1) + + Gvec[2] * static_cast(G2)); + qGvec_ik[idx] = qGvec; + if (G0 == 0 && G1 == 0 && G2 == 0) + check_gamma_ik[idx] = true; + else + check_gamma_ik[idx] = false; + } + ModuleBase::matrix ylm_ik(total_lm, total_cells); + ModuleBase::YlmReal::Ylm_Real(total_lm, + total_cells, + qGvec_ik.data(), + ylm_ik); + +#pragma omp critical(Gaussian_Abfs_init) + { + this->n_cells[ik] = total_cells; + this->qGvecs[ik] = qGvec_ik; + this->check_gamma[ik] = check_gamma_ik; + this->ylm[ik] = ylm_ik; + } + } + + ModuleBase::timer::tick("Gaussian_Abfs", "init"); +} + +auto Gaussian_Abfs::get_Vq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt) -> RI::Tensor> { + ModuleBase::TITLE("Gaussian_Abfs", "get_Vq"); + ModuleBase::timer::tick("Gaussian_Abfs", "get_Vq"); + + const T_func_DPcal_lattice_sum> func_DPcal_lattice_sum + = std::bind(&Gaussian_Abfs::get_lattice_sum, + this, + ik, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + tau); + auto res = this->DPcal_Vq_dVq>>( + lp_max, + lq_max, + ik, + chi, + tau, + gaunt, + func_DPcal_lattice_sum); + + ModuleBase::timer::tick("Gaussian_Abfs", "get_Vq"); + return res; +} + +auto Gaussian_Abfs::get_dVq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt) + -> std::array>, 3> { + ModuleBase::TITLE("Gaussian_Abfs", "get_dVq"); + ModuleBase::timer::tick("Gaussian_Abfs", "get_dVq"); + + const T_func_DPcal_lattice_sum, 3>> + func_DPcal_d_lattice_sum = std::bind(&Gaussian_Abfs::get_d_lattice_sum, + this, + ik, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + tau); + auto res + = this->DPcal_Vq_dVq>, 3>>( + lp_max, + lq_max, + ik, + chi, + tau, + gaunt, + func_DPcal_d_lattice_sum); + + ModuleBase::timer::tick("Gaussian_Abfs", "get_Vq"); + return res; +} + +template +auto Gaussian_Abfs::DPcal_Vq_dVq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt, + const T_func_DPcal_lattice_sum& func_DPcal_lattice_sum) -> Tout { + const int Lmax = lp_max + lq_max; + const int n_LM = (Lmax + 1) * (Lmax + 1); + const size_t vq_ndim0 = (lp_max + 1) * (lp_max + 1); + const size_t vq_ndim1 = (lq_max + 1) * (lq_max + 1); + Tout Vq_dVq; + LRI_CV_Tools::init_elem(Vq_dVq, vq_ndim0, vq_ndim1); + /* + n_add_ksq * 2 = lp_max + lq_max - abs(lp_max - lq_max) + if lp_max < lq_max + n_add_ksq * 2 = lp_max + lq_max - (lq_max - lp_max) + = lp_max * 2 + if lp_max > lq_max + n_add_ksq * 2 = lp_max + lq_max - (lp_max - lq_max) + = lq_max * 2 + thus, + n_add_ksq = min(lp_max, lq_max) + */ + const int n_add_ksq = std::min(lp_max, lq_max); + std::vector> lattice_sum; + lattice_sum.resize(n_add_ksq + 1); + + const double exponent = 1.0 / this->lambda; + ModuleBase::Vector3 qvec = this->kvec_c[ik]; + + for (int i_add_ksq = 0; i_add_ksq != n_add_ksq + 1; + ++i_add_ksq) // integrate lp, lq, L to one index i_add_ksq, i.e. + // (lp+lq-L)/2 + { + const double power = -2.0 + 2 * i_add_ksq; + const int this_Lmax + = Lmax - 2 * i_add_ksq; // calculate Lmax at current lp+lq + const bool exclude_Gamma + = (qvec.norm() < 1e-10 + && i_add_ksq == 0); // only Gamma point and lq+lp-2>0 need to be + // corrected + lattice_sum[i_add_ksq] + = func_DPcal_lattice_sum(power, exponent, exclude_Gamma, this_Lmax); + } + + /* The exponent term comes in from Taylor expanding the + Gaussian at zero to first order in k^2, which cancels the k^-2 from the + Coulomb interaction. While terms of this order are in principle + neglected, we make one exception here. Without this, the final result + would (slightly) depend on the Ewald lambda.*/ + if (qvec.norm() < 1e-10) { + std::complex val = chi - exponent; + std::complex frac = 1.0 / std::sqrt(ModuleBase::FOUR_PI); + LRI_CV_Tools::add_elem(lattice_sum[0][0], val, frac); + } + + for (int lp = 0; lp != lp_max + 1; ++lp) { + double norm_1 + = double_factorial(2 * lp - 1) * std::sqrt(ModuleBase::PI * 0.5); + for (int lq = 0; lq != lq_max + 1; ++lq) { + double norm_2 = double_factorial(2 * lq - 1) + * std::sqrt(ModuleBase::PI * 0.5); + std::complex phase + = std::pow(ModuleBase::IMAG_UNIT, lp - lq); + std::complex cfac + = ModuleBase::FOUR_PI * phase * std::pow(ModuleBase::TWO_PI, 3) + / (norm_1 * norm_2) / GlobalC::ucell.omega; + for (int L = std::abs(lp - lq); L <= lp + lq; + L += 2) // if lp+lq-L == odd, then Gaunt_Coefficients = 0 + { + const int i_add_ksq = (lp + lq - L) / 2; + for (int mp = 0; mp != 2 * lp + 1; ++mp) { + const int lmp = lp * lp + mp; + for (int mq = 0; mq != 2 * lq + 1; ++mq) { + const int lmq = lq * lq + mq; + for (int m = 0; m != 2 * L + 1; ++m) { + const int lm = L * L + m; + double triple_Y = gaunt(lmp, lmq, lm); + std::complex fac = triple_Y * cfac; + LRI_CV_Tools::add_elem(Vq_dVq, + lmp, + lmq, + lattice_sum[i_add_ksq][lm], + fac); + } + } + } + } + } + } + + return Vq_dVq; +} + +Numerical_Orbital_Lm Gaussian_Abfs::Gauss(const Numerical_Orbital_Lm& orb, + const double& lambda) { + Numerical_Orbital_Lm gaussian; + const int angular_momentum_l = orb.getL(); + const double eta = 35; + const double rcut = std::sqrt(eta / lambda); + const double dr = orb.get_rab().back(); + int Nr = std::ceil(rcut / dr); + if (Nr % 2 == 0) + Nr += 1; + + std::vector rab(Nr); + for (size_t ir = 0; ir < Nr; ++ir) + rab[ir] = dr; + std::vector r_radial(Nr); + for (size_t ir = 0; ir < Nr; ++ir) + r_radial[ir] = ir * dr; + + const double frac = std::pow(lambda, angular_momentum_l + 1.5) + / double_factorial(2 * angular_momentum_l - 1) + / std::sqrt(ModuleBase::PI * 0.5); + + std::vector psi(Nr); + + for (size_t ir = 0; ir != Nr; ++ir) + psi[ir] = frac * std::pow(r_radial[ir], angular_momentum_l) + * std::exp(-lambda * r_radial[ir] * r_radial[ir] * 0.5); + + gaussian.set_orbital_info(orb.getLabel(), + orb.getType(), + angular_momentum_l, + orb.getChi(), + Nr, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(rab), + ModuleBase::GlobalFunc::VECTOR_TO_PTR(r_radial), + Numerical_Orbital_Lm::Psi_Type::Psi, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(psi), + orb.getNk(), + orb.getDk(), + orb.getDruniform(), + false, + true, + PARAM.inp.cal_force); + + return gaussian; +} + +double Gaussian_Abfs::double_factorial(const int& n) { + double result = 1.0; + for (int i = n; i > 0; i -= 2) { + if (i == 1) + result *= 1.0; + else + result *= static_cast(i); + } + return result; +} + +auto Gaussian_Abfs::get_lattice_sum( + const size_t& ik, + const double& + power, // Will be 0. for straight GTOs and -2. for Coulomb interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const ModuleBase::Vector3& tau) + -> std::vector> { + const T_func_DPcal_phase> func_DPcal_phase = + [&tau](const ModuleBase::Vector3& vec) -> std::complex { + return std::exp(ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT + * (vec * tau)); + }; + + return this->DPcal_lattice_sum>(ik, + power, + exponent, + exclude_Gamma, + lmax, + func_DPcal_phase); +} + +auto Gaussian_Abfs::get_d_lattice_sum( + const size_t& ik, + const double& + power, // Will be 0. for straight GTOs and -2. for Coulomb interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const ModuleBase::Vector3& tau) + -> std::vector, 3>> { + const T_func_DPcal_phase, 3>> + func_DPcal_d_phase = [&tau](const ModuleBase::Vector3& vec) + -> std::array, 3> { + using namespace RI::Array_Operator; + std::complex phase = std::exp( + ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (vec * tau)); + std::array, 3> ip_vec + = {phase * vec.x, phase * vec.y, phase * vec.z}; + std::array, 3> d_phase + = GlobalC::ucell.tpiba * ModuleBase::IMAG_UNIT * ip_vec; + + return d_phase; + }; + + return this->DPcal_lattice_sum, 3>>( + ik, + power, + exponent, + exclude_Gamma, + lmax, + func_DPcal_d_phase); +} + +template +auto Gaussian_Abfs::DPcal_lattice_sum( + const size_t& ik, + const double& + power, // Will be 0. for straight GTOs and -2. for Coulomb interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const T_func_DPcal_phase& func_DPcal_phase) + -> std::vector { + if (power < 0.0 && !exclude_Gamma && this->kvec_c[ik].norm() < 1e-10) + ModuleBase::WARNING_QUIT( + "Gaussian_Abfs::lattice_sum", + "Gamma point for power<0.0 cannot be evaluated!"); + + using namespace RI::Array_Operator; + + const int total_lm = (lmax + 1) * (lmax + 1); + std::vector result(total_lm, Tresult{}); + const int total_cells = this->n_cells[ik]; + +#pragma omp declare reduction( \ + vec_plus : std::vector : std::transform( \ + omp_out.begin(), \ + omp_out.end(), \ + omp_in.begin(), \ + omp_out.begin(), \ + LRI_CV_Tools::plus())) \ + initializer(omp_priv = decltype(omp_orig)(omp_orig.size())) +// // auto start0 = std::chrono::system_clock::now(); +#pragma omp parallel for reduction(vec_plus : result) + for (int idx = 0; idx < total_cells; ++idx) { + if (exclude_Gamma && this->check_gamma[ik][idx]) + continue; + + ModuleBase::Vector3 vec = this->qGvecs[ik][idx]; + const double vec_sq = vec.norm2() * GlobalC::ucell.tpiba2; + const double vec_abs = std::sqrt(vec_sq); + + const double val_s + = std::exp(-exponent * vec_sq) * std::pow(vec_abs, power); + + Tresult phase = func_DPcal_phase(vec); + for (int L = 0; L != lmax + 1; ++L) { + const double val_l = val_s * std::pow(vec_abs, L); + for (int m = 0; m != 2 * L + 1; ++m) { + const int lm = L * L + m; + const double val_lm = val_l * this->ylm[ik](lm, idx); + result[lm] + = result[lm] + + RI::Global_Func::convert>(val_lm) + * phase; + } + } + } + // auto end0 = std::chrono::system_clock::now(); + // auto duration0 = + // std::chrono::duration_cast(end0 - start0); + // std::cout << "lattice Time: " + // << double(duration0.count()) * + // std::chrono::microseconds::period::num + // / std::chrono::microseconds::period::den + // << " s" << std::endl; + + return result; +} + +std::vector Gaussian_Abfs::get_n_supercells(const ModuleBase::Matrix3& G, + const double& Gmax) { + std::vector n_supercells(3); + ModuleBase::Matrix3 GI = G.Inverse(); + ModuleBase::Matrix3 latvec = GI.Transpose(); + latvec *= GlobalC::ucell.lat0; + std::vector> lat; + lat.resize(3); + lat[0].x = latvec.e11; + lat[0].y = latvec.e12; + lat[0].z = latvec.e13; + lat[1].x = latvec.e21; + lat[1].y = latvec.e22; + lat[1].z = latvec.e23; + lat[2].x = latvec.e31; + lat[2].y = latvec.e32; + lat[2].z = latvec.e33; + + n_supercells[0] = static_cast( + std::floor(lat[0].norm() * Gmax / ModuleBase::TWO_PI + 1e-5)); + n_supercells[1] = static_cast( + std::floor(lat[1].norm() * Gmax / ModuleBase::TWO_PI + 1e-5)); + n_supercells[2] = static_cast( + std::floor(lat[2].norm() * Gmax / ModuleBase::TWO_PI + 1e-5)); + + return n_supercells; +} + +#endif \ No newline at end of file diff --git a/source/module_ri/gaussian_abfs.h b/source/module_ri/gaussian_abfs.h new file mode 100644 index 00000000000..69f6f1a7771 --- /dev/null +++ b/source/module_ri/gaussian_abfs.h @@ -0,0 +1,114 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-02-27 +//======================= + +#ifndef GAUSSIAN_ABFS_H +#define GAUSSIAN_ABFS_H + +#include "conv_coulomb_pot_k.h" +#include "module_basis/module_ao/ORB_atomic_lm.h" +#include "module_basis/module_ao/ORB_gaunt_table.h" +#include "module_basis/module_pw/pw_basis_k.h" +#include "module_cell/klist.h" + +#include +#include +#include +#include + +class Gaussian_Abfs { + public: + void init(const int& Lmax, + const std::vector>& kvec_c, + const ModuleBase::Matrix3& G, + const double& lambda); + + RI::Tensor> get_Vq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt); + + std::array>, 3> get_dVq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt); + + /* +Calculate the lattice sum over a Gaussian: + S(k) := \sum_G |k+G|^{power+L} \exp(-lambda*|k+G|^2) Y_{LM}(k+G) * +\exp(i(k+G)\tau) d_S(k) := S(k) * i * (k+G) +*/ + std::vector> get_lattice_sum( + const size_t& ik, + const double& power, // Will be 0. for straight GTOs and -2. for Coulomb + // interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const ModuleBase::Vector3& tau); + + std::vector, 3>> get_d_lattice_sum( + const size_t& ik, + const double& power, // Will be 0. for straight GTOs and -2. for Coulomb + // interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const ModuleBase::Vector3& tau); + + // construct gaussian basis based on original NAO + Numerical_Orbital_Lm Gauss(const Numerical_Orbital_Lm& orb, + const double& lambda); + + private: + double lambda; + std::vector> kvec_c; + std::vector>> qGvecs; + std::vector n_cells; + std::vector> check_gamma; + std::vector ylm; + template + using T_func_DPcal_phase + = std::function& vec)>; + template + using T_func_DPcal_lattice_sum = std::function( + const double& power, // Will be 0. for straight GTOs and -2. for Coulomb + // interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax)>; + + template + Tout DPcal_Vq_dVq( + const int& lp_max, + const int& lq_max, // Maximum L for which to calculate interaction. + const size_t& ik, + const double& chi, // Singularity corrected value at q=0. + const ModuleBase::Vector3& tau, + const ModuleBase::realArray& gaunt, + const T_func_DPcal_lattice_sum& func_DPcal_lattice_sum); + + template + std::vector DPcal_lattice_sum( + const size_t& ik, + const double& power, // Will be 0. for straight GTOs and -2. for Coulomb + // interaction + const double& exponent, + const bool& exclude_Gamma, // The R==0. can be excluded by this flag. + const int& lmax, // Maximum angular momentum the sum is needed for. + const T_func_DPcal_phase& func_DPcal_phase); + + // calculates the double factorial n!! of n + static double double_factorial(const int& n); + static std::vector get_n_supercells(const ModuleBase::Matrix3& G, + const double& Gmax); +}; + +#endif \ No newline at end of file diff --git a/source/module_ri/module_exx_symmetry/irreducible_sector.cpp b/source/module_ri/module_exx_symmetry/irreducible_sector.cpp index c9f1d4e87f7..9cb889b831c 100644 --- a/source/module_ri/module_exx_symmetry/irreducible_sector.cpp +++ b/source/module_ri/module_exx_symmetry/irreducible_sector.cpp @@ -86,9 +86,9 @@ namespace ModuleSymmetry return TCdouble(std::round(return_lattice_double.x), std::round(return_lattice_double.y), std::round(return_lattice_double.z)); } - void Irreducible_Sector::get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st) + void Irreducible_Sector::cal_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st) { - ModuleBase::TITLE("Symmetry_rotation", "get_return_lattice_all"); + ModuleBase::TITLE("Symmetry_rotation", "cal_return_lattice_all"); this->return_lattice_.resize(st.nat, std::vector(symm.nrotk)); for (int iat1 = 0;iat1 < st.nat;++iat1) { @@ -163,7 +163,7 @@ namespace ModuleSymmetry this->irreducible_sector_.clear(); this->sector_stars_.clear(); - if (this->return_lattice_.empty()) this->get_return_lattice_all(symm, atoms, st); + if (this->return_lattice_.empty()) this->cal_return_lattice_all(symm, atoms, st); // if (this->atompair_stars_.empty()) this->find_irreducible_atom_pairs(symm); // contruct {atom pair, R} set diff --git a/source/module_ri/module_exx_symmetry/irreducible_sector.h b/source/module_ri/module_exx_symmetry/irreducible_sector.h index 369f5f6b31a..6f9ab3cb8c8 100644 --- a/source/module_ri/module_exx_symmetry/irreducible_sector.h +++ b/source/module_ri/module_exx_symmetry/irreducible_sector.h @@ -67,9 +67,10 @@ namespace ModuleSymmetry TCdouble get_return_lattice(const Symmetry& symm, const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, const TCdouble& posd_a1, const TCdouble& posd_a2)const; - void get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); protected: + void cal_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); + //-------------------------------------------------------------------------------- /// The sub functions to find irreducible sector: {abR} diff --git a/source/module_ri/module_exx_symmetry/symmetry_rotation.cpp b/source/module_ri/module_exx_symmetry/symmetry_rotation.cpp index ab9c7b97563..bfdef1fab94 100644 --- a/source/module_ri/module_exx_symmetry/symmetry_rotation.cpp +++ b/source/module_ri/module_exx_symmetry/symmetry_rotation.cpp @@ -95,8 +95,7 @@ namespace ModuleSymmetry auto vec_conj = [](const std::vector>& z, const double scal = 1.0) -> std::vector> { std::vector> z_conj(z.size()); - for (int i = 0;i < z.size();++i) { z_conj[i] = std::conj(z[i]) * scal; -} + for (int i = 0;i < z.size();++i) { z_conj[i] = std::conj(z[i]) * scal; } return z_conj; }; std::vector>> dm_k_full; @@ -110,8 +109,7 @@ namespace ModuleSymmetry { double factor = 1.0 / static_cast(kv.kstars[ik_ibz].size()); std::vector> dm_scaled(pv.get_local_size()); - for (int i = 0;i < pv.get_local_size();++i) { dm_scaled[i] = factor * dm_k_ibz[ik_ibz + is * nk][i]; -} + for (int i = 0;i < pv.get_local_size();++i) { dm_scaled[i] = factor * dm_k_ibz[ik_ibz + is * nk][i]; } dm_k_full.push_back(dm_scaled); } else if (vec3_eq(isym_kvd.second, -kv.kvec_d[ik_ibz], this->eps_) && this->TRS_first_) { @@ -420,7 +418,7 @@ namespace ModuleSymmetry const char notrans = 'N'; std::complex alpha(1.0, 0.0); const std::complex beta(0.0, 0.0); - const int nbasis = GlobalV::NLOCAL; + const int nbasis = PARAM.globalv.nlocal; const int i1 = 1; if (TRS_conj) { diff --git a/source/module_ri/module_exx_symmetry/symmetry_rotation.h b/source/module_ri/module_exx_symmetry/symmetry_rotation.h index 1b58fbc8935..9bef3510c39 100644 --- a/source/module_ri/module_exx_symmetry/symmetry_rotation.h +++ b/source/module_ri/module_exx_symmetry/symmetry_rotation.h @@ -21,11 +21,6 @@ namespace ModuleSymmetry //-------------------------------------------------------------------------------- // getters const std::map>& get_irreducible_sector()const { return this->irs_.get_irreducible_sector(); } - void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, - const std::vector& Rs, const TC& period, const Lattice& lat) - { - this->irs_.find_irreducible_sector(symm, atoms, st, Rs, period, lat); - } TCdouble get_return_lattice(const Symmetry& symm, const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, const TCdouble& posd_a1, const TCdouble& posd_a2)const @@ -34,6 +29,11 @@ namespace ModuleSymmetry } //-------------------------------------------------------------------------------- // setters + void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::vector& Rs, const TC& period, const Lattice& lat) + { + this->irs_.find_irreducible_sector(symm, atoms, st, Rs, period, lat); + } void set_Cs_rotation(const std::vector>& abfs_l_nchi); //-------------------------------------------------------------------------------- /// functions to contruct rotation matrix in AO-representation diff --git a/source/module_ri/singular_value.cpp b/source/module_ri/singular_value.cpp new file mode 100644 index 00000000000..516feb805df --- /dev/null +++ b/source/module_ri/singular_value.cpp @@ -0,0 +1,316 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-01-01 +//======================= + +#ifndef AUXILIARY_FUNC_CPP +#define AUXILIARY_FUNC_CPP + +#include "singular_value.h" + +#include "conv_coulomb_pot_k.h" +#include "module_base/global_variable.h" +#include "module_base/math_ylmreal.h" +#include "module_base/timer.h" +#include "module_base/tool_title.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" + +#include +#include +#include + +// for analytic integral of fq +double Singular_Value::sum_for_solve_chi( + const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const double& fq_int) { + const int nks = kvec_c.size(); + + // cal fq sum except q=0 + double fq_sum = 0; + for (size_t ik = 0; ik != nks; ++ik) + fq_sum += kvec_c[ik].norm() ? func_cal_fq(kvec_c[ik]) : 0; + + double chi = fq_int * nks - fq_sum; + + return chi; +} + +// for numerical integral of fq +double Singular_Value::solve_chi( + const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const std::array& nq_arr, + const int& niter, + const double& eps, + const int& a_rate) { + // cal fq integral + double fq_int = Iter_Integral(func_cal_fq, nq_arr, niter, eps, a_rate); + + return sum_for_solve_chi(kvec_c, func_cal_fq, fq_int); +} + +// for analytic integral of fq +double Singular_Value::solve_chi( + const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const double& fq_int) { + return sum_for_solve_chi(kvec_c, func_cal_fq, fq_int); +} + +// for analytic integral of fq with gaussian sum +double Singular_Value::solve_chi(const int& nks, + const T_cal_fq_type_no& func_cal_fq, + const double& fq_int) { + double chi = fq_int * nks - func_cal_fq(); + + return chi; +} + +double + Singular_Value::fq_type_0(const ModuleBase::Vector3& qvec, + const int& qdiv, + std::vector>& avec, + std::vector>& bvec) { + assert(qvec.norm2()); + + std::vector> baq(3); + std::vector> baq_2(3); + const int qexpo = -abs(qdiv); + const double prefactor = std::pow(ModuleBase::TWO_PI, -qexpo); + + for (size_t i = 0; i != 3; ++i) { + baq[i] = GlobalC::ucell.tpiba * bvec[i] + * std::sin(avec[i] * qvec * ModuleBase::TWO_PI); + baq_2[i] = GlobalC::ucell.tpiba * bvec[i] + * std::sin(avec[i] * qvec * ModuleBase::PI); + } + + double sum_baq = 0; + double sum_baq_2 = 0; + for (size_t i = 1; i != 4; ++i) { + size_t j = i % 3 + 1; + size_t new_i = i - 1; + size_t new_j = j - 1; + sum_baq_2 += baq_2[new_i] * baq_2[new_i]; + sum_baq += baq[new_i] * baq[new_j]; + } + double fq = prefactor * std::pow(4 * sum_baq_2 + 2 * sum_baq, 0.5 * qexpo); + + return fq; +} + +double Singular_Value::cal_type_0( + const std::vector>& kvec_c, + const int& qdiv, + const double& qdense, + const int& niter, + const double& eps, + const int& a_rate) { + ModuleBase::TITLE("Singular_Value", "cal_type_0"); + ModuleBase::timer::tick("Singular_Value", "cal_type_0"); + + std::vector> avec + = {GlobalC::ucell.a1, GlobalC::ucell.a2, GlobalC::ucell.a3}; + std::vector> bvec; + bvec.resize(3); + bvec[0].x = GlobalC::ucell.G.e11; + bvec[0].y = GlobalC::ucell.G.e12; + bvec[0].z = GlobalC::ucell.G.e13; + + bvec[1].x = GlobalC::ucell.G.e21; + bvec[1].y = GlobalC::ucell.G.e22; + bvec[1].z = GlobalC::ucell.G.e23; + + bvec[2].x = GlobalC::ucell.G.e31; + bvec[2].y = GlobalC::ucell.G.e32; + bvec[2].z = GlobalC::ucell.G.e33; + + std::array nq_arr; + std::transform(bvec.begin(), + bvec.end(), + nq_arr.begin(), + [&qdense, &a_rate](ModuleBase::Vector3& vec) -> int { + int index = static_cast(vec.norm() * qdense + * GlobalC::ucell.tpiba); + return index ? index - index % a_rate : a_rate; + }); + const T_cal_fq_type func_cal_fq_type_0 + = std::bind(&fq_type_0, std::placeholders::_1, qdiv, avec, bvec); + + double val + = solve_chi(kvec_c, func_cal_fq_type_0, nq_arr, niter, eps, a_rate); + ModuleBase::timer::tick("Singular_Value", "cal_type_0"); + return val; +} + +double Singular_Value::fq_type_1(Gaussian_Abfs& gaussian_abfs, + const int& qdiv, + const double& lambda, + const int& lmax) { + const size_t ik = 0; + const double qexpo = -abs(qdiv); + const bool exclude_Gamma = true; + const ModuleBase::Vector3 tau(0, 0, 0); + + auto lattice_sum = gaussian_abfs.get_lattice_sum(ik, + qexpo, + lambda, + exclude_Gamma, + lmax, + tau); + assert(lattice_sum[0].imag() < 1e-10); + double fq = lattice_sum[0].real() * std::sqrt(ModuleBase::FOUR_PI); + + return fq; +} + +double Singular_Value::cal_type_1(const std::array& nmp, + const int& qdiv, + const double& start_lambda, + const int& niter, + const double& eps) { + ModuleBase::TITLE("Singular_Value", "cal_type_1"); + ModuleBase::timer::tick("Singular_Value", "cal_type_1"); + + ModuleBase::Matrix3 bvec; + bvec.e11 = GlobalC::ucell.G.e11 / nmp[0]; + bvec.e12 = GlobalC::ucell.G.e12 / nmp[0]; + bvec.e13 = GlobalC::ucell.G.e13 / nmp[0]; + + bvec.e21 = GlobalC::ucell.G.e21 / nmp[1]; + bvec.e22 = GlobalC::ucell.G.e22 / nmp[1]; + bvec.e23 = GlobalC::ucell.G.e23 / nmp[1]; + + bvec.e31 = GlobalC::ucell.G.e31 / nmp[2]; + bvec.e32 = GlobalC::ucell.G.e32 / nmp[2]; + bvec.e33 = GlobalC::ucell.G.e33 / nmp[2]; + + const int nks = nmp[0] * nmp[1] * nmp[2]; + const std::vector> qvec( + 1, + ModuleBase::Vector3{0, 0, 0}); + const int lmax = 0; + + auto cal_chi = [&qdiv, &bvec, &nks, &qvec, &lmax](const double& lambda) { + Gaussian_Abfs gaussian_abfs; + const double exponent = 1 / lambda; + gaussian_abfs.init(lmax, qvec, bvec, exponent); + const T_cal_fq_type_no func_cal_fq_type_1 + = std::bind(&fq_type_1, gaussian_abfs, qdiv, lambda, lmax); + double prefactor = ModuleBase::TWO_PI * std::pow(lambda, -1.0 / qdiv) + * GlobalC::ucell.omega + / std::pow(ModuleBase::TWO_PI, 3); + double fq_int; + if (qdiv == 2) + fq_int = prefactor * std::sqrt(ModuleBase::PI); + else if (qdiv == 1) + fq_int = prefactor; + else + ModuleBase::WARNING_QUIT( + "Singular_Value::cal_type_1", + "Type 1 fq only supports qdiv=1 or qdiv=2!"); + return solve_chi(nks, func_cal_fq_type_1, fq_int); + }; + + int tot_iter = 0; + double val_extra_old = 0.5 * std::numeric_limits::max(); + double lammda_old = start_lambda; + double val_old = cal_chi(lammda_old); + double val_extra; + for (size_t iter = 0; iter != niter; ++iter) { + double lammda_new = lammda_old * 0.5; + double val_new = cal_chi(lammda_new); + double dval = (val_new - val_old) / (lammda_new - lammda_old); + val_extra = val_new + dval * (0.0 - lammda_new); + if (std::abs(val_extra - val_extra_old) < eps) + break; + lammda_old = lammda_new; + val_old = val_new; + val_extra_old = val_extra; + tot_iter += 1; + } + + if (tot_iter == niter) + ModuleBase::WARNING_QUIT("Singular_Value::cal_type_1", + "not converged!"); + + ModuleBase::timer::tick("Singular_Value", "cal_type_1"); + return val_extra; +} + +double Singular_Value::Iter_Integral(const T_cal_fq_type& func_cal_fq, + const std::array& nq_arr, + const int& niter, + const double& eps, + const int& a_rate) { + bool any_negative = std::any_of(nq_arr.begin(), nq_arr.end(), [](int i) { + return i < 0; + }); + bool any_nthree = std::any_of(nq_arr.begin(), + nq_arr.end(), + [&a_rate](int i) { return i % a_rate != 0; }); + if (any_negative || any_nthree) + ModuleBase::WARNING_QUIT("Singular_Value::Iter_Integral", + "The elements of `nq_arr` should be " + "non-negative and multiples of a_rate!"); + bool all_zero = std::all_of(nq_arr.begin(), nq_arr.end(), [](int i) { + return i == 0; + }); + if (all_zero) + ModuleBase::WARNING_QUIT( + "Singular_Value::Iter_Integral", + "At least one element of `nq_arr` should be non-zero!"); + + const int nqs + = std::accumulate(nq_arr.begin(), nq_arr.end(), 1, [](int a, int b) { + return a * (2 * b + 1); + }); + std::array qstep{}; + std::array nq_arr_in{}; + int ndim = 0; + for (size_t i = 0; i != 3; ++i) { + if (nq_arr[i] != 0) { + qstep[i] = 1.0 / (2 * nq_arr[i] + 1); + ndim += 1; + } + nq_arr_in[i] = static_cast(nq_arr[i] / a_rate); + } + + double integ = 0.0; + int tot_iter = 0; + for (size_t iter = 0; iter != niter; ++iter) { + double integ_iter = 0.0; + for (int ig1 = -nq_arr[0]; ig1 != nq_arr[0] + 1; ++ig1) + for (int ig2 = -nq_arr[1]; ig2 != nq_arr[1] + 1; ++ig2) + for (int ig3 = -nq_arr[2]; ig3 != nq_arr[2] + 1; ++ig3) { + if (std::abs(ig1) <= nq_arr_in[0] + && std::abs(ig2) <= nq_arr_in[1] + && std::abs(ig3) <= nq_arr_in[2]) + continue; + ModuleBase::Vector3 qvec; // direct + qvec.x = qstep[0] * ig1; + qvec.y = qstep[1] * ig2; + qvec.z = qstep[2] * ig3; + integ_iter += func_cal_fq(qvec * GlobalC::ucell.G); + } + integ_iter + /= nqs * pow(a_rate, ndim * iter); // Each iteration reduces dq by a + // multiple of a_rate + integ += integ_iter; + if (iter != 0 && integ_iter < eps) + break; + std::for_each(qstep.begin(), qstep.end(), [&a_rate](double& qs) { + qs /= a_rate; + }); + tot_iter += 1; + } + + if (tot_iter == niter) + ModuleBase::WARNING_QUIT("Singular_Value::Iter_Integral", + "not converged!"); + + return integ; +} + +#endif \ No newline at end of file diff --git a/source/module_ri/singular_value.h b/source/module_ri/singular_value.h new file mode 100644 index 00000000000..641ca96966e --- /dev/null +++ b/source/module_ri/singular_value.h @@ -0,0 +1,74 @@ +//======================= +// AUTHOR : jiyy +// DATE : 2024-01-10 +//======================= + +#ifndef AUXILIARY_FUNC_H +#define AUXILIARY_FUNC_H + +#include +#include + +#include "gaussian_abfs.h" +#include "module_basis/module_pw/pw_basis_k.h" +#include "module_cell/klist.h" + +class Singular_Value +{ + public: + enum class Fq_type + { + Type_0, // Phys. Rev. B, 75:205126, May 2007. + Type_1, // Phys. Rev. B 48, 5058. August 1993. + }; + + private: + using T_cal_fq_type = std::function& gk)>; + using T_cal_fq_type_no = std::function; + + public: + static double cal_type_0(const std::vector>& kvec_c, + const int& qdiv, + const double& qdense, + const int& niter, + const double& eps, + const int& a_rate); + static double cal_type_1(const std::array& nmp, + const int& qdiv, + const double& start_lambda, + const int& niter, + const double& eps); + + private: + static double solve_chi(const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const std::array& nq_arr, + const int& niter, + const double& eps, + const int& a_rate); + static double solve_chi(const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const double& fq_int); + static double solve_chi(const int& nks, const T_cal_fq_type_no& func_cal_fq, const double& fq_int); + static double sum_for_solve_chi(const std::vector>& kvec_c, + const T_cal_fq_type& func_cal_fq, + const double& fq_int); + static double Iter_Integral(const T_cal_fq_type& func_cal_fq, + const std::array& nq_arr, + const int& niter, + const double& eps, + const int& a_rate); + + // TODO: lower dimension please see PHYSICAL REVIEW B 87, 165122 (2013) + + // qdiv=2 i.e. q^{-2} for 3D; + // qdiv=1 i.e. q^{-1} for 2D. + static double fq_type_0(const ModuleBase::Vector3& qvec, + const int& qdiv, + std::vector>& avec, + std::vector>& bvec); + // gamma: chosen as the radius of sphere which has the same volume as the Brillouin zone. + static double fq_type_1(Gaussian_Abfs& gaussian_abfs, const int& qdiv, const double& lambda, const int& lmax); +}; + +#endif \ No newline at end of file diff --git a/source/version.h b/source/version.h index b4ed4f23484..20d1b438a1c 100644 --- a/source/version.h +++ b/source/version.h @@ -1,3 +1,3 @@ #ifndef VERSION -#define VERSION "v3.7.5" +#define VERSION "v3.8.2" #endif diff --git a/tests/integrate/101_PW_15_pseudopots_LibxcLDA/INPUT b/tests/integrate/101_PW_15_pseudopots_LibxcLDA/INPUT index 96a7d117e1a..e46ac262e88 100644 --- a/tests/integrate/101_PW_15_pseudopots_LibxcLDA/INPUT +++ b/tests/integrate/101_PW_15_pseudopots_LibxcLDA/INPUT @@ -28,3 +28,5 @@ dft_functional XC_LDA_X+XC_LDA_C_PZ cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/101_PW_GTH_CF_CS_Si/INPUT b/tests/integrate/101_PW_GTH_CF_CS_Si/INPUT index 865002a7a15..376e57192b7 100644 --- a/tests/integrate/101_PW_GTH_CF_CS_Si/INPUT +++ b/tests/integrate/101_PW_GTH_CF_CS_Si/INPUT @@ -20,3 +20,5 @@ mixing_beta 0.7 mixing_gg0 1.5 pseudo_dir ../../PP_ORB + +pw_seed 1 diff --git a/tests/integrate/101_PW_lps6_pseudopots/INPUT b/tests/integrate/101_PW_lps6_pseudopots/INPUT index 367c0254c83..54ac435adec 100644 --- a/tests/integrate/101_PW_lps6_pseudopots/INPUT +++ b/tests/integrate/101_PW_lps6_pseudopots/INPUT @@ -25,3 +25,5 @@ dft_functional pbe #Parameters (5.Mixing) mixing_type broyden mixing_beta 0.7 + +pw_seed 1 diff --git a/tests/integrate/101_PW_upf100_Rappe_Fe/INPUT b/tests/integrate/101_PW_upf100_Rappe_Fe/INPUT index 98793a09e5c..e38a7a16d91 100644 --- a/tests/integrate/101_PW_upf100_Rappe_Fe/INPUT +++ b/tests/integrate/101_PW_upf100_Rappe_Fe/INPUT @@ -27,3 +27,5 @@ mixing_gg0 1.0 cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/101_PW_upf100_uspp_Fe/INPUT b/tests/integrate/101_PW_upf100_uspp_Fe/INPUT index 1f9e53c1e09..761237e9c52 100644 --- a/tests/integrate/101_PW_upf100_uspp_Fe/INPUT +++ b/tests/integrate/101_PW_upf100_uspp_Fe/INPUT @@ -32,3 +32,5 @@ pseudo_rcut 10 cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/101_PW_upf201_uspp_Fe/INPUT b/tests/integrate/101_PW_upf201_uspp_Fe/INPUT index 27d5dcb5a4a..f0a3784a14f 100644 --- a/tests/integrate/101_PW_upf201_uspp_Fe/INPUT +++ b/tests/integrate/101_PW_upf201_uspp_Fe/INPUT @@ -35,3 +35,5 @@ cal_force 1 cal_stress 1 kpar 3 + +pw_seed 1 diff --git a/tests/integrate/102_PW_BPCG_GPU/INPUT b/tests/integrate/102_PW_BPCG_GPU/INPUT index 79a14084dee..1f246024879 100644 --- a/tests/integrate/102_PW_BPCG_GPU/INPUT +++ b/tests/integrate/102_PW_BPCG_GPU/INPUT @@ -32,3 +32,5 @@ cal_stress 1 mixing_type broyden mixing_beta 0.4 mixing_gg0 1.5 + +pw_seed 1 diff --git a/tests/integrate/102_PW_DS_davsubspace/INPUT b/tests/integrate/102_PW_DS_davsubspace/INPUT index 1a834c95b6a..18f7dc5714a 100644 --- a/tests/integrate/102_PW_DS_davsubspace/INPUT +++ b/tests/integrate/102_PW_DS_davsubspace/INPUT @@ -25,4 +25,3 @@ mixing_type plain mixing_beta 0.5 ks_solver dav_subspace -diago_full_acc 1 diff --git a/tests/integrate/102_PW_PINT_UKS/result.ref b/tests/integrate/102_PW_PINT_UKS/result.ref index 5ac2ef86042..7bd1b9f13ec 100644 --- a/tests/integrate/102_PW_PINT_UKS/result.ref +++ b/tests/integrate/102_PW_PINT_UKS/result.ref @@ -1,3 +1,3 @@ -etotref -6147.553111352082 -etotperatomref -3073.7765556760 +etotref -6147.55311190 +etotperatomref -3073.77655595 totaltimeref 16.68 diff --git a/tests/integrate/103_PW_15_CS_CF/INPUT b/tests/integrate/103_PW_15_CS_CF/INPUT index c783334fe8e..bdf69f92aa1 100644 --- a/tests/integrate/103_PW_15_CS_CF/INPUT +++ b/tests/integrate/103_PW_15_CS_CF/INPUT @@ -31,3 +31,5 @@ cal_stress 1 mixing_type broyden mixing_beta 0.4 mixing_gg0 1.5 + +pw_seed 1 diff --git a/tests/integrate/103_PW_15_CS_CF_bspline/INPUT b/tests/integrate/103_PW_15_CS_CF_bspline/INPUT index b4034e604ba..b30bb33ec82 100644 --- a/tests/integrate/103_PW_15_CS_CF_bspline/INPUT +++ b/tests/integrate/103_PW_15_CS_CF_bspline/INPUT @@ -32,3 +32,5 @@ mixing_type broyden mixing_beta 0.4 mixing_gg0 1.5 nbspline 20 + +pw_seed 1 diff --git a/tests/integrate/103_PW_OU_CS_CF/INPUT b/tests/integrate/103_PW_OU_CS_CF/INPUT index 9b68f4388fe..0e623ef6d55 100644 --- a/tests/integrate/103_PW_OU_CS_CF/INPUT +++ b/tests/integrate/103_PW_OU_CS_CF/INPUT @@ -33,3 +33,5 @@ cal_stress 1 mixing_type broyden mixing_beta 0.4 mixing_gg0 1.5 + +pw_seed 1 diff --git a/tests/integrate/104_PW_FM_magnetic/INPUT b/tests/integrate/104_PW_FM_magnetic/INPUT index a0dc2f1fa43..3e35f70dece 100644 --- a/tests/integrate/104_PW_FM_magnetic/INPUT +++ b/tests/integrate/104_PW_FM_magnetic/INPUT @@ -26,3 +26,5 @@ basis_type pw symmetry 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB + +pw_seed 1 diff --git a/tests/integrate/104_PW_NC_magnetic/INPUT b/tests/integrate/104_PW_NC_magnetic/INPUT index 622af75b868..d761feb2c1e 100644 --- a/tests/integrate/104_PW_NC_magnetic/INPUT +++ b/tests/integrate/104_PW_NC_magnetic/INPUT @@ -4,10 +4,9 @@ suffix autotest #nbands 40 calculation scf -nspin 2 -ecutwfc 15 -scf_thr 1.0e-8 -scf_nmax 200 +ecutwfc 20 +scf_thr 1.0e-6 +scf_nmax 50 out_chg 0 #init_chg file @@ -16,14 +15,17 @@ out_chg 0 #out_band 1 noncolin 1 smearing_method gaussian -smearing_sigma 0.07 +smearing_sigma 0.02 mixing_type broyden -mixing_beta 0.5 +mixing_beta 0.2 mixing_ndim 10 -ks_solver cg +ks_solver dav_subspace +pw_diag_ndim 2 basis_type pw -symmetry 1 +symmetry 0 +cal_force 1 +cal_stress 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB diff --git a/tests/integrate/104_PW_NC_magnetic/KPT b/tests/integrate/104_PW_NC_magnetic/KPT index db314324451..28006d5e2df 100644 --- a/tests/integrate/104_PW_NC_magnetic/KPT +++ b/tests/integrate/104_PW_NC_magnetic/KPT @@ -1,4 +1,4 @@ K_POINTS 0 Gamma -1 1 1 0 0 0 +2 2 2 0 0 0 diff --git a/tests/integrate/104_PW_NC_magnetic/STRU b/tests/integrate/104_PW_NC_magnetic/STRU index d1981a2504d..5b61e75c50c 100644 --- a/tests/integrate/104_PW_NC_magnetic/STRU +++ b/tests/integrate/104_PW_NC_magnetic/STRU @@ -18,5 +18,5 @@ Fe 1.0 2 0.00 0.00 0.00 1 1 1 angle1 90 angle2 0 -0.50 0.50 0.50 1 1 1 angle1 90 angle2 180 +0.51 0.52 0.53 1 1 1 angle1 90 angle2 0 diff --git a/tests/integrate/104_PW_NC_magnetic/jd b/tests/integrate/104_PW_NC_magnetic/jd new file mode 100644 index 00000000000..a4292b9c28d --- /dev/null +++ b/tests/integrate/104_PW_NC_magnetic/jd @@ -0,0 +1 @@ +Test noncolliner-spin calculation for FM-Fe2 , test force and stress for k-222 diff --git a/tests/integrate/104_PW_NC_magnetic/result.ref b/tests/integrate/104_PW_NC_magnetic/result.ref index 384804bb8db..21c5c366134 100644 --- a/tests/integrate/104_PW_NC_magnetic/result.ref +++ b/tests/integrate/104_PW_NC_magnetic/result.ref @@ -1,6 +1,5 @@ -etotref -5866.197307043378 -etotperatomref -2933.0986535217 -pointgroupref O_h -spacegroupref O_h -nksibzref 1 -totaltimeref 2.23 +etotref -6156.9375288905130219 +etotperatomref -3078.4687644453 +totalforceref 2.221910 +totalstressref 76009.325784 +totaltimeref 3.03 diff --git a/tests/integrate/107_PW_OB_outputbands/INPUT b/tests/integrate/107_PW_OB_outputbands/INPUT index 9e45150d597..ded78ffae6e 100644 --- a/tests/integrate/107_PW_OB_outputbands/INPUT +++ b/tests/integrate/107_PW_OB_outputbands/INPUT @@ -31,3 +31,5 @@ smearing_sigma 0.002 mixing_type plain mixing_beta 0.7 + +pw_seed 1 diff --git a/tests/integrate/107_PW_W90/INPUT b/tests/integrate/107_PW_W90/INPUT index 117a2ee9662..f088e3a40ff 100644 --- a/tests/integrate/107_PW_W90/INPUT +++ b/tests/integrate/107_PW_W90/INPUT @@ -14,3 +14,5 @@ symmetry 0 towannier90 1 nnkpfile diamond.nnkp read_file_dir ./ + +pw_seed 1 diff --git a/tests/integrate/107_PW_outWfcPw/INPUT b/tests/integrate/107_PW_outWfcPw/INPUT index a42633a20a9..b4579450918 100644 --- a/tests/integrate/107_PW_outWfcPw/INPUT +++ b/tests/integrate/107_PW_outWfcPw/INPUT @@ -16,3 +16,5 @@ scf_nmax 100 basis_type pw out_wfc_pw 1 + +pw_seed 1 diff --git a/tests/integrate/107_PW_outWfcR/INPUT b/tests/integrate/107_PW_outWfcR/INPUT index 3b8e62abd06..1c11d476cf7 100644 --- a/tests/integrate/107_PW_outWfcR/INPUT +++ b/tests/integrate/107_PW_outWfcR/INPUT @@ -16,3 +16,5 @@ scf_nmax 100 basis_type pw out_wfc_r 1 + +pw_seed 1 diff --git a/tests/integrate/110_PW_SY/INPUT b/tests/integrate/110_PW_SY/INPUT index 933789c832a..5c14639acbc 100644 --- a/tests/integrate/110_PW_SY/INPUT +++ b/tests/integrate/110_PW_SY/INPUT @@ -25,3 +25,5 @@ dft_functional XC_GGA_X_PBE+XC_GGA_C_PBE cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/112_PW_dipole/INPUT b/tests/integrate/112_PW_dipole/INPUT index 67fb24bafc5..22b9b9a172a 100644 --- a/tests/integrate/112_PW_dipole/INPUT +++ b/tests/integrate/112_PW_dipole/INPUT @@ -29,3 +29,5 @@ efield_pos_dec 0.1 efield_amp 0.01 cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/112_PW_efield/INPUT b/tests/integrate/112_PW_efield/INPUT index f674fe18bb3..e6ea9fe492e 100644 --- a/tests/integrate/112_PW_efield/INPUT +++ b/tests/integrate/112_PW_efield/INPUT @@ -27,3 +27,5 @@ efield_flag 1 dip_cor_flag 0 cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/113_PW_gatefield/INPUT b/tests/integrate/113_PW_gatefield/INPUT index 382e7061a23..d669d47ca66 100644 --- a/tests/integrate/113_PW_gatefield/INPUT +++ b/tests/integrate/113_PW_gatefield/INPUT @@ -33,3 +33,5 @@ cal_stress 1 gate_flag 1 zgate 0.2 nelec 7 + +pw_seed 1 diff --git a/tests/integrate/114_PW_BD_15/INPUT b/tests/integrate/114_PW_BD_15/INPUT index cfcbca9950d..3f9d9ddcce6 100644 --- a/tests/integrate/114_PW_BD_15/INPUT +++ b/tests/integrate/114_PW_BD_15/INPUT @@ -24,3 +24,5 @@ smearing_sigma 0.002 mixing_type broyden mixing_beta 0.7 + +pw_seed 1 diff --git a/tests/integrate/115_PW_sol_H2O/INPUT b/tests/integrate/115_PW_sol_H2O/INPUT index 30e6e83703d..94d7e0e3576 100644 --- a/tests/integrate/115_PW_sol_H2O/INPUT +++ b/tests/integrate/115_PW_sol_H2O/INPUT @@ -18,3 +18,5 @@ eb_k 80 tau 0.000010798 sigma_k 0.6 nc_k 0.00037 + +pw_seed 1 diff --git a/tests/integrate/116_PW_scan_Si2/INPUT b/tests/integrate/116_PW_scan_Si2/INPUT index 8135ff13417..2e9a4ec38bc 100644 --- a/tests/integrate/116_PW_scan_Si2/INPUT +++ b/tests/integrate/116_PW_scan_Si2/INPUT @@ -28,3 +28,5 @@ cal_force 1 cal_stress 1 mixing_tau 1 + +pw_seed 1 diff --git a/tests/integrate/118_PW_CHG_BINARY/INPUT b/tests/integrate/118_PW_CHG_BINARY/INPUT index bd9a67afd41..20e786ba0ea 100644 --- a/tests/integrate/118_PW_CHG_BINARY/INPUT +++ b/tests/integrate/118_PW_CHG_BINARY/INPUT @@ -31,3 +31,5 @@ cal_stress 1 init_chg auto read_file_dir . + +pw_seed 1 diff --git a/tests/integrate/119_PW_out_elf/INPUT b/tests/integrate/119_PW_out_elf/INPUT new file mode 100644 index 00000000000..cdf99b93434 --- /dev/null +++ b/tests/integrate/119_PW_out_elf/INPUT @@ -0,0 +1,27 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation scf + +nbands 6 +symmetry 1 +pseudo_dir ../../PP_ORB + +#Parameters (2.Iteration) +ecutwfc 5 +scf_thr 1e-9 +scf_nmax 100 + + +#Parameters (3.Basis) +basis_type pw + +#Parameters (4.Smearing) +smearing_method gauss +smearing_sigma 0.002 + +#Parameters (5.Mixing) +mixing_type broyden +mixing_beta 0.7 + +out_elf 1 diff --git a/tests/integrate/119_PW_out_elf/KPT b/tests/integrate/119_PW_out_elf/KPT new file mode 100644 index 00000000000..c289c0158aa --- /dev/null +++ b/tests/integrate/119_PW_out_elf/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +1 1 1 0 0 0 diff --git a/tests/integrate/119_PW_out_elf/STRU b/tests/integrate/119_PW_out_elf/STRU new file mode 100644 index 00000000000..7c8bbf99085 --- /dev/null +++ b/tests/integrate/119_PW_out_elf/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +Si 14 Si_ONCV_PBE-1.0.upf upf201 + +LATTICE_CONSTANT +10.2 // add lattice constant + +LATTICE_VECTORS +0.5 0.5 0.0 +0.5 0.0 0.5 +0.0 0.5 0.5 + +ATOMIC_POSITIONS +Direct + +Si // Element type +0.0 // magnetism +2 +0.00 0.00 0.00 1 1 1 +0.25 0.25 0.25 1 1 1 diff --git a/tests/integrate/119_PW_out_elf/jd b/tests/integrate/119_PW_out_elf/jd new file mode 100644 index 00000000000..d58bf23e16f --- /dev/null +++ b/tests/integrate/119_PW_out_elf/jd @@ -0,0 +1 @@ +test out_elf in PW KSDFT. symmetry = on.; test init_chg=auto, and no chg file (will use atomic chg). diff --git a/tests/integrate/119_PW_out_elf/refELF.cube b/tests/integrate/119_PW_out_elf/refELF.cube new file mode 100644 index 00000000000..8fb31f75b45 --- /dev/null +++ b/tests/integrate/119_PW_out_elf/refELF.cube @@ -0,0 +1,296 @@ +STEP: 0 Cubefile created from ABACUS. Inner loop is z, followed by y and x +1 (nspin) +2 0.0 0.0 0.0 +12 0.425000 0.425000 0.000000 +12 0.425000 0.000000 0.425000 +12 0.000000 0.425000 0.425000 + 14 4.000000 0.000000 0.000000 0.000000 + 14 4.000000 2.550000 2.550000 2.550000 + 1.318e-04 1.477e-02 3.999e-01 8.349e-01 8.631e-01 5.225e-01 + 2.341e-01 5.225e-01 8.631e-01 8.349e-01 3.999e-01 1.477e-02 + 1.477e-02 5.423e-01 9.580e-01 9.857e-01 9.151e-01 4.414e-01 + 4.414e-01 9.151e-01 9.857e-01 9.580e-01 5.423e-01 1.477e-02 + 3.999e-01 9.580e-01 9.955e-01 9.857e-01 7.214e-01 2.780e-01 + 7.214e-01 9.857e-01 9.955e-01 9.580e-01 3.999e-01 5.220e-02 + 8.349e-01 9.857e-01 9.857e-01 8.349e-01 1.969e-01 1.969e-01 + 8.349e-01 9.857e-01 9.857e-01 8.349e-01 1.969e-01 1.969e-01 + 8.631e-01 9.151e-01 7.214e-01 1.969e-01 5.231e-02 1.969e-01 + 7.214e-01 9.151e-01 8.631e-01 3.711e-01 1.042e-01 3.711e-01 + 5.225e-01 4.414e-01 2.780e-01 1.969e-01 1.969e-01 2.780e-01 + 4.414e-01 5.225e-01 3.057e-01 6.999e-02 6.999e-02 3.057e-01 + 2.341e-01 4.414e-01 7.214e-01 8.349e-01 7.214e-01 4.414e-01 + 2.341e-01 1.279e-01 5.464e-02 3.021e-02 5.464e-02 1.279e-01 + 5.225e-01 9.151e-01 9.857e-01 9.857e-01 9.151e-01 5.225e-01 + 1.279e-01 5.248e-02 7.128e-02 7.128e-02 5.248e-02 1.279e-01 + 8.631e-01 9.857e-01 9.955e-01 9.857e-01 8.631e-01 3.057e-01 + 5.464e-02 7.128e-02 3.826e-01 7.128e-02 5.464e-02 3.057e-01 + 8.349e-01 9.580e-01 9.580e-01 8.349e-01 3.711e-01 6.999e-02 + 3.021e-02 7.128e-02 7.128e-02 3.021e-02 6.999e-02 3.711e-01 + 3.999e-01 5.423e-01 3.999e-01 1.969e-01 1.042e-01 6.999e-02 + 5.464e-02 5.248e-02 5.464e-02 6.999e-02 1.042e-01 1.969e-01 + 1.477e-02 1.477e-02 5.220e-02 1.969e-01 3.711e-01 3.057e-01 + 1.279e-01 1.279e-01 3.057e-01 3.711e-01 1.969e-01 5.220e-02 + 1.477e-02 5.423e-01 9.580e-01 9.857e-01 9.151e-01 4.414e-01 + 4.414e-01 9.151e-01 9.857e-01 9.580e-01 5.423e-01 1.477e-02 + 5.423e-01 9.878e-01 9.996e-01 9.955e-01 8.135e-01 3.655e-01 + 8.135e-01 9.955e-01 9.996e-01 9.878e-01 5.423e-01 5.705e-02 + 9.580e-01 9.996e-01 9.996e-01 9.580e-01 3.553e-01 3.553e-01 + 9.580e-01 9.996e-01 9.996e-01 9.580e-01 3.553e-01 3.553e-01 + 9.857e-01 9.955e-01 9.580e-01 3.999e-01 5.220e-02 3.999e-01 + 9.580e-01 9.955e-01 9.857e-01 7.214e-01 2.780e-01 7.214e-01 + 9.151e-01 8.135e-01 3.553e-01 5.220e-02 5.220e-02 3.553e-01 + 8.135e-01 9.151e-01 7.660e-01 2.624e-01 2.624e-01 7.660e-01 + 4.414e-01 3.655e-01 3.553e-01 3.999e-01 3.553e-01 3.655e-01 + 4.414e-01 4.227e-01 1.940e-01 8.700e-02 1.940e-01 4.227e-01 + 4.414e-01 8.135e-01 9.580e-01 9.580e-01 8.135e-01 4.414e-01 + 1.842e-01 9.824e-02 7.331e-02 7.331e-02 9.824e-02 1.842e-01 + 9.151e-01 9.955e-01 9.996e-01 9.955e-01 9.151e-01 4.227e-01 + 9.824e-02 1.101e-01 4.486e-01 1.101e-01 9.824e-02 4.227e-01 + 9.857e-01 9.996e-01 9.996e-01 9.857e-01 7.660e-01 1.940e-01 + 7.331e-02 4.486e-01 4.486e-01 7.331e-02 1.940e-01 7.660e-01 + 9.580e-01 9.878e-01 9.580e-01 7.214e-01 2.624e-01 8.700e-02 + 7.331e-02 1.101e-01 7.331e-02 8.700e-02 2.624e-01 7.214e-01 + 5.423e-01 5.423e-01 3.553e-01 2.780e-01 2.624e-01 1.940e-01 + 9.824e-02 9.824e-02 1.940e-01 2.624e-01 2.780e-01 3.553e-01 + 1.477e-02 5.705e-02 3.553e-01 7.214e-01 7.660e-01 4.227e-01 + 1.842e-01 4.227e-01 7.660e-01 7.214e-01 3.553e-01 5.705e-02 + 3.999e-01 9.580e-01 9.955e-01 9.857e-01 7.214e-01 2.780e-01 + 7.214e-01 9.857e-01 9.955e-01 9.580e-01 3.999e-01 5.220e-02 + 9.580e-01 9.996e-01 9.996e-01 9.580e-01 3.553e-01 3.553e-01 + 9.580e-01 9.996e-01 9.996e-01 9.580e-01 3.553e-01 3.553e-01 + 9.955e-01 9.996e-01 9.878e-01 5.423e-01 5.705e-02 5.423e-01 + 9.878e-01 9.996e-01 9.955e-01 8.135e-01 3.655e-01 8.135e-01 + 9.857e-01 9.580e-01 5.423e-01 1.477e-02 1.477e-02 5.423e-01 + 9.580e-01 9.857e-01 9.151e-01 4.414e-01 4.414e-01 9.151e-01 + 7.214e-01 3.553e-01 5.705e-02 1.477e-02 5.705e-02 3.553e-01 + 7.214e-01 7.660e-01 4.227e-01 1.842e-01 4.227e-01 7.660e-01 + 2.780e-01 3.553e-01 5.423e-01 5.423e-01 3.553e-01 2.780e-01 + 2.624e-01 1.940e-01 9.824e-02 9.824e-02 1.940e-01 2.624e-01 + 7.214e-01 9.580e-01 9.878e-01 9.580e-01 7.214e-01 2.624e-01 + 8.700e-02 7.331e-02 1.101e-01 7.331e-02 8.700e-02 2.624e-01 + 9.857e-01 9.996e-01 9.996e-01 9.857e-01 7.660e-01 1.940e-01 + 7.331e-02 4.486e-01 4.486e-01 7.331e-02 1.940e-01 7.660e-01 + 9.955e-01 9.996e-01 9.955e-01 9.151e-01 4.227e-01 9.824e-02 + 1.101e-01 4.486e-01 1.101e-01 9.824e-02 4.227e-01 9.151e-01 + 9.580e-01 9.580e-01 8.135e-01 4.414e-01 1.842e-01 9.824e-02 + 7.331e-02 7.331e-02 9.824e-02 1.842e-01 4.414e-01 8.135e-01 + 3.999e-01 3.553e-01 3.655e-01 4.414e-01 4.227e-01 1.940e-01 + 8.700e-02 1.940e-01 4.227e-01 4.414e-01 3.655e-01 3.553e-01 + 5.220e-02 3.553e-01 8.135e-01 9.151e-01 7.660e-01 2.624e-01 + 2.624e-01 7.660e-01 9.151e-01 8.135e-01 3.553e-01 5.220e-02 + 8.349e-01 9.857e-01 9.857e-01 8.349e-01 1.969e-01 1.969e-01 + 8.349e-01 9.857e-01 9.857e-01 8.349e-01 1.969e-01 1.969e-01 + 9.857e-01 9.955e-01 9.580e-01 3.999e-01 5.220e-02 3.999e-01 + 9.580e-01 9.955e-01 9.857e-01 7.214e-01 2.780e-01 7.214e-01 + 9.857e-01 9.580e-01 5.423e-01 1.477e-02 1.477e-02 5.423e-01 + 9.580e-01 9.857e-01 9.151e-01 4.414e-01 4.414e-01 9.151e-01 + 8.349e-01 3.999e-01 1.477e-02 1.318e-04 1.477e-02 3.999e-01 + 8.349e-01 8.631e-01 5.225e-01 2.341e-01 5.225e-01 8.631e-01 + 1.969e-01 5.220e-02 1.477e-02 1.477e-02 5.220e-02 1.969e-01 + 3.711e-01 3.057e-01 1.279e-01 1.279e-01 3.057e-01 3.711e-01 + 1.969e-01 3.999e-01 5.423e-01 3.999e-01 1.969e-01 1.042e-01 + 6.999e-02 5.464e-02 5.248e-02 5.464e-02 6.999e-02 1.042e-01 + 8.349e-01 9.580e-01 9.580e-01 8.349e-01 3.711e-01 6.999e-02 + 3.021e-02 7.128e-02 7.128e-02 3.021e-02 6.999e-02 3.711e-01 + 9.857e-01 9.955e-01 9.857e-01 8.631e-01 3.057e-01 5.464e-02 + 7.128e-02 3.826e-01 7.128e-02 5.464e-02 3.057e-01 8.631e-01 + 9.857e-01 9.857e-01 9.151e-01 5.225e-01 1.279e-01 5.248e-02 + 7.128e-02 7.128e-02 5.248e-02 1.279e-01 5.225e-01 9.151e-01 + 8.349e-01 7.214e-01 4.414e-01 2.341e-01 1.279e-01 5.464e-02 + 3.021e-02 5.464e-02 1.279e-01 2.341e-01 4.414e-01 7.214e-01 + 1.969e-01 2.780e-01 4.414e-01 5.225e-01 3.057e-01 6.999e-02 + 6.999e-02 3.057e-01 5.225e-01 4.414e-01 2.780e-01 1.969e-01 + 1.969e-01 7.214e-01 9.151e-01 8.631e-01 3.711e-01 1.042e-01 + 3.711e-01 8.631e-01 9.151e-01 7.214e-01 1.969e-01 5.231e-02 + 8.631e-01 9.151e-01 7.214e-01 1.969e-01 5.231e-02 1.969e-01 + 7.214e-01 9.151e-01 8.631e-01 3.711e-01 1.042e-01 3.711e-01 + 9.151e-01 8.135e-01 3.553e-01 5.220e-02 5.220e-02 3.553e-01 + 8.135e-01 9.151e-01 7.660e-01 2.624e-01 2.624e-01 7.660e-01 + 7.214e-01 3.553e-01 5.705e-02 1.477e-02 5.705e-02 3.553e-01 + 7.214e-01 7.660e-01 4.227e-01 1.842e-01 4.227e-01 7.660e-01 + 1.969e-01 5.220e-02 1.477e-02 1.477e-02 5.220e-02 1.969e-01 + 3.711e-01 3.057e-01 1.279e-01 1.279e-01 3.057e-01 3.711e-01 + 5.231e-02 5.220e-02 5.705e-02 5.220e-02 5.231e-02 6.226e-02 + 6.587e-02 5.089e-02 4.361e-02 5.089e-02 6.587e-02 6.226e-02 + 1.969e-01 3.553e-01 3.553e-01 1.969e-01 6.226e-02 1.893e-02 + 1.293e-02 2.418e-02 2.418e-02 1.293e-02 1.893e-02 6.226e-02 + 7.214e-01 8.135e-01 7.214e-01 3.711e-01 6.587e-02 1.293e-02 + 1.983e-02 6.035e-02 1.983e-02 1.293e-02 6.587e-02 3.711e-01 + 9.151e-01 9.151e-01 7.660e-01 3.057e-01 5.089e-02 2.418e-02 + 6.035e-02 6.035e-02 2.418e-02 5.089e-02 3.057e-01 7.660e-01 + 8.631e-01 7.660e-01 4.227e-01 1.279e-01 4.361e-02 2.418e-02 + 1.983e-02 2.418e-02 4.361e-02 1.279e-01 4.227e-01 7.660e-01 + 3.711e-01 2.624e-01 1.842e-01 1.279e-01 5.089e-02 1.293e-02 + 1.293e-02 5.089e-02 1.279e-01 1.842e-01 2.624e-01 3.711e-01 + 1.042e-01 2.624e-01 4.227e-01 3.057e-01 6.587e-02 1.893e-02 + 6.587e-02 3.057e-01 4.227e-01 2.624e-01 1.042e-01 6.226e-02 + 3.711e-01 7.660e-01 7.660e-01 3.711e-01 6.226e-02 6.226e-02 + 3.711e-01 7.660e-01 7.660e-01 3.711e-01 6.226e-02 6.226e-02 + 5.225e-01 4.414e-01 2.780e-01 1.969e-01 1.969e-01 2.780e-01 + 4.414e-01 5.225e-01 3.057e-01 6.999e-02 6.999e-02 3.057e-01 + 4.414e-01 3.655e-01 3.553e-01 3.999e-01 3.553e-01 3.655e-01 + 4.414e-01 4.227e-01 1.940e-01 8.700e-02 1.940e-01 4.227e-01 + 2.780e-01 3.553e-01 5.423e-01 5.423e-01 3.553e-01 2.780e-01 + 2.624e-01 1.940e-01 9.824e-02 9.824e-02 1.940e-01 2.624e-01 + 1.969e-01 3.999e-01 5.423e-01 3.999e-01 1.969e-01 1.042e-01 + 6.999e-02 5.464e-02 5.248e-02 5.464e-02 6.999e-02 1.042e-01 + 1.969e-01 3.553e-01 3.553e-01 1.969e-01 6.226e-02 1.893e-02 + 1.293e-02 2.418e-02 2.418e-02 1.293e-02 1.893e-02 6.226e-02 + 2.780e-01 3.655e-01 2.780e-01 1.042e-01 1.893e-02 5.255e-03 + 1.113e-02 3.301e-02 1.113e-02 5.255e-03 1.893e-02 1.042e-01 + 4.414e-01 4.414e-01 2.624e-01 6.999e-02 1.293e-02 1.113e-02 + 4.867e-02 4.867e-02 1.113e-02 1.293e-02 6.999e-02 2.624e-01 + 5.225e-01 4.227e-01 1.940e-01 5.464e-02 2.418e-02 3.301e-02 + 4.867e-02 3.301e-02 2.418e-02 5.464e-02 1.940e-01 4.227e-01 + 3.057e-01 1.940e-01 9.824e-02 5.248e-02 2.418e-02 1.113e-02 + 1.113e-02 2.418e-02 5.248e-02 9.824e-02 1.940e-01 3.057e-01 + 6.999e-02 8.700e-02 9.824e-02 5.464e-02 1.293e-02 5.255e-03 + 1.293e-02 5.464e-02 9.824e-02 8.700e-02 6.999e-02 6.587e-02 + 6.999e-02 1.940e-01 1.940e-01 6.999e-02 1.893e-02 1.893e-02 + 6.999e-02 1.940e-01 1.940e-01 6.999e-02 1.893e-02 1.893e-02 + 3.057e-01 4.227e-01 2.624e-01 1.042e-01 6.226e-02 1.042e-01 + 2.624e-01 4.227e-01 3.057e-01 6.587e-02 1.893e-02 6.587e-02 + 2.341e-01 4.414e-01 7.214e-01 8.349e-01 7.214e-01 4.414e-01 + 2.341e-01 1.279e-01 5.464e-02 3.021e-02 5.464e-02 1.279e-01 + 4.414e-01 8.135e-01 9.580e-01 9.580e-01 8.135e-01 4.414e-01 + 1.842e-01 9.824e-02 7.331e-02 7.331e-02 9.824e-02 1.842e-01 + 7.214e-01 9.580e-01 9.878e-01 9.580e-01 7.214e-01 2.624e-01 + 8.700e-02 7.331e-02 1.101e-01 7.331e-02 8.700e-02 2.624e-01 + 8.349e-01 9.580e-01 9.580e-01 8.349e-01 3.711e-01 6.999e-02 + 3.021e-02 7.128e-02 7.128e-02 3.021e-02 6.999e-02 3.711e-01 + 7.214e-01 8.135e-01 7.214e-01 3.711e-01 6.587e-02 1.293e-02 + 1.983e-02 6.035e-02 1.983e-02 1.293e-02 6.587e-02 3.711e-01 + 4.414e-01 4.414e-01 2.624e-01 6.999e-02 1.293e-02 1.113e-02 + 4.867e-02 4.867e-02 1.113e-02 1.293e-02 6.999e-02 2.624e-01 + 2.341e-01 1.842e-01 8.700e-02 3.021e-02 1.983e-02 4.867e-02 + 9.658e-02 4.867e-02 1.983e-02 3.021e-02 8.700e-02 1.842e-01 + 1.279e-01 9.824e-02 7.331e-02 7.128e-02 6.035e-02 4.867e-02 + 4.867e-02 6.035e-02 7.128e-02 7.331e-02 9.824e-02 1.279e-01 + 5.464e-02 7.331e-02 1.101e-01 7.128e-02 1.983e-02 1.113e-02 + 1.983e-02 7.128e-02 1.101e-01 7.331e-02 5.464e-02 5.089e-02 + 3.021e-02 7.331e-02 7.331e-02 3.021e-02 1.293e-02 1.293e-02 + 3.021e-02 7.331e-02 7.331e-02 3.021e-02 1.293e-02 1.293e-02 + 5.464e-02 9.824e-02 8.700e-02 6.999e-02 6.587e-02 6.999e-02 + 8.700e-02 9.824e-02 5.464e-02 1.293e-02 5.255e-03 1.293e-02 + 1.279e-01 1.842e-01 2.624e-01 3.711e-01 3.711e-01 2.624e-01 + 1.842e-01 1.279e-01 5.089e-02 1.293e-02 1.293e-02 5.089e-02 + 5.225e-01 9.151e-01 9.857e-01 9.857e-01 9.151e-01 5.225e-01 + 1.279e-01 5.248e-02 7.128e-02 7.128e-02 5.248e-02 1.279e-01 + 9.151e-01 9.955e-01 9.996e-01 9.955e-01 9.151e-01 4.227e-01 + 9.824e-02 1.101e-01 4.486e-01 1.101e-01 9.824e-02 4.227e-01 + 9.857e-01 9.996e-01 9.996e-01 9.857e-01 7.660e-01 1.940e-01 + 7.331e-02 4.486e-01 4.486e-01 7.331e-02 1.940e-01 7.660e-01 + 9.857e-01 9.955e-01 9.857e-01 8.631e-01 3.057e-01 5.464e-02 + 7.128e-02 3.826e-01 7.128e-02 5.464e-02 3.057e-01 8.631e-01 + 9.151e-01 9.151e-01 7.660e-01 3.057e-01 5.089e-02 2.418e-02 + 6.035e-02 6.035e-02 2.418e-02 5.089e-02 3.057e-01 7.660e-01 + 5.225e-01 4.227e-01 1.940e-01 5.464e-02 2.418e-02 3.301e-02 + 4.867e-02 3.301e-02 2.418e-02 5.464e-02 1.940e-01 4.227e-01 + 1.279e-01 9.824e-02 7.331e-02 7.128e-02 6.035e-02 4.867e-02 + 4.867e-02 6.035e-02 7.128e-02 7.331e-02 9.824e-02 1.279e-01 + 5.248e-02 1.101e-01 4.486e-01 3.826e-01 6.035e-02 3.301e-02 + 6.035e-02 3.826e-01 4.486e-01 1.101e-01 5.248e-02 4.361e-02 + 7.128e-02 4.486e-01 4.486e-01 7.128e-02 2.418e-02 2.418e-02 + 7.128e-02 4.486e-01 4.486e-01 7.128e-02 2.418e-02 2.418e-02 + 7.128e-02 1.101e-01 7.331e-02 5.464e-02 5.089e-02 5.464e-02 + 7.331e-02 1.101e-01 7.128e-02 1.983e-02 1.113e-02 1.983e-02 + 5.248e-02 9.824e-02 1.940e-01 3.057e-01 3.057e-01 1.940e-01 + 9.824e-02 5.248e-02 2.418e-02 1.113e-02 1.113e-02 2.418e-02 + 1.279e-01 4.227e-01 7.660e-01 8.631e-01 7.660e-01 4.227e-01 + 1.279e-01 4.361e-02 2.418e-02 1.983e-02 2.418e-02 4.361e-02 + 8.631e-01 9.857e-01 9.955e-01 9.857e-01 8.631e-01 3.057e-01 + 5.464e-02 7.128e-02 3.826e-01 7.128e-02 5.464e-02 3.057e-01 + 9.857e-01 9.996e-01 9.996e-01 9.857e-01 7.660e-01 1.940e-01 + 7.331e-02 4.486e-01 4.486e-01 7.331e-02 1.940e-01 7.660e-01 + 9.955e-01 9.996e-01 9.955e-01 9.151e-01 4.227e-01 9.824e-02 + 1.101e-01 4.486e-01 1.101e-01 9.824e-02 4.227e-01 9.151e-01 + 9.857e-01 9.857e-01 9.151e-01 5.225e-01 1.279e-01 5.248e-02 + 7.128e-02 7.128e-02 5.248e-02 1.279e-01 5.225e-01 9.151e-01 + 8.631e-01 7.660e-01 4.227e-01 1.279e-01 4.361e-02 2.418e-02 + 1.983e-02 2.418e-02 4.361e-02 1.279e-01 4.227e-01 7.660e-01 + 3.057e-01 1.940e-01 9.824e-02 5.248e-02 2.418e-02 1.113e-02 + 1.113e-02 2.418e-02 5.248e-02 9.824e-02 1.940e-01 3.057e-01 + 5.464e-02 7.331e-02 1.101e-01 7.128e-02 1.983e-02 1.113e-02 + 1.983e-02 7.128e-02 1.101e-01 7.331e-02 5.464e-02 5.089e-02 + 7.128e-02 4.486e-01 4.486e-01 7.128e-02 2.418e-02 2.418e-02 + 7.128e-02 4.486e-01 4.486e-01 7.128e-02 2.418e-02 2.418e-02 + 3.826e-01 4.486e-01 1.101e-01 5.248e-02 4.361e-02 5.248e-02 + 1.101e-01 4.486e-01 3.826e-01 6.035e-02 3.301e-02 6.035e-02 + 7.128e-02 7.331e-02 9.824e-02 1.279e-01 1.279e-01 9.824e-02 + 7.331e-02 7.128e-02 6.035e-02 4.867e-02 4.867e-02 6.035e-02 + 5.464e-02 1.940e-01 4.227e-01 5.225e-01 4.227e-01 1.940e-01 + 5.464e-02 2.418e-02 3.301e-02 4.867e-02 3.301e-02 2.418e-02 + 3.057e-01 7.660e-01 9.151e-01 9.151e-01 7.660e-01 3.057e-01 + 5.089e-02 2.418e-02 6.035e-02 6.035e-02 2.418e-02 5.089e-02 + 8.349e-01 9.580e-01 9.580e-01 8.349e-01 3.711e-01 6.999e-02 + 3.021e-02 7.128e-02 7.128e-02 3.021e-02 6.999e-02 3.711e-01 + 9.580e-01 9.878e-01 9.580e-01 7.214e-01 2.624e-01 8.700e-02 + 7.331e-02 1.101e-01 7.331e-02 8.700e-02 2.624e-01 7.214e-01 + 9.580e-01 9.580e-01 8.135e-01 4.414e-01 1.842e-01 9.824e-02 + 7.331e-02 7.331e-02 9.824e-02 1.842e-01 4.414e-01 8.135e-01 + 8.349e-01 7.214e-01 4.414e-01 2.341e-01 1.279e-01 5.464e-02 + 3.021e-02 5.464e-02 1.279e-01 2.341e-01 4.414e-01 7.214e-01 + 3.711e-01 2.624e-01 1.842e-01 1.279e-01 5.089e-02 1.293e-02 + 1.293e-02 5.089e-02 1.279e-01 1.842e-01 2.624e-01 3.711e-01 + 6.999e-02 8.700e-02 9.824e-02 5.464e-02 1.293e-02 5.255e-03 + 1.293e-02 5.464e-02 9.824e-02 8.700e-02 6.999e-02 6.587e-02 + 3.021e-02 7.331e-02 7.331e-02 3.021e-02 1.293e-02 1.293e-02 + 3.021e-02 7.331e-02 7.331e-02 3.021e-02 1.293e-02 1.293e-02 + 7.128e-02 1.101e-01 7.331e-02 5.464e-02 5.089e-02 5.464e-02 + 7.331e-02 1.101e-01 7.128e-02 1.983e-02 1.113e-02 1.983e-02 + 7.128e-02 7.331e-02 9.824e-02 1.279e-01 1.279e-01 9.824e-02 + 7.331e-02 7.128e-02 6.035e-02 4.867e-02 4.867e-02 6.035e-02 + 3.021e-02 8.700e-02 1.842e-01 2.341e-01 1.842e-01 8.700e-02 + 3.021e-02 1.983e-02 4.867e-02 9.658e-02 4.867e-02 1.983e-02 + 6.999e-02 2.624e-01 4.414e-01 4.414e-01 2.624e-01 6.999e-02 + 1.293e-02 1.113e-02 4.867e-02 4.867e-02 1.113e-02 1.293e-02 + 3.711e-01 7.214e-01 8.135e-01 7.214e-01 3.711e-01 6.587e-02 + 1.293e-02 1.983e-02 6.035e-02 1.983e-02 1.293e-02 6.587e-02 + 3.999e-01 5.423e-01 3.999e-01 1.969e-01 1.042e-01 6.999e-02 + 5.464e-02 5.248e-02 5.464e-02 6.999e-02 1.042e-01 1.969e-01 + 5.423e-01 5.423e-01 3.553e-01 2.780e-01 2.624e-01 1.940e-01 + 9.824e-02 9.824e-02 1.940e-01 2.624e-01 2.780e-01 3.553e-01 + 3.999e-01 3.553e-01 3.655e-01 4.414e-01 4.227e-01 1.940e-01 + 8.700e-02 1.940e-01 4.227e-01 4.414e-01 3.655e-01 3.553e-01 + 1.969e-01 2.780e-01 4.414e-01 5.225e-01 3.057e-01 6.999e-02 + 6.999e-02 3.057e-01 5.225e-01 4.414e-01 2.780e-01 1.969e-01 + 1.042e-01 2.624e-01 4.227e-01 3.057e-01 6.587e-02 1.893e-02 + 6.587e-02 3.057e-01 4.227e-01 2.624e-01 1.042e-01 6.226e-02 + 6.999e-02 1.940e-01 1.940e-01 6.999e-02 1.893e-02 1.893e-02 + 6.999e-02 1.940e-01 1.940e-01 6.999e-02 1.893e-02 1.893e-02 + 5.464e-02 9.824e-02 8.700e-02 6.999e-02 6.587e-02 6.999e-02 + 8.700e-02 9.824e-02 5.464e-02 1.293e-02 5.255e-03 1.293e-02 + 5.248e-02 9.824e-02 1.940e-01 3.057e-01 3.057e-01 1.940e-01 + 9.824e-02 5.248e-02 2.418e-02 1.113e-02 1.113e-02 2.418e-02 + 5.464e-02 1.940e-01 4.227e-01 5.225e-01 4.227e-01 1.940e-01 + 5.464e-02 2.418e-02 3.301e-02 4.867e-02 3.301e-02 2.418e-02 + 6.999e-02 2.624e-01 4.414e-01 4.414e-01 2.624e-01 6.999e-02 + 1.293e-02 1.113e-02 4.867e-02 4.867e-02 1.113e-02 1.293e-02 + 1.042e-01 2.780e-01 3.655e-01 2.780e-01 1.042e-01 1.893e-02 + 5.255e-03 1.113e-02 3.301e-02 1.113e-02 5.255e-03 1.893e-02 + 1.969e-01 3.553e-01 3.553e-01 1.969e-01 6.226e-02 1.893e-02 + 1.293e-02 2.418e-02 2.418e-02 1.293e-02 1.893e-02 6.226e-02 + 1.477e-02 1.477e-02 5.220e-02 1.969e-01 3.711e-01 3.057e-01 + 1.279e-01 1.279e-01 3.057e-01 3.711e-01 1.969e-01 5.220e-02 + 1.477e-02 5.705e-02 3.553e-01 7.214e-01 7.660e-01 4.227e-01 + 1.842e-01 4.227e-01 7.660e-01 7.214e-01 3.553e-01 5.705e-02 + 5.220e-02 3.553e-01 8.135e-01 9.151e-01 7.660e-01 2.624e-01 + 2.624e-01 7.660e-01 9.151e-01 8.135e-01 3.553e-01 5.220e-02 + 1.969e-01 7.214e-01 9.151e-01 8.631e-01 3.711e-01 1.042e-01 + 3.711e-01 8.631e-01 9.151e-01 7.214e-01 1.969e-01 5.231e-02 + 3.711e-01 7.660e-01 7.660e-01 3.711e-01 6.226e-02 6.226e-02 + 3.711e-01 7.660e-01 7.660e-01 3.711e-01 6.226e-02 6.226e-02 + 3.057e-01 4.227e-01 2.624e-01 1.042e-01 6.226e-02 1.042e-01 + 2.624e-01 4.227e-01 3.057e-01 6.587e-02 1.893e-02 6.587e-02 + 1.279e-01 1.842e-01 2.624e-01 3.711e-01 3.711e-01 2.624e-01 + 1.842e-01 1.279e-01 5.089e-02 1.293e-02 1.293e-02 5.089e-02 + 1.279e-01 4.227e-01 7.660e-01 8.631e-01 7.660e-01 4.227e-01 + 1.279e-01 4.361e-02 2.418e-02 1.983e-02 2.418e-02 4.361e-02 + 3.057e-01 7.660e-01 9.151e-01 9.151e-01 7.660e-01 3.057e-01 + 5.089e-02 2.418e-02 6.035e-02 6.035e-02 2.418e-02 5.089e-02 + 3.711e-01 7.214e-01 8.135e-01 7.214e-01 3.711e-01 6.587e-02 + 1.293e-02 1.983e-02 6.035e-02 1.983e-02 1.293e-02 6.587e-02 + 1.969e-01 3.553e-01 3.553e-01 1.969e-01 6.226e-02 1.893e-02 + 1.293e-02 2.418e-02 2.418e-02 1.293e-02 1.893e-02 6.226e-02 + 5.220e-02 5.705e-02 5.220e-02 5.231e-02 6.226e-02 6.587e-02 + 5.089e-02 4.361e-02 5.089e-02 6.587e-02 6.226e-02 5.231e-02 diff --git a/tests/integrate/119_PW_out_elf/result.ref b/tests/integrate/119_PW_out_elf/result.ref new file mode 100644 index 00000000000..83d024030f2 --- /dev/null +++ b/tests/integrate/119_PW_out_elf/result.ref @@ -0,0 +1,7 @@ +etotref -194.6234112615314 +etotperatomref -97.3117056308 +ComparePot1_pass 0 +pointgroupref T_d +spacegroupref O_h +nksibzref 1 +totaltimeref 0.25 diff --git a/tests/integrate/120_PW_KP_MD_MSST/INPUT b/tests/integrate/120_PW_KP_MD_MSST/INPUT index 8d1269b65ff..b110b0a8da8 100644 --- a/tests/integrate/120_PW_KP_MD_MSST/INPUT +++ b/tests/integrate/120_PW_KP_MD_MSST/INPUT @@ -32,3 +32,5 @@ init_vel 1 msst_qmass 1 msst_vel 10 + +pw_seed 1 diff --git a/tests/integrate/120_PW_KP_MD_NVT/STRU b/tests/integrate/120_PW_KP_MD_NVT/STRU deleted file mode 100644 index 9fd56865d46..00000000000 --- a/tests/integrate/120_PW_KP_MD_NVT/STRU +++ /dev/null @@ -1,19 +0,0 @@ -ATOMIC_SPECIES -Si 1 Si_ONCV_PBE-1.0.upf - -LATTICE_CONSTANT -10.2 - -LATTICE_VECTORS -0.5 0.5 0 #latvec1 -0.5 0 0.5 #latvec2 -0 0.5 0.5 #latvec3 - -ATOMIC_POSITIONS -Cartesian - -Si #label -0 #magnetism -2 #number of atoms -0 0 0 m 1 1 1 v -0.00016026383234 1.88587389656e-05 4.31519285331e-06 -0.241 0.255 0.250999999999 m 1 1 1 v 0.00016026383234 -1.88587389656e-05 -4.31519285331e-06 diff --git a/tests/integrate/120_PW_KP_MD_NVT/STRU_MD_2 b/tests/integrate/120_PW_KP_MD_NVT/STRU_MD_2 index e918ed59b06..9fd56865d46 100644 --- a/tests/integrate/120_PW_KP_MD_NVT/STRU_MD_2 +++ b/tests/integrate/120_PW_KP_MD_NVT/STRU_MD_2 @@ -1,13 +1,13 @@ ATOMIC_SPECIES -Si 1 Si_ONCV_PBE-1.0.upf upf201 +Si 1 Si_ONCV_PBE-1.0.upf LATTICE_CONSTANT 10.2 LATTICE_VECTORS - 0.5000000000 0.5000000000 0.0000000000 #latvec1 - 0.5000000000 0.0000000000 0.5000000000 #latvec2 - 0.0000000000 0.5000000000 0.5000000000 #latvec3 +0.5 0.5 0 #latvec1 +0.5 0 0.5 #latvec2 +0 0.5 0.5 #latvec3 ATOMIC_POSITIONS Cartesian @@ -15,5 +15,5 @@ Cartesian Si #label 0 #magnetism 2 #number of atoms - 0.9961377061 0.5017059282 0.5004642243 m 1 1 1 v -0.0005823336 0.0003037059 0.0000737542 - 0.2448622939 0.2532940718 0.2505357757 m 1 1 1 v 0.0005823336 -0.0003037059 -0.0000737542 +0 0 0 m 1 1 1 v -0.00016026383234 1.88587389656e-05 4.31519285331e-06 +0.241 0.255 0.250999999999 m 1 1 1 v 0.00016026383234 -1.88587389656e-05 -4.31519285331e-06 diff --git a/tests/integrate/127_PW_15_PK_AF/INPUT b/tests/integrate/127_PW_15_PK_AF/INPUT index ab0934aa841..5ad0ffb4aeb 100644 --- a/tests/integrate/127_PW_15_PK_AF/INPUT +++ b/tests/integrate/127_PW_15_PK_AF/INPUT @@ -31,3 +31,5 @@ symmetry 0 nspin 2 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB + +pw_seed 1 diff --git a/tests/integrate/140_PW_15_SO/INPUT b/tests/integrate/140_PW_15_SO/INPUT index d68a3f41465..1c588404359 100644 --- a/tests/integrate/140_PW_15_SO/INPUT +++ b/tests/integrate/140_PW_15_SO/INPUT @@ -25,12 +25,16 @@ ecutwfc 20 scf_thr 1e-6 scf_nmax 100 +cal_force 1 +cal_stress 1 + #cal_stress 1 #noncolin 1 lspinorb 1 basis_type pw -ks_solver dav +ks_solver dav_subspace +pw_diag_ndim 2 chg_extrap second-order out_dm 0 pw_diag_thr 0.00001 @@ -38,3 +42,5 @@ pw_diag_thr 0.00001 mixing_type broyden mixing_beta 0.4 mixing_gg0 1.5 + +pw_seed 1 diff --git a/tests/integrate/140_PW_15_SO/KPT b/tests/integrate/140_PW_15_SO/KPT index c289c0158aa..e769af76382 100644 --- a/tests/integrate/140_PW_15_SO/KPT +++ b/tests/integrate/140_PW_15_SO/KPT @@ -1,4 +1,4 @@ K_POINTS 0 Gamma -1 1 1 0 0 0 +2 1 1 0 0 0 diff --git a/tests/integrate/140_PW_15_SO/result.ref b/tests/integrate/140_PW_15_SO/result.ref index 449c4786a95..6bb325aacbc 100644 --- a/tests/integrate/140_PW_15_SO/result.ref +++ b/tests/integrate/140_PW_15_SO/result.ref @@ -1,3 +1,5 @@ -etotref -1668.616835067548 -etotperatomref -834.3084175338 -totaltimeref 6.35 +etotref -1678.3650981686614614 +etotperatomref -839.1825490843 +totalforceref 1.739332 +totalstressref 34372.194072 +totaltimeref 0.99 diff --git a/tests/integrate/140_PW_15_SO_wfcinit/INPUT b/tests/integrate/140_PW_15_SO_wfcinit/INPUT new file mode 100644 index 00000000000..af84ec539f4 --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/INPUT @@ -0,0 +1,31 @@ +INPUT_PARAMETERS +#Parameters (General) +suffix autotest +pseudo_dir ../../PP_ORB + +calculation scf + +gamma_only 0 +symmetry 0 + +#out_wfc_pw 2 +init_chg wfc +init_wfc file + +smearing_method gaussian +smearing_sigma 0.001 + +ecutwfc 20 +scf_thr 1e-6 +scf_nmax 2 + +#noncolin 1 +lspinorb 1 + +basis_type pw +ks_solver dav +pw_diag_thr 0.00001 + +mixing_type broyden +mixing_beta 0.4 +mixing_gg0 1.5 diff --git a/tests/integrate/140_PW_15_SO_wfcinit/KPT b/tests/integrate/140_PW_15_SO_wfcinit/KPT new file mode 100644 index 00000000000..c289c0158aa --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +1 1 1 0 0 0 diff --git a/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/WAVEFUNC1.dat b/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/WAVEFUNC1.dat new file mode 100644 index 00000000000..e2b6a82c91f Binary files /dev/null and b/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/WAVEFUNC1.dat differ diff --git a/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/istate.info b/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/istate.info new file mode 100644 index 00000000000..19f81a7f100 --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/OUT.autotest/istate.info @@ -0,0 +1,41 @@ +BAND Energy(ev) Occupation Kpoint = 1 (0 0 0) + 1 -5.803263354735877 1 + 2 -4.866061381925486 1 + 3 -1.359289336627868 1 + 4 -1.291335226565177 1 + 5 -1.210467148364243 1 + 6 -0.835724683428713 1 + 7 -0.7487598034766753 1 + 8 -0.7006064755786422 1 + 9 -0.1159407379615029 1 + 10 0.1202752942058206 1 + 11 0.3379864351497489 1 + 12 0.42475093966947 1 + 13 5.03913292971009 1 + 14 5.777091867159064 1 + 15 7.804249418022549 1 + 16 7.875810965994963 1 + 17 8.15305132930491 1 + 18 8.892183044618475 1 + 19 9.118640257671171 0 + 20 9.194376411776567 0 + 21 10.52053980690489 0 + 22 10.63124418435923 0 + 23 10.85237946040846 0 + 24 11.34745313536697 0 + 25 11.52540297156072 0 + 26 11.65802813524961 0 + 27 14.3643931732005 0 + 28 14.64648815353438 0 + 29 20.21048953868734 0 + 30 20.23168597745261 0 + 31 20.23594172430127 0 + 32 20.34318034125117 0 + 33 20.49433237237518 0 + 34 20.60686492006229 0 + 35 20.65290020434089 0 + 36 20.67304188342674 0 + 37 21.21963361965688 0 + 38 21.43507306548812 0 + + diff --git a/tests/integrate/140_PW_15_SO_wfcinit/README b/tests/integrate/140_PW_15_SO_wfcinit/README new file mode 100644 index 00000000000..c3e0557c774 --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/README @@ -0,0 +1,11 @@ +This test for: +*GaAs-soc +*PW +*kpoints 2*2*2 +*sg15 pseudopotential +*smearing_method gauss +*ks_solver cg +*mixing_type broyden-kerker +*mixing_beta 0.4 +init_wfc file +init_chg wfc diff --git a/tests/integrate/140_PW_15_SO_wfcinit/STRU b/tests/integrate/140_PW_15_SO_wfcinit/STRU new file mode 100644 index 00000000000..901aa2771d4 --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/STRU @@ -0,0 +1,23 @@ +ATOMIC_SPECIES +As 1 As_ONCV_PBE_FR-1.1.upf upf201 +Ga 1 Ga_ONCV_PBE_FR-1.0.upf.txt upf201 + +LATTICE_CONSTANT +1 // add lattice constant, 10.58 ang + +LATTICE_VECTORS +5.34197 5.34197 0.0 +0.0 5.34197 5.34197 +5.34197 0.0 5.34197 +ATOMIC_POSITIONS +Direct //Cartesian or Direct coordinate. + +As +0 +1 +0.2500000 0.2500000 0.25000000 0 0 0 + +Ga //Element Label +0 +1 //number of atom +0.00000 0.00000 0.000000 0 0 0 diff --git a/tests/integrate/140_PW_15_SO_wfcinit/jd b/tests/integrate/140_PW_15_SO_wfcinit/jd new file mode 100644 index 00000000000..05bbcfea56b --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/jd @@ -0,0 +1 @@ +test SG15 soc pseudopotential with soc on and init with wfc diff --git a/tests/integrate/140_PW_15_SO_wfcinit/result.ref b/tests/integrate/140_PW_15_SO_wfcinit/result.ref new file mode 100644 index 00000000000..152dfeb681a --- /dev/null +++ b/tests/integrate/140_PW_15_SO_wfcinit/result.ref @@ -0,0 +1,3 @@ +etotref -1668.616829837883 +etotperatomref -834.3084149189 +totaltimeref 0.41 diff --git a/tests/integrate/150_PW_15_CR_VDW3/INPUT b/tests/integrate/150_PW_15_CR_VDW3/INPUT index 75926221a83..fd89158b418 100644 --- a/tests/integrate/150_PW_15_CR_VDW3/INPUT +++ b/tests/integrate/150_PW_15_CR_VDW3/INPUT @@ -20,3 +20,4 @@ cal_force 1 cal_stress 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB +dft_functional pbe diff --git a/tests/integrate/219_NO_out_elf/INPUT b/tests/integrate/219_NO_out_elf/INPUT new file mode 100644 index 00000000000..6d9116e9a44 --- /dev/null +++ b/tests/integrate/219_NO_out_elf/INPUT @@ -0,0 +1,27 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation scf + +nbands 6 +symmetry 1 +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB +out_elf 1 + +#Parameters (2.Iteration) +ecutwfc 5 +scf_thr 1e-6 +scf_nmax 100 + + +#Parameters (3.Basis) +basis_type lcao + +#Parameters (4.Smearing) +smearing_method gauss +smearing_sigma 0.002 + +#Parameters (5.Mixing) +mixing_type broyden +mixing_beta 0.3 diff --git a/tests/integrate/219_NO_out_elf/KPT b/tests/integrate/219_NO_out_elf/KPT new file mode 100644 index 00000000000..c289c0158aa --- /dev/null +++ b/tests/integrate/219_NO_out_elf/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +1 1 1 0 0 0 diff --git a/tests/integrate/219_NO_out_elf/STRU b/tests/integrate/219_NO_out_elf/STRU new file mode 100644 index 00000000000..37d65977279 --- /dev/null +++ b/tests/integrate/219_NO_out_elf/STRU @@ -0,0 +1,22 @@ +ATOMIC_SPECIES +Si 14 Si_ONCV_PBE-1.0.upf upf201 + +NUMERICAL_ORBITAL +Si_gga_8au_60Ry_2s2p1d.orb + +LATTICE_CONSTANT +10.2 // add lattice constant + +LATTICE_VECTORS +0.5 0.5 0.0 +0.5 0.0 0.5 +0.0 0.5 0.5 + +ATOMIC_POSITIONS +Direct + +Si // Element type +0.0 // magnetism +2 +0.00 0.00 0.00 1 1 1 +0.25 0.25 0.25 1 1 1 diff --git a/tests/integrate/219_NO_out_elf/jd b/tests/integrate/219_NO_out_elf/jd new file mode 100644 index 00000000000..1a48d127fea --- /dev/null +++ b/tests/integrate/219_NO_out_elf/jd @@ -0,0 +1 @@ +test out_elf with LCAO basis, symmetry=on diff --git a/tests/integrate/219_NO_out_elf/refELF.cube b/tests/integrate/219_NO_out_elf/refELF.cube new file mode 100644 index 00000000000..6224358b65d --- /dev/null +++ b/tests/integrate/219_NO_out_elf/refELF.cube @@ -0,0 +1,296 @@ +STEP: 0 Cubefile created from ABACUS. Inner loop is z, followed by y and x +1 (nspin) +2 0.0 0.0 0.0 +12 0.425000 0.425000 0.000000 +12 0.425000 0.000000 0.425000 +12 0.000000 0.425000 0.425000 + 14 4.000000 0.000000 0.000000 0.000000 + 14 4.000000 2.550000 2.550000 2.550000 + 8.615e-08 1.569e-02 5.651e-01 9.171e-01 8.578e-01 5.075e-01 + 1.971e-01 5.075e-01 8.578e-01 9.171e-01 5.651e-01 1.569e-02 + 1.569e-02 8.013e-01 9.904e-01 9.851e-01 9.062e-01 4.158e-01 + 4.158e-01 9.062e-01 9.851e-01 9.904e-01 8.013e-01 1.569e-02 + 5.651e-01 9.904e-01 9.950e-01 9.851e-01 7.810e-01 2.180e-01 + 7.810e-01 9.851e-01 9.950e-01 9.904e-01 5.651e-01 2.953e-02 + 9.171e-01 9.851e-01 9.851e-01 9.171e-01 1.676e-01 1.676e-01 + 9.171e-01 9.851e-01 9.851e-01 9.171e-01 1.676e-01 1.676e-01 + 8.578e-01 9.062e-01 7.810e-01 1.676e-01 2.299e-02 1.676e-01 + 7.810e-01 9.062e-01 8.578e-01 4.400e-01 9.647e-02 4.400e-01 + 5.075e-01 4.158e-01 2.180e-01 1.676e-01 1.676e-01 2.180e-01 + 4.158e-01 5.075e-01 3.249e-01 9.283e-02 9.283e-02 3.249e-01 + 1.971e-01 4.158e-01 7.810e-01 9.171e-01 7.810e-01 4.158e-01 + 1.971e-01 7.344e-02 3.301e-02 2.092e-02 3.301e-02 7.344e-02 + 5.075e-01 9.062e-01 9.851e-01 9.851e-01 9.062e-01 5.075e-01 + 7.344e-02 1.720e-02 3.073e-02 3.073e-02 1.720e-02 7.344e-02 + 8.578e-01 9.851e-01 9.950e-01 9.851e-01 8.578e-01 3.249e-01 + 3.301e-02 3.073e-02 2.156e-02 3.073e-02 3.301e-02 3.249e-01 + 9.171e-01 9.904e-01 9.904e-01 9.171e-01 4.400e-01 9.283e-02 + 2.092e-02 3.073e-02 3.073e-02 2.092e-02 9.283e-02 4.400e-01 + 5.651e-01 8.013e-01 5.651e-01 1.676e-01 9.647e-02 9.283e-02 + 3.301e-02 1.720e-02 3.301e-02 9.283e-02 9.647e-02 1.676e-01 + 1.569e-02 1.569e-02 2.953e-02 1.676e-01 4.400e-01 3.249e-01 + 7.344e-02 7.344e-02 3.249e-01 4.400e-01 1.676e-01 2.953e-02 + 1.569e-02 8.013e-01 9.904e-01 9.851e-01 9.062e-01 4.158e-01 + 4.158e-01 9.062e-01 9.851e-01 9.904e-01 8.013e-01 1.569e-02 + 8.013e-01 9.994e-01 9.992e-01 9.950e-01 8.668e-01 3.073e-01 + 8.668e-01 9.950e-01 9.992e-01 9.994e-01 8.013e-01 5.039e-02 + 9.904e-01 9.992e-01 9.992e-01 9.904e-01 3.749e-01 3.749e-01 + 9.904e-01 9.992e-01 9.992e-01 9.904e-01 3.749e-01 3.749e-01 + 9.851e-01 9.950e-01 9.904e-01 5.651e-01 2.953e-02 5.651e-01 + 9.904e-01 9.950e-01 9.851e-01 7.810e-01 2.180e-01 7.810e-01 + 9.062e-01 8.668e-01 3.749e-01 2.953e-02 2.953e-02 3.749e-01 + 8.668e-01 9.062e-01 7.469e-01 2.401e-01 2.401e-01 7.469e-01 + 4.158e-01 3.073e-01 3.749e-01 5.651e-01 3.749e-01 3.073e-01 + 4.158e-01 3.862e-01 1.660e-01 6.436e-02 1.660e-01 3.862e-01 + 4.158e-01 8.668e-01 9.904e-01 9.904e-01 8.668e-01 4.158e-01 + 1.367e-01 5.357e-02 5.197e-02 5.197e-02 5.357e-02 1.367e-01 + 9.062e-01 9.950e-01 9.992e-01 9.950e-01 9.062e-01 3.862e-01 + 5.357e-02 7.662e-02 4.157e-01 7.662e-02 5.357e-02 3.862e-01 + 9.851e-01 9.992e-01 9.992e-01 9.851e-01 7.469e-01 1.660e-01 + 5.197e-02 4.157e-01 4.157e-01 5.197e-02 1.660e-01 7.469e-01 + 9.904e-01 9.994e-01 9.904e-01 7.810e-01 2.401e-01 6.436e-02 + 5.197e-02 7.662e-02 5.197e-02 6.436e-02 2.401e-01 7.810e-01 + 8.013e-01 8.013e-01 3.749e-01 2.180e-01 2.401e-01 1.660e-01 + 5.357e-02 5.357e-02 1.660e-01 2.401e-01 2.180e-01 3.749e-01 + 1.569e-02 5.039e-02 3.749e-01 7.810e-01 7.469e-01 3.862e-01 + 1.367e-01 3.862e-01 7.469e-01 7.810e-01 3.749e-01 5.039e-02 + 5.651e-01 9.904e-01 9.950e-01 9.851e-01 7.810e-01 2.180e-01 + 7.810e-01 9.851e-01 9.950e-01 9.904e-01 5.651e-01 2.953e-02 + 9.904e-01 9.992e-01 9.992e-01 9.904e-01 3.749e-01 3.749e-01 + 9.904e-01 9.992e-01 9.992e-01 9.904e-01 3.749e-01 3.749e-01 + 9.950e-01 9.992e-01 9.994e-01 8.013e-01 5.039e-02 8.013e-01 + 9.994e-01 9.992e-01 9.950e-01 8.668e-01 3.073e-01 8.668e-01 + 9.851e-01 9.904e-01 8.013e-01 1.569e-02 1.569e-02 8.013e-01 + 9.904e-01 9.851e-01 9.062e-01 4.158e-01 4.158e-01 9.062e-01 + 7.810e-01 3.749e-01 5.039e-02 1.569e-02 5.039e-02 3.749e-01 + 7.810e-01 7.469e-01 3.862e-01 1.367e-01 3.862e-01 7.469e-01 + 2.180e-01 3.749e-01 8.013e-01 8.013e-01 3.749e-01 2.180e-01 + 2.401e-01 1.660e-01 5.357e-02 5.357e-02 1.660e-01 2.401e-01 + 7.810e-01 9.904e-01 9.994e-01 9.904e-01 7.810e-01 2.401e-01 + 6.436e-02 5.197e-02 7.662e-02 5.197e-02 6.436e-02 2.401e-01 + 9.851e-01 9.992e-01 9.992e-01 9.851e-01 7.469e-01 1.660e-01 + 5.197e-02 4.157e-01 4.157e-01 5.197e-02 1.660e-01 7.469e-01 + 9.950e-01 9.992e-01 9.950e-01 9.062e-01 3.862e-01 5.357e-02 + 7.662e-02 4.157e-01 7.662e-02 5.357e-02 3.862e-01 9.062e-01 + 9.904e-01 9.904e-01 8.668e-01 4.158e-01 1.367e-01 5.357e-02 + 5.197e-02 5.197e-02 5.357e-02 1.367e-01 4.158e-01 8.668e-01 + 5.651e-01 3.749e-01 3.073e-01 4.158e-01 3.862e-01 1.660e-01 + 6.436e-02 1.660e-01 3.862e-01 4.158e-01 3.073e-01 3.749e-01 + 2.953e-02 3.749e-01 8.668e-01 9.062e-01 7.469e-01 2.401e-01 + 2.401e-01 7.469e-01 9.062e-01 8.668e-01 3.749e-01 2.953e-02 + 9.171e-01 9.851e-01 9.851e-01 9.171e-01 1.676e-01 1.676e-01 + 9.171e-01 9.851e-01 9.851e-01 9.171e-01 1.676e-01 1.676e-01 + 9.851e-01 9.950e-01 9.904e-01 5.651e-01 2.953e-02 5.651e-01 + 9.904e-01 9.950e-01 9.851e-01 7.810e-01 2.180e-01 7.810e-01 + 9.851e-01 9.904e-01 8.013e-01 1.569e-02 1.569e-02 8.013e-01 + 9.904e-01 9.851e-01 9.062e-01 4.158e-01 4.158e-01 9.062e-01 + 9.171e-01 5.651e-01 1.569e-02 8.615e-08 1.569e-02 5.651e-01 + 9.171e-01 8.578e-01 5.075e-01 1.971e-01 5.075e-01 8.578e-01 + 1.676e-01 2.953e-02 1.569e-02 1.569e-02 2.953e-02 1.676e-01 + 4.400e-01 3.249e-01 7.344e-02 7.344e-02 3.249e-01 4.400e-01 + 1.676e-01 5.651e-01 8.013e-01 5.651e-01 1.676e-01 9.647e-02 + 9.283e-02 3.301e-02 1.720e-02 3.301e-02 9.283e-02 9.647e-02 + 9.171e-01 9.904e-01 9.904e-01 9.171e-01 4.400e-01 9.283e-02 + 2.092e-02 3.073e-02 3.073e-02 2.092e-02 9.283e-02 4.400e-01 + 9.851e-01 9.950e-01 9.851e-01 8.578e-01 3.249e-01 3.301e-02 + 3.073e-02 2.156e-02 3.073e-02 3.301e-02 3.249e-01 8.578e-01 + 9.851e-01 9.851e-01 9.062e-01 5.075e-01 7.344e-02 1.720e-02 + 3.073e-02 3.073e-02 1.720e-02 7.344e-02 5.075e-01 9.062e-01 + 9.171e-01 7.810e-01 4.158e-01 1.971e-01 7.344e-02 3.301e-02 + 2.092e-02 3.301e-02 7.344e-02 1.971e-01 4.158e-01 7.810e-01 + 1.676e-01 2.180e-01 4.158e-01 5.075e-01 3.249e-01 9.283e-02 + 9.283e-02 3.249e-01 5.075e-01 4.158e-01 2.180e-01 1.676e-01 + 1.676e-01 7.810e-01 9.062e-01 8.578e-01 4.400e-01 9.647e-02 + 4.400e-01 8.578e-01 9.062e-01 7.810e-01 1.676e-01 2.299e-02 + 8.578e-01 9.062e-01 7.810e-01 1.676e-01 2.299e-02 1.676e-01 + 7.810e-01 9.062e-01 8.578e-01 4.400e-01 9.647e-02 4.400e-01 + 9.062e-01 8.668e-01 3.749e-01 2.953e-02 2.953e-02 3.749e-01 + 8.668e-01 9.062e-01 7.469e-01 2.401e-01 2.401e-01 7.469e-01 + 7.810e-01 3.749e-01 5.039e-02 1.569e-02 5.039e-02 3.749e-01 + 7.810e-01 7.469e-01 3.862e-01 1.367e-01 3.862e-01 7.469e-01 + 1.676e-01 2.953e-02 1.569e-02 1.569e-02 2.953e-02 1.676e-01 + 4.400e-01 3.249e-01 7.344e-02 7.344e-02 3.249e-01 4.400e-01 + 2.299e-02 2.953e-02 5.039e-02 2.953e-02 2.299e-02 6.631e-02 + 1.298e-01 3.236e-02 1.488e-02 3.236e-02 1.298e-01 6.631e-02 + 1.676e-01 3.749e-01 3.749e-01 1.676e-01 6.631e-02 4.807e-02 + 1.143e-02 3.344e-02 3.344e-02 1.143e-02 4.807e-02 6.631e-02 + 7.810e-01 8.668e-01 7.810e-01 4.400e-01 1.298e-01 1.143e-02 + 1.031e-02 1.406e-01 1.031e-02 1.143e-02 1.298e-01 4.400e-01 + 9.062e-01 9.062e-01 7.469e-01 3.249e-01 3.236e-02 3.344e-02 + 1.406e-01 1.406e-01 3.344e-02 3.236e-02 3.249e-01 7.469e-01 + 8.578e-01 7.469e-01 3.862e-01 7.344e-02 1.488e-02 3.344e-02 + 1.031e-02 3.344e-02 1.488e-02 7.344e-02 3.862e-01 7.469e-01 + 4.400e-01 2.401e-01 1.367e-01 7.344e-02 3.236e-02 1.143e-02 + 1.143e-02 3.236e-02 7.344e-02 1.367e-01 2.401e-01 4.400e-01 + 9.647e-02 2.401e-01 3.862e-01 3.249e-01 1.298e-01 4.807e-02 + 1.298e-01 3.249e-01 3.862e-01 2.401e-01 9.647e-02 6.631e-02 + 4.400e-01 7.469e-01 7.469e-01 4.400e-01 6.631e-02 6.631e-02 + 4.400e-01 7.469e-01 7.469e-01 4.400e-01 6.631e-02 6.631e-02 + 5.075e-01 4.158e-01 2.180e-01 1.676e-01 1.676e-01 2.180e-01 + 4.158e-01 5.075e-01 3.249e-01 9.283e-02 9.283e-02 3.249e-01 + 4.158e-01 3.073e-01 3.749e-01 5.651e-01 3.749e-01 3.073e-01 + 4.158e-01 3.862e-01 1.660e-01 6.436e-02 1.660e-01 3.862e-01 + 2.180e-01 3.749e-01 8.013e-01 8.013e-01 3.749e-01 2.180e-01 + 2.401e-01 1.660e-01 5.357e-02 5.357e-02 1.660e-01 2.401e-01 + 1.676e-01 5.651e-01 8.013e-01 5.651e-01 1.676e-01 9.647e-02 + 9.283e-02 3.301e-02 1.720e-02 3.301e-02 9.283e-02 9.647e-02 + 1.676e-01 3.749e-01 3.749e-01 1.676e-01 6.631e-02 4.807e-02 + 1.143e-02 3.344e-02 3.344e-02 1.143e-02 4.807e-02 6.631e-02 + 2.180e-01 3.073e-01 2.180e-01 9.647e-02 4.807e-02 4.638e-03 + 6.778e-03 5.676e-02 6.778e-03 4.638e-03 4.807e-02 9.647e-02 + 4.158e-01 4.158e-01 2.401e-01 9.283e-02 1.143e-02 6.778e-03 + 6.601e-02 6.601e-02 6.778e-03 1.143e-02 9.283e-02 2.401e-01 + 5.075e-01 3.862e-01 1.660e-01 3.301e-02 3.344e-02 5.676e-02 + 6.601e-02 5.676e-02 3.344e-02 3.301e-02 1.660e-01 3.862e-01 + 3.249e-01 1.660e-01 5.357e-02 1.720e-02 3.344e-02 6.778e-03 + 6.778e-03 3.344e-02 1.720e-02 5.357e-02 1.660e-01 3.249e-01 + 9.283e-02 6.436e-02 5.357e-02 3.301e-02 1.143e-02 4.638e-03 + 1.143e-02 3.301e-02 5.357e-02 6.436e-02 9.283e-02 1.298e-01 + 9.283e-02 1.660e-01 1.660e-01 9.283e-02 4.807e-02 4.807e-02 + 9.283e-02 1.660e-01 1.660e-01 9.283e-02 4.807e-02 4.807e-02 + 3.249e-01 3.862e-01 2.401e-01 9.647e-02 6.631e-02 9.647e-02 + 2.401e-01 3.862e-01 3.249e-01 1.298e-01 4.807e-02 1.298e-01 + 1.971e-01 4.158e-01 7.810e-01 9.171e-01 7.810e-01 4.158e-01 + 1.971e-01 7.344e-02 3.301e-02 2.092e-02 3.301e-02 7.344e-02 + 4.158e-01 8.668e-01 9.904e-01 9.904e-01 8.668e-01 4.158e-01 + 1.367e-01 5.357e-02 5.197e-02 5.197e-02 5.357e-02 1.367e-01 + 7.810e-01 9.904e-01 9.994e-01 9.904e-01 7.810e-01 2.401e-01 + 6.436e-02 5.197e-02 7.662e-02 5.197e-02 6.436e-02 2.401e-01 + 9.171e-01 9.904e-01 9.904e-01 9.171e-01 4.400e-01 9.283e-02 + 2.092e-02 3.073e-02 3.073e-02 2.092e-02 9.283e-02 4.400e-01 + 7.810e-01 8.668e-01 7.810e-01 4.400e-01 1.298e-01 1.143e-02 + 1.031e-02 1.406e-01 1.031e-02 1.143e-02 1.298e-01 4.400e-01 + 4.158e-01 4.158e-01 2.401e-01 9.283e-02 1.143e-02 6.778e-03 + 6.601e-02 6.601e-02 6.778e-03 1.143e-02 9.283e-02 2.401e-01 + 1.971e-01 1.367e-01 6.436e-02 2.092e-02 1.031e-02 6.601e-02 + 8.923e-05 6.601e-02 1.031e-02 2.092e-02 6.436e-02 1.367e-01 + 7.344e-02 5.357e-02 5.197e-02 3.073e-02 1.406e-01 6.601e-02 + 6.601e-02 1.406e-01 3.073e-02 5.197e-02 5.357e-02 7.344e-02 + 3.301e-02 5.197e-02 7.662e-02 3.073e-02 1.031e-02 6.778e-03 + 1.031e-02 3.073e-02 7.662e-02 5.197e-02 3.301e-02 3.236e-02 + 2.092e-02 5.197e-02 5.197e-02 2.092e-02 1.143e-02 1.143e-02 + 2.092e-02 5.197e-02 5.197e-02 2.092e-02 1.143e-02 1.143e-02 + 3.301e-02 5.357e-02 6.436e-02 9.283e-02 1.298e-01 9.283e-02 + 6.436e-02 5.357e-02 3.301e-02 1.143e-02 4.638e-03 1.143e-02 + 7.344e-02 1.367e-01 2.401e-01 4.400e-01 4.400e-01 2.401e-01 + 1.367e-01 7.344e-02 3.236e-02 1.143e-02 1.143e-02 3.236e-02 + 5.075e-01 9.062e-01 9.851e-01 9.851e-01 9.062e-01 5.075e-01 + 7.344e-02 1.720e-02 3.073e-02 3.073e-02 1.720e-02 7.344e-02 + 9.062e-01 9.950e-01 9.992e-01 9.950e-01 9.062e-01 3.862e-01 + 5.357e-02 7.662e-02 4.157e-01 7.662e-02 5.357e-02 3.862e-01 + 9.851e-01 9.992e-01 9.992e-01 9.851e-01 7.469e-01 1.660e-01 + 5.197e-02 4.157e-01 4.157e-01 5.197e-02 1.660e-01 7.469e-01 + 9.851e-01 9.950e-01 9.851e-01 8.578e-01 3.249e-01 3.301e-02 + 3.073e-02 2.156e-02 3.073e-02 3.301e-02 3.249e-01 8.578e-01 + 9.062e-01 9.062e-01 7.469e-01 3.249e-01 3.236e-02 3.344e-02 + 1.406e-01 1.406e-01 3.344e-02 3.236e-02 3.249e-01 7.469e-01 + 5.075e-01 3.862e-01 1.660e-01 3.301e-02 3.344e-02 5.676e-02 + 6.601e-02 5.676e-02 3.344e-02 3.301e-02 1.660e-01 3.862e-01 + 7.344e-02 5.357e-02 5.197e-02 3.073e-02 1.406e-01 6.601e-02 + 6.601e-02 1.406e-01 3.073e-02 5.197e-02 5.357e-02 7.344e-02 + 1.720e-02 7.662e-02 4.157e-01 2.156e-02 1.406e-01 5.676e-02 + 1.406e-01 2.156e-02 4.157e-01 7.662e-02 1.720e-02 1.488e-02 + 3.073e-02 4.157e-01 4.157e-01 3.073e-02 3.344e-02 3.344e-02 + 3.073e-02 4.157e-01 4.157e-01 3.073e-02 3.344e-02 3.344e-02 + 3.073e-02 7.662e-02 5.197e-02 3.301e-02 3.236e-02 3.301e-02 + 5.197e-02 7.662e-02 3.073e-02 1.031e-02 6.778e-03 1.031e-02 + 1.720e-02 5.357e-02 1.660e-01 3.249e-01 3.249e-01 1.660e-01 + 5.357e-02 1.720e-02 3.344e-02 6.778e-03 6.778e-03 3.344e-02 + 7.344e-02 3.862e-01 7.469e-01 8.578e-01 7.469e-01 3.862e-01 + 7.344e-02 1.488e-02 3.344e-02 1.031e-02 3.344e-02 1.488e-02 + 8.578e-01 9.851e-01 9.950e-01 9.851e-01 8.578e-01 3.249e-01 + 3.301e-02 3.073e-02 2.156e-02 3.073e-02 3.301e-02 3.249e-01 + 9.851e-01 9.992e-01 9.992e-01 9.851e-01 7.469e-01 1.660e-01 + 5.197e-02 4.157e-01 4.157e-01 5.197e-02 1.660e-01 7.469e-01 + 9.950e-01 9.992e-01 9.950e-01 9.062e-01 3.862e-01 5.357e-02 + 7.662e-02 4.157e-01 7.662e-02 5.357e-02 3.862e-01 9.062e-01 + 9.851e-01 9.851e-01 9.062e-01 5.075e-01 7.344e-02 1.720e-02 + 3.073e-02 3.073e-02 1.720e-02 7.344e-02 5.075e-01 9.062e-01 + 8.578e-01 7.469e-01 3.862e-01 7.344e-02 1.488e-02 3.344e-02 + 1.031e-02 3.344e-02 1.488e-02 7.344e-02 3.862e-01 7.469e-01 + 3.249e-01 1.660e-01 5.357e-02 1.720e-02 3.344e-02 6.778e-03 + 6.778e-03 3.344e-02 1.720e-02 5.357e-02 1.660e-01 3.249e-01 + 3.301e-02 5.197e-02 7.662e-02 3.073e-02 1.031e-02 6.778e-03 + 1.031e-02 3.073e-02 7.662e-02 5.197e-02 3.301e-02 3.236e-02 + 3.073e-02 4.157e-01 4.157e-01 3.073e-02 3.344e-02 3.344e-02 + 3.073e-02 4.157e-01 4.157e-01 3.073e-02 3.344e-02 3.344e-02 + 2.156e-02 4.157e-01 7.662e-02 1.720e-02 1.488e-02 1.720e-02 + 7.662e-02 4.157e-01 2.156e-02 1.406e-01 5.676e-02 1.406e-01 + 3.073e-02 5.197e-02 5.357e-02 7.344e-02 7.344e-02 5.357e-02 + 5.197e-02 3.073e-02 1.406e-01 6.601e-02 6.601e-02 1.406e-01 + 3.301e-02 1.660e-01 3.862e-01 5.075e-01 3.862e-01 1.660e-01 + 3.301e-02 3.344e-02 5.676e-02 6.601e-02 5.676e-02 3.344e-02 + 3.249e-01 7.469e-01 9.062e-01 9.062e-01 7.469e-01 3.249e-01 + 3.236e-02 3.344e-02 1.406e-01 1.406e-01 3.344e-02 3.236e-02 + 9.171e-01 9.904e-01 9.904e-01 9.171e-01 4.400e-01 9.283e-02 + 2.092e-02 3.073e-02 3.073e-02 2.092e-02 9.283e-02 4.400e-01 + 9.904e-01 9.994e-01 9.904e-01 7.810e-01 2.401e-01 6.436e-02 + 5.197e-02 7.662e-02 5.197e-02 6.436e-02 2.401e-01 7.810e-01 + 9.904e-01 9.904e-01 8.668e-01 4.158e-01 1.367e-01 5.357e-02 + 5.197e-02 5.197e-02 5.357e-02 1.367e-01 4.158e-01 8.668e-01 + 9.171e-01 7.810e-01 4.158e-01 1.971e-01 7.344e-02 3.301e-02 + 2.092e-02 3.301e-02 7.344e-02 1.971e-01 4.158e-01 7.810e-01 + 4.400e-01 2.401e-01 1.367e-01 7.344e-02 3.236e-02 1.143e-02 + 1.143e-02 3.236e-02 7.344e-02 1.367e-01 2.401e-01 4.400e-01 + 9.283e-02 6.436e-02 5.357e-02 3.301e-02 1.143e-02 4.638e-03 + 1.143e-02 3.301e-02 5.357e-02 6.436e-02 9.283e-02 1.298e-01 + 2.092e-02 5.197e-02 5.197e-02 2.092e-02 1.143e-02 1.143e-02 + 2.092e-02 5.197e-02 5.197e-02 2.092e-02 1.143e-02 1.143e-02 + 3.073e-02 7.662e-02 5.197e-02 3.301e-02 3.236e-02 3.301e-02 + 5.197e-02 7.662e-02 3.073e-02 1.031e-02 6.778e-03 1.031e-02 + 3.073e-02 5.197e-02 5.357e-02 7.344e-02 7.344e-02 5.357e-02 + 5.197e-02 3.073e-02 1.406e-01 6.601e-02 6.601e-02 1.406e-01 + 2.092e-02 6.436e-02 1.367e-01 1.971e-01 1.367e-01 6.436e-02 + 2.092e-02 1.031e-02 6.601e-02 8.923e-05 6.601e-02 1.031e-02 + 9.283e-02 2.401e-01 4.158e-01 4.158e-01 2.401e-01 9.283e-02 + 1.143e-02 6.778e-03 6.601e-02 6.601e-02 6.778e-03 1.143e-02 + 4.400e-01 7.810e-01 8.668e-01 7.810e-01 4.400e-01 1.298e-01 + 1.143e-02 1.031e-02 1.406e-01 1.031e-02 1.143e-02 1.298e-01 + 5.651e-01 8.013e-01 5.651e-01 1.676e-01 9.647e-02 9.283e-02 + 3.301e-02 1.720e-02 3.301e-02 9.283e-02 9.647e-02 1.676e-01 + 8.013e-01 8.013e-01 3.749e-01 2.180e-01 2.401e-01 1.660e-01 + 5.357e-02 5.357e-02 1.660e-01 2.401e-01 2.180e-01 3.749e-01 + 5.651e-01 3.749e-01 3.073e-01 4.158e-01 3.862e-01 1.660e-01 + 6.436e-02 1.660e-01 3.862e-01 4.158e-01 3.073e-01 3.749e-01 + 1.676e-01 2.180e-01 4.158e-01 5.075e-01 3.249e-01 9.283e-02 + 9.283e-02 3.249e-01 5.075e-01 4.158e-01 2.180e-01 1.676e-01 + 9.647e-02 2.401e-01 3.862e-01 3.249e-01 1.298e-01 4.807e-02 + 1.298e-01 3.249e-01 3.862e-01 2.401e-01 9.647e-02 6.631e-02 + 9.283e-02 1.660e-01 1.660e-01 9.283e-02 4.807e-02 4.807e-02 + 9.283e-02 1.660e-01 1.660e-01 9.283e-02 4.807e-02 4.807e-02 + 3.301e-02 5.357e-02 6.436e-02 9.283e-02 1.298e-01 9.283e-02 + 6.436e-02 5.357e-02 3.301e-02 1.143e-02 4.638e-03 1.143e-02 + 1.720e-02 5.357e-02 1.660e-01 3.249e-01 3.249e-01 1.660e-01 + 5.357e-02 1.720e-02 3.344e-02 6.778e-03 6.778e-03 3.344e-02 + 3.301e-02 1.660e-01 3.862e-01 5.075e-01 3.862e-01 1.660e-01 + 3.301e-02 3.344e-02 5.676e-02 6.601e-02 5.676e-02 3.344e-02 + 9.283e-02 2.401e-01 4.158e-01 4.158e-01 2.401e-01 9.283e-02 + 1.143e-02 6.778e-03 6.601e-02 6.601e-02 6.778e-03 1.143e-02 + 9.647e-02 2.180e-01 3.073e-01 2.180e-01 9.647e-02 4.807e-02 + 4.638e-03 6.778e-03 5.676e-02 6.778e-03 4.638e-03 4.807e-02 + 1.676e-01 3.749e-01 3.749e-01 1.676e-01 6.631e-02 4.807e-02 + 1.143e-02 3.344e-02 3.344e-02 1.143e-02 4.807e-02 6.631e-02 + 1.569e-02 1.569e-02 2.953e-02 1.676e-01 4.400e-01 3.249e-01 + 7.344e-02 7.344e-02 3.249e-01 4.400e-01 1.676e-01 2.953e-02 + 1.569e-02 5.039e-02 3.749e-01 7.810e-01 7.469e-01 3.862e-01 + 1.367e-01 3.862e-01 7.469e-01 7.810e-01 3.749e-01 5.039e-02 + 2.953e-02 3.749e-01 8.668e-01 9.062e-01 7.469e-01 2.401e-01 + 2.401e-01 7.469e-01 9.062e-01 8.668e-01 3.749e-01 2.953e-02 + 1.676e-01 7.810e-01 9.062e-01 8.578e-01 4.400e-01 9.647e-02 + 4.400e-01 8.578e-01 9.062e-01 7.810e-01 1.676e-01 2.299e-02 + 4.400e-01 7.469e-01 7.469e-01 4.400e-01 6.631e-02 6.631e-02 + 4.400e-01 7.469e-01 7.469e-01 4.400e-01 6.631e-02 6.631e-02 + 3.249e-01 3.862e-01 2.401e-01 9.647e-02 6.631e-02 9.647e-02 + 2.401e-01 3.862e-01 3.249e-01 1.298e-01 4.807e-02 1.298e-01 + 7.344e-02 1.367e-01 2.401e-01 4.400e-01 4.400e-01 2.401e-01 + 1.367e-01 7.344e-02 3.236e-02 1.143e-02 1.143e-02 3.236e-02 + 7.344e-02 3.862e-01 7.469e-01 8.578e-01 7.469e-01 3.862e-01 + 7.344e-02 1.488e-02 3.344e-02 1.031e-02 3.344e-02 1.488e-02 + 3.249e-01 7.469e-01 9.062e-01 9.062e-01 7.469e-01 3.249e-01 + 3.236e-02 3.344e-02 1.406e-01 1.406e-01 3.344e-02 3.236e-02 + 4.400e-01 7.810e-01 8.668e-01 7.810e-01 4.400e-01 1.298e-01 + 1.143e-02 1.031e-02 1.406e-01 1.031e-02 1.143e-02 1.298e-01 + 1.676e-01 3.749e-01 3.749e-01 1.676e-01 6.631e-02 4.807e-02 + 1.143e-02 3.344e-02 3.344e-02 1.143e-02 4.807e-02 6.631e-02 + 2.953e-02 5.039e-02 2.953e-02 2.299e-02 6.631e-02 1.298e-01 + 3.236e-02 1.488e-02 3.236e-02 1.298e-01 6.631e-02 2.299e-02 diff --git a/tests/integrate/219_NO_out_elf/result.ref b/tests/integrate/219_NO_out_elf/result.ref new file mode 100644 index 00000000000..a63c46c8f34 --- /dev/null +++ b/tests/integrate/219_NO_out_elf/result.ref @@ -0,0 +1,7 @@ +etotref -196.6254053459516 +etotperatomref -98.3127026730 +ComparePot1_pass 0 +pointgroupref T_d +spacegroupref O_h +nksibzref 1 +totaltimeref 1.14 diff --git a/tests/integrate/250_NO_KP_CR_VDW3/INPUT b/tests/integrate/250_NO_KP_CR_VDW3/INPUT index 2ee242a2dc6..62b007f191e 100644 --- a/tests/integrate/250_NO_KP_CR_VDW3/INPUT +++ b/tests/integrate/250_NO_KP_CR_VDW3/INPUT @@ -20,3 +20,4 @@ cal_force 1 cal_stress 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB +dft_functional pbe diff --git a/tests/integrate/250_NO_KP_CR_VDW3ABC/INPUT b/tests/integrate/250_NO_KP_CR_VDW3ABC/INPUT index 7a1ecc47623..83222fd70ca 100644 --- a/tests/integrate/250_NO_KP_CR_VDW3ABC/INPUT +++ b/tests/integrate/250_NO_KP_CR_VDW3ABC/INPUT @@ -17,3 +17,4 @@ cal_force 1 cal_stress 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB +dft_functional pbe diff --git a/tests/integrate/250_NO_KP_CR_VDW3BJ/INPUT b/tests/integrate/250_NO_KP_CR_VDW3BJ/INPUT index e3eda149066..a0753cdbc61 100644 --- a/tests/integrate/250_NO_KP_CR_VDW3BJ/INPUT +++ b/tests/integrate/250_NO_KP_CR_VDW3BJ/INPUT @@ -20,3 +20,4 @@ cal_force 1 cal_stress 1 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB +dft_functional pbe diff --git a/tests/integrate/285_NO_KP_RE_HSE/result.ref b/tests/integrate/285_NO_KP_RE_HSE/result.ref index e09444967fa..5b613afba2f 100644 --- a/tests/integrate/285_NO_KP_RE_HSE/result.ref +++ b/tests/integrate/285_NO_KP_RE_HSE/result.ref @@ -1,3 +1,3 @@ -etotref -200.8969758707964 -etotperatomref -100.4484879354 +etotref -199.35070744 +etotperatomref -99.67535372 totaltimeref 19.17 diff --git a/tests/integrate/286_NO_KP_CR_HSE/result.ref b/tests/integrate/286_NO_KP_CR_HSE/result.ref index c938417ee64..de76ea26c2a 100644 --- a/tests/integrate/286_NO_KP_CR_HSE/result.ref +++ b/tests/integrate/286_NO_KP_CR_HSE/result.ref @@ -1,4 +1,4 @@ -etotref -196.7312320266655092 -etotperatomref -98.3656160133 +etotref -192.82622412 +etotperatomref -96.41311206 totaltimeref 56.4969 37.12 diff --git a/tests/integrate/291_NO_KP_LR/INPUT b/tests/integrate/291_NO_KP_LR/INPUT index df499ddc165..1826d4f6180 100644 --- a/tests/integrate/291_NO_KP_LR/INPUT +++ b/tests/integrate/291_NO_KP_LR/INPUT @@ -6,6 +6,7 @@ orbital_dir ../../../tests/PP_ORB calculation scf nbands 6 symmetry -1 +nspin 2 #Parameters (2.Iteration) ecutwfc 20 @@ -26,12 +27,12 @@ mixing_beta 0.4 lr_nstates 2 # for test/debug, you can try a smaller one like 2 xc_kernel lda -lr_solver dav +lr_solver dav_subspace lr_thr 1e-2 pw_diag_ndim 4 esolver_type ks-lr nvirt 2 -abs_wavelen_range 100 175 +abs_wavelen_range 200 600 diff --git a/tests/integrate/291_NO_KP_LR/result.ref b/tests/integrate/291_NO_KP_LR/result.ref index bcd88244857..3c5a8347b09 100644 --- a/tests/integrate/291_NO_KP_LR/result.ref +++ b/tests/integrate/291_NO_KP_LR/result.ref @@ -1,2 +1 @@ -totexcitationenergyref 0.391462 -totaltimeref +totexcitationenergyref 0.784963 \ No newline at end of file diff --git a/tests/integrate/312_NO_GO_wfc_ienvelope/result.ref b/tests/integrate/312_NO_GO_wfc_ienvelope/result.ref index c516128531f..2daac8dfa02 100644 --- a/tests/integrate/312_NO_GO_wfc_ienvelope/result.ref +++ b/tests/integrate/312_NO_GO_wfc_ienvelope/result.ref @@ -1,5 +1,5 @@ -BAND1_s_1_ENV.cube 1.06415 -BAND2_s_1_ENV.cube 1.07189 -BAND3_s_1_ENV.cube 1.06892 -BAND4_s_1_ENV.cube 1.06874 +BAND1_GAMMA_SPIN1_ENV.cube 1.06417 +BAND2_GAMMA_SPIN1_ENV.cube 1.0719 +BAND3_GAMMA_SPIN1_ENV.cube 1.06891 +BAND4_GAMMA_SPIN1_ENV.cube 1.06869 totaltimeref 0.16356 diff --git a/tests/integrate/385_NO_GO_RE_S1_HSE/result.ref b/tests/integrate/385_NO_GO_RE_S1_HSE/result.ref index ddb1a478be9..356e2319712 100644 --- a/tests/integrate/385_NO_GO_RE_S1_HSE/result.ref +++ b/tests/integrate/385_NO_GO_RE_S1_HSE/result.ref @@ -1,3 +1,3 @@ -etotref -465.7333468413376 -etotperatomref -155.2444489471 +etotref -465.73367480 +etotperatomref -155.24455827 totaltimeref 16.44 diff --git a/tests/integrate/386_NO_GO_MD_S1_HSE/result.ref b/tests/integrate/386_NO_GO_MD_S1_HSE/result.ref index 953aacd308d..fb27bcbb5a0 100644 --- a/tests/integrate/386_NO_GO_MD_S1_HSE/result.ref +++ b/tests/integrate/386_NO_GO_MD_S1_HSE/result.ref @@ -1,3 +1,3 @@ -etotref -465.8658203382321 -etotperatomref -155.2886067794 +etotref -465.86709810 +etotperatomref -155.28903270 totaltimeref 17.49 diff --git a/tests/integrate/391_NO_GO_LR/INPUT b/tests/integrate/391_NO_GO_LR/INPUT index 62a139c69d6..38476bd9333 100644 --- a/tests/integrate/391_NO_GO_LR/INPUT +++ b/tests/integrate/391_NO_GO_LR/INPUT @@ -6,6 +6,7 @@ orbital_dir ../../../tests/PP_ORB calculation scf nbands 6 symmetry -1 +nspin 2 #Parameters (2.Iteration) ecutwfc 10 diff --git a/tests/integrate/391_NO_GO_LR/result.ref b/tests/integrate/391_NO_GO_LR/result.ref index e40418c0260..8d6a343a51a 100644 --- a/tests/integrate/391_NO_GO_LR/result.ref +++ b/tests/integrate/391_NO_GO_LR/result.ref @@ -1,2 +1 @@ -totexcitationenergyref 1.313946 -totaltimeref +totexcitationenergyref 2.641295 \ No newline at end of file diff --git a/tests/integrate/392_NO_GO_LR_HF/INPUT b/tests/integrate/392_NO_GO_LR_HF/INPUT new file mode 100644 index 00000000000..e48285b5722 --- /dev/null +++ b/tests/integrate/392_NO_GO_LR_HF/INPUT @@ -0,0 +1,45 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +calculation scf +nbands 6 +symmetry -1 +nspin 2 + +#Parameters (2.Iteration) +ecutwfc 10 +scf_thr 1e-2 +scf_nmax 20 +exx_hybrid_step 1 + +#Parameters (3.Basis) +basis_type lcao +gamma_only 1 + +#Parameters (4.Smearing) +smearing_method gaussian +smearing_sigma 0.02 + +#Parameters (5.Mixing) +mixing_type pulay +mixing_beta 0.4 +mixing_gg0 0 + +dft_functional hf +exx_real_number 1 +exx_ccp_rmesh_times 1 + +lr_nstates 2 +xc_kernel hf +lr_solver dav +lr_thr 1e-2 +pw_diag_ndim 2 + +esolver_type ks-lr + +nocc 4 +nvirt 2 +abs_wavelen_range 40 180 +abs_broadening 0.01 \ No newline at end of file diff --git a/tests/integrate/392_NO_GO_LR_HF/KPT b/tests/integrate/392_NO_GO_LR_HF/KPT new file mode 100644 index 00000000000..c289c0158aa --- /dev/null +++ b/tests/integrate/392_NO_GO_LR_HF/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +1 1 1 0 0 0 diff --git a/tests/integrate/392_NO_GO_LR_HF/STRU b/tests/integrate/392_NO_GO_LR_HF/STRU new file mode 100644 index 00000000000..ceb8aaa84cb --- /dev/null +++ b/tests/integrate/392_NO_GO_LR_HF/STRU @@ -0,0 +1,29 @@ +ATOMIC_SPECIES +H 1.008 H_ONCV_PBE-1.0.upf +O 15.9994 O_ONCV_PBE-1.0.upf + +NUMERICAL_ORBITAL +H_gga_8au_60Ry_2s1p.orb +O_gga_7au_60Ry_2s2p1d.orb + + +LATTICE_CONSTANT +1 + +LATTICE_VECTORS +28 0 0 +0 28 0 +0 0 28 + +ATOMIC_POSITIONS +Cartesian + +H +0 +2 +-12.046787058887078 18.76558614676448 8.395247471328744 1 1 1 +-14.228868795885418 20.61549300274637 7.611989524516571 1 1 1 +O +0 +1 +-13.486789117423204 19.684192208418636 8.958321352749174 1 1 1 diff --git a/tests/integrate/392_NO_GO_LR_HF/jd b/tests/integrate/392_NO_GO_LR_HF/jd new file mode 100644 index 00000000000..aa1d7b8dc2a --- /dev/null +++ b/tests/integrate/392_NO_GO_LR_HF/jd @@ -0,0 +1 @@ +test for linear response TDHF \ No newline at end of file diff --git a/tests/integrate/392_NO_GO_LR_HF/result.ref b/tests/integrate/392_NO_GO_LR_HF/result.ref new file mode 100644 index 00000000000..e5caf54572d --- /dev/null +++ b/tests/integrate/392_NO_GO_LR_HF/result.ref @@ -0,0 +1 @@ +totexcitationenergyref 3.067979 \ No newline at end of file diff --git a/tests/integrate/393_NO_GO_ULR_HF/INPUT b/tests/integrate/393_NO_GO_ULR_HF/INPUT new file mode 100644 index 00000000000..e9acbcda6d2 --- /dev/null +++ b/tests/integrate/393_NO_GO_ULR_HF/INPUT @@ -0,0 +1,44 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +pseudo_dir ../../../tests/PP_ORB +orbital_dir ../../../tests/PP_ORB +calculation scf +nbands 6 +symmetry -1 +nspin 2 + +#Parameters (2.Iteration) +ecutwfc 10 +scf_thr 1e-2 +scf_nmax 20 +exx_hybrid_step 1 + +#Parameters (3.Basis) +basis_type lcao +gamma_only 1 + +#Parameters (4.Smearing) +smearing_method gaussian +smearing_sigma 0.02 + +#Parameters (5.Mixing) +mixing_type pulay +mixing_beta 0.4 +mixing_gg0 0 + +dft_functional lda +exx_real_number 1 +exx_ccp_rmesh_times 1 + +lr_nstates 3 +xc_kernel lda +lr_solver lapack +lr_thr 1e-2 +lr_unrestricted 1 +pw_diag_ndim 2 + +esolver_type ks-lr + +nvirt 2 +nocc 2 \ No newline at end of file diff --git a/tests/integrate/393_NO_GO_ULR_HF/STRU b/tests/integrate/393_NO_GO_ULR_HF/STRU new file mode 100644 index 00000000000..ceb8aaa84cb --- /dev/null +++ b/tests/integrate/393_NO_GO_ULR_HF/STRU @@ -0,0 +1,29 @@ +ATOMIC_SPECIES +H 1.008 H_ONCV_PBE-1.0.upf +O 15.9994 O_ONCV_PBE-1.0.upf + +NUMERICAL_ORBITAL +H_gga_8au_60Ry_2s1p.orb +O_gga_7au_60Ry_2s2p1d.orb + + +LATTICE_CONSTANT +1 + +LATTICE_VECTORS +28 0 0 +0 28 0 +0 0 28 + +ATOMIC_POSITIONS +Cartesian + +H +0 +2 +-12.046787058887078 18.76558614676448 8.395247471328744 1 1 1 +-14.228868795885418 20.61549300274637 7.611989524516571 1 1 1 +O +0 +1 +-13.486789117423204 19.684192208418636 8.958321352749174 1 1 1 diff --git a/tests/integrate/393_NO_GO_ULR_HF/jd b/tests/integrate/393_NO_GO_ULR_HF/jd new file mode 100644 index 00000000000..ef8a41364a8 --- /dev/null +++ b/tests/integrate/393_NO_GO_ULR_HF/jd @@ -0,0 +1 @@ +test for linear response TDHF using open-shell solver \ No newline at end of file diff --git a/tests/integrate/393_NO_GO_ULR_HF/result.ref b/tests/integrate/393_NO_GO_ULR_HF/result.ref new file mode 100644 index 00000000000..e395c0fb9d4 --- /dev/null +++ b/tests/integrate/393_NO_GO_ULR_HF/result.ref @@ -0,0 +1 @@ +totexcitationenergyref 1.940703 \ No newline at end of file diff --git a/tests/integrate/401_NP_KP_sp/result.ref b/tests/integrate/401_NP_KP_sp/result.ref index dce8f484691..a8ade4ce383 100644 --- a/tests/integrate/401_NP_KP_sp/result.ref +++ b/tests/integrate/401_NP_KP_sp/result.ref @@ -1,4 +1,4 @@ -etotref -723.7838345681450 +etotref -723.78383467 etotperatomref -361.8919172840725 pointgroupref C_1h spacegroupref C_2h diff --git a/tests/integrate/401_NP_KP_spd/result.ref b/tests/integrate/401_NP_KP_spd/result.ref index a0c5f6713a3..22728822092 100644 --- a/tests/integrate/401_NP_KP_spd/result.ref +++ b/tests/integrate/401_NP_KP_spd/result.ref @@ -1,4 +1,4 @@ -etotref -211.3351662834205 +etotref -211.33516646 etotperatomref -105.6675831417103 pointgroupref T_d spacegroupref O_h diff --git a/tests/integrate/601_NO_TDDFT_H2_kpoint/result.ref b/tests/integrate/601_NO_TDDFT_H2_kpoint/result.ref index 179e280c026..acec3055cac 100644 --- a/tests/integrate/601_NO_TDDFT_H2_kpoint/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_kpoint/result.ref @@ -1,5 +1,5 @@ etotref -18.05466171990316 etotperatomref -9.0273308600 -totalforceref 44.887962 -totalstressref 79.547659 +totalforceref 44.85505600 +totalstressref 79.48569300 totaltimeref 1.51 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_gauss/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_gauss/result.ref index fddba87a4fd..9b4c7051c23 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_gauss/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_gauss/result.ref @@ -1,5 +1,5 @@ etotref -30.45477750879012 etotperatomref -15.2273887544 -totalforceref 0.574814 +totalforceref 0.57576800 totalstressref 4.287440 totaltimeref 1.57 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_gauss_dire/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_gauss_dire/result.ref index 5d2e57b6efa..ed14fa024d8 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_gauss_dire/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_gauss_dire/result.ref @@ -1,5 +1,5 @@ etotref -30.45466274119030 etotperatomref -15.2273313706 -totalforceref 0.573436 +totalforceref 0.57439400 totalstressref 4.285714 totaltimeref 1.55 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_heavi/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_heavi/result.ref index de8d31b7db2..7fe9afe5aca 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_heavi/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_heavi/result.ref @@ -1,5 +1,5 @@ etotref -22.97718184915547 etotperatomref -11.4885909246 -totalforceref 0.564908 +totalforceref 0.56587600 totalstressref 76.073961 totaltimeref 1.56 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_hhg/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_hhg/result.ref index 70aa5fdf099..6e676b2f56b 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_hhg/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_hhg/result.ref @@ -1,5 +1,5 @@ etotref 20.38731422853930 etotperatomref 10.1936571143 -totalforceref 0.738256 +totalforceref 0.73949000 totalstressref 489.377111 totaltimeref 1.56 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_trape/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_trape/result.ref index b8cbe20aa05..264acd99d03 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_trape/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_trape/result.ref @@ -1,5 +1,5 @@ etotref -30.89965242483882 etotperatomref -15.4498262124 -totalforceref 0.574662 -totalstressref 1.034216 +totalforceref 0.57561800 +totalstressref 1.03619000 totaltimeref 1.44 diff --git a/tests/integrate/601_NO_TDDFT_H2_len_trigo/result.ref b/tests/integrate/601_NO_TDDFT_H2_len_trigo/result.ref index b0cdd8ce318..6948429d127 100644 --- a/tests/integrate/601_NO_TDDFT_H2_len_trigo/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_len_trigo/result.ref @@ -1,5 +1,5 @@ etotref -30.90912142263002 etotperatomref -15.4545607113 -totalforceref 0.574662 -totalstressref 1.108904 +totalforceref 0.57561800 +totalstressref 1.11089700 totaltimeref 1.43 diff --git a/tests/integrate/601_NO_TDDFT_H2_oldedm/INPUT b/tests/integrate/601_NO_TDDFT_H2_oldedm/INPUT index cbda64819e9..87fdb4d2085 100755 --- a/tests/integrate/601_NO_TDDFT_H2_oldedm/INPUT +++ b/tests/integrate/601_NO_TDDFT_H2_oldedm/INPUT @@ -32,4 +32,4 @@ md_dt 0.05 init_vel 1 ocp 1 ocp_set 1*0.5 1*0.5 3*0 1*0.5 1*0.5 3*0 -td_edm 0 +td_edm 1 diff --git a/tests/integrate/601_NO_TDDFT_H2_oldedm/result.ref b/tests/integrate/601_NO_TDDFT_H2_oldedm/result.ref index aa47e7d5a20..e8e3d2d48c9 100644 --- a/tests/integrate/601_NO_TDDFT_H2_oldedm/result.ref +++ b/tests/integrate/601_NO_TDDFT_H2_oldedm/result.ref @@ -1,5 +1,5 @@ etotref -18.05466171990316 etotperatomref -9.0273308600 -totalforceref 44.887962 -totalstressref 79.547659 +totalforceref 43.10812600 +totalstressref 76.35413900 totaltimeref 1.53 diff --git a/tests/integrate/601_NO_TDDFT_graphene_kpoint/result.ref b/tests/integrate/601_NO_TDDFT_graphene_kpoint/result.ref index c19b78e3c8b..a7467a26cc9 100644 --- a/tests/integrate/601_NO_TDDFT_graphene_kpoint/result.ref +++ b/tests/integrate/601_NO_TDDFT_graphene_kpoint/result.ref @@ -1,5 +1,5 @@ etotref -321.2089497177532 etotperatomref -107.0696499059 -totalforceref 14.639754 -totalstressref 1803.570000 +totalforceref 2.10083100 +totalstressref 198.29401300 totaltimeref 14.01 diff --git a/tests/integrate/701_LJ_MD_NVE/INPUT b/tests/integrate/701_LJ_MD_NVE/INPUT index 619aa642be9..9673def0f2e 100644 --- a/tests/integrate/701_LJ_MD_NVE/INPUT +++ b/tests/integrate/701_LJ_MD_NVE/INPUT @@ -15,9 +15,12 @@ cal_force 1 cal_stress 1 #Parameters (MD) -md_nstep 5 +md_nstep 160 md_type nve md_dt 1 md_tfirst 300 init_vel 1 + +md_restart 1 +read_file_dir . diff --git a/tests/integrate/701_LJ_MD_NVE/Restart_md.dat b/tests/integrate/701_LJ_MD_NVE/Restart_md.dat new file mode 100644 index 00000000000..d00a7458553 --- /dev/null +++ b/tests/integrate/701_LJ_MD_NVE/Restart_md.dat @@ -0,0 +1,2 @@ +155 +0.000950045 diff --git a/tests/integrate/701_LJ_MD_NVE/STRU b/tests/integrate/701_LJ_MD_NVE/STRU deleted file mode 100644 index f1c0576192e..00000000000 --- a/tests/integrate/701_LJ_MD_NVE/STRU +++ /dev/null @@ -1,49 +0,0 @@ -ATOMIC_SPECIES -He 4.0026 auto auto - -LATTICE_CONSTANT -1.889727 - -LATTICE_VECTORS - 10.0000000000 0.0000000000 0.0000000000 #latvec1 - 0.0000000000 10.0000000000 0.0000000000 #latvec2 - 0.0000000000 0.0000000000 10.0000000000 #latvec3 - -ATOMIC_POSITIONS -Cartesian - -He #label -0 #magnetism -32 #number of atoms - 0.0000000000 0.0000000000 0.0000000000 m 1 1 1 v 0.0003051236 -0.0001506039 0.0002563783 - 0.0000000000 0.0000000000 5.0000000000 m 1 1 1 v 0.0001330836 -0.0002844927 0.0004575604 - 0.0000000000 5.0000000000 0.0000000000 m 1 1 1 v -0.0007284395 0.0001278596 -0.0001116420 - 0.0000000000 5.0000000000 5.0000000000 m 1 1 1 v 0.0007317461 -0.0008538537 0.0001165929 - 5.0000000000 0.0000000000 0.0000000000 m 1 1 1 v 0.0002153406 0.0004818484 -0.0003425506 - 5.0000000000 0.0000000000 5.0000000000 m 1 1 1 v 0.0000115849 -0.0001553058 0.0001440467 - 5.0000000000 5.0000000000 0.0000000000 m 1 1 1 v -0.0005075296 -0.0001418554 0.0000517226 - 5.0000000000 5.0000000000 5.0000000000 m 1 1 1 v 0.0003532731 0.0002838795 -0.0005240855 - 2.5000000000 2.5000000000 0.0000000000 m 1 1 1 v 0.0007110217 0.0001188223 0.0000320587 - 2.5000000000 2.5000000000 5.0000000000 m 1 1 1 v 0.0000716800 -0.0002982750 0.0003924065 - 2.5000000000 7.5000000000 0.0000000000 m 1 1 1 v -0.0000446191 0.0005436754 -0.0000488239 - 2.5000000000 7.5000000000 5.0000000000 m 1 1 1 v 0.0002256764 -0.0005094877 -0.0002958008 - 7.5000000000 2.5000000000 0.0000000000 m 1 1 1 v -0.0000811382 -0.0003395719 -0.0003533055 - 7.5000000000 2.5000000000 5.0000000000 m 1 1 1 v 0.0001046891 0.0002627214 -0.0000768329 - 7.5000000000 7.5000000000 0.0000000000 m 1 1 1 v -0.0001263117 -0.0002867947 -0.0005880112 - 7.5000000000 7.5000000000 5.0000000000 m 1 1 1 v 0.0000051377 -0.0002585502 0.0005224161 - 2.5000000000 0.0000000000 2.5000000000 m 1 1 1 v -0.0000441228 0.0007354340 0.0000484884 - 2.5000000000 0.0000000000 7.5000000000 m 1 1 1 v -0.0003062640 -0.0000630593 0.0003011308 - 2.5000000000 5.0000000000 2.5000000000 m 1 1 1 v 0.0000156182 0.0000352305 -0.0002909118 - 2.5000000000 5.0000000000 7.5000000000 m 1 1 1 v 0.0002588185 0.0004562910 -0.0004669455 - 7.5000000000 0.0000000000 2.5000000000 m 1 1 1 v 0.0000836607 -0.0003527362 -0.0000237714 - 7.5000000000 0.0000000000 7.5000000000 m 1 1 1 v 0.0002682220 0.0003310257 -0.0001488492 - 7.5000000000 5.0000000000 2.5000000000 m 1 1 1 v -0.0001893987 0.0001038739 -0.0003576744 - 7.5000000000 5.0000000000 7.5000000000 m 1 1 1 v 0.0003881776 0.0001685539 0.0000718978 - 0.0000000000 2.5000000000 2.5000000000 m 1 1 1 v 0.0000439981 0.0003058987 -0.0000061514 - 0.0000000000 2.5000000000 7.5000000000 m 1 1 1 v 0.0001835450 -0.0001686670 0.0004810819 - 0.0000000000 7.5000000000 2.5000000000 m 1 1 1 v -0.0000043640 0.0001908703 0.0000007071 - 0.0000000000 7.5000000000 7.5000000000 m 1 1 1 v -0.0006477776 0.0006839538 -0.0003073223 - 5.0000000000 2.5000000000 2.5000000000 m 1 1 1 v 0.0001909232 -0.0005588096 0.0004036625 - 5.0000000000 2.5000000000 7.5000000000 m 1 1 1 v -0.0003495156 -0.0001304327 -0.0005131768 - 5.0000000000 7.5000000000 2.5000000000 m 1 1 1 v -0.0004054115 -0.0002425928 0.0005518707 - 5.0000000000 7.5000000000 7.5000000000 m 1 1 1 v -0.0008664276 -0.0000348499 0.0006238335 diff --git a/tests/integrate/701_LJ_MD_NVE/STRU_MD_155 b/tests/integrate/701_LJ_MD_NVE/STRU_MD_155 new file mode 100644 index 00000000000..e268f33c164 --- /dev/null +++ b/tests/integrate/701_LJ_MD_NVE/STRU_MD_155 @@ -0,0 +1,49 @@ +ATOMIC_SPECIES +He 4.0026 auto auto + +LATTICE_CONSTANT +1.8897270000 + +LATTICE_VECTORS + 10.0000000000 0.0000000000 0.0000000000 + 0.0000000000 10.0000000000 0.0000000000 + 0.0000000000 0.0000000000 10.0000000000 + +ATOMIC_POSITIONS +Cartesian + +He #label +0.0000 #magnetism +32 #number of atoms + 0.2326403411 0.1805586531 9.8262424108 m 1 1 1 v -0.0000121378 -0.0002237088 -0.0000117252 + 0.1290011046 9.8675255727 5.1196032873 m 1 1 1 v -0.0001472165 -0.0001030776 0.0001218950 + 9.9328123711 4.7424879243 0.1127761048 m 1 1 1 v 0.0000533903 0.0000737924 -0.0001002520 + 0.0883359764 5.0466198180 4.9376340225 m 1 1 1 v 0.0000114005 0.0000308851 -0.0002758447 + 5.1567286276 9.6701708077 0.0720605175 m 1 1 1 v 0.0000797853 -0.0002910361 0.0002806497 + 4.9729770896 0.2523099247 4.8249429749 m 1 1 1 v -0.0000454343 -0.0002134570 0.0000906867 + 5.0259271309 5.0195597999 0.1284189796 m 1 1 1 v -0.0000736120 -0.0002625762 -0.0000325229 + 5.0845526566 4.9911110707 5.2224341707 m 1 1 1 v 0.0001394765 -0.0000715475 0.0002598028 + 2.3762114831 2.5329743364 0.0010311292 m 1 1 1 v 0.0001722709 0.0002976706 -0.0003480793 + 2.3308490267 2.5334843809 5.1084963341 m 1 1 1 v 0.0003107598 -0.0000490207 0.0000608596 + 2.6425636904 7.4014841094 9.6818561372 m 1 1 1 v -0.0000440260 0.0000306772 -0.0001045476 + 2.7555043799 7.4958096690 4.9663551309 m 1 1 1 v 0.0001676051 -0.0001407551 0.0000374823 + 7.5498978773 2.4019404441 9.9051437743 m 1 1 1 v -0.0000404775 -0.0004937666 -0.0002417073 + 7.0878872794 2.6398358481 5.2207704373 m 1 1 1 v 0.0000446631 -0.0001111729 0.0002772739 + 7.6306348110 7.2523052857 0.1879671715 m 1 1 1 v -0.0002650167 0.0000223905 0.0004208865 + 7.5019632892 7.7167191447 4.8113372067 m 1 1 1 v 0.0001431757 0.0001818078 -0.0004933417 + 2.4827381044 9.9093725459 2.3803925949 m 1 1 1 v 0.0004335723 0.0003136178 -0.0000374626 + 2.5667822143 0.1172638315 7.4599516344 m 1 1 1 v 0.0000840626 -0.0000288634 -0.0001960829 + 2.3506570501 5.2876910311 2.4783194446 m 1 1 1 v -0.0005280147 0.0005108524 -0.0002761533 + 2.4266156895 4.8469473963 7.4585069415 m 1 1 1 v -0.0002227251 0.0000553886 -0.0002414346 + 7.4978278440 0.2186955512 2.2854682214 m 1 1 1 v 0.0002061109 0.0000125043 -0.0001318463 + 7.4306464470 9.7982198196 7.5197935505 m 1 1 1 v -0.0001547693 0.0003731227 0.0002641078 + 7.5050495358 4.8100482242 2.7557225603 m 1 1 1 v 0.0005099203 -0.0001534080 -0.0002708300 + 7.5827553390 5.0825896221 7.6133407395 m 1 1 1 v -0.0002026006 -0.0004137035 -0.0000968275 + 0.0639279225 2.3314295584 2.8919146960 m 1 1 1 v -0.0003352759 -0.0002671850 0.0002228256 + 9.7059574272 2.4001848236 7.1843159676 m 1 1 1 v -0.0000842986 -0.0000802494 0.0002060414 + 0.1537051705 7.7328815133 2.2300281961 m 1 1 1 v 0.0000627880 0.0000878973 -0.0001059948 + 0.0336716230 7.5802323444 7.3828898964 m 1 1 1 v -0.0000501165 0.0000290086 0.0001592017 + 4.7535864052 2.6546520439 2.3575869556 m 1 1 1 v -0.0001280401 -0.0001046688 0.0001303011 + 4.9143288348 2.3613176229 7.4999150246 m 1 1 1 v -0.0000822629 0.0002548092 0.0001181581 + 4.9937745538 7.3933612435 2.7335288627 m 1 1 1 v 0.0001275830 0.0002930131 0.0000222267 + 5.0394893823 7.7302156995 7.6412539073 m 1 1 1 v -0.0001305395 0.0004407590 0.0002922533 diff --git a/tests/integrate/701_LJ_MD_NVE/result.ref b/tests/integrate/701_LJ_MD_NVE/result.ref index 22b6d660a14..1e4b22ae3c7 100644 --- a/tests/integrate/701_LJ_MD_NVE/result.ref +++ b/tests/integrate/701_LJ_MD_NVE/result.ref @@ -1,5 +1,5 @@ -etotref -2.231664481084234 -etotperatomref -0.0697395150 -totalforceref 2.523373 -totalstressref 28.540803 -totaltimeref 0.03 +etotref -1.562635884297464 +etotperatomref -0.0488323714 +totalforceref 9.771882 +totalstressref 46.307098 +totaltimeref 0.02 diff --git a/tests/integrate/701_LJ_MD_rescale_v/INPUT b/tests/integrate/701_LJ_MD_rescale_v/INPUT index 1f42e75c39f..41bcb07bcd7 100644 --- a/tests/integrate/701_LJ_MD_rescale_v/INPUT +++ b/tests/integrate/701_LJ_MD_rescale_v/INPUT @@ -15,11 +15,11 @@ cal_force 1 cal_stress 1 #Parameters (MD) -md_nstep 5 +md_nstep 14 md_type nvt md_dt 1 md_tfirst 300 - +md_restart 1 init_vel 1 #Parameters (thermostat) diff --git a/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/Restart_md.dat b/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/Restart_md.dat new file mode 100644 index 00000000000..aaa07929f11 --- /dev/null +++ b/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/Restart_md.dat @@ -0,0 +1,2 @@ +10 +0.000950045 diff --git a/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/STRU/STRU_MD_10 b/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/STRU/STRU_MD_10 new file mode 100644 index 00000000000..47e784dcef4 --- /dev/null +++ b/tests/integrate/701_LJ_MD_rescale_v/OUT.autotest/STRU/STRU_MD_10 @@ -0,0 +1,49 @@ +ATOMIC_SPECIES +He 4.0026 auto auto + +LATTICE_CONSTANT +1.8897270000 + +LATTICE_VECTORS + 10.0000000000 0.0000000000 0.0000000000 + 0.0000000000 10.0000000000 0.0000000000 + 0.0000000000 0.0000000000 10.0000000000 + +ATOMIC_POSITIONS +Cartesian + +He #label +0.0000 #magnetism +32 #number of atoms + 0.0655588081 9.9683119490 0.0573495702 m 1 1 1 v 0.0002950037 -0.0001359087 0.0002817142 + 0.0296020455 9.9394287800 5.0974576575 m 1 1 1 v 0.0001450707 -0.0002659284 0.0004288033 + 9.8437701902 5.0285548903 9.9750151927 m 1 1 1 v -0.0007044281 0.0001389467 -0.0001200141 + 0.1593199064 4.8142404625 5.0254534456 m 1 1 1 v 0.0007415303 -0.0008638378 0.0001205085 + 5.0478627152 0.1039334022 9.9257632192 m 1 1 1 v 0.0002314661 0.0004741028 -0.0003442097 + 5.0029102003 9.9636970071 5.0330422438 m 1 1 1 v 0.0000172209 -0.0001939876 0.0001700901 + 4.8903853112 4.9686490249 0.0111471151 m 1 1 1 v -0.0004991972 -0.0001467827 0.0000501866 + 5.0777210495 5.0598930691 4.8868119138 m 1 1 1 v 0.0003692795 0.0002563320 -0.0005158799 + 2.6540295807 2.5271295893 0.0063399217 m 1 1 1 v 0.0007084865 0.0001346339 0.0000232620 + 2.5161768072 2.4343319000 5.0855185376 m 1 1 1 v 0.0000798909 -0.0003153276 0.0003981596 + 2.4885226114 7.6183654890 9.9916893544 m 1 1 1 v -0.0000705801 0.0005501795 -0.0000119107 + 2.5472229404 7.3903651016 4.9353714563 m 1 1 1 v 0.0001986861 -0.0004975157 -0.0003020557 + 7.4815287957 2.4263888494 9.9233415484 m 1 1 1 v -0.0000920512 -0.0003376769 -0.0003536841 + 7.5241804124 2.5573040389 4.9833906701 m 1 1 1 v 0.0001258496 0.0002684644 -0.0000759589 + 7.4695431022 7.4394976591 9.8722710346 m 1 1 1 v -0.0001710906 -0.0002611367 -0.0005919685 + 7.5005490316 7.4428194462 5.1135787733 m 1 1 1 v -0.0000055483 -0.0002727539 0.0005241266 + 2.4904082317 0.1601904807 2.5115332253 m 1 1 1 v -0.0000457050 0.0007460947 0.0000629334 + 2.4331552911 9.9859414563 7.5652838492 m 1 1 1 v -0.0003120657 -0.0000668895 0.0003013885 + 2.5023759747 5.0062549748 2.4352866258 m 1 1 1 v -0.0000001888 0.0000162094 -0.0003142300 + 2.5546402518 5.0993060966 7.3995116538 m 1 1 1 v 0.0002383422 0.0004574823 -0.0004564841 + 7.5185693929 9.9213221538 2.4952978333 m 1 1 1 v 0.0000890360 -0.0003842210 -0.0000176632 + 7.5566224950 0.0732059047 7.4670019245 m 1 1 1 v 0.0002452208 0.0003541221 -0.0001600036 + 7.4586761755 5.0230751233 2.4212251455 m 1 1 1 v -0.0001945627 0.0001116452 -0.0003764660 + 7.5826720157 5.0347139511 7.5141572910 m 1 1 1 v 0.0003678149 0.0001399331 0.0000487214 + 0.0089573689 2.5662392942 2.4973462274 m 1 1 1 v 0.0000351825 0.0003053353 -0.0000266476 + 0.0417566390 2.4636651990 7.6067552685 m 1 1 1 v 0.0002120403 -0.0001648501 0.0005167711 + 9.9989679634 7.5404906965 2.5014145451 m 1 1 1 v -0.0000047379 0.0001780690 0.0000184666 + 9.8612024820 7.6473271727 7.4337306273 m 1 1 1 v -0.0006222054 0.0006675675 -0.0002959123 + 5.0432660960 2.3783889173 2.5889289401 m 1 1 1 v 0.0002188891 -0.0005654607 0.0004240516 + 4.9250307726 2.4734365320 7.3864959938 m 1 1 1 v -0.0003367943 -0.0001065234 -0.0005436354 + 4.9123907180 7.4499967239 2.6171837953 m 1 1 1 v -0.0003999327 -0.0002036017 0.0005137604 + 4.8124246568 7.4935346648 7.6353053219 m 1 1 1 v -0.0008599223 -0.0000167156 0.0006237795 diff --git a/tests/integrate/701_LJ_MD_rescale_v/STRU b/tests/integrate/701_LJ_MD_rescale_v/STRU deleted file mode 100644 index f1c0576192e..00000000000 --- a/tests/integrate/701_LJ_MD_rescale_v/STRU +++ /dev/null @@ -1,49 +0,0 @@ -ATOMIC_SPECIES -He 4.0026 auto auto - -LATTICE_CONSTANT -1.889727 - -LATTICE_VECTORS - 10.0000000000 0.0000000000 0.0000000000 #latvec1 - 0.0000000000 10.0000000000 0.0000000000 #latvec2 - 0.0000000000 0.0000000000 10.0000000000 #latvec3 - -ATOMIC_POSITIONS -Cartesian - -He #label -0 #magnetism -32 #number of atoms - 0.0000000000 0.0000000000 0.0000000000 m 1 1 1 v 0.0003051236 -0.0001506039 0.0002563783 - 0.0000000000 0.0000000000 5.0000000000 m 1 1 1 v 0.0001330836 -0.0002844927 0.0004575604 - 0.0000000000 5.0000000000 0.0000000000 m 1 1 1 v -0.0007284395 0.0001278596 -0.0001116420 - 0.0000000000 5.0000000000 5.0000000000 m 1 1 1 v 0.0007317461 -0.0008538537 0.0001165929 - 5.0000000000 0.0000000000 0.0000000000 m 1 1 1 v 0.0002153406 0.0004818484 -0.0003425506 - 5.0000000000 0.0000000000 5.0000000000 m 1 1 1 v 0.0000115849 -0.0001553058 0.0001440467 - 5.0000000000 5.0000000000 0.0000000000 m 1 1 1 v -0.0005075296 -0.0001418554 0.0000517226 - 5.0000000000 5.0000000000 5.0000000000 m 1 1 1 v 0.0003532731 0.0002838795 -0.0005240855 - 2.5000000000 2.5000000000 0.0000000000 m 1 1 1 v 0.0007110217 0.0001188223 0.0000320587 - 2.5000000000 2.5000000000 5.0000000000 m 1 1 1 v 0.0000716800 -0.0002982750 0.0003924065 - 2.5000000000 7.5000000000 0.0000000000 m 1 1 1 v -0.0000446191 0.0005436754 -0.0000488239 - 2.5000000000 7.5000000000 5.0000000000 m 1 1 1 v 0.0002256764 -0.0005094877 -0.0002958008 - 7.5000000000 2.5000000000 0.0000000000 m 1 1 1 v -0.0000811382 -0.0003395719 -0.0003533055 - 7.5000000000 2.5000000000 5.0000000000 m 1 1 1 v 0.0001046891 0.0002627214 -0.0000768329 - 7.5000000000 7.5000000000 0.0000000000 m 1 1 1 v -0.0001263117 -0.0002867947 -0.0005880112 - 7.5000000000 7.5000000000 5.0000000000 m 1 1 1 v 0.0000051377 -0.0002585502 0.0005224161 - 2.5000000000 0.0000000000 2.5000000000 m 1 1 1 v -0.0000441228 0.0007354340 0.0000484884 - 2.5000000000 0.0000000000 7.5000000000 m 1 1 1 v -0.0003062640 -0.0000630593 0.0003011308 - 2.5000000000 5.0000000000 2.5000000000 m 1 1 1 v 0.0000156182 0.0000352305 -0.0002909118 - 2.5000000000 5.0000000000 7.5000000000 m 1 1 1 v 0.0002588185 0.0004562910 -0.0004669455 - 7.5000000000 0.0000000000 2.5000000000 m 1 1 1 v 0.0000836607 -0.0003527362 -0.0000237714 - 7.5000000000 0.0000000000 7.5000000000 m 1 1 1 v 0.0002682220 0.0003310257 -0.0001488492 - 7.5000000000 5.0000000000 2.5000000000 m 1 1 1 v -0.0001893987 0.0001038739 -0.0003576744 - 7.5000000000 5.0000000000 7.5000000000 m 1 1 1 v 0.0003881776 0.0001685539 0.0000718978 - 0.0000000000 2.5000000000 2.5000000000 m 1 1 1 v 0.0000439981 0.0003058987 -0.0000061514 - 0.0000000000 2.5000000000 7.5000000000 m 1 1 1 v 0.0001835450 -0.0001686670 0.0004810819 - 0.0000000000 7.5000000000 2.5000000000 m 1 1 1 v -0.0000043640 0.0001908703 0.0000007071 - 0.0000000000 7.5000000000 7.5000000000 m 1 1 1 v -0.0006477776 0.0006839538 -0.0003073223 - 5.0000000000 2.5000000000 2.5000000000 m 1 1 1 v 0.0001909232 -0.0005588096 0.0004036625 - 5.0000000000 2.5000000000 7.5000000000 m 1 1 1 v -0.0003495156 -0.0001304327 -0.0005131768 - 5.0000000000 7.5000000000 2.5000000000 m 1 1 1 v -0.0004054115 -0.0002425928 0.0005518707 - 5.0000000000 7.5000000000 7.5000000000 m 1 1 1 v -0.0008664276 -0.0000348499 0.0006238335 diff --git a/tests/integrate/701_LJ_MD_rescale_v/result.ref b/tests/integrate/701_LJ_MD_rescale_v/result.ref index 5e667336ed7..cad88e73de5 100644 --- a/tests/integrate/701_LJ_MD_rescale_v/result.ref +++ b/tests/integrate/701_LJ_MD_rescale_v/result.ref @@ -1,5 +1,8 @@ -etotref -2.231166224971229 -etotperatomref -0.0697239445 -totalforceref 2.535421 -totalstressref 28.554171 +etotref -1.834707034866914 +etotperatomref -0.0573345948 +totalforceref 8.470218 +totalstressref 39.004676 totaltimeref 0.03 +0.02 +0.02 +0.02 diff --git a/tests/integrate/801_PW_LT_sc/INPUT b/tests/integrate/801_PW_LT_sc/INPUT index f658549dcb1..92b92f06145 100644 --- a/tests/integrate/801_PW_LT_sc/INPUT +++ b/tests/integrate/801_PW_LT_sc/INPUT @@ -16,3 +16,5 @@ scf_thr 1e-10 cal_force 1 cal_stress 1 + +pw_seed 1 diff --git a/tests/integrate/919_OF_out_elf/INPUT b/tests/integrate/919_OF_out_elf/INPUT new file mode 100644 index 00000000000..2cb31334099 --- /dev/null +++ b/tests/integrate/919_OF_out_elf/INPUT @@ -0,0 +1,25 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation scf +esolver_type ofdft + +symmetry 1 +pseudo_dir ../../PP_ORB/ +pseudo_rcut 16 +nspin 1 + +#Parameters (2.Iteration) +ecutwfc 5 +scf_nmax 50 + +#OFDFT +of_kinetic wt +of_method tn +of_conv energy +of_tole 2e-6 + +#Parameters (3.Basis) +basis_type pw + +out_elf 1 diff --git a/tests/integrate/919_OF_out_elf/KPT b/tests/integrate/919_OF_out_elf/KPT new file mode 100644 index 00000000000..c289c0158aa --- /dev/null +++ b/tests/integrate/919_OF_out_elf/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +1 1 1 0 0 0 diff --git a/tests/integrate/919_OF_out_elf/STRU b/tests/integrate/919_OF_out_elf/STRU new file mode 100644 index 00000000000..e797c064328 --- /dev/null +++ b/tests/integrate/919_OF_out_elf/STRU @@ -0,0 +1,18 @@ +ATOMIC_SPECIES +Al 26.98 al.lda.lps blps + +LATTICE_CONSTANT +7.50241114482312 // add lattice constant + +LATTICE_VECTORS +0.000000000000 0.500000000000 0.500000000000 +0.500000000000 0.000000000000 0.500000000000 +0.500000000000 0.500000000000 0.000000000000 + +ATOMIC_POSITIONS +Direct + +Al +0 +1 + 0.000000000000 0.000000000000 0.000000000000 1 1 1 diff --git a/tests/integrate/919_OF_out_elf/jd b/tests/integrate/919_OF_out_elf/jd new file mode 100644 index 00000000000..4cd07ce898d --- /dev/null +++ b/tests/integrate/919_OF_out_elf/jd @@ -0,0 +1 @@ +Test out_elf in OFDFT, symmetry=on diff --git a/tests/integrate/919_OF_out_elf/refELF.cube b/tests/integrate/919_OF_out_elf/refELF.cube new file mode 100644 index 00000000000..9988ee52d72 --- /dev/null +++ b/tests/integrate/919_OF_out_elf/refELF.cube @@ -0,0 +1,135 @@ +STEP: 0 Cubefile created from ABACUS. Inner loop is z, followed by y and x +1 (nspin) +1 0.0 0.0 0.0 +8 0.000000 0.468901 0.468901 +8 0.468901 0.000000 0.468901 +8 0.468901 0.468901 0.000000 + 13 3.000000 0.000000 0.000000 0.000000 + 2.328e-02 8.303e-02 4.696e-01 5.990e-01 5.706e-01 5.990e-01 + 4.696e-01 8.303e-02 + 8.303e-02 3.513e-01 5.887e-01 5.674e-01 5.687e-01 5.904e-01 + 3.507e-01 1.488e-01 + 4.696e-01 5.887e-01 5.600e-01 5.238e-01 5.598e-01 5.855e-01 + 4.756e-01 3.507e-01 + 5.990e-01 5.674e-01 5.238e-01 5.239e-01 5.638e-01 5.991e-01 + 5.855e-01 5.904e-01 + 5.706e-01 5.687e-01 5.598e-01 5.638e-01 5.706e-01 5.638e-01 + 5.598e-01 5.687e-01 + 5.990e-01 5.904e-01 5.855e-01 5.991e-01 5.638e-01 5.239e-01 + 5.238e-01 5.674e-01 + 4.696e-01 3.507e-01 4.756e-01 5.855e-01 5.598e-01 5.238e-01 + 5.600e-01 5.887e-01 + 8.303e-02 1.488e-01 3.507e-01 5.904e-01 5.687e-01 5.674e-01 + 5.887e-01 3.513e-01 + 8.303e-02 3.513e-01 5.887e-01 5.674e-01 5.687e-01 5.904e-01 + 3.507e-01 1.488e-01 + 3.513e-01 5.751e-01 5.857e-01 5.521e-01 5.860e-01 5.751e-01 + 4.141e-01 2.344e-01 + 5.887e-01 5.857e-01 5.445e-01 5.445e-01 5.854e-01 5.848e-01 + 5.180e-01 5.199e-01 + 5.674e-01 5.521e-01 5.445e-01 5.521e-01 5.636e-01 5.614e-01 + 5.509e-01 5.617e-01 + 5.687e-01 5.860e-01 5.854e-01 5.636e-01 5.237e-01 4.874e-01 + 4.880e-01 5.241e-01 + 5.904e-01 5.751e-01 5.848e-01 5.614e-01 4.874e-01 4.510e-01 + 4.885e-01 5.617e-01 + 3.507e-01 4.141e-01 5.180e-01 5.509e-01 4.880e-01 4.885e-01 + 5.495e-01 5.199e-01 + 1.488e-01 2.344e-01 5.199e-01 5.617e-01 5.241e-01 5.617e-01 + 5.199e-01 2.344e-01 + 4.696e-01 5.887e-01 5.600e-01 5.238e-01 5.598e-01 5.855e-01 + 4.756e-01 3.507e-01 + 5.887e-01 5.857e-01 5.445e-01 5.445e-01 5.854e-01 5.848e-01 + 5.180e-01 5.199e-01 + 5.600e-01 5.445e-01 5.346e-01 5.444e-01 5.594e-01 5.517e-01 + 5.365e-01 5.495e-01 + 5.238e-01 5.445e-01 5.444e-01 5.239e-01 4.872e-01 4.563e-01 + 4.565e-01 4.885e-01 + 5.598e-01 5.854e-01 5.594e-01 4.872e-01 4.089e-01 3.755e-01 + 4.089e-01 4.880e-01 + 5.855e-01 5.848e-01 5.517e-01 4.563e-01 3.755e-01 3.751e-01 + 4.565e-01 5.509e-01 + 4.756e-01 5.180e-01 5.365e-01 4.565e-01 4.089e-01 4.565e-01 + 5.365e-01 5.180e-01 + 3.507e-01 5.199e-01 5.495e-01 4.885e-01 4.880e-01 5.509e-01 + 5.180e-01 4.141e-01 + 5.990e-01 5.674e-01 5.238e-01 5.239e-01 5.638e-01 5.991e-01 + 5.855e-01 5.904e-01 + 5.674e-01 5.521e-01 5.445e-01 5.521e-01 5.636e-01 5.614e-01 + 5.509e-01 5.617e-01 + 5.238e-01 5.445e-01 5.444e-01 5.239e-01 4.872e-01 4.563e-01 + 4.565e-01 4.885e-01 + 5.239e-01 5.521e-01 5.239e-01 4.510e-01 3.756e-01 3.441e-01 + 3.751e-01 4.510e-01 + 5.638e-01 5.636e-01 4.872e-01 3.756e-01 2.999e-01 2.998e-01 + 3.755e-01 4.874e-01 + 5.991e-01 5.614e-01 4.563e-01 3.441e-01 2.998e-01 3.441e-01 + 4.563e-01 5.614e-01 + 5.855e-01 5.509e-01 4.565e-01 3.751e-01 3.755e-01 4.563e-01 + 5.517e-01 5.848e-01 + 5.904e-01 5.617e-01 4.885e-01 4.510e-01 4.874e-01 5.614e-01 + 5.848e-01 5.751e-01 + 5.706e-01 5.687e-01 5.598e-01 5.638e-01 5.706e-01 5.638e-01 + 5.598e-01 5.687e-01 + 5.687e-01 5.860e-01 5.854e-01 5.636e-01 5.237e-01 4.874e-01 + 4.880e-01 5.241e-01 + 5.598e-01 5.854e-01 5.594e-01 4.872e-01 4.089e-01 3.755e-01 + 4.089e-01 4.880e-01 + 5.638e-01 5.636e-01 4.872e-01 3.756e-01 2.999e-01 2.998e-01 + 3.755e-01 4.874e-01 + 5.706e-01 5.237e-01 4.089e-01 2.999e-01 2.587e-01 2.999e-01 + 4.089e-01 5.237e-01 + 5.638e-01 4.874e-01 3.755e-01 2.998e-01 2.999e-01 3.756e-01 + 4.872e-01 5.636e-01 + 5.598e-01 4.880e-01 4.089e-01 3.755e-01 4.089e-01 4.872e-01 + 5.594e-01 5.854e-01 + 5.687e-01 5.241e-01 4.880e-01 4.874e-01 5.237e-01 5.636e-01 + 5.854e-01 5.860e-01 + 5.990e-01 5.904e-01 5.855e-01 5.991e-01 5.638e-01 5.239e-01 + 5.238e-01 5.674e-01 + 5.904e-01 5.751e-01 5.848e-01 5.614e-01 4.874e-01 4.510e-01 + 4.885e-01 5.617e-01 + 5.855e-01 5.848e-01 5.517e-01 4.563e-01 3.755e-01 3.751e-01 + 4.565e-01 5.509e-01 + 5.991e-01 5.614e-01 4.563e-01 3.441e-01 2.998e-01 3.441e-01 + 4.563e-01 5.614e-01 + 5.638e-01 4.874e-01 3.755e-01 2.998e-01 2.999e-01 3.756e-01 + 4.872e-01 5.636e-01 + 5.239e-01 4.510e-01 3.751e-01 3.441e-01 3.756e-01 4.510e-01 + 5.239e-01 5.521e-01 + 5.238e-01 4.885e-01 4.565e-01 4.563e-01 4.872e-01 5.239e-01 + 5.444e-01 5.445e-01 + 5.674e-01 5.617e-01 5.509e-01 5.614e-01 5.636e-01 5.521e-01 + 5.445e-01 5.521e-01 + 4.696e-01 3.507e-01 4.756e-01 5.855e-01 5.598e-01 5.238e-01 + 5.600e-01 5.887e-01 + 3.507e-01 4.141e-01 5.180e-01 5.509e-01 4.880e-01 4.885e-01 + 5.495e-01 5.199e-01 + 4.756e-01 5.180e-01 5.365e-01 4.565e-01 4.089e-01 4.565e-01 + 5.365e-01 5.180e-01 + 5.855e-01 5.509e-01 4.565e-01 3.751e-01 3.755e-01 4.563e-01 + 5.517e-01 5.848e-01 + 5.598e-01 4.880e-01 4.089e-01 3.755e-01 4.089e-01 4.872e-01 + 5.594e-01 5.854e-01 + 5.238e-01 4.885e-01 4.565e-01 4.563e-01 4.872e-01 5.239e-01 + 5.444e-01 5.445e-01 + 5.600e-01 5.495e-01 5.365e-01 5.517e-01 5.594e-01 5.444e-01 + 5.346e-01 5.445e-01 + 5.887e-01 5.199e-01 5.180e-01 5.848e-01 5.854e-01 5.445e-01 + 5.445e-01 5.857e-01 + 8.303e-02 1.488e-01 3.507e-01 5.904e-01 5.687e-01 5.674e-01 + 5.887e-01 3.513e-01 + 1.488e-01 2.344e-01 5.199e-01 5.617e-01 5.241e-01 5.617e-01 + 5.199e-01 2.344e-01 + 3.507e-01 5.199e-01 5.495e-01 4.885e-01 4.880e-01 5.509e-01 + 5.180e-01 4.141e-01 + 5.904e-01 5.617e-01 4.885e-01 4.510e-01 4.874e-01 5.614e-01 + 5.848e-01 5.751e-01 + 5.687e-01 5.241e-01 4.880e-01 4.874e-01 5.237e-01 5.636e-01 + 5.854e-01 5.860e-01 + 5.674e-01 5.617e-01 5.509e-01 5.614e-01 5.636e-01 5.521e-01 + 5.445e-01 5.521e-01 + 5.887e-01 5.199e-01 5.180e-01 5.848e-01 5.854e-01 5.445e-01 + 5.445e-01 5.857e-01 + 3.513e-01 2.344e-01 4.141e-01 5.751e-01 5.860e-01 5.521e-01 + 5.857e-01 5.751e-01 diff --git a/tests/integrate/919_OF_out_elf/result.ref b/tests/integrate/919_OF_out_elf/result.ref new file mode 100644 index 00000000000..f7761f4215f --- /dev/null +++ b/tests/integrate/919_OF_out_elf/result.ref @@ -0,0 +1,7 @@ +etotref -57.93099111619954 +etotperatomref -57.9309911162 +ComparePot1_pass 0 +pointgroupref O_h +spacegroupref O_h +nksibzref 1 +totaltimeref 0.27 diff --git a/tests/integrate/933_NO_H_dzp_ns2_GPU/INPUT b/tests/integrate/933_NO_H_dzp_ns2_GPU/INPUT index a01a8bbb3c8..0f6a5d0ff59 100644 --- a/tests/integrate/933_NO_H_dzp_ns2_GPU/INPUT +++ b/tests/integrate/933_NO_H_dzp_ns2_GPU/INPUT @@ -26,6 +26,6 @@ mixing_beta_mag 0.4 mixing_gg0 0.0 mixing_gg0_mag 0.0 gamma_only 1 -ks_solver genelpa -device cpu +ks_solver cusolver +device gpu nspin 2 diff --git a/tests/integrate/935_NO_Si2_tzdp_ns2_k_GPU/INPUT b/tests/integrate/935_NO_Si2_tzdp_ns2_k_GPU/INPUT index 618cae2cb5a..69c5ba3ceea 100644 --- a/tests/integrate/935_NO_Si2_tzdp_ns2_k_GPU/INPUT +++ b/tests/integrate/935_NO_Si2_tzdp_ns2_k_GPU/INPUT @@ -24,5 +24,5 @@ mixing_type broyden mixing_beta 0.3 gamma_only 0 ks_solver cusolver -device cpu +device gpu nspin 2 diff --git a/tests/integrate/CASES_CPU.txt b/tests/integrate/CASES_CPU.txt index 16b58bfee1e..4c1929ce32b 100644 --- a/tests/integrate/CASES_CPU.txt +++ b/tests/integrate/CASES_CPU.txt @@ -90,6 +90,7 @@ 117_PW_out_pot_nscf 118_PW_CHG_BINARY 118_PW_WFC_BINARY +119_PW_out_elf 120_PW_KP_MD_MSST #120_PW_KP_MD_MSST_level2 120_PW_KP_MD_NPT @@ -102,6 +103,7 @@ 135_PW_15_PK 140_PW_15_SO 140_PW_15_SO_average +140_PW_15_SO_wfcinit 150_PW_15_CR_VDW3 170_PW_MD_1O 170_PW_MD_2O @@ -178,6 +180,7 @@ 216_NO_scan_Si2 217_NO_out_pot 217_NO_out_pot_nscf +219_NO_out_elf 220_NO_KP_MD_MSST #220_NO_KP_MD_MSST_level2 220_NO_KP_MD_NVT @@ -240,6 +243,8 @@ 385_NO_GO_RE_S1_HSE 386_NO_GO_MD_S1_HSE 391_NO_GO_LR +392_NO_GO_LR_HF +393_NO_GO_ULR_HF 401_NP_KP_sp 401_NP_KP_spd #501_NO_neighboring_GaAs512 @@ -345,6 +350,7 @@ 905_OF_FFT_fullpw_off 906_OF_LibxcPBE 907_OF_LPS +919_OF_out_elf 920_OF_MD_LDA 920_OF_MD_LibxcPBE 921_OF_CR_LDA diff --git a/tests/integrate/tools/catch_properties.sh b/tests/integrate/tools/catch_properties.sh index e064ec61e3f..13af75d5df9 100755 --- a/tests/integrate/tools/catch_properties.sh +++ b/tests/integrate/tools/catch_properties.sh @@ -58,6 +58,7 @@ gamma_only=$(get_input_key_value "gamma_only" "INPUT") imp_sol=$(get_input_key_value "imp_sol" "INPUT") run_rpa=$(get_input_key_value "rpa" "INPUT") out_pot=$(get_input_key_value "out_pot" "INPUT") +out_elf=$(get_input_key_value "out_elf" "INPUT") out_dm1=$(get_input_key_value "out_dm1" "INPUT") get_s=$(get_input_key_value "calculation" "INPUT") out_pband=$(get_input_key_value "out_proj_band" "INPUT") @@ -165,6 +166,14 @@ if ! test -z "$out_pot" && [ $out_pot == 2 ]; then echo "ComparePot_pass $?" >>$1 fi +#echo $out_elf +if ! test -z "$out_elf" && [ $out_elf == 1 ]; then + elf1ref=refELF.cube + elf1cal=OUT.autotest/ELF.cube + python3 ../tools/CompareFile.py $elf1ref $elf1cal 3 + echo "ComparePot1_pass $?" >>$1 +fi + #echo $get_s if ! test -z "$get_s" && [ $get_s == "get_S" ]; then sref=refSR.csr @@ -530,7 +539,7 @@ if [ $is_lr == 1 ]; then lr_path=OUT.autotest/running_lr.log lrns=$(get_input_key_value "lr_nstates" "INPUT") lrns1=`echo "$lrns + 1" |bc` - grep -A$lrns1 "Excitation Energy" $lr_path | tail -$lrns | awk '{print $2}' > lr_eig.txt + grep -A$lrns1 "Excitation Energy" $lr_path | awk 'NR > 2 && $2 ~ /^[0-9]+\.[0-9]+$/ {print $2}' > lr_eig.txt lreig_tot=`sum_file lr_eig.txt` echo "totexcitationenergyref $lreig_tot" >>$1 fi diff --git a/toolchain/README.md b/toolchain/README.md index 9f13f6614e1..386efc83133 100644 --- a/toolchain/README.md +++ b/toolchain/README.md @@ -1,6 +1,6 @@ # The ABACUS Toolchain -Version 2024.2 +Version 2024.3 ## Author @@ -108,13 +108,13 @@ The needed dependencies version default: - `cmake` 3.30.0 - `gcc` 13.2.0 (which will always NOT be installed, But use system) -- `OpenMPI` 5.0.5 +- `OpenMPI` 4.1.6 (5.0.5 can be used but have some problem in OpenMP parallel computation in ELPA) - `MPICH` 4.2.2 -- `OpenBLAS` 0.3.27 (Intel toolchain need `get_vars.sh` tool from it) -- `ScaLAPACK` 2.2.1 +- `OpenBLAS` 0.3.28 (Intel toolchain need `get_vars.sh` tool from it) +- `ScaLAPACK` 2.2.1 (a developing version) - `FFTW` 3.3.10 - `LibXC` 6.2.2 -- `ELPA` 2024.03.001 +- `ELPA` 2024.05.001 - `CEREAL` 1.3.2 - `RapidJSON` 1.1.0 And Intel-oneAPI need user or server manager to manually install from Intel. diff --git a/toolchain/build_abacus_gnu.sh b/toolchain/build_abacus_gnu.sh index a5b88316feb..d882b3e996c 100755 --- a/toolchain/build_abacus_gnu.sh +++ b/toolchain/build_abacus_gnu.sh @@ -22,14 +22,15 @@ BUILD_DIR=build_abacus_gnu rm -rf $BUILD_DIR PREFIX=$ABACUS_DIR -LAPACK=$INSTALL_DIR/openblas-0.3.27/lib +LAPACK=$INSTALL_DIR/openblas-0.3.28/lib SCALAPACK=$INSTALL_DIR/scalapack-2.2.1/lib -ELPA=$INSTALL_DIR/elpa-2024.03.001/cpu +ELPA=$INSTALL_DIR/elpa-2024.05.001/cpu FFTW3=$INSTALL_DIR/fftw-3.3.10 CEREAL=$INSTALL_DIR/cereal-1.3.2/include/cereal LIBXC=$INSTALL_DIR/libxc-6.2.2 -# LIBRI=$INSTALL_DIR/LibRI-0.1.1 -# LIBCOMM=$INSTALL_DIR/LibComm-0.1.0 +RAPIDJSON=$INSTALL_DIR/rapidjson-1.1.0/ +# LIBRI=$INSTALL_DIR/LibRI-0.2.1.0 +# LIBCOMM=$INSTALL_DIR/LibComm-0.1.1 # LIBTORCH=$INSTALL_DIR/libtorch-2.1.2/share/cmake/Torch # LIBNPY=$INSTALL_DIR/libnpy-1.0.1/include # DEEPMD=$HOME/apps/anaconda3/envs/deepmd @@ -47,7 +48,8 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DENABLE_LIBXC=ON \ -DUSE_OPENMP=ON \ -DUSE_ELPA=ON \ - -DENABLE_RAPIDJSON=OFF \ + -DENABLE_RAPIDJSON=ON \ + -DRapdidJSON_DIR=$RAPIDJSON \ # -DENABLE_DEEPKS=1 \ # -DTorch_DIR=$LIBTORCH \ # -Dlibnpy_INCLUDE_DIR=$LIBNPY \ @@ -80,6 +82,6 @@ cat << EOF ========================== usage ========================= Done! To use the installed ABACUS version -You need to source $(pwd)/abacus_env.sh first ! +You need to source ${TOOL}/abacus_env.sh first ! """ EOF \ No newline at end of file diff --git a/toolchain/build_abacus_intel-mpich.sh b/toolchain/build_abacus_intel-mpich.sh index e199f049cf1..ac16a7e2ccc 100755 --- a/toolchain/build_abacus_intel-mpich.sh +++ b/toolchain/build_abacus_intel-mpich.sh @@ -23,13 +23,14 @@ BUILD_DIR=build_abacus_intel-mpich rm -rf $BUILD_DIR PREFIX=$ABACUS_DIR -ELPA=$INSTALL_DIR/elpa-2024.03.001/cpu +ELPA=$INSTALL_DIR/elpa-2024.05.001/cpu CEREAL=$INSTALL_DIR/cereal-1.3.2/include/cereal LIBXC=$INSTALL_DIR/libxc-6.2.2 +RAPIDJSON=$INSTALL_DIR/rapidjson-1.1.0/ # LIBTORCH=$INSTALL_DIR/libtorch-2.1.2/share/cmake/Torch # LIBNPY=$INSTALL_DIR/libnpy-1.0.1/include -# LIBRI=$INSTALL_DIR/LibRI-0.1.1 -# LIBCOMM=$INSTALL_DIR/LibComm-0.1.0 +# LIBRI=$INSTALL_DIR/LibRI-0.2.1.0 +# LIBCOMM=$INSTALL_DIR/LibComm-0.1.1 # DEEPMD=$HOME/apps/anaconda3/envs/deepmd cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \ @@ -43,7 +44,8 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DENABLE_LIBXC=ON \ -DUSE_OPENMP=ON \ -DUSE_ELPA=ON \ - -DENABLE_RAPIDJSON=OFF \ + -DENABLE_RAPIDJSON=ON \ + -DRapdidJSON_DIR=$RAPIDJSON \ # -DENABLE_DEEPKS=1 \ # -DTorch_DIR=$LIBTORCH \ # -Dlibnpy_INCLUDE_DIR=$LIBNPY \ @@ -71,6 +73,6 @@ cat << EOF ========================== usage ========================= Done! To use the installed ABACUS version -You need to source $(pwd)/abacus_env.sh first ! +You need to source ${TOOL}/abacus_env.sh first ! """ EOF \ No newline at end of file diff --git a/toolchain/build_abacus_intel.sh b/toolchain/build_abacus_intel.sh index 777c812655e..9e88c53e6a4 100755 --- a/toolchain/build_abacus_intel.sh +++ b/toolchain/build_abacus_intel.sh @@ -23,13 +23,14 @@ BUILD_DIR=build_abacus_intel rm -rf $BUILD_DIR PREFIX=$ABACUS_DIR -ELPA=$INSTALL_DIR/elpa-2024.03.001/cpu +ELPA=$INSTALL_DIR/elpa-2024.05.001/cpu CEREAL=$INSTALL_DIR/cereal-1.3.2/include/cereal LIBXC=$INSTALL_DIR/libxc-6.2.2 +RAPIDJSON=$INSTALL_DIR/rapidjson-1.1.0/ # LIBTORCH=$INSTALL_DIR/libtorch-2.1.2/share/cmake/Torch # LIBNPY=$INSTALL_DIR/libnpy-1.0.1/include -# LIBRI=$INSTALL_DIR/LibRI-0.1.1 -# LIBCOMM=$INSTALL_DIR/LibComm-0.1.0 +# LIBRI=$INSTALL_DIR/LibRI-0.2.1.0 +# LIBCOMM=$INSTALL_DIR/LibComm-0.1.1 # DEEPMD=$HOME/apps/anaconda3/envs/deepmd # if use deepks and deepmd @@ -44,7 +45,8 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DENABLE_LIBXC=ON \ -DUSE_OPENMP=ON \ -DUSE_ELPA=ON \ - -DENABLE_RAPIDJSON=OFF \ + -DENABLE_RAPIDJSON=ON \ + -DRapidJSON_DIR=$RAPIDJSON \ # -DENABLE_DEEPKS=1 \ # -DTorch_DIR=$LIBTORCH \ # -Dlibnpy_INCLUDE_DIR=$LIBNPY \ @@ -72,6 +74,6 @@ cat << EOF ========================== usage ========================= Done! To use the installed ABACUS version -You need to source $(pwd)/abacus_env.sh first ! +You need to source ${TOOL}/abacus_env.sh first ! """ EOF \ No newline at end of file diff --git a/toolchain/scripts/VERSION b/toolchain/scripts/VERSION index a6faad3be89..bce1d6fc015 100644 --- a/toolchain/scripts/VERSION +++ b/toolchain/scripts/VERSION @@ -1,2 +1,2 @@ # version file to force a rebuild of the entire toolchain -VERSION="2024.2" +VERSION="2024.3" diff --git a/toolchain/scripts/get_openblas_arch.sh b/toolchain/scripts/get_openblas_arch.sh index 70b492d576c..4104ff821c2 100755 --- a/toolchain/scripts/get_openblas_arch.sh +++ b/toolchain/scripts/get_openblas_arch.sh @@ -8,8 +8,8 @@ [ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0 SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")" && pwd -P)" -openblas_ver="0.3.27" # Keep in sync with install_openblas.sh -openblas_sha256="aa2d68b1564fe2b13bc292672608e9cdeeeb6dc34995512e65c3b10f4599e897" +openblas_ver="0.3.28" # Keep in sync with install_openblas.sh +openblas_sha256="f1003466ad074e9b0c8d421a204121100b0751c96fc6fcf3d1456bd12f8a00a1" openblas_pkg="OpenBLAS-${openblas_ver}.tar.gz" source "${SCRIPT_DIR}"/common_vars.sh diff --git a/toolchain/scripts/stage0/install_cmake.sh b/toolchain/scripts/stage0/install_cmake.sh index a76472901bb..b16c9719b2c 100755 --- a/toolchain/scripts/stage0/install_cmake.sh +++ b/toolchain/scripts/stage0/install_cmake.sh @@ -36,17 +36,18 @@ case "${with_cmake}" in pkg_install_dir="${INSTALLDIR}/cmake-${cmake_ver}" #pkg_install_dir="${HOME}/apps/cmake/${cmake_ver}" install_lock_file="$pkg_install_dir/install_successful" + cmake_pkg="cmake-${cmake_ver}-${cmake_arch}.sh" if verify_checksums "${install_lock_file}"; then echo "cmake-${cmake_ver} is already installed, skipping it." else - if [ -f cmake-${cmake_ver}-${cmake_arch}.sh ]; then - echo "cmake-${cmake_ver}-${cmake_arch}.sh is found" + if [ -f $cmake_pkg ]; then + echo "$cmake_pkg is found" else - download_pkg_from_ABACUS_org "${cmake_sha256}" "cmake-${cmake_ver}-${cmake_arch}.sh" + download_pkg_from_ABACUS_org "${cmake_sha256}" "$cmake_pkg" fi echo "Installing from scratch into ${pkg_install_dir}" mkdir -p ${pkg_install_dir} - /bin/sh cmake-${cmake_ver}-${cmake_arch}.sh --prefix=${pkg_install_dir} --skip-license > install.log 2>&1 || tail -n ${LOG_LINES} install.log + /bin/sh $cmake_pkg --prefix=${pkg_install_dir} --skip-license > install.log 2>&1 || tail -n ${LOG_LINES} install.log write_checksums "${install_lock_file}" "${SCRIPT_DIR}/stage0/$(basename ${SCRIPT_NAME})" fi ;; diff --git a/toolchain/scripts/stage1/install_openmpi.sh b/toolchain/scripts/stage1/install_openmpi.sh index c5baa47843c..99adfc5bd94 100755 --- a/toolchain/scripts/stage1/install_openmpi.sh +++ b/toolchain/scripts/stage1/install_openmpi.sh @@ -8,10 +8,10 @@ [ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0 SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")/.." && pwd -P)" -openmpi_ver="5.0.5" -openmpi_sha256="6588d57c0a4bd299a24103f4e196051b29e8b55fbda49e11d5b3d32030a32776" -# openmpi_ver="4.1.6" -# openmpi_sha256="f740994485516deb63b5311af122c265179f5328a0d857a567b85db00b11e415" +#openmpi_ver="5.0.5" +#openmpi_sha256="6588d57c0a4bd299a24103f4e196051b29e8b55fbda49e11d5b3d32030a32776" +openmpi_ver="4.1.6" +openmpi_sha256="f740994485516deb63b5311af122c265179f5328a0d857a567b85db00b11e415" openmpi_pkg="openmpi-${openmpi_ver}.tar.bz2" source "${SCRIPT_DIR}"/common_vars.sh @@ -64,6 +64,7 @@ case "${with_openmpi}" in # OpenMPI 5.0 only supports PMIx # PMI support is required for Slurm, but not for other schedulers # default not use + # for OpenMPI 4.1 with pmi slurm, we can open this setting manually # if [ $(command -v srun) ]; then # echo "Slurm installation found. OpenMPI will be configured with --with-pmi." # EXTRA_CONFIGURE_FLAGS="--with-pmi" diff --git a/toolchain/scripts/stage2/install_openblas.sh b/toolchain/scripts/stage2/install_openblas.sh index 18039b20237..6c411edaad1 100755 --- a/toolchain/scripts/stage2/install_openblas.sh +++ b/toolchain/scripts/stage2/install_openblas.sh @@ -8,8 +8,8 @@ [ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0 SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")/.." && pwd -P)" -openblas_ver="0.3.27" # Keep in sync with get_openblas_arch.sh -openblas_sha256="aa2d68b1564fe2b13bc292672608e9cdeeeb6dc34995512e65c3b10f4599e897" +openblas_ver="0.3.28" # Keep in sync with get_openblas_arch.sh +openblas_sha256="f1003466ad074e9b0c8d421a204121100b0751c96fc6fcf3d1456bd12f8a00a1" openblas_pkg="OpenBLAS-${openblas_ver}.tar.gz" source "${SCRIPT_DIR}"/common_vars.sh diff --git a/toolchain/scripts/stage3/install_elpa.sh b/toolchain/scripts/stage3/install_elpa.sh index 24756c43b7e..c077097f36c 100755 --- a/toolchain/scripts/stage3/install_elpa.sh +++ b/toolchain/scripts/stage3/install_elpa.sh @@ -9,8 +9,8 @@ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")/.." && pwd -P)" # From https://elpa.mpcdf.mpg.de/software/tarball-archive/ELPA_TARBALL_ARCHIVE.html -elpa_ver="2024.03.001" -elpa_sha256="41c6cbf56d2dac26443faaba8a77307d261bf511682a64b96e24def77c813622" +elpa_ver="2024.05.001" +elpa_sha256="9caf41a3e600e2f6f4ce1931bd54185179dade9c171556d0c9b41bbc6940f2f6" source "${SCRIPT_DIR}"/common_vars.sh @@ -59,13 +59,15 @@ case "$with_elpa" in echo "elpa-${elpa_ver} is already installed, skipping it." else require_env MATH_LIBS - if [ -f elpa-${elpa_ver}.tar.gz ]; then - echo "elpa-${elpa_ver}.tar.gz is found" + elpa_pkg="elpa-${elpa_ver}.tar.gz" + url="https://elpa.mpcdf.mpg.de/software/tarball-archive/Releases/${elpa_ver}/${elpa_pkg}" + if [ -f ${elpa_pkg} ]; then + echo "${elpa_pkg} is found" else - download_pkg_from_ABACUS_org "${elpa_sha256}" "elpa-${elpa_ver}.tar.gz" + download_pkg_from_url "${elpa_sha256}" "${elpa_pkg}" "${url}" fi [ -d elpa-${elpa_ver} ] && rm -rf elpa-${elpa_ver} - tar -xzf elpa-${elpa_ver}.tar.gz + tar -xzf ${elpa_pkg} # elpa expect FC to be an mpi fortran compiler that is happy # with long lines, and that a bunch of libs can be found diff --git a/toolchain/scripts/stage4/install_libtorch.sh b/toolchain/scripts/stage4/install_libtorch.sh index b29fd7789e3..5320b275399 100755 --- a/toolchain/scripts/stage4/install_libtorch.sh +++ b/toolchain/scripts/stage4/install_libtorch.sh @@ -37,17 +37,17 @@ case "${with_libtorch}" in __INSTALL__) echo "==================== Installing libtorch ====================" dirname="libtorch-${libtorch_ver}" - filename="${dirname}.zip" - pkg_install_dir="${INSTALLDIR}/${filename}" + pkg_install_dir="${INSTALLDIR}/${dirname}" #pkg_install_dir="${HOME}/lib/libtorch/${libtorch_ver}" install_lock_file="${pkg_install_dir}/install_successful" archive_file="libtorch-cxx11-abi-shared-with-deps-${libtorch_ver}%2Bcpu.zip" + filename="${dirname}.zip" if verify_checksums "${install_lock_file}"; then echo "${filename} is already installed, skipping it." else - if [ -f ${archive_file} ]; then - echo "${archive_file} is found" + if [ -f ${filename} ]; then + echo "${filename} is found" else # download from pytorch.com and checksum url=https://download.pytorch.org/libtorch/cpu/${archive_file} diff --git a/toolchain/scripts/stage4/install_rapidjson.sh b/toolchain/scripts/stage4/install_rapidjson.sh index 7883c96943e..bce4d84d6fd 100755 --- a/toolchain/scripts/stage4/install_rapidjson.sh +++ b/toolchain/scripts/stage4/install_rapidjson.sh @@ -55,6 +55,8 @@ case "$with_rapidjson" in tar -xzf $filename mkdir -p "${pkg_install_dir}" cp -r $dirname/* "${pkg_install_dir}/" + # for CMake to find rapidjson + cp ${pkg_install_dir}/RapidJSONConfig.cmake.in ${pkg_install_dir}/RapidJSONConfig.cmake write_checksums "${install_lock_file}" "${SCRIPT_DIR}/stage4/$(basename ${SCRIPT_NAME})" fi ;; diff --git a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.cpp b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.cpp index 7adaef55b26..34813b732b2 100644 --- a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.cpp +++ b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.cpp @@ -27,7 +27,7 @@ void Parallel_Global::myProd(complex *in,complex *inout,int *len } #endif -void Parallel_Global::read_mpi_parameters(int argc,char **argv) +void Parallel_Global::read_pal_param(int argc,char **argv) { #if defined __MPI //for test diff --git a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.h b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.h index 932d8979942..92c6b135f16 100644 --- a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.h +++ b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_parallel/parallel_global.h @@ -18,7 +18,7 @@ extern MPI_Comm POOL_WORLD; namespace Parallel_Global { - void read_mpi_parameters(int argc, char **argv); + void read_pal_param(int argc, char **argv); #ifdef __MPI void myProd(complex *in,complex *inout,int *len,MPI_Datatype *dptr); diff --git a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_spillage/main.cpp b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_spillage/main.cpp index 7be17e4ae12..00baedd818a 100644 --- a/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_spillage/main.cpp +++ b/tools/SIAB/SimulatedAnnealing/backup_old_version/1_Source/src_spillage/main.cpp @@ -19,7 +19,7 @@ int main(int argc, char **argv) // (2) if parallel, prepare. cout << " First read in the parameters from INPUT." << endl; - Parallel_Global::read_mpi_parameters(argc,argv); + Parallel_Global::read_pal_param(argc,argv); // (2) init class input. input.init(); diff --git a/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.cpp b/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.cpp index 166644e802e..0fd079c9e32 100644 --- a/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.cpp +++ b/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.cpp @@ -25,7 +25,7 @@ void Parallel_Global::myProd(complex *in,complex *inout,int *len } #endif -void Parallel_Global::read_mpi_parameters(int argc,char **argv) +void Parallel_Global::read_pal_param(int argc,char **argv) { #if defined __MPI //for test diff --git a/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.h b/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.h index fe51c0d3237..66ad240cba8 100644 --- a/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.h +++ b/tools/SIAB/SimulatedAnnealing/source/src_parallel/parallel_global.h @@ -16,7 +16,7 @@ extern MPI_Comm POOL_WORLD; namespace Parallel_Global { - void read_mpi_parameters(int argc, char **argv); + void read_pal_param(int argc, char **argv); #ifdef __MPI void myProd(complex *in,complex *inout,int *len,MPI_Datatype *dptr); diff --git a/tools/SIAB/SimulatedAnnealing/source/src_spillage/main.cpp b/tools/SIAB/SimulatedAnnealing/source/src_spillage/main.cpp index a5033b34f1c..97b85d202cf 100644 --- a/tools/SIAB/SimulatedAnnealing/source/src_spillage/main.cpp +++ b/tools/SIAB/SimulatedAnnealing/source/src_spillage/main.cpp @@ -20,7 +20,7 @@ int main(int argc, char **argv) // (2) if parallel, prepare. cout << " First read in the parameters from INPUT." << endl; - Parallel_Global::read_mpi_parameters(argc,argv); + Parallel_Global::read_pal_param(argc,argv); // (2) init class input. input.init(); diff --git a/tools/molden/molden.py b/tools/molden/molden.py index a24faf2f079..10745c04992 100644 --- a/tools/molden/molden.py +++ b/tools/molden/molden.py @@ -905,7 +905,8 @@ def moldengen(folder: str, ndigits=3, ngto=7, rel_r=2, fmolden="ABACUS.molden"): import numpy as np files = os.listdir(folder) - assert ("STRU" in files) and ("INPUT" in files) and ("KPT" in files) + assert ("STRU" in files) and ("INPUT" in files) and ("KPT" in files),\ + "STRU, INPUT, KPT files are required in the folder." cwd = os.path.abspath(os.getcwd()) os.chdir(folder) #################### @@ -938,7 +939,8 @@ def moldengen(folder: str, ndigits=3, ngto=7, rel_r=2, fmolden="ABACUS.molden"): elif stru['coord_type'] == "Direct": # in fractional coordinates vec = np.array(stru['lat']['vec']) * stru['lat']['const'] coords = np.dot(coords, vec) - elif stru['coord_type'] == "Cartesian_Angstrom": + elif stru['coord_type'].startswith("Cartesian_angstrom"): + # including *_center_xy, *_center_z, *_center_xyz, ... cases coords *= 0.529177249 else: raise NotImplementedError(f"Unknown coordinate type {stru['coord_type']}")