diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d849396a7d0..5467ae3b311 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -641,7 +641,7 @@ list( source_basis/module_pw/kernels/pw_op.cpp source_hsolver/kernels/hegvd_op.cpp source_hsolver/kernels/bpcg_kernel_op.cpp - source_hsolver/kernels/linear_op.cpp + source_hsolver/module_linalg/kernels/linear_op.cpp source_estate/kernels/elecstate_op.cpp source_base/module_device/device.cpp source_base/module_device/device_helpers.cpp @@ -675,7 +675,7 @@ if(USE_CUDA) source_basis/module_pw/kernels/cuda/pw_op.cu source_hsolver/kernels/cuda/hegvd_op.cu source_hsolver/kernels/cuda/bpcg_kernel_op.cu - source_hsolver/kernels/cuda/linear_op.cu + source_hsolver/module_linalg/kernels/cuda/linear_op.cu source_estate/kernels/cuda/elecstate_op.cu source_base/module_device/cuda/memory_op.cu source_pw/module_pwdft/kernels/cuda/force_op.cu @@ -714,7 +714,7 @@ if(USE_ROCM) source_basis/module_pw/kernels/rocm/pw_op.hip.cu source_hsolver/kernels/rocm/hegvd_op.hip.cu source_hsolver/kernels/rocm/bpcg_kernel_op.hip.cu - source_hsolver/kernels/rocm/linear_op.hip.cu + source_hsolver/module_linalg/kernels/rocm/linear_op.hip.cu source_estate/kernels/rocm/elecstate_op.hip.cu source_base/module_device/rocm/memory_op.hip.cu source_pw/module_pwdft/kernels/rocm/force_op.hip.cu @@ -757,9 +757,11 @@ target_link_libraries( driver esolver hsolver + hsolver_linalg hamilt_general elecstate module_pwdft + module_rt_pw module_proj nao_smoothgen module_ofdft diff --git a/source/Makefile.Objects b/source/Makefile.Objects index b2361a72e26..9145af6c2cd 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -36,6 +36,8 @@ VPATH=./src_global:\ ./source_base/module_fft:\ ./source_esolver:\ ./source_hsolver:\ +./source_hsolver/module_linalg:\ +./source_hsolver/module_linalg/kernels:\ ./source_hsolver/kernels:\ ./source_hsolver/module_genelpa:\ ./source_hsolver/module_pexsi:\ @@ -54,6 +56,7 @@ VPATH=./src_global:\ ./source_hamilt/module_xc/kernels:\ ./source_pw/module_proj:\ ./source_pw/module_pwdft:\ +./source_pw/module_rt:\ ./source_pw/module_ofdft:\ ./source_pw/module_stodft:\ ./source_pw/module_pwdft/kernels:\ @@ -380,7 +383,15 @@ OBJS_GINT=batch_biggrid.o\ OBJS_HAMILT=hamilt_pw.o\ pw_hybrid_nscf.o\ pw_hybrid_source.o\ + td_prop_pw.o\ + td_hamilt_pw.o\ + prop_cn_pw.o\ + prop_etrs_pw.o\ td_history_pw.o\ + td_conserv_pw.o\ + td_endpoint_pw.o\ + td_vel_pw.o\ + td_spin_pw.o\ td_pw.o\ hs_matrix_k.o\ sto_hamilt_pw.o\ @@ -489,7 +500,12 @@ OBJS_HSOLVER=diago_cg.o\ para_lin_tf.o\ hsolver.o\ hsolver_pw.o\ - hsolver_pw_tddft.o\ + cn_solver_pw.o\ + td_orbital_ops.o\ + orb_buffer.o\ + exp_action.o\ + exp_taylor.o\ + exp_lanczos.o\ orthonormal.o\ orthonormal_small.o\ hsolver_lcaopw.o\ @@ -701,6 +717,9 @@ OBJS_IO=module_parameter/input_conv.o\ module_dos/write_dos_pw.o\ module_energy/write_bands.o\ module_energy/td_eij_io.o\ + module_energy/td_eij_pw.o\ + module_ctrl/ctrl_output_td_pw.o\ + module_output/td_conserv_io.o\ module_dos/cal_dos.o\ module_dos/cal_pdos_gamma.o\ module_dos/cal_pdos_multik.o\ @@ -741,8 +760,9 @@ OBJS_IO=module_parameter/input_conv.o\ module_current/td_current_io.o\ module_current/td_current_io_comm.o\ module_current/td_current_pw.o\ + module_current/td_spin_pw_io.o\ td_efield_io.o\ - td_vector_pot_io.o\ + td_vecpot_io.o\ module_chgpot/write_libxc_r.o\ module_chgpot/get_pchg_pw.o\ module_output/output_log.o\ diff --git a/source/source_base/module_container/ATen/kernels/cuda/blas.cu b/source/source_base/module_container/ATen/kernels/cuda/blas.cu index 7f794768ad5..3068ed155e0 100644 --- a/source/source_base/module_container/ATen/kernels/cuda/blas.cu +++ b/source/source_base/module_container/ATen/kernels/cuda/blas.cu @@ -1,9 +1,15 @@ #include +#include #include #include #include +#include +#include +#include +#include + namespace container { namespace kernels { @@ -22,6 +28,86 @@ void destroyGpuBlasHandle() { } } +namespace { +template +__global__ void set_identity(T* matrix, const int n) +{ + const size_t count = static_cast(n) * n; + const size_t stride = static_cast(blockDim.x) * gridDim.x; + for (size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; i < count; i += stride) + { + matrix[i] = i % n == i / n ? T(1) : T(0); + } +} + +template +__global__ void copy_triangle(const T* inverse, T* matrix, const int n, const int lda, const bool upper) +{ + const size_t count = static_cast(n) * n; + const size_t stride = static_cast(blockDim.x) * gridDim.x; + for (size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; i < count; i += stride) + { + const size_t row = i % n; + const size_t column = i / n; + if (upper ? row <= column : row >= column) + { + matrix[column * lda + row] = inverse[i]; + } + } +} +} // namespace + +template +struct lapack_trtri { + void operator()(const char& uplo, const char& diag, const int& n, T* matrix, const int& lda) + { + if (n < 0 || lda < std::max(1, n)) + { + throw std::invalid_argument("trtri: invalid matrix dimensions"); + } + const bool upper = cublas_fill_mode(uplo) == CUBLAS_FILL_MODE_UPPER; + const bool unit_diag = cublas_diag_type(diag) == CUBLAS_DIAG_UNIT; + if (n == 0) + { + return; + } + if (!unit_diag) + { + // TRSM does not report singularity; preserve TRTRI's zero-diagonal rejection. + std::vector diagonal(n); + const size_t pitch = (static_cast(lda) + 1) * sizeof(T); + CHECK_CUDA(cudaMemcpy2D(diagonal.data(), sizeof(T), matrix, pitch, sizeof(T), n, cudaMemcpyDeviceToHost)); + for (int i = 0; i < n; ++i) + { + if (diagonal[i] == T(0)) + { + throw std::runtime_error("trtri: zero diagonal at index " + std::to_string(i + 1)); + } + } + } + + // Solve A * inverse = I without the Xtrtri workspace overrun seen in CUDA 11.8/12.1. + Tensor inverse(DataTypeToEnum::value, DeviceType::GpuDevice, {n, n}); + T* data = inverse.data(); + using CudaType = typename GetTypeThrust::type; + CudaType* cuda_data = reinterpret_cast(data); + CudaType* cuda_matrix = reinterpret_cast(matrix); + const size_t count = static_cast(n) * n; + const size_t blocks_needed = (count + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + const int blocks = std::min(65535, blocks_needed); + set_identity<<>>(cuda_data, n); + CHECK_CUDA(cudaGetLastError()); + cuBlasConnector::trsm(cublas_handle, uplo, diag, n, matrix, lda, data); + copy_triangle<<>>(cuda_data, cuda_matrix, n, lda, upper); + CHECK_CUDA_SYNC(); + } +}; + +template struct lapack_trtri; +template struct lapack_trtri; +template struct lapack_trtri, DEVICE_GPU>; +template struct lapack_trtri, DEVICE_GPU>; + template struct blas_nrm2 { using Real = typename GetTypeReal::type; diff --git a/source/source_base/module_container/ATen/kernels/cuda/lapack.cu b/source/source_base/module_container/ATen/kernels/cuda/lapack.cu index 4c69973b6be..722ffb99452 100644 --- a/source/source_base/module_container/ATen/kernels/cuda/lapack.cu +++ b/source/source_base/module_container/ATen/kernels/cuda/lapack.cu @@ -67,22 +67,6 @@ struct set_matrix { // --- 1. Matrix Decomposition --- -template -struct lapack_trtri { - void operator()( - const char& uplo, - const char& diag, - const int& dim, - T* Mat, - const int& lda) - { - // TODO: trtri is not implemented in this method yet - // Cause the trtri in cuSolver is not stable for ABACUS! - cuSolverConnector::trtri(cusolver_handle, uplo, diag, dim, Mat, lda); - // cuSolverConnector::potri(cusolver_handle, uplo, diag, dim, Mat, lda); - } -}; - template struct lapack_potrf { void operator()( @@ -343,11 +327,6 @@ template struct set_matrix; template struct set_matrix, DEVICE_GPU>; template struct set_matrix, DEVICE_GPU>; -template struct lapack_trtri; -template struct lapack_trtri; -template struct lapack_trtri, DEVICE_GPU>; -template struct lapack_trtri, DEVICE_GPU>; - template struct lapack_potrf; template struct lapack_potrf; template struct lapack_potrf, DEVICE_GPU>; diff --git a/source/source_base/module_container/base/third_party/blas.h b/source/source_base/module_container/base/third_party/blas.h index 1fdbac67b2b..1345a442cab 100644 --- a/source/source_base/module_container/base/third_party/blas.h +++ b/source/source_base/module_container/base/third_party/blas.h @@ -141,6 +141,15 @@ namespace container { // Usage example: BlasConnector::functionname(parameter list). namespace BlasConnector { +// Column-major rank-one update; preserve the supplied vector strides and leading dimension. +static inline +void ger(const int m, const int n, const double alpha, + const double* x, const int incx, const double* y, const int incy, + double* a, const int lda) +{ + dger_(&m, &n, &alpha, x, &incx, y, &incy, a, &lda); +} + static inline void axpy( const int& n, const float& alpha, const float *x, const int& incx, float *y, const int& incy) { diff --git a/source/source_base/module_container/base/third_party/cublas.h b/source/source_base/module_container/base/third_party/cublas.h index fabc32e9836..bbf8c6f34bf 100644 --- a/source/source_base/module_container/base/third_party/cublas.h +++ b/source/source_base/module_container/base/third_party/cublas.h @@ -8,6 +8,50 @@ namespace container { namespace cuBlasConnector { +static inline +void trsm(cublasHandle_t& handle, const char uplo, const char diag, const int n, + const float* matrix, const int lda, float* inverse) +{ + const float one = 1.0f; + const cublasFillMode_t triangle = cublas_fill_mode(uplo); + const cublasDiagType_t diagonal = cublas_diag_type(diag); + CHECK_CUBLAS(cublasStrsm(handle, CUBLAS_SIDE_LEFT, triangle, CUBLAS_OP_N, diagonal, n, n, &one, matrix, lda, inverse, n)); +} + +static inline +void trsm(cublasHandle_t& handle, const char uplo, const char diag, const int n, + const double* matrix, const int lda, double* inverse) +{ + const double one = 1.0; + const cublasFillMode_t triangle = cublas_fill_mode(uplo); + const cublasDiagType_t diagonal = cublas_diag_type(diag); + CHECK_CUBLAS(cublasDtrsm(handle, CUBLAS_SIDE_LEFT, triangle, CUBLAS_OP_N, diagonal, n, n, &one, matrix, lda, inverse, n)); +} + +static inline +void trsm(cublasHandle_t& handle, const char uplo, const char diag, const int n, + const std::complex* matrix, const int lda, std::complex* inverse) +{ + const cuComplex one = make_cuComplex(1.0f, 0.0f); + const cublasFillMode_t triangle = cublas_fill_mode(uplo); + const cublasDiagType_t diagonal = cublas_diag_type(diag); + const cuComplex* cuda_matrix = reinterpret_cast(matrix); + cuComplex* cuda_inverse = reinterpret_cast(inverse); + CHECK_CUBLAS(cublasCtrsm(handle, CUBLAS_SIDE_LEFT, triangle, CUBLAS_OP_N, diagonal, n, n, &one, cuda_matrix, lda, cuda_inverse, n)); +} + +static inline +void trsm(cublasHandle_t& handle, const char uplo, const char diag, const int n, + const std::complex* matrix, const int lda, std::complex* inverse) +{ + const cuDoubleComplex one = make_cuDoubleComplex(1.0, 0.0); + const cublasFillMode_t triangle = cublas_fill_mode(uplo); + const cublasDiagType_t diagonal = cublas_diag_type(diag); + const cuDoubleComplex* cuda_matrix = reinterpret_cast(matrix); + cuDoubleComplex* cuda_inverse = reinterpret_cast(inverse); + CHECK_CUBLAS(cublasZtrsm(handle, CUBLAS_SIDE_LEFT, triangle, CUBLAS_OP_N, diagonal, n, n, &one, cuda_matrix, lda, cuda_inverse, n)); +} + static inline void copy(cublasHandle_t& handle, const int& n, const float *x, const int& incx, float *y, const int& incy) { diff --git a/source/source_base/module_container/base/third_party/cusolver.h b/source/source_base/module_container/base/third_party/cusolver.h index ac370679b0c..968db605071 100644 --- a/source/source_base/module_container/base/third_party/cusolver.h +++ b/source/source_base/module_container/base/third_party/cusolver.h @@ -29,48 +29,6 @@ struct CudaDeleter { template using unique_cuda_ptr = std::unique_ptr; -struct HostDeleter { - void operator()(void* ptr) const noexcept { - if (ptr) free(ptr); - } -}; - -template -using unique_host_ptr = std::unique_ptr; - -#if CUDA_VERSION >= 11000 -// Generic API (CUDA 11.0+) -template -static inline -void trtri (cusolverDnHandle_t& cusolver_handle, const char& uplo, const char& diag, const int& n, T* A, const int& lda) -{ - size_t d_lwork = 0, h_lwork = 0; - using Type = typename GetTypeThrust::type; - CHECK_CUSOLVER(cusolverDnXtrtri_bufferSize(cusolver_handle, cublas_fill_mode(uplo), cublas_diag_type(diag), n, GetTypeCuda::cuda_data_type, reinterpret_cast(A), lda, &d_lwork, &h_lwork)); - void* raw_d_work = nullptr; - CHECK_CUDA(cudaMalloc((void**)&raw_d_work, d_lwork)); - unique_cuda_ptr d_work(raw_d_work); - unique_host_ptr h_work; - if (h_lwork) { - void* raw_h_work = malloc(h_lwork); - if (raw_h_work == nullptr) { - throw std::bad_alloc(); - } - h_work.reset(raw_h_work); - } - int h_info = 0; - int* raw_d_info = nullptr; - CHECK_CUDA(cudaMalloc((void**)&raw_d_info, sizeof(int))); - unique_cuda_ptr d_info(raw_d_info); - CHECK_CUSOLVER(cusolverDnXtrtri(cusolver_handle, cublas_fill_mode(uplo), cublas_diag_type(diag), n, GetTypeCuda::cuda_data_type, reinterpret_cast(A), n, d_work.get(), d_lwork, h_work.get(), h_lwork, d_info.get())); - CHECK_CUDA(cudaMemcpy(&h_info, d_info.get(), sizeof(int), cudaMemcpyDeviceToHost)); - if (h_info != 0) { - throw std::runtime_error("trtri: failed to invert matrix"); - } -} -#else -#error "CUDA version < 11.0 is not supported. cusolverDnXtrtri (CUDA 11.0+) is required." -#endif static inline void potri (cusolverDnHandle_t& cusolver_handle, const char& uplo, const char& diag, const int& n, float * A, const int& lda) diff --git a/source/source_base/module_container/base/third_party/lapack.h b/source/source_base/module_container/base/third_party/lapack.h index f413cb31dec..1bb3a25bebc 100644 --- a/source/source_base/module_container/base/third_party/lapack.h +++ b/source/source_base/module_container/base/third_party/lapack.h @@ -48,10 +48,22 @@ int ilaenv_(const int* ispec, const char* name, const char* opts, // Symmetric/Hermitian eigenproblems (QR algorithm) void dsyev_(const char* jobz, const char* uplo, const int* n, double* a, const int* lda, double* w, double* work, const int* lwork, int* info); +void cheev_(const char* jobz, const char* uplo, const int* n, std::complex* a, + const int* lda, float* w, std::complex* work, const int* lwork, + float* rwork, int* info); void zheev_(const char* jobz, const char* uplo, const int* n, std::complex* a, const int* lda, double* w, std::complex* work, const int* lwork, double* rwork, int* info); +// Generalized symmetric/Hermitian eigenproblems (QR algorithm) +void dsygv_(const int* itype, const char* jobz, const char* uplo, const int* n, + double* a, const int* lda, double* b, const int* ldb, double* w, + double* work, const int* lwork, int* info); +void zhegv_(const int* itype, const char* jobz, const char* uplo, const int* n, + std::complex* a, const int* lda, std::complex* b, + const int* ldb, double* w, std::complex* work, + const int* lwork, double* rwork, int* info); + // General nonsymmetric eigenproblems void dgeev_(const char* jobvl, const char* jobvr, const int* n, double* a, const int* lda, double* wr, double* wi, double* vl, const int* ldvl, double* vr, @@ -381,12 +393,34 @@ void heev(const char jobz, const char uplo, const int n, double* a, const int ld dsyev_(&jobz, &uplo, &n, a, &lda, w, work, &lwork, &info); } static inline +void heev(const char jobz, const char uplo, const int n, std::complex* a, const int lda, + float* w, std::complex* work, const int lwork, float* rwork, int& info) +{ + cheev_(&jobz, &uplo, &n, a, &lda, w, work, &lwork, rwork, &info); +} +static inline void heev(const char jobz, const char uplo, const int n, std::complex* a, const int lda, double* w, std::complex* work, const int lwork, double* rwork, int& info) { zheev_(&jobz, &uplo, &n, a, &lda, w, work, &lwork, rwork, &info); } +// Column-major generalized eigenproblems; preserve uplo, workspace queries, and info. +static inline +void hegv(const int itype, const char jobz, const char uplo, const int n, + double* a, const int lda, double* b, const int ldb, double* w, + double* work, const int lwork, int& info) +{ + dsygv_(&itype, &jobz, &uplo, &n, a, &lda, b, &ldb, w, work, &lwork, &info); +} +static inline +void hegv(const int itype, const char jobz, const char uplo, const int n, + std::complex* a, const int lda, std::complex* b, const int ldb, + double* w, std::complex* work, const int lwork, double* rwork, int& info) +{ + zhegv_(&itype, &jobz, &uplo, &n, a, &lda, b, &ldb, w, work, &lwork, rwork, &info); +} + // wrap function of fortran lapack routine zheevx. static inline void heevx(const char jobz, const char range, const char uplo, const int n, diff --git a/source/source_base/module_device/rocm/memory_op.hip.cu b/source/source_base/module_device/rocm/memory_op.hip.cu index 56eb6f06b70..6b3f1c9d3e9 100644 --- a/source/source_base/module_device/rocm/memory_op.hip.cu +++ b/source/source_base/module_device/rocm/memory_op.hip.cu @@ -58,6 +58,16 @@ void set_memory_op::operator()(FPTYPE* arr, hipErrcheck(hipMemset(arr, var, sizeof(FPTYPE) * size)); } +template +void set_memory_2d_op::operator()(FPTYPE* arr, + const size_t pitch, + const int var, + const size_t width, + const size_t height) +{ + hipErrcheck(hipMemset2D(arr, sizeof(FPTYPE) * pitch, var, sizeof(FPTYPE) * width, height)); +} + template void synchronize_memory_op::operator()( FPTYPE* arr_out, @@ -244,6 +254,12 @@ template struct cast_memory_op, base_device::DEVICE_CPU, base_device::DEVICE_GPU>; +template struct set_memory_2d_op; +template struct set_memory_2d_op; +template struct set_memory_2d_op; +template struct set_memory_2d_op, base_device::DEVICE_GPU>; +template struct set_memory_2d_op, base_device::DEVICE_GPU>; + template struct delete_memory_op; template struct delete_memory_op; template struct delete_memory_op; @@ -255,4 +271,4 @@ template struct delete_memory_op*, base_device::DEVICE_GPU>; template struct delete_memory_op*, base_device::DEVICE_GPU>; } // namespace memory -} // end of namespace base_device \ No newline at end of file +} // end of namespace base_device diff --git a/source/source_base/module_external/blacs_connector.h b/source/source_base/module_external/blacs_connector.h index 4a60c94141f..d24c2667849 100644 --- a/source/source_base/module_external/blacs_connector.h +++ b/source/source_base/module_external/blacs_connector.h @@ -64,6 +64,31 @@ extern "C" void Cigsum2d(int ConTxt, char *scope, char *top, int m, int n, int *A, int lda, int rdest, int cdest); } +class BlacsConnector +{ +public: + static inline void get(int context, int what, int& value) + { + Cblacs_get(context, what, &value); + } + + static inline void pinfo(int& rank, int& size) + { + Cblacs_pinfo(&rank, &size); + } + + // BLACS reads usermap in column-major order with the supplied leading dimension. + static inline void gridmap(int& context, int* usermap, int ldumap, int nprow, int npcol) + { + Cblacs_gridmap(&context, usermap, ldumap, nprow, npcol); + } + + static inline void gridinfo(int context, int& nprow, int& npcol, int& myprow, int& mypcol) + { + Cblacs_gridinfo(context, &nprow, &npcol, &myprow, &mypcol); + } +}; + // unified interface for broadcast template void Cxgebs2d(int ConTxt, char *scope, char *top, int m, int n, T *A, int lda) diff --git a/source/source_base/module_external/blas_connector.h b/source/source_base/module_external/blas_connector.h index 22f9f99212d..e78c4a00843 100644 --- a/source/source_base/module_external/blas_connector.h +++ b/source/source_base/module_external/blas_connector.h @@ -454,7 +454,7 @@ class BlasConnector namespace BlasUtils{ - static cublasHandle_t cublas_handle = nullptr; + extern cublasHandle_t cublas_handle; void createGpuBlasHandle(); // Create a cublas/hipblas handle. diff --git a/source/source_base/module_external/blas_connector_base.cpp b/source/source_base/module_external/blas_connector_base.cpp index be0bc342c00..0c041753e25 100644 --- a/source/source_base/module_external/blas_connector_base.cpp +++ b/source/source_base/module_external/blas_connector_base.cpp @@ -11,6 +11,8 @@ namespace BlasUtils{ + cublasHandle_t cublas_handle = nullptr; + void createGpuBlasHandle(){ if (cublas_handle == nullptr) { CHECK_CUBLAS(cublasCreate(&cublas_handle)); @@ -74,4 +76,4 @@ namespace BlasUtils{ } // namespace BlasUtils -#endif \ No newline at end of file +#endif diff --git a/source/source_base/module_external/scalapack_connector.h b/source/source_base/module_external/scalapack_connector.h index bf1928fb972..b9fc79c0fee 100644 --- a/source/source_base/module_external/scalapack_connector.h +++ b/source/source_base/module_external/scalapack_connector.h @@ -232,6 +232,14 @@ extern "C" class ScalapackConnector { public: + // Preserve the block-cyclic descriptor layout and local column-major leading dimension. + static inline + void descinit(int* desc, const int m, const int n, const int mb, const int nb, + const int irsrc, const int icsrc, const int ictxt, const int lld, int& info) + { + descinit_(desc, &m, &n, &mb, &nb, &irsrc, &icsrc, &ictxt, &lld, &info); + } + static inline void geadd( const char transa, diff --git a/source/source_cell/cif_io.h b/source/source_cell/cif_io.h index 538a04a678c..6c6e3e426c9 100644 --- a/source/source_cell/cif_io.h +++ b/source/source_cell/cif_io.h @@ -65,7 +65,7 @@ namespace ModuleIO * ... * NOTE1: only keys in table will have value with length larger than 1, otherwise all words will be * saved in the only element in std::vector. For example please see unittest of this - * class at source/source_io/test/cif_io_test.cpp. + * class at source/source_cell/test/cif_io_test.cpp. * NOTE2: One should note that for some cif files, the number will be in the format like * "0.00000000(1)", which means the uncertainty of the number is 1 in the last digit. * In this case, user should be careful to convert the string to double by its own. @@ -191,4 +191,4 @@ namespace ModuleIO std::map> raw_; }; } // namespace ModuleIO -#endif // MODULE_IO_CIF_IO_H \ No newline at end of file +#endif // MODULE_IO_CIF_IO_H diff --git a/source/source_esolver/esolver_fp.cpp b/source/source_esolver/esolver_fp.cpp index 149f50dc8cb..070e860f388 100644 --- a/source/source_esolver/esolver_fp.cpp +++ b/source/source_esolver/esolver_fp.cpp @@ -278,46 +278,23 @@ void ESolver_FP::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& { if (iter % this->inp_->out_freq_elec == 0 || iter == this->inp_->scf_nmax || conv_esolver) { - for (int is = 0; is < this->inp_->nspin; is++) - { - this->pw_rhod->real2recip(this->chr.rho_save[is], this->chr.rhog_save[is]); - } - // Temporary bridge: use factory until ParaCollection is wired into driver. - Parallel::ParaWorld pw_world = Parallel::make_pw_world(); - // Only pool 0 writes the rhog file (rhog is identical across pools). - if (GlobalV::MY_POOL == 0) - { - module_charge::write_rhog(PARAM.globalv.global_out_dir + this->inp_->suffix + "-CHARGE-DENSITY.restart", - PARAM.globalv.gamma_only_pw, - this->pw_rhod, - this->inp_->nspin, - ucell.GT, - this->chr.rhog_save, - pw_world, - &GlobalV::ofs_warning); - } - - if (XC_Functional::get_ked_flag()) - { - std::vector> kin_g_space(this->inp_->nspin * this->chr.ngmc, {0.0, 0.0}); - std::vector*> kin_g; - for (int is = 0; is < this->inp_->nspin; is++) - { - kin_g.push_back(kin_g_space.data() + is * this->chr.ngmc); - this->pw_rhod->real2recip(this->chr.kin_r_save[is], kin_g[is]); - } - if (GlobalV::MY_POOL == 0) - { - module_charge::write_rhog(PARAM.globalv.global_out_dir + this->inp_->suffix + "-TAU-DENSITY.restart", - PARAM.globalv.gamma_only_pw, - this->pw_rhod, - this->inp_->nspin, - ucell.GT, - kin_g.data(), - pw_world, - &GlobalV::ofs_warning); - } - } + const System_para& system = PARAM.globalv; + const bool write_restart = this->inp_->out_chg[0] != -1; + const std::string prefix = system.global_out_dir + this->inp_->suffix; + const bool write_tau = XC_Functional::get_ked_flag(); + const bool writer_pool = GlobalV::MY_POOL == 0; + const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); + module_charge::write_density_restart(this->chr, + *this->pw_rhod, + ucell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); } } } diff --git a/source/source_esolver/esolver_ks.cpp b/source/source_esolver/esolver_ks.cpp index 9d12dfe07dd..d81f3bf435c 100644 --- a/source/source_esolver/esolver_ks.cpp +++ b/source/source_esolver/esolver_ks.cpp @@ -1,5 +1,6 @@ #include "esolver_ks.h" #include "source_base/timer_wrapper.h" +#include "source_base/module_parallel/para_bridge.h" // for jason output information #include "source_io/module_json/output_info.h" @@ -9,6 +10,7 @@ #include "source_estate/module_charge/chg_drho.h" // module_charge::cal_drho/cal_dkin #include "source_estate/module_charge/chg_init.h" // module_charge::InitRhoCfg #include "source_estate/module_charge/chg_tools.h" // module_charge::check_rho +#include "source_estate/module_charge/chg_rhog_io.h" #include "source_pw/module_pwdft/setup_pwwfc.h" // mohan add 20251018 #include "source_hsolver/hsolver.h" #include "source_io/module_energy/write_eig_occ.h" @@ -181,9 +183,24 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) this->before_scf(ucell, istep); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT SCF"); + const int iter_limit = this->scf_iter_limit(istep); + const bool converged = this->scf_loop(ucell, istep, iter_limit); + this->after_scf(ucell, istep, converged); + this->conv_esolver = converged; + ModuleBase::timer::end(this->classname, "runner"); +} + +int ESolver_KS::scf_iter_limit(const int istep) const +{ + return this->maxniter; +} + +bool ESolver_KS::scf_loop(UnitCell& ucell, int istep, int iter_limit) +{ + ModuleBase::timer::start("ESolver_KS", "scf_loop"); // 2) SCF iterations bool conv_esolver = false; - this->niter = this->maxniter; + this->niter = iter_limit; this->diag_ethr = this->inp_->pw_diag_thr; this->scf_nmax_flag = false; // mohan add 2025-09-21 this->scf_rerun_ = false; // clear any stale rerun request before the loop @@ -191,9 +208,9 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) int iter = 1; int rerun_count = 0; const int max_rerun = 100; // safety net: EXX rerun should never exceed this - while (iter <= this->maxniter) + while (iter <= iter_limit) { - if(iter == this->maxniter) + if(iter == iter_limit) { this->scf_nmax_flag=true; } @@ -211,7 +228,7 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) if (conv_esolver || this->oscillate_esolver) { this->niter = iter; - if (this->oscillate_esolver) + if (this->oscillate_esolver && !this->defer_iter_output(istep)) { std::cout << " !! Density oscillation is found, STOP HERE !!" << std::endl; } @@ -242,13 +259,9 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) ++iter; } // end scf iterations - // 7) after scf - this->after_scf(ucell, istep, conv_esolver); - this->conv_esolver = conv_esolver; - - ModuleBase::timer::end(this->classname, "runner"); - return; -}; + ModuleBase::timer::end("ESolver_KS", "scf_loop"); + return conv_esolver; +} void ESolver_KS::before_scf(UnitCell& ucell, const int istep) { @@ -293,8 +306,14 @@ ESolver_KS::DensityStage ESolver_KS::density_stage(const int istep, const int it return DensityStage::standard; } +bool ESolver_KS::defer_iter_output(const int istep) const +{ + return false; +} + void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool &conv_esolver) { + const int iter_limit = this->scf_iter_limit(istep); // 1.1) print out band gap if (!PARAM.globalv.two_fermi) @@ -307,15 +326,11 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & } // 1.2) print out eigenvalues and occupations - if (this->inp_->out_band[0]) + if (this->inp_->out_band[0] && !this->defer_iter_output(istep)) { - if (iter % this->inp_->out_freq_elec == 0 || iter == this->inp_->scf_nmax || conv_esolver) + if (iter % this->inp_->out_freq_elec == 0 || iter == iter_limit || conv_esolver) { - ModuleIO::write_eig_iter(this->pelec->ekb, - this->pelec->wg, - *this->pelec->klist, - this->inp_->nbands, - this->inp_->nspin); + this->write_iter_bands(); } } @@ -336,6 +351,7 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & #endif module_charge::ScfMixingCtx ctx; + ctx.iter_limit = iter_limit; ctx.hsolver_error = hsolver_error; ctx.scf_thr = this->scf_thr; ctx.scf_ene_thr = this->scf_ene_thr; @@ -391,26 +407,60 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & p_chgmix->get_mixing_config(), ucell.omega); } - // Iter finish - ESolver_FP::iter_finish(ucell, istep, iter, conv_esolver); - + // Iter finish + const bool output_charge = iter % this->inp_->out_freq_elec == 0 || conv_esolver || iter == iter_limit; + if (!this->defer_iter_output(istep) && output_charge) + { + const System_para& system = PARAM.globalv; + const bool write_restart = this->inp_->out_chg[0] != -1; + const std::string prefix = system.global_out_dir + this->inp_->suffix; + const bool write_tau = XC_Functional::get_ked_flag(); + const bool writer_pool = GlobalV::MY_POOL == 0; + const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); + module_charge::write_density_restart(this->chr, + *this->pw_rhod, + ucell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); + } // the end, print time double duration = ModuleBase::get_duration(iter_time, ModuleBase::get_time()); // print energies - elecstate::print_etot(ucell.magnet, *pelec, conv_esolver, iter, drho, + elecstate::print_etot(ucell.magnet, *pelec, conv_esolver, iter, iter_limit, drho, dkin, duration, *this->inp_, PARAM.globalv.two_fermi, diag_ethr, 0, true, this->ds_rms_); + if (!this->defer_iter_output(istep)) + { + this->record_iteration(ucell, duration); + } +} + +void ESolver_KS::write_iter_bands() +{ + if (this->inp_->out_band[0]) + { + ModuleIO::write_eig_iter(this->pelec->ekb, this->pelec->wg, *this->pelec->klist, + this->inp_->nbands, this->inp_->nspin); + } +} + +void ESolver_KS::record_iteration(const UnitCell& ucell, double duration) +{ #ifdef __JSON - // add Json of scf mag Json::add_output_scf_mag(ucell.magnet.tot_mag, ucell.magnet.abs_mag, this->pelec->f_en.etot * ModuleBase::Ry_to_eV, this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV, drho, duration); #endif //__JSON - } //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index 29001c4180a..6fde06b0d33 100644 --- a/source/source_esolver/esolver_ks.h +++ b/source/source_esolver/esolver_ks.h @@ -32,6 +32,16 @@ class ESolver_KS : public ESolver_FP virtual void after_all_runners(BaseCell& basecell) override; protected: + //! Maximum SCF iterations for the current electronic step. + virtual int scf_iter_limit(const int istep) const; + + /** @brief Run SCF iterations without preparing or committing a physical endpoint. */ + bool scf_loop(UnitCell& ucell, int istep, int iter_limit); + /** @brief Record an accepted iteration in JSON without changing its convergence status. */ + void record_iteration(const UnitCell& ucell, double duration); + /** @brief Write current band expectations when iterative band output is requested. */ + void write_iter_bands(); + /** @brief Select whether the density is an endpoint predictor or an SCF iterate. */ enum class DensityStage { @@ -48,6 +58,9 @@ class ESolver_KS : public ESolver_FP //! Something to do before hamilt2rho function in each iter loop. virtual void iter_init(UnitCell& ucell, const int istep, const int iter); + //! Whether KS iterations defer output until the final state is accepted. + virtual bool defer_iter_output(const int istep) const; + //! Something to do after hamilt2rho function in each iter loop. virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index 2622e593074..f476cf78d90 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -474,7 +474,9 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const // call iter_init() of ESolver_KS ESolver_KS::iter_init(ucell, istep, iter); - module_charge::chgmixing_ks_lcao(iter, this->p_chgmix, *this->dftu_, this->dmat.dm->get_dmr_ptr(1)->get_nnr(), *this->inp_); + const int iter_limit = this->scf_iter_limit(istep); + const int nnr = this->dmat.dm->get_dmr_ptr(1)->get_nnr(); + module_charge::chgmixing_ks_lcao(iter, iter_limit, this->p_chgmix, *this->dftu_, nnr, *this->inp_); if (iter == 1) { @@ -670,9 +672,10 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& const std::vector>& dm_vec = this->dmat.dm->get_dmk_vec(); // 1) calculate the local occupation number matrix and energy correction in DFT+U + const int iter_limit = this->scf_iter_limit(istep); const DFTU_BASE::OccmatOutputCfg occmat_cfg{this->inp_->out_freq_ion, this->inp_->out_freq_elec, - this->inp_->scf_nmax, + iter_limit, this->inp_->out_occ_mat, this->inp_->dft_plus_u}; // Read globalv values once into locals so the repeated DFT+U call sites @@ -751,7 +754,7 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& // Mix the density matrix after a mixing restart when mixing_dmr is enabled, // except at convergence or the maximum iteration count. - if (iter != this->inp_->scf_nmax && !conv_esolver) + if (iter != iter_limit && !conv_esolver) { if (this->inp_->mixing_restart > 0 && this->p_chgmix->mixing_restart_count > 0 && this->inp_->mixing_dmr) { diff --git a/source/source_esolver/esolver_ks_lcao_tddft.cpp b/source/source_esolver/esolver_ks_lcao_tddft.cpp index ff2b1e06e40..bc4c5bbc448 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.cpp +++ b/source/source_esolver/esolver_ks_lcao_tddft.cpp @@ -7,7 +7,7 @@ #include "source_base/global_variable.h" #include "source_io/module_ctrl/ctrl_output_td.h" #include "source_io/module_efield/td_efield_io.h" -#include "source_io/module_efield/td_vector_pot_io.h" +#include "source_io/module_efield/td_vecpot_io.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" #include "source_io/module_wf/read_wfc_nao.h" @@ -88,7 +88,7 @@ void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell& basecell, c if (inp.init_vecpot) { // An empty directory selects the calculation working directory, not OUT.. - const std::vector> samples = ModuleIO::read_td_vector_pot(""); + const std::vector> samples = ModuleIO::read_td_vecpot(""); td_field_manager_->set_A_samples(samples); } if (inp.mdp.md_restart) @@ -97,15 +97,16 @@ void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell& basecell, c } if (inp.out_efield && GlobalV::MY_RANK == 0) { - ModuleIO::prepare_td_field_output(output_dir, *td_field_manager_, inp.mdp.md_restart); + ModuleIO::prep_td_field_out(output_dir, *td_field_manager_, inp.mdp.md_restart); } if (inp.out_vecpot && GlobalV::MY_RANK == 0) { if (inp.init_vecpot) { - ModuleIO::check_td_vector_pot_paths("", output_dir); + // Reject output that aliases the input file before truncating it. + ModuleIO::check_td_vecpot_paths("", output_dir); } - ModuleIO::prepare_td_vector_pot_output(output_dir, inp.mdp.md_restart); + ModuleIO::prep_td_vecpot_out(output_dir, inp.mdp.md_restart); } // Run before_all_runners in ESolver_KS_LCAO @@ -135,6 +136,13 @@ void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell& basecell, c } } +template +int ESolver_KS_LCAO_TDDFT::scf_iter_limit(const int istep) const +{ + const int initial_step = this->inp_->init_wfc == "file" ? restart_step_ : 0; + return istep > initial_step ? this->inp_->td_scf_nmax : this->inp_->scf_nmax; +} + template void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int istep) { @@ -227,7 +235,7 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist const bool replay_restart = this->inp_->mdp.md_restart && !restart_done; if (this->inp_->out_vecpot && GlobalV::MY_RANK == 0 && !replay_restart) { - ModuleIO::write_td_vector_pot(PARAM.globalv.global_out_dir, this->totstep, td_field_manager_->A_right_ha()); + ModuleIO::write_td_vecpot(PARAM.globalv.global_out_dir, this->totstep, td_field_manager_->A_right_ha()); } ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ax(t)", td_p->endpoint_A()[0]); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ay(t)", td_p->endpoint_A()[1]); @@ -242,7 +250,7 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist const bool replay_restart = this->inp_->mdp.md_restart && !restart_done; if (this->inp_->out_efield && GlobalV::MY_RANK == 0 && !replay_restart) { - ModuleIO::write_td_field_values(*td_field_manager_, PARAM.globalv.global_out_dir); + ModuleIO::write_td_field(*td_field_manager_, PARAM.globalv.global_out_dir); } if (estep != 0) @@ -290,10 +298,13 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist // 2) SCF iterations //---------------------------------------------------------------- bool conv_esolver = false; - this->niter = this->maxniter; + const int iter_limit = this->scf_iter_limit(totstep); + this->niter = iter_limit; + this->scf_nmax_flag = false; this->diag_ethr = this->inp_->pw_diag_thr; - for (int iter = 1; iter <= this->maxniter; ++iter) + for (int iter = 1; iter <= iter_limit; ++iter) { + this->scf_nmax_flag = iter == iter_limit; ModuleIO::write_head_td(GlobalV::ofs_running, istep, totstep, iter, this->basisname); // 2.1) Initialization of the SCF iteration @@ -506,13 +517,19 @@ void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell, ESolver_KS_LCAO, TR>::iter_finish(ucell, istep, iter, conv_esolver); - // Store wave functions, Hamiltonian and overlap matrix, to be used in the next electronic step - // Store when converged or when the maximum iteration count is reached - bool force_save = conv_esolver || (iter == this->maxniter); - this->store_h_s_psi(ucell, istep, iter, force_save); + // Save the endpoint at convergence or the iteration limit for the next electronic step. + const int iter_limit = this->scf_iter_limit(istep); + const bool accept_state = conv_esolver || iter == iter_limit; + this->store_h_s_psi(ucell, istep, iter, accept_state); + + // At an ionic-step boundary, runner exits immediately after replaying the restart endpoint. + // Refresh EDM here before that early exit leads to force and stress calculations. + const bool replay_endpoint = this->inp_->mdp.md_restart && !restart_done && estep == 0 + && restart_step_ % this->inp_->estep_per_md == 0; + const bool last_endpoint = estep == estep_max - 1 || replay_endpoint; - // Calculate the RT-TDDFT energy-density matrix at the last converged substep when required by td_edm and the gauge - if (conv_esolver && estep == estep_max - 1 && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) && this->inp_->td_edm == 0 + // Refresh the energy-density matrix at convergence or the iteration limit for forces and stress. + if (accept_state && last_endpoint && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) && this->inp_->td_edm == 0 && this->inp_->td_stype != 2) { if (use_tensor && use_lapack) diff --git a/source/source_esolver/esolver_ks_lcao_tddft.h b/source/source_esolver/esolver_ks_lcao_tddft.h index b5fa43c01f9..b1401c16da9 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.h +++ b/source/source_esolver/esolver_ks_lcao_tddft.h @@ -33,6 +33,9 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> void before_all_runners(BaseCell& basecell, const Input_para& inp) override; protected: + //! Use the initial-state limit for initialization or restart replay, and the RT limit for propagation. + int scf_iter_limit(const int istep) const override; + //! Return the solver-owned RT state used by LCAO operators and output. TD_info* get_td_info() const override { return td_p; } diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index f1e6c5fa47c..c700eefa055 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -188,6 +188,13 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) this->allocate_hamilt(ucell); //! Setup potentials (local, non-local, spin constraint, DFT-1/2) + psi::Psi, Device>* onsite_psi = nullptr; + const bool spinor_rt = this->inp_->esolver_type == "tddft" && this->inp_->nspin == 4; + if (this->inp_->onsite_radius > 0 && !spinor_rt) + { + this->stp.update_psi_d(); + onsite_psi = this->stp.template get_psi_d(); + } pw::setup_pot(istep, ucell, this->kv, @@ -199,6 +206,7 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) this->ppcell, this->vsep_cell, this->stp.template get_psi_t(), + onsite_psi, this->p_hamilt, this->pw_wfc, this->pw_rhod, @@ -243,7 +251,8 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const mag_converged = sc.mag_converged(); } - module_charge::chgmixing_ks_pw(iter, this->p_chgmix, *this->dftu_, mag_converged, *this->inp_); + const int iter_limit = this->scf_iter_limit(istep); + module_charge::chgmixing_ks_pw(iter, iter_limit, this->p_chgmix, *this->dftu_, mag_converged, *this->inp_); // mohan move harris functional here, 2012-06-05 // use 'rho(in)' and 'v_h and v_xc'(in) @@ -253,7 +262,7 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const // should before lambda loop in DeltaSpin const DFTU_BASE::OccmatOutputCfg init_occmat_cfg{this->inp_->out_freq_ion, this->inp_->out_freq_elec, - this->inp_->scf_nmax, + iter_limit, this->inp_->out_occ_mat, this->inp_->dft_plus_u}; DFTU_BASE::iter_init_dftu_pw(iter, @@ -392,9 +401,10 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int // first step (istep 0, iter 1) the PW occupation matrix does not exist // yet (iter_init_dftu_pw returns before calculating it), so skip it and // keep the previous behavior where occ_mat.txt first appears at iter 2. + const int iter_limit = this->scf_iter_limit(istep); const DFTU_BASE::OccmatOutputCfg occmat_cfg{this->inp_->out_freq_ion, this->inp_->out_freq_elec, - this->inp_->scf_nmax, + iter_limit, this->inp_->out_occ_mat, this->inp_->dft_plus_u}; const DFTU_BASE::OccmatStepInfo occmat_step{istep, @@ -430,7 +440,10 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int DFTU_BASE::SOC_LAYOUT_PAULI); // the output quantities - ModuleIO::ctrl_iter_pw(istep, iter, conv_esolver, this->stp, this->kv, this->pw_wfc, *this->inp_, GlobalV::ofs_running); + if (!this->defer_iter_output(istep)) + { + ModuleIO::ctrl_iter_pw(istep, iter, conv_esolver, this->stp, this->kv, this->pw_wfc, *this->inp_, false, GlobalV::ofs_running); + } } template diff --git a/source/source_esolver/esolver_ks_pw_tddft.cpp b/source/source_esolver/esolver_ks_pw_tddft.cpp index 0008a72f3fe..cec0c4f8e1d 100644 --- a/source/source_esolver/esolver_ks_pw_tddft.cpp +++ b/source/source_esolver/esolver_ks_pw_tddft.cpp @@ -1,28 +1,33 @@ #include "source_esolver/esolver_ks_pw_tddft.h" +#include "source_base/constants.h" #include "source_base/global_function.h" #include "source_base/global_variable.h" -#include "source_base/parallel_comm.h" -#include "source_base/parallel_device.h" -#include "source_base/parallel_reduce.h" +#include "source_base/module_parallel/para_bridge.h" #include "source_base/timer.h" #include "source_estate/elecstate_pw.h" #include "source_estate/elecstate_tools.h" +#include "source_estate/module_charge/chg_rhog_io.h" #include "source_estate/module_charge/chg_symm.h" #include "source_hamilt/hamilt_hs_adapter.h" #include "source_hamilt/module_xc/xc_functional.h" +#include "source_io/module_ctrl/ctrl_output_pw.h" +#include "source_io/module_ctrl/ctrl_output_td_pw.h" #include "source_io/module_efield/td_efield_io.h" -#include "source_io/module_efield/td_vector_pot_io.h" -#include "source_io/module_energy/td_eij_io.h" +#include "source_io/module_efield/td_vecpot_io.h" +#include "source_io/module_energy/td_eij_pw.h" #include "source_io/module_output/output_log.h" +#include "source_io/module_output/td_conserv_io.h" #include "source_io/module_parameter/parameter.h" #include "source_pw/module_pwdft/hamilt_pw.h" -#include "source_pw/module_pwdft/td_pw.h" +#include "source_pw/module_rt/td_endpoint_pw.h" +#include "source_pw/module_rt/td_pw.h" #include #include #include #include +#include namespace ModuleESolver { @@ -42,50 +47,74 @@ void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell& basecell, cons const std::string& output_dir = PARAM.globalv.global_out_dir; this->td_field_manager_ = elecstate::create_td_field_manager(inp); + if (inp.td_max_halvings > 0) + { + const int parts = 1 << inp.td_max_halvings; + for (const elecstate::TDField& field: this->td_field_manager_->fields()) + { + if (field.subdivisions() > std::numeric_limits::max() / parts) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "td_max_halvings exceeds the field sampling integer range."); + } + } + } if (inp.init_vecpot) { // An empty directory selects the calculation working directory, not OUT.. - const std::vector> samples = ModuleIO::read_td_vector_pot(""); + const std::vector> samples = ModuleIO::read_td_vecpot(""); this->td_field_manager_->set_A_samples(samples); } ESolver_KS_PW::before_all_runners(ucell, inp); + // The parent resolves the XC functional, including pseudopotential defaults. - pw::check_td_input(inp, ucell, XC_Functional::get_ked_flag(), this->general_exx_info_.cal_exx); + const int xc_type = XC_Functional::get_func_type(); + pw::check_td_input(inp, ucell, xc_type, this->general_exx_info_.cal_exx); + + current_req_.charge_total = inp.out_current == 1; + current_req_.charge_per_k = current_req_.charge_total && inp.out_current_k; + current_req_.spin_current = inp.nspin == 4 && inp.td_out_spincur; + vel_.initialize(ucell, *this->pw_wfc, this->kv, this->ppcell); + + if (inp.nspin == 4) + { + spin_.initialize(ucell, + *this->pw_rhod, + *this->pw_wfc, + this->kv, + this->sf, + this->ppcell, + inp.td_out_mag, + inp.orbital_dir, + inp.onsite_radius, + inp.td_out_torque); + } + this->pelec->pot->set_td_field_manager(this->td_field_manager_); #ifdef __MPI const hsolver::diag_comm_info comm(this->pw_wfc->pool_world, this->pw_wfc->poolrank, this->pw_wfc->poolnproc); #else const hsolver::diag_comm_info comm(0, 1); #endif - hsolver::PWLinearOptions options; - options.orthonormal = hsolver::parse_orth_method(inp.td_orthonormal); - options.out_stat = inp.td_out_stat; - options.global_k_indices = this->kv.ik2iktot; - options.linear.method = hsolver::parse_linear_method(inp.lin_solver); - options.linear.tolerance = inp.lin_thr; - options.linear.max_iterations = inp.lin_maxiter; - options.linear.restart = inp.lin_gmres_restart; - options.linear.reconstruct = inp.lin_reconstruct; - options.preconditioner = hsolver::parse_pw_precond(inp.lin_precond); - options.cn_init = inp.td_cn_init; - options.kinetic_enabled = inp.t_in_h; - this->td_solver_.reset(new hsolver::HSolverPWTDDFT(*this->pw_wfc, options, comm, log_)); - this->history_.prepare(*this->pelec->pot, XC_Functional::get_ked_flag()); + const int npol = ucell.get_npol(); + this->td_prop_ = pw::make_td_prop(*this->pw_wfc, inp, npol, this->kv.ik2iktot, comm, log_); + this->history_.prepare(*this->pelec->pot); + // Preserve existing field history until input validation and initialization succeed. if (GlobalV::MY_RANK == 0) { if (inp.out_efield) { - ModuleIO::prepare_td_field_output(output_dir, *this->td_field_manager_, false); + ModuleIO::prep_td_field_out(output_dir, *this->td_field_manager_, false); } if (inp.out_vecpot) { if (inp.init_vecpot) { - ModuleIO::check_td_vector_pot_paths("", output_dir); + // Reject output that aliases the input file before truncating it. + ModuleIO::check_td_vecpot_paths("", output_dir); } - ModuleIO::prepare_td_vector_pot_output(output_dir, false); + ModuleIO::prep_td_vecpot_out(output_dir, false); } } } @@ -106,10 +135,187 @@ void ESolver_KS_PW_TDDFT::runner(BaseCell& basecell, const int istep) first_step = (istep - 1) * steps_per_md + 1; last_step = istep * steps_per_md; } + for (int electronic_step = first_step; electronic_step <= last_step; ++electronic_step) { - ESolver_KS::runner(basecell, electronic_step); + if (electronic_step > 0) + { + basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); + UnitCell& cell = static_cast(basecell); + this->run_prop(cell, electronic_step); + } + else + { + ESolver_KS::runner(basecell, electronic_step); + } + } +} + +template +bool ESolver_KS_PW_TDDFT::defer_iter_output(const int istep) const +{ + return istep > 0; +} + +template +int ESolver_KS_PW_TDDFT::scf_iter_limit(const int istep) const +{ + return istep > 0 ? this->inp_->td_scf_nmax : this->inp_->scf_nmax; +} + +template +bool ESolver_KS_PW_TDDFT::advance_interval(UnitCell& cell, + int step, + int index, + int depth, + const elecstate::TDFieldState& full, + pw::TDElecSnap& accepted, + hsolver::TDOrthStats& stats) +{ + const int parts = 1 << depth; + if (depth > 0) + { + *this->stp.template get_psi_t() = this->history_.previous(); + pw::restore_td(accepted, this->pelec->f_en, this->pelec->ekb, this->chr); + this->pelec->vnew_exist = false; + this->td_prop_->invalidate_basis(); + this->td_prop_->orbitals().reset_orth_stats(); + + const elecstate::TDFieldState trial = this->td_field_manager_->subinterval(full, index, parts); + this->td_field_manager_->bind_field(trial); + + // Length-gauge fields are fixed potential components and must be rebuilt + // at the trial endpoint, just as before_scf does for an original step. + this->pelec->pot->init_pot(&this->chr); + this->prepare_init_hamilt(cell); + } + + const double left_time = (step - 1 + static_cast(index) / parts) * full.dt * ModuleBase::AU_to_FS; + const double right_time = (step - 1 + static_cast(index + 1) / parts) * full.dt * ModuleBase::AU_to_FS; + const std::streamsize precision = log_.precision(); + log_ << " TD trial: [" << std::setprecision(12) << left_time << ", " << right_time << "] fs, depth=" << depth << '\n'; + log_.precision(precision); + + std::ostringstream interval; + interval << std::setprecision(12) << "[" << left_time << ", " << right_time << "] fs"; + const std::string interval_text = interval.str(); + if (depth > 0) + { + std::cout << " TD substep: " << interval_text << std::endl; + } + + const int iter_limit = this->scf_iter_limit(step); + this->td_prop_->begin_trial(); + const bool converged = this->scf_loop(cell, step, iter_limit); + + const bool accept_trial = converged || depth == this->inp_->td_max_halvings; + log_ << " TD trial result: iterations=" << this->niter << ", residual=" << this->drho << ", converged=" << converged + << ", accepted=" << accept_trial << '\n'; + if (!converged && depth < this->inp_->td_max_halvings) + { + std::cout << " TD retry: SCF not converged; splitting " << interval_text << " into two half steps." << std::endl; + this->td_prop_->discard_trial(); + + const int next_depth = depth + 1; + const int left_index = 2 * index; + const int right_index = left_index + 1; + + const bool left_converged = advance_interval(cell, step, left_index, next_depth, full, accepted, stats); + const bool right_converged = advance_interval(cell, step, right_index, next_depth, full, accepted, stats); + return left_converged && right_converged; + } + + if (!converged) + { + psi::Psi& current = *this->stp.template get_psi_t(); + elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); + hamilt::HamiltPW& hamilt = *static_cast*>(this->p_hamilt); + const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); + pw::rebuild_td_end(current, + estate, + this->chr, + cell, + hamilt, + this->td_prop_->orbitals(), + *this->pw_wfc, + *this->pw_rhod, + vecpot, + this->inp_->nspin, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); + } + + const hsolver::TDOrthStats& trial_stats = this->td_prop_->orbitals().orth_stats(); + stats.before = std::max(stats.before, trial_stats.before); + stats.after = std::max(stats.after, trial_stats.after); + + const psi::Psi* current = this->stp.template get_psi_t(); + this->history_.save(*current, *this->pelec->pot); + this->td_prop_->finish_trial(); + if (this->inp_->td_max_halvings > 0) + { + accepted = pw::capture_td(this->pelec->f_en, this->pelec->ekb, this->chr); + } + + return converged; +} + +template +void ESolver_KS_PW_TDDFT::run_prop(UnitCell& cell, int step) +{ + ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "run_prop"); + const ModuleBase::TimePoint started = ModuleBase::get_time(); + + pw::TDElecSnap accepted; + if (this->inp_->td_max_halvings > 0) + { + accepted = pw::capture_td(this->pelec->f_en, this->pelec->ekb, this->chr); } + + this->before_scf(cell, step); + ModuleBase::GlobalFunc::DONE(log_, "INIT SCF"); + + const elecstate::TDFieldState full = this->td_field_manager_->field_state(); + hsolver::TDOrthStats stats; + const bool converged = advance_interval(cell, step, 0, 0, full, accepted, stats); + + // Restore original-grid sampling metadata without altering the accepted endpoint. + this->td_field_manager_->bind_field(full); + this->td_prop_->orbitals().set_orth_stats(stats); + this->chr.save_rho_before_sum_band(); + + const System_para& system = PARAM.globalv; + const bool write_restart = this->inp_->out_chg[0] != -1; + const std::string prefix = system.global_out_dir + this->inp_->suffix; + const bool write_tau = XC_Functional::get_ked_flag(); + const bool writer_pool = GlobalV::MY_POOL == 0; + const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); + module_charge::write_density_restart(this->chr, + *this->pw_rhod, + cell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); + + this->write_iter_bands(); + ModuleIO::ctrl_iter_pw(step, this->niter, converged, this->stp, this->kv, this->pw_wfc, *this->inp_, true, log_); + + const double duration = ModuleBase::get_duration(started, ModuleBase::get_time()); + this->record_iteration(cell, duration); + + this->output_field(step); + + this->after_scf(cell, step, converged); + this->conv_esolver = converged; + + ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "run_prop"); } template @@ -125,15 +331,17 @@ template void ESolver_KS_PW_TDDFT::before_scf(UnitCell& ucell, const int istep) { this->print_step(istep); - this->prepare_td_step(istep); - this->td_solver_->reset_orth_stats(); + this->prep_td_step(istep); + this->td_prop_->orbitals().reset_orth_stats(); + const bool basis_updated = ucell.cell_parameter_updated; ESolver_KS_PW::before_scf(ucell, istep); if (basis_updated) { - this->td_solver_->invalidate_basis(); + this->td_prop_->invalidate_basis(); } - this->history_.prepare(*this->pelec->pot, XC_Functional::get_ked_flag()); + + this->history_.prepare(*this->pelec->pot); } template @@ -141,27 +349,31 @@ void ESolver_KS_PW_TDDFT::prepare_init_hamilt(const UnitCell& ucell) { if (this->td_field_manager_->gauge() == 1) { - // The updated basis and endpoint A determine the required nonlocal projector range. + // Both endpoints also bound any interpolated sample inside the interval. const double q_unshifted = pw::td_momentum_bound(*this->pw_wfc, ucell.tpiba); - pw::ensure_td_vnl(ucell, q_unshifted, this->td_field_manager_->A_right_ha(), this->td_field_manager_->A_prop_ha(), &this->ppcell); + const ModuleBase::Vector3& left = this->td_field_manager_->A_left_ha(); + const ModuleBase::Vector3& right = this->td_field_manager_->A_right_ha(); + pw::ensure_td_vnl(ucell, q_unshifted, right, left, &this->ppcell); + elecstate::Potential& potential = *this->pelec->pot; const Real* veff = potential.template get_veff_smooth_data(); - const Real* vofk = potential.template get_vofk_smooth_data(); auto* hamiltonian = static_cast*>(this->p_hamilt); // A file can supply nonzero A(0), which must enter H before the initial wavefunctions are prepared. - hamiltonian->bind_td_state(veff, vofk, this->td_field_manager_->A_right_ha()); + hamiltonian->bind_td_state(veff, this->td_field_manager_->A_right_ha()); } } template -void ESolver_KS_PW_TDDFT::prepare_td_step(const int istep) +void ESolver_KS_PW_TDDFT::prep_td_step(const int istep) { - ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "prepare_td_step"); + ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "prep_td_step"); + if (this->td_field_manager_->current_step() == istep) { - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "prepare_td_step"); + ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "prep_td_step"); return; } + if (this->td_field_manager_->gauge() == 0 || istep == 0) { this->td_field_manager_->prepare_sample(istep); @@ -171,6 +383,7 @@ void ESolver_KS_PW_TDDFT::prepare_td_step(const int istep) const int interval_left = istep - 1; this->td_field_manager_->prepare_interval(interval_left, istep); } + if (this->td_field_manager_->gauge() == 1) { const ModuleBase::Vector3& A_right_ha = this->td_field_manager_->A_right_ha(); @@ -178,18 +391,29 @@ void ESolver_KS_PW_TDDFT::prepare_td_step(const int istep) ModuleBase::GlobalFunc::OUT(log_, "Cartesian vector potential Ay(t)", A_right_ha[1]); ModuleBase::GlobalFunc::OUT(log_, "Cartesian vector potential Az(t)", A_right_ha[2]); } + + if (!this->defer_iter_output(istep)) + { + this->output_field(istep); + } + + ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "prep_td_step"); +} + +template +void ESolver_KS_PW_TDDFT::output_field(int istep) const +{ if (GlobalV::MY_RANK == 0) { if (this->inp_->out_vecpot) { - ModuleIO::write_td_vector_pot(PARAM.globalv.global_out_dir, istep, this->td_field_manager_->A_right_ha()); + ModuleIO::write_td_vecpot(PARAM.globalv.global_out_dir, istep, this->td_field_manager_->A_right_ha()); } if (this->inp_->out_efield) { - ModuleIO::write_td_field_values(*this->td_field_manager_, PARAM.globalv.global_out_dir); + ModuleIO::write_td_field(*this->td_field_manager_, PARAM.globalv.global_out_dir); } } - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "prepare_td_step"); } template @@ -217,7 +441,7 @@ void ESolver_KS_PW_TDDFT::iter_init(UnitCell& ucell, const int istep, template ESolver_KS::DensityStage ESolver_KS_PW_TDDFT::density_stage(const int istep, const int iter) const { - if (istep > 0 && iter == 1) + if (istep > 0 && this->td_prop_->stage(iter) == pw::PropStage::predictor) { return ESolver_KS::DensityStage::predictor; } @@ -228,34 +452,28 @@ template void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) { ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); + if (istep == 0) { ESolver_KS_PW::hamilt2rho_single(ucell, istep, iter, ethr); - if (this->inp_->td_orthonormal != "none") - { - psi::Psi* current = this->stp.template get_psi_t(); - int changed = this->td_solver_->correct_initial(current, iter); - // Occupations and density construction contain collectives across k-point pools. - Parallel_Reduce::reduce_all(changed); - if (changed > 0) - { - hamilt::Hamilt* hamiltonian = static_cast*>(this->p_hamilt); - hamilt::HamiltHSOperator op(hamiltonian, this->pw_wfc); - this->td_solver_->cal_band_energy(op, *current, &this->pelec->ekb); - elecstate::calculate_weights(this->pelec->ekb, - this->pelec->wg, - this->pelec->klist, - this->pelec->eferm, - this->pelec->f_en, - this->pelec->nelec_spin, - this->inp_->nbands, - this->pelec->skip_weights); - elecstate::calEBand(this->pelec->ekb, this->pelec->wg, this->pelec->f_en); - elecstate::ElecStatePW* estate = static_cast*>(this->pelec); - estate->psiToRho(*current); - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rhod, ucell.symm); - } - } + + psi::Psi& current = *this->stp.template get_psi_t(); + elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); + hamilt::Hamilt* hamilt = static_cast*>(this->p_hamilt); + hamilt::HamiltHSOperator op(hamilt, this->pw_wfc); + const bool do_orth = this->inp_->td_orthonormal != "none"; + pw::orth_init_pw(this->td_prop_->orbitals(), + op, + current, + estate, + this->chr, + ucell, + *this->pw_rhod, + this->inp_->nspin, + this->inp_->nbands, + iter, + do_orth); + ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); return; } @@ -266,30 +484,9 @@ void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const in hamilt::HamiltPW* hamiltonian = static_cast*>(this->p_hamilt); hamilt::HamiltHSOperator op(hamiltonian, this->pw_wfc); - // Predict with the current potential, then correct with the midpoint. - const Real* endpoint_veff = potential.template get_veff_smooth_data(); - const Real* endpoint_vofk = potential.template get_vofk_smooth_data(); - const ESolver_KS::DensityStage stage = this->density_stage(istep, iter); - const bool corrector = stage != ESolver_KS::DensityStage::predictor; - const pw::TDPotentialView propagation = this->history_.prop_pot(potential, XC_Functional::get_ked_flag(), corrector); - ModuleBase::Vector3 momentum_shift(0.0, 0.0, 0.0); - if (this->td_field_manager_->gauge() == 1) - { - momentum_shift = this->td_field_manager_->A_prop_ha(); - } - hamiltonian->bind_td_state(propagation.veff, propagation.vofk, momentum_shift); - // The solver sequence follows electronic steps across MD boundaries. - this->td_solver_->solve(op, - this->history_.previous(), - current, - this->td_field_manager_->dt_ha(), - momentum_shift, - istep, - iter, - this->inp_->out_level == "ie"); - - // Restore the endpoint Hamiltonian before evaluating density and energy. - hamiltonian->bind_td_state(endpoint_veff, endpoint_vofk, this->td_field_manager_->A_right_ha()); + const bool detailed = this->inp_->out_level == "ie"; + this->td_prop_->evolve(*hamiltonian, potential, this->history_, *this->td_field_manager_, current, istep, iter, detailed); + elecstate::ElecStatePW* estate = static_cast*>(this->pelec); // Propagation keeps the occupations of the initial state fixed. estate->psiToRho(*current); @@ -297,211 +494,125 @@ void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const in // Pair the band sum with KS double-counting terms using this same potential. // The later KS potential update belongs to the next SCF iteration. - this->td_solver_->cal_band_energy(op, *current, &this->pelec->ekb); + this->td_prop_->orbitals().cal_band_energy(op, *current, &this->pelec->ekb); elecstate::calEBand(this->pelec->ekb, this->pelec->wg, this->pelec->f_en); - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); -} -template -void ESolver_KS_PW_TDDFT::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) -{ - ESolver_KS_PW::iter_finish(ucell, istep, iter, conv_esolver); - if (istep > 0 && !conv_esolver && iter >= this->inp_->scf_nmax) - { - const int evolution_step = istep + 1; - const std::string message = "The time-dependent SCF step did not converge. Electronic evolution step: " - + std::to_string(evolution_step) + ", SCF iteration: " + std::to_string(iter) + "."; - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", message); - } + ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); } template void ESolver_KS_PW_TDDFT::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) { - if (!conv_esolver) - { - const int evolution_step = istep + 1; - const std::string message - = "Cannot propagate an unconverged electronic state. Electronic evolution step: " + std::to_string(evolution_step) + "."; - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", message); - } if (istep == 0 && this->inp_->td_orthonormal == "none") { const psi::Psi* current = this->stp.template get_psi_t(); - this->td_solver_->check_initial(*current, this->niter); + this->td_prop_->orbitals().check_initial(*current, this->niter); + } + if (!conv_esolver && istep == 0) + { + psi::Psi& current = *this->stp.template get_psi_t(); + elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); + hamilt::HamiltPW& hamilt = *static_cast*>(this->p_hamilt); + const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); + pw::rebuild_td_end(current, + estate, + this->chr, + ucell, + hamilt, + this->td_prop_->orbitals(), + *this->pw_wfc, + *this->pw_rhod, + vecpot, + this->inp_->nspin, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); } + + // Endpoint diagnostics use the accepted endpoint, not the propagation midpoint or a mixed trial density. + hamilt::HamiltPW* endpoint_hamilt = static_cast*>(this->p_hamilt); + const Real* endpoint_veff = this->pelec->pot->template get_veff_smooth_data(); + endpoint_hamilt->bind_td_state(endpoint_veff, this->td_field_manager_->A_right_ha()); if (this->inp_->td_print_eij >= 0.0) { - print_eij(istep); + psi::Psi& current = *this->stp.template get_psi_t(); + hamilt::HamiltHSOperator op(endpoint_hamilt, this->pw_wfc); + ModuleIO::print_eij_pw(op, + this->td_prop_->orbitals(), + current, + this->kv, + this->inp_->nspin, + istep, + this->niter, + this->inp_->td_print_eij, + log_); } + ESolver_KS_PW::after_scf(ucell, istep, conv_esolver); + const std::streamsize original_precision = std::cout.precision(); std::cout << " Potential (Ry): " << std::setprecision(15) << this->pelec->f_en.etot << std::endl; std::cout.precision(original_precision); + if (istep >= 0) { - psi::Psi* current = this->stp.template get_psi_t(); - this->history_.save(*current, *this->pelec->pot, XC_Functional::get_ked_flag()); - - if (this->inp_->out_current == 1) + // Propagation intervals already saved their accepted endpoint before reaching this hook. + if (istep == 0) { - const ModuleBase::Vector3& A_right_ha = this->td_field_manager_->A_right_ha(); - this->current_output_.write(istep, - ucell, - this->pw_wfc, - current, - this->pelec, - this->kv, - &this->ppcell, - this->td_field_manager_->gauge(), - A_right_ha, - this->inp_->out_current_k, - PARAM.globalv.global_out_dir, - GlobalV::MY_RANK); + psi::Psi* current = this->stp.template get_psi_t(); + this->history_.save(*current, *this->pelec->pot); } - } - if (this->inp_->td_out_stat) - { - report_orth(ucell, istep); - } -} -template -void ESolver_KS_PW_TDDFT::print_eij(const int istep) -{ - ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "print_eij"); - psi::Psi* current = this->stp.template get_psi_t(); - const int original_k = current->get_current_k(); - const int nband = current->get_nbands(); - const size_t elements = static_cast(nband) * nband; - const int nspin = this->inp_->nspin; - const int nk = this->kv.get_nkstot() / (nspin == 2 ? 2 : 1); - const Parallel_Kpoints& pools = this->kv.para_k; - const bool main_rank = pools.my_pool == 0 && pools.rank_in_pool == 0; - auto* hamiltonian = static_cast*>(this->p_hamilt); - const Real* veff = this->pelec->pot->template get_veff_smooth_data(); - const Real* vofk = this->pelec->pot->template get_vofk_smooth_data(); - // cal_converged() updates the potential from the final density, after the last band-energy evaluation. - hamiltonian->bind_td_state(veff, vofk, this->td_field_manager_->A_right_ha()); - hamilt::HamiltHSOperator op(hamiltonian, this->pw_wfc); - for (int global_k = 0; global_k < this->kv.get_nkstot(); ++global_k) - { - const int physical_k = global_k % nk; - const int spin = global_k / nk; - int owner = 0; - int local_k = global_k; -#ifdef __MPI - owner = pools.whichpool[physical_k]; - local_k = physical_k - pools.startk_pool[owner] + spin * pools.nks_pool[owner]; -#endif - std::vector> eij; - if (pools.my_pool == owner) - { - eij = this->td_solver_->cal_eij(op, *current, local_k); - } -#ifdef __MPI - // Each pool already has the full matrix; transfer only one copy to the main log. - if (owner != 0 && pools.rank_in_pool == 0 && (main_rank || pools.my_pool == owner)) - { - if (main_rank) - { - eij.resize(elements); - } - MPI_Comm world = MPI_COMM_WORLD; - const int source = pools.get_startpro_pool(owner); - const size_t max_count = std::numeric_limits::max(); - for (size_t offset = 0; offset < elements; offset += max_count) - { - const int count = static_cast(std::min(max_count, elements - offset)); - if (main_rank) - { - Parallel_Common::recv_data(eij.data() + offset, count, source, 0, world, MPI_STATUS_IGNORE); - } - else - { - Parallel_Common::send_data(eij.data() + offset, count, 0, 0, world); - } - } - } -#endif - if (main_rank) - { - const ModuleIO::EijOutputInfo info{this->inp_->td_print_eij, istep + 1, this->niter, physical_k + 1, nspin, spin + 1}; - ModuleIO::print_eij(eij.data(), nband, nband, info, log_); - } - } - current->fix_k(original_k); - op.update_k(original_k); - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "print_eij"); -} + const psi::Psi& current = *this->stp.template get_psi_t(); + const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); + const pw::TDVelResultPW currents = vel_.calculate(current, *this->pelec, vecpot, current_req_); -template -void ESolver_KS_PW_TDDFT::report_orth(const UnitCell& ucell, int istep) -{ - ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "report_orth"); - double electrons = this->td_solver_->wave_electrons(this->pelec->wg); - // Norms are replicated within a pool; only its root contributes to the total. - if (this->pw_wfc->poolrank != 0) - { - electrons = 0.0; - } - Parallel_Reduce::reduce_all(electrons); - double rho_electrons = 0.0; - const int density_spins = this->chr.nspin == 2 ? 2 : 1; - for (int spin = 0; spin < density_spins; ++spin) - { - for (int ir = 0; ir < this->chr.nrxx; ++ir) + pw::TDSpinResultPW moments; + if (this->inp_->nspin == 4 && (this->inp_->td_out_mag != "none" || this->inp_->td_out_torque)) { - rho_electrons += this->chr.rho[spin][ir]; + moments = spin_.calculate(current, *this->pelec, vecpot); } + + const double dt_ha = this->td_field_manager_->dt_ha(); + const int nkstot = this->kv.get_nkstot(); + ModuleIO::ctrl_output_td_pw(currents, + moments, + current_req_, + this->inp_->td_out_mag, + this->inp_->orbital_dir, + this->inp_->onsite_radius, + this->inp_->td_out_torque, + ucell.orbital_fn, + istep, + dt_ha, + this->inp_->nspin, + nkstot, + GlobalV::MY_RANK, + PARAM.globalv.global_out_dir, + log_); } - rho_electrons *= ucell.omega / this->chr.rhopw->nxyz; - Parallel_Reduce::reduce_pool(rho_electrons); - if (istep == 0) - { - initial_wave_electrons_ = electrons; - initial_rho_electrons_ = rho_electrons; - } - const hsolver::TDOrthStats& stats = this->td_solver_->orth_stats(); - const bool full_gram = this->inp_->td_orthonormal != "none"; - double maxima[] = {stats.before, stats.after}; - if (full_gram) - { - Parallel_Reduce::reduce_max(maxima, 2); - } - if (!log_.good()) - { - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "report_orth"); - return; - } - const char* stage = istep == 0 ? "initial state" : "propagation"; - const int evolution_step = istep + 1; - const double delta_wave = electrons - initial_wave_electrons_; - const double delta_rho = rho_electrons - initial_rho_electrons_; - const std::ios::fmtflags saved_flags = log_.flags(); - const std::streamsize saved_precision = log_.precision(); - log_ << " PW RT-TDDFT conservation: evolution step " << evolution_step << ", " << stage << ", " << this->inp_->td_orthonormal << '\n'; - log_ << std::right << std::fixed << std::setprecision(10); - ModuleBase::GlobalFunc::OUT(log_, "Npsi", electrons); - ModuleBase::GlobalFunc::OUT(log_, "Nrho", rho_electrons); - log_ << std::scientific << std::setprecision(6); - ModuleBase::GlobalFunc::OUT(log_, "dNpsi", delta_wave); - ModuleBase::GlobalFunc::OUT(log_, "dNrho", delta_rho); - if (full_gram) + + if (this->inp_->td_out_stat) { + const double local_npsi = this->td_prop_->orbitals().wave_electrons(this->pelec->wg); + const hsolver::TDOrthStats& stats = this->td_prop_->orbitals().orth_stats(); + const bool full_gram = this->inp_->td_orthonormal != "none"; + const pw::TDConserv values + = pw::cal_td_conserv(local_npsi, this->chr, ucell.omega, this->pw_wfc->poolrank, stats.before, stats.after, full_gram); if (istep == 0) { - ModuleBase::GlobalFunc::OUT(log_, "initial_orth_error", maxima[1]); - } - else - { - ModuleBase::GlobalFunc::OUT(log_, "orth_before_step_max", maxima[0]); - ModuleBase::GlobalFunc::OUT(log_, "orth_after_step_max", maxima[1]); + initial_wave_electrons_ = values.npsi; + initial_rho_electrons_ = values.nrho; } + ModuleIO::print_conserv(values, + initial_wave_electrons_, + initial_rho_electrons_, + istep, + full_gram, + this->inp_->td_orthonormal, + log_); } - log_.flags(saved_flags); - log_.precision(saved_precision); - ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "report_orth"); } template class ESolver_KS_PW_TDDFT, base_device::DEVICE_CPU>; diff --git a/source/source_esolver/esolver_ks_pw_tddft.h b/source/source_esolver/esolver_ks_pw_tddft.h index 3ab6bd7cfcd..cd7af6fcfd0 100644 --- a/source/source_esolver/esolver_ks_pw_tddft.h +++ b/source/source_esolver/esolver_ks_pw_tddft.h @@ -3,9 +3,10 @@ #include "source_esolver/esolver_ks_pw.h" #include "source_estate/module_pot/td_field_manager.h" -#include "source_hsolver/hsolver_pw_tddft.h" -#include "source_io/module_current/td_current_pw.h" -#include "source_pw/module_pwdft/td_history_pw.h" +#include "source_pw/module_rt/td_history_pw.h" +#include "source_pw/module_rt/td_prop_pw.h" +#include "source_pw/module_rt/td_spin_pw.h" +#include "source_pw/module_rt/td_vel_pw.h" #include #include @@ -27,11 +28,14 @@ class ESolver_KS_PW_TDDFT : public ESolver_KS_PW void runner(BaseCell& basecell, const int istep) override; protected: + /** @brief Use independent iteration limits for initial-state SCF and propagation. */ + int scf_iter_limit(const int istep) const override; /** @brief Use ground-state diagonalization for the initial electronic step. */ std::string diag_policy(const int istep) const override; /** @brief Require an unmixed endpoint prediction before accepting a corrected step. */ ESolver_KS::DensityStage density_stage(const int istep, const int iter) const override; + bool defer_iter_output(const int istep) const override; void before_scf(UnitCell& ucell, const int istep) override; @@ -44,29 +48,35 @@ class ESolver_KS_PW_TDDFT : public ESolver_KS_PW /** @brief Switch between ground-state diagonalization and real-time propagation. */ void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; - /** @brief Apply the convergence policy appropriate to the current stage. */ - void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; - - /** @brief Save the converged state as the origin of the next propagation step. */ + /** @brief Save the converged or iteration-limited endpoint for the next propagation step. */ void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; private: using Real = typename GetTypeReal::type; std::ofstream& log_; - std::unique_ptr> td_solver_; + std::unique_ptr> td_prop_; std::shared_ptr td_field_manager_; - ModuleIO::CurrentPW current_output_; + pw::TDVelPW vel_; + pw::TDSpinPW spin_; + pw::CurrentRequest current_req_; pw::TDHistoryPW history_; double initial_wave_electrons_ = 0.0; double initial_rho_electrons_ = 0.0; + + void run_prop(UnitCell& cell, int step); + bool advance_interval(UnitCell& cell, + int step, + int index, + int depth, + const elecstate::TDFieldState& full, + pw::TDElecSnap& accepted, + hsolver::TDOrthStats& stats); + void output_field(int step) const; /** @brief Print the one-based electronic step header. */ void print_step(const int istep) const; - /** @brief Print Eij from the converged density, collecting all k-point pools on the main rank. */ - void print_eij(const int istep); - void report_orth(const UnitCell& ucell, int istep); - void prepare_td_step(const int istep); + void prep_td_step(const int istep); }; } // namespace ModuleESolver diff --git a/source/source_estate/CMakeLists.txt b/source/source_estate/CMakeLists.txt index b78f8422663..e1e481a5ac9 100644 --- a/source/source_estate/CMakeLists.txt +++ b/source/source_estate/CMakeLists.txt @@ -97,7 +97,7 @@ endif() if(BUILD_TESTING) if(ENABLE_MPI) - add_subdirectory(test) + add_subdirectory(unittests) add_subdirectory(module_charge/unittests) endif() endif() diff --git a/source/source_estate/elecstate_print.cpp b/source/source_estate/elecstate_print.cpp index 457c9483c89..4c4a2d9edf5 100644 --- a/source/source_estate/elecstate_print.cpp +++ b/source/source_estate/elecstate_print.cpp @@ -172,6 +172,7 @@ void print_etot(const Magnetism& magnet, const ElecState& elec, const bool converged, const int& iter_in, + const int iter_limit, const double& scf_thr, const double& scf_thr_kin, const double& duration, @@ -205,7 +206,7 @@ void print_etot(const Magnetism& magnet, // electronic step so E_plusU can be monitored. Charge-density and // wavefunction output remain gated by out_freq_elec elsewhere. const bool print_table = (iter % inp.out_freq_elec == 0) || converged - || (iter == inp.scf_nmax) || inp.dft_plus_u; + || (iter == iter_limit) || inp.dft_plus_u; if (print_table) { int n_order = std::max(0, Occupy::gaussian_type); diff --git a/source/source_estate/elecstate_print.h b/source/source_estate/elecstate_print.h index e6f89f5b969..1686eb2ff7e 100644 --- a/source/source_estate/elecstate_print.h +++ b/source/source_estate/elecstate_print.h @@ -12,10 +12,12 @@ namespace elecstate /// headers are printed /// @param two_fermi whether the run keeps two Fermi levels; derived, so it /// does not live in Input_para + /// @param iter_limit maximum iterations for this SCF attempt, including propagation void print_etot(const Magnetism& magnet, const ElecState& elec, const bool converged, const int& iter_in, + const int iter_limit, const double& scf_thr, const double& scf_thr_kin, const double& duration, diff --git a/source/source_estate/module_charge/chg_mix.cpp b/source/source_estate/module_charge/chg_mix.cpp index 89a2f94abc7..45d93180a4d 100644 --- a/source/source_estate/module_charge/chg_mix.cpp +++ b/source/source_estate/module_charge/chg_mix.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "source_base/module_mixing/broyden_mixing.h" #include "source_base/module_mixing/pulay_mixing.h" @@ -200,6 +201,14 @@ void Charge_Mixing::mix_reset() } } +void Charge_Mixing::reset_scf_history(int iter_limit) +{ + this->_drho_history.assign(iter_limit, std::numeric_limits::quiet_NaN()); + this->mixing_restart_step = iter_limit + 1; + this->mixing_restart_last = 0; + this->mixing_restart_count = 0; +} + bool Charge_Mixing::if_scf_oscillate(const int iteration, const double drho, const int iternum_used, const double threshold) { @@ -213,16 +222,15 @@ bool Charge_Mixing::if_scf_oscillate(const int iteration, const double drho, ModuleBase::WARNING_QUIT("Charge_Mixing", "set_mixing must be called before if_scf_oscillate"); } - if (iteration < 1 || iteration > this->cfg_.scf_nmax) - { - ModuleBase::WARNING_QUIT("Charge_Mixing", - "iteration must be within [1, scf_nmax]"); - } - if(this->_drho_history.size() == 0) { this->_drho_history.resize(this->cfg_.scf_nmax); } + if (iteration < 1 || static_cast(iteration) > this->_drho_history.size()) + { + ModuleBase::WARNING_QUIT("Charge_Mixing", + "iteration must be within the active SCF history limit"); + } // add drho into history this->_drho_history[iteration - 1] = drho; @@ -246,6 +254,12 @@ bool Charge_Mixing::if_scf_oscillate(const int iteration, const double drho, double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0; for (int i = iteration - iternum_used; i < iteration; i++) { + // A predictor does not enter mixing. Wait until the whole fitting + // window contains residuals from correctors in this trial. + if (std::isnan(this->_drho_history[i])) + { + return false; + } sumX += i; sumY += std::log10(this->_drho_history[i]); sumXY += i * std::log10(this->_drho_history[i]); diff --git a/source/source_estate/module_charge/chg_mix.h b/source/source_estate/module_charge/chg_mix.h index b52d9b96f82..db9d7a32494 100644 --- a/source/source_estate/module_charge/chg_mix.h +++ b/source/source_estate/module_charge/chg_mix.h @@ -74,6 +74,9 @@ class Charge_Mixing * @brief reset mixing, actually we only call init_mixing() to reset mixing instead of this function */ void mix_reset(); + + /** @brief Reset restart counters and residual history for an independently limited SCF trial. */ + void reset_scf_history(int iter_limit); // extracting parameters normally these parameters will not be used outside charge mixing // while Exx is using them as well as some other places @@ -149,7 +152,7 @@ class Charge_Mixing MixingConfig cfg_; ///< aggregated mixing config, also holds nspin/scf_thr_type/double_grid double* omega = nullptr; ///< omega for non-linear core correction double* tpiba = nullptr; ///< 2*pi/beta for non-linear core correction - std::vector _drho_history; ///< history of drho used to determine the oscillation, size is scf_nmax + std::vector _drho_history; ///< Residual history for oscillation detection, sized to the active SCF limit. ModulePW::PW_Basis* rhopw = nullptr; ///< smooth grid ModulePW::PW_Basis* rhodpw = nullptr; ///< dense grid, same as rhopw for ncpp. diff --git a/source/source_estate/module_charge/chg_rhog_io.cpp b/source/source_estate/module_charge/chg_rhog_io.cpp index 9de2dca4a9b..c199db7313a 100644 --- a/source/source_estate/module_charge/chg_rhog_io.cpp +++ b/source/source_estate/module_charge/chg_rhog_io.cpp @@ -1,17 +1,16 @@ +#include "chg_rhog_io.h" + #include "source_base/module_out/binstream.h" -#include "source_base/vector3.h" #include "source_base/module_parallel/para_mpi_func.h" -#include "chg_rhog_io.h" +#include "source_base/vector3.h" + #include #include #include namespace { -inline void warn(std::ostream* os, - const Parallel::ParaWorld& pw_world, - const std::string& file, - const std::string& desc) +inline void warn(std::ostream* os, const Parallel::ParaWorld& pw_world, const std::string& file, const std::string& desc) { if (pw_world.rank() == 0 && os != nullptr) { @@ -20,12 +19,56 @@ inline void warn(std::ostream* os, } } // namespace +void module_charge::write_density_restart(Charge& charge, + ModulePW::PW_Basis& pw_rhod, + const ModuleBase::Matrix3& reciprocal_lattice, + const std::string& prefix, + const int nspin, + const bool enabled, + const bool gamma_only, + const bool write_tau, + const bool writer_pool, + const Parallel::ParaWorld& pw_world, + std::ostream* warning) +{ + if (!enabled) + { + return; + } + + for (int is = 0; is < nspin; ++is) + { + pw_rhod.real2recip(charge.rho_save[is], charge.rhog_save[is]); + } + if (writer_pool) + { + const std::string filename = prefix + "-CHARGE-DENSITY.restart"; + write_rhog(filename, gamma_only, &pw_rhod, nspin, reciprocal_lattice, charge.rhog_save, pw_world, warning); + } + + if (write_tau) + { + std::vector> kin_g_space(nspin * charge.ngmc, {0.0, 0.0}); + std::vector*> kin_g; + for (int is = 0; is < nspin; ++is) + { + kin_g.push_back(kin_g_space.data() + is * charge.ngmc); + pw_rhod.real2recip(charge.kin_r_save[is], kin_g[is]); + } + if (writer_pool) + { + const std::string filename = prefix + "-TAU-DENSITY.restart"; + write_rhog(filename, gamma_only, &pw_rhod, nspin, reciprocal_lattice, kin_g.data(), pw_world, warning); + } + } +} + bool module_charge::read_rhog(const std::string& filename, - const ModulePW::PW_Basis* pw_rhod, - const int nspin, - std::complex** rhog, - const Parallel::ParaWorld& pw_world, - std::ostream* os_warning) + const ModulePW::PW_Basis* pw_rhod, + const int nspin, + std::complex** rhog, + const Parallel::ParaWorld& pw_world, + std::ostream* os_warning) { if (pw_rhod == nullptr) { @@ -127,7 +170,7 @@ bool module_charge::read_rhog(const std::string& filename, ifs >> size; for (int i = 0; i < npwtot_in; ++i) // loop over rows... { - ifs >> miller[i*3] >> miller[i*3+1] >> miller[i*3+2]; + ifs >> miller[i * 3] >> miller[i * 3 + 1] >> miller[i * 3 + 2]; } ifs >> size; } @@ -210,13 +253,13 @@ bool module_charge::read_rhog(const std::string& filename, } bool module_charge::write_rhog(const std::string& fchg, - const bool gamma_only, - const ModulePW::PW_Basis* pw_rho, - const int nspin, - const ModuleBase::Matrix3& GT, - std::complex** rhog, - const Parallel::ParaWorld& pw_world, - std::ostream* os_warning) + const bool gamma_only, + const ModulePW::PW_Basis* pw_rho, + const int nspin, + const ModuleBase::Matrix3& GT, + std::complex** rhog, + const Parallel::ParaWorld& pw_world, + std::ostream* os_warning) { if (pw_rho == nullptr) { @@ -371,4 +414,4 @@ bool module_charge::write_rhog(const std::string& fchg, // diff = np.array(read) - np.array(write) // print(np.max(np.abs(diff))) // test system: integrated test 118_PW_CHG_BINARY -// yielding error 5.290000000000175e-11 \ No newline at end of file +// yielding error 5.290000000000175e-11 diff --git a/source/source_estate/module_charge/chg_rhog_io.h b/source/source_estate/module_charge/chg_rhog_io.h index 3f3f2d2edad..e6c2220eb6b 100644 --- a/source/source_estate/module_charge/chg_rhog_io.h +++ b/source/source_estate/module_charge/chg_rhog_io.h @@ -1,18 +1,20 @@ #ifndef CHG_RHOG_IO_H #define CHG_RHOG_IO_H -#include +#include "source_base/module_parallel/para_world.h" +#include "source_basis/module_pw/pw_basis.h" +#include "source_estate/module_charge/charge.h" + #include #include -#include "source_basis/module_pw/pw_basis.h" -#include "source_base/module_parallel/para_world.h" +#include /** * I/O free function of rho(G) in binary format * Author: YuLiu98, Kirk0830 - * + * * The designed foramt of the binary file is kept similar to the one in QuantumESPRESSO * Modules/io_base.f90, function write_rhog (non-HDF5): - * + * * /3/ /gammaonly/ /ngm_g/ /nspin/ /3/ ! bool, int, int. ngm_g is the global, total number of G-vectors * /9/ /b11/ /b12/ /b13/ /b21/ /b22/ /b23/ /b31/ /b32/ /b33/ /9/ ! 9 real numbers, the three lattice vectors * /ngm_g*3/ @@ -27,24 +29,43 @@ * !/ngm_g/ ! ngm_g complex numbers, the rho(G) values for the second spin component * !/rhog(1)/ /rhog(2)/ /rhog(3)/ ... * !/ngm_g/ ! ngm_g complex numbers, the rho(G) values for the second spin component - * + * * There are some aspects needed to ensure: * 1. the correspondence between ABACUS PW and QuantumESPRESSO * ABACUS PW QuantumESPRESSO * bij UnitCell::GT b1, b2, b3 * miller index ibox[*] mill * rho Charge::rhog rho - * + * * 2. the unit of each quantity * ABACUS PW QuantumESPRESSO * bij a.u. * miller index - * rho + * rho */ namespace module_charge { +/** + * @brief Write saved charge and optional kinetic-energy densities in reciprocal space. + * + * All pools participate in their density transforms; only the designated writer + * pool writes files. The caller selects the output time and supplies saved + * densities in rho_save and kin_r_save. rhog_save is updated by the transform. + */ +void write_density_restart(Charge& charge, + ModulePW::PW_Basis& pw_rhod, + const ModuleBase::Matrix3& reciprocal_lattice, + const std::string& prefix, + const int nspin, + const bool enabled, + const bool gamma_only, + const bool write_tau, + const bool writer_pool, + const Parallel::ParaWorld& pw_world, + std::ostream* warning); + bool read_rhog(const std::string& filename, const ModulePW::PW_Basis* pw_rhod, const int nspin, diff --git a/source/source_estate/module_charge/chg_routine.cpp b/source/source_estate/module_charge/chg_routine.cpp index 938de4dcaab..020af1c3cd9 100644 --- a/source/source_estate/module_charge/chg_routine.cpp +++ b/source/source_estate/module_charge/chg_routine.cpp @@ -115,7 +115,7 @@ void module_charge::chgmixing_ks(const int iter, // SCF restart information if (inp.mixing_restart > 0 && iter == p_chgmix->mixing_restart_step - 1 - && iter != inp.scf_nmax) + && iter != ctx.iter_limit) { p_chgmix->mixing_restart_last = iter; std::cout << " SCF restart after this step!" << std::endl; @@ -126,6 +126,7 @@ void module_charge::chgmixing_ks(const int iter, void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number + const int iter_limit, Charge_Mixing* p_chgmix, // charge mixing class Plus_U_Base& dftu, const bool mag_converged, ///< whether DeltaSpin magnetization converged (true when disabled) @@ -136,7 +137,7 @@ void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number if (iter == 1) { p_chgmix->init_mixing(); - p_chgmix->mixing_restart_step = inp.scf_nmax + 1; + p_chgmix->reset_scf_history(iter_limit); if (inp.dft_plus_u && dftu.has_occ_mixer()) { // allocate memory for uom_mdata sized to the flat occupation buffer @@ -154,7 +155,7 @@ void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number { if (dftu.get_uramping() > 0.01 && !dftu.u_converged()) { - p_chgmix->mixing_restart_step = inp.scf_nmax + 1; + p_chgmix->mixing_restart_step = iter_limit + 1; } if (dftu.get_uramping() > 0.01) { @@ -176,6 +177,7 @@ void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number } void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number + const int iter_limit, Charge_Mixing* p_chgmix, // charge mixing class Plus_U_Base& dftu, const int nnr, // dimension of density matrix @@ -186,8 +188,7 @@ void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number if (iter == 1) { p_chgmix->mix_reset(); // init mixing - p_chgmix->mixing_restart_step = inp.scf_nmax + 1; - p_chgmix->mixing_restart_count = 0; + p_chgmix->reset_scf_history(iter_limit); // this output will be removed once the feeature is stable if (dftu.get_uramping() > 0.01) { @@ -219,7 +220,7 @@ void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number } if (dftu.get_uramping() > 0.01 && !dftu.u_converged()) { - p_chgmix->mixing_restart_step = inp.scf_nmax + 1; + p_chgmix->mixing_restart_step = iter_limit + 1; } } if (inp.mixing_dmr) // for mixing_dmr diff --git a/source/source_estate/module_charge/chg_routine.h b/source/source_estate/module_charge/chg_routine.h index 19a67cd1335..2bfe5c83c39 100644 --- a/source/source_estate/module_charge/chg_routine.h +++ b/source/source_estate/module_charge/chg_routine.h @@ -17,6 +17,7 @@ namespace module_charge /// Aggregated SCF convergence thresholds and status flags for chgmixing_ks struct ScfMixingCtx { + int iter_limit; ///< maximum iterations for the current SCF attempt double hsolver_error; ///< solver error from diagonalization double scf_thr; ///< charge density convergence threshold double scf_ene_thr; ///< energy convergence threshold @@ -37,12 +38,14 @@ void chgmixing_ks(const int iter, const Input_para& inp); void chgmixing_ks_pw(const int iter, + const int iter_limit, Charge_Mixing* p_chgmix, Plus_U_Base& dftu, const bool mag_converged, ///< whether DeltaSpin magnetization converged; pass true when sc_mag_switch is off const Input_para& inp); // input parameters void chgmixing_ks_lcao(const int iter, // scf iteration number + const int iter_limit, Charge_Mixing* p_chgmix, // charge mixing class Plus_U_Base& dftu, const int nnr, // dimension of density matrix diff --git a/source/source_estate/module_charge/unittests/test_chg_routine.cpp b/source/source_estate/module_charge/unittests/test_chg_routine.cpp index 8755d6329b6..3b4de081d5f 100644 --- a/source/source_estate/module_charge/unittests/test_chg_routine.cpp +++ b/source/source_estate/module_charge/unittests/test_chg_routine.cpp @@ -75,7 +75,7 @@ TEST_F(ChgRoutineTest, ChgmixingKsPwIter1SetsRestartStep) inp.mixing_restart = 0.0; inp.dft_plus_u = false; - module_charge::chgmixing_ks_pw(1, &cm, dftu, true, inp); + module_charge::chgmixing_ks_pw(1, inp.scf_nmax, &cm, dftu, true, inp); EXPECT_EQ(cm.mixing_restart_step, inp.scf_nmax + 1); } @@ -90,7 +90,7 @@ TEST_F(ChgRoutineTest, ChgmixingKsLcaoIter1SetsRestartStep) inp.mixing_restart = 0.0; inp.dft_plus_u = false; - module_charge::chgmixing_ks_lcao(1, &cm, dftu, 0, inp); + module_charge::chgmixing_ks_lcao(1, inp.scf_nmax, &cm, dftu, 0, inp); EXPECT_EQ(cm.mixing_restart_step, inp.scf_nmax + 1); } @@ -107,6 +107,7 @@ TEST_F(ChgRoutineTest, ChgmixingKsConvergedSkipsMixing) inp.nelec = 1.0; module_charge::ScfMixingCtx ctx; + ctx.iter_limit = inp.scf_nmax; ctx.hsolver_error = 1e-6; ctx.scf_thr = 1e-4; ctx.scf_ene_thr = 0.0; @@ -138,6 +139,7 @@ TEST_F(ChgRoutineTest, ChgmixingKsDrhoBelowHsolverSkipsMixing) inp.nelec = 1.0; module_charge::ScfMixingCtx ctx; + ctx.iter_limit = inp.scf_nmax; ctx.hsolver_error = 1e-3; ctx.scf_thr = 1e-4; ctx.scf_ene_thr = 0.0; diff --git a/source/source_estate/module_pot/td_field_manager.cpp b/source/source_estate/module_pot/td_field_manager.cpp index e18f8d66a21..687638dd176 100644 --- a/source/source_estate/module_pot/td_field_manager.cpp +++ b/source/source_estate/module_pot/td_field_manager.cpp @@ -85,8 +85,8 @@ TDFieldManager::TDFieldManager(const bool enabled, const double length_cut1, const double length_cut2, std::vector fields) - : enabled_(enabled), gauge_(gauge), start_step_(start_step), end_step_(end_step), dt_ha_(dt), length_cut1_(length_cut1), - length_cut2_(length_cut2), fields_(std::move(fields)), current_step_(-1), active_(false) + : enabled_(enabled), gauge_(gauge), start_step_(start_step), end_step_(end_step), dt_ha_(dt), interval_dt_ha_(dt), + length_cut1_(length_cut1), length_cut2_(length_cut2), fields_(std::move(fields)), current_step_(-1), active_(false) { field_vals_ha_.resize(fields_.size(), 0.0); } @@ -249,6 +249,112 @@ void TDFieldManager::read_restart(const std::string& file_dir) select_A_prop(); } +TDFieldState TDFieldManager::field_state() const +{ + TDFieldState state; + state.active = active_; + state.dt = interval_dt_ha_; + state.values = field_vals_ha_; + state.left = A_left_ha_; + state.right = A_right_ha_; + state.propagation = A_prop_ha_; + state.electric = efield_ha_; + return state; +} + +void TDFieldManager::bind_field(const TDFieldState& state) +{ + active_ = state.active; + interval_dt_ha_ = state.dt; + field_vals_ha_ = state.values; + A_left_ha_ = state.left; + A_right_ha_ = state.right; + A_prop_ha_ = state.propagation; + efield_ha_ = state.electric; +} + +ModuleBase::Vector3 TDFieldManager::substep_a(const TDFieldState& full, int node, int parts) const +{ + if (node == 0) + { + return full.left; + } + if (node == parts) + { + return full.right; + } + const double fraction = static_cast(node) / parts; + if (file_source()) + { + return full.left + (full.right - full.left) * fraction; + } + ModuleBase::Vector3 result = full.left; + const int left_step = current_step_ - 1; + if (gauge_ != 0 && enabled_ && left_step >= start_step_ && left_step <= end_step_) + { + // Anchor each prefix integral to the original left endpoint. A failed trial + // never contributes to the field integral or changes the original right endpoint. + for (const TDField& field: fields_) + { + const int count = field.subdivisions(); + std::vector samples(count + 1); + const int denominator = parts * count; + for (int j = 0; j <= count; ++j) + { + const int numerator = node * j; + const double time = (left_step + static_cast(numerator) / denominator) * dt_ha_; + const TDFieldSample sample(left_step, numerator, denominator, time); + samples[j] = field.electric_field(sample); + } + double integral = 0.0; + const double spacing = dt_ha_ * fraction / count; + const int points = count + 1; + ModuleBase::Integral::Simpson_Integral(points, samples.data(), spacing, integral); + result[field.direction()] -= integral; + } + } + return result; +} + +TDFieldState TDFieldManager::subinterval(const TDFieldState& full, int index, int parts) const +{ + TDFieldState state = full; + state.dt = dt_ha_ / parts; + state.left = substep_a(full, index, parts); + const int right = index + 1; + state.right = substep_a(full, right, parts); + state.propagation = (state.left + state.right) * 0.5; + if (right == parts) + { + return state; + } + const int left_step = current_step_ - 1; + state.active = enabled_ && left_step >= start_step_ && left_step <= end_step_; + std::fill(state.values.begin(), state.values.end(), 0.0); + state.electric.set(0.0, 0.0, 0.0); + if (file_source()) + { + state.active = true; + state.electric = (full.left - full.right) * (1.0 / dt_ha_); + } + else if (state.active) + { + const double time = (left_step + static_cast(right) / parts) * dt_ha_; + const TDFieldSample sample(left_step, right, parts, time); + for (std::size_t i = 0; i < fields_.size(); ++i) + { + state.values[i] = fields_[i].electric_field(sample); + state.electric[fields_[i].direction()] += state.values[i]; + } + } + return state; +} + +double TDFieldManager::interval_dt_ha() const +{ + return interval_dt_ha_; +} + void TDFieldManager::write_restart(const std::string& file_dir) const { std::ofstream file((file_dir + "Restart_td.txt").c_str()); diff --git a/source/source_estate/module_pot/td_field_manager.h b/source/source_estate/module_pot/td_field_manager.h index fc905ec4874..e38d0553f0c 100644 --- a/source/source_estate/module_pot/td_field_manager.h +++ b/source/source_estate/module_pot/td_field_manager.h @@ -13,6 +13,18 @@ struct Input_para; namespace elecstate { +/** @brief Field values for one trial interval, independent of the committed step counter. */ +struct TDFieldState +{ + bool active = false; + double dt = 0.0; + std::vector values; + ModuleBase::Vector3 left; + ModuleBase::Vector3 right; + ModuleBase::Vector3 propagation; + ModuleBase::Vector3 electric; +}; + /** * @brief Own and advance all time-dependent electric fields in RT-TDDFT. * @@ -32,6 +44,15 @@ class TDFieldManager */ void prepare_interval(const int left_step, const int sample_step); + /** @brief Capture the current field without advancing the original sampling grid. */ + TDFieldState field_state() const; + /** @brief Bind trial fields without advancing or integrating the original interval again. */ + void bind_field(const TDFieldState& state); + /** @brief Evaluate interval [index/parts,(index+1)/parts] inside the prepared original step. */ + TDFieldState subinterval(const TDFieldState& full, int index, int parts) const; + /** @brief Duration of the currently bound trial interval in Hartree atomic units. */ + double interval_dt_ha() const; + /** @brief Supply endpoint samples starting at t=0 before preparing any steps. */ void set_A_samples(const std::vector>& samples_ha); @@ -95,6 +116,7 @@ class TDFieldManager int start_step_; int end_step_; double dt_ha_; + double interval_dt_ha_; double length_cut1_; double length_cut2_; std::vector fields_; @@ -109,6 +131,7 @@ class TDFieldManager ModuleBase::Vector3 efield_ha_; void sample_field(const int step); void select_A_prop(); + ModuleBase::Vector3 substep_a(const TDFieldState& full, int node, int parts) const; friend std::shared_ptr create_td_field_manager(const Input_para& input); }; diff --git a/source/source_estate/test/CMakeLists.txt b/source/source_estate/unittests/CMakeLists.txt similarity index 89% rename from source/source_estate/test/CMakeLists.txt rename to source/source_estate/unittests/CMakeLists.txt index 6a4036fe388..9cb03fbcc36 100644 --- a/source/source_estate/test/CMakeLists.txt +++ b/source/source_estate/unittests/CMakeLists.txt @@ -56,19 +56,19 @@ endif() AddTest( TARGET MODULE_ESTATE_elecstate_occupy LIBS parameter base device - SOURCES elecstate_occupy_test.cpp ../occupy.cpp + SOURCES test_occupy.cpp ../occupy.cpp ) AddTest( TARGET MODULE_ESTATE_elecstate_fp_energy LIBS parameter base device - SOURCES elecstate_fp_energy_test.cpp ../fp_energy.cpp + SOURCES test_fp_energy.cpp ../fp_energy.cpp ) AddTest( TARGET MODULE_ESTATE_elecstate_print LIBS parameter base device symmetry - SOURCES elecstate_print_test.cpp ../elecstate_print.cpp ../occupy.cpp + SOURCES test_elecstate_print.cpp ../elecstate_print.cpp ../occupy.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) @@ -76,7 +76,7 @@ AddTest( TARGET MODULE_ESTATE_elecstate_base KEEP_FEATURE_DEFINITIONS __MPI LIBS parameter base device symmetry - SOURCES elecstate_base_test.cpp ../elecstate.cpp ../elecstate_tools.cpp ../occupy.cpp ../../source_psi/psi.cpp + SOURCES test_elecstate.cpp ../elecstate.cpp ../elecstate_tools.cpp ../occupy.cpp ../../source_psi/psi.cpp ../../source_base/module_fft/fft_bundle.cpp ../../source_base/module_fft/fft_cpu.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) @@ -84,7 +84,7 @@ AddTest( AddTest( TARGET MODULE_ESTATE_elecstate_pw LIBS parameter planewave_serial base device symmetry - SOURCES elecstate_pw_test.cpp + SOURCES test_elecstate_pw.cpp ../elecstate_pw.cpp ../uspp_density.cpp ../elecstate_pw_cal_tau.cpp @@ -101,7 +101,7 @@ AddTest( AddTest( TARGET MODULE_ESTATE_elecstate_energy LIBS parameter base device planewave_serial symmetry - SOURCES elecstate_energy_test.cpp + SOURCES test_elecstate_energy.cpp ../elecstate_energy.cpp ../fp_energy.cpp ../makov_payne.cpp @@ -111,7 +111,7 @@ AddTest( AddTest( TARGET MODULE_ESTATE_potentials_base - SOURCES potentials_base_test.cpp + SOURCES test_pot_base.cpp ) AddTest( @@ -135,7 +135,7 @@ AddTest( AddTest( TARGET MODULE_ESTATE_potentials_new LIBS parameter base device planewave_serial - SOURCES potential_new_test.cpp td_field_test.cpp ../module_pot/potential_new.cpp + SOURCES test_potential_new.cpp test_td_field.cpp ../module_pot/potential_new.cpp ../module_pot/td_field.cpp ../module_pot/td_field_profiles.cpp ../module_pot/td_field_manager.cpp ${pcc_test_sources} ) diff --git a/source/source_estate/test/sccs_cell_test.h b/source/source_estate/unittests/sccs_cell_test.h similarity index 100% rename from source/source_estate/test/sccs_cell_test.h rename to source/source_estate/unittests/sccs_cell_test.h diff --git a/source/source_estate/test/support/H.pz-vbc.UPF b/source/source_estate/unittests/support/H.pz-vbc.UPF similarity index 100% rename from source/source_estate/test/support/H.pz-vbc.UPF rename to source/source_estate/unittests/support/H.pz-vbc.UPF diff --git a/source/source_estate/test/support/KPT b/source/source_estate/unittests/support/KPT similarity index 100% rename from source/source_estate/test/support/KPT rename to source/source_estate/unittests/support/KPT diff --git a/source/source_estate/test/support/LOWF_GAMMA_S1.dat b/source/source_estate/unittests/support/LOWF_GAMMA_S1.dat similarity index 100% rename from source/source_estate/test/support/LOWF_GAMMA_S1.dat rename to source/source_estate/unittests/support/LOWF_GAMMA_S1.dat diff --git a/source/source_estate/test/support/LOWF_K_1.dat b/source/source_estate/unittests/support/LOWF_K_1.dat similarity index 100% rename from source/source_estate/test/support/LOWF_K_1.dat rename to source/source_estate/unittests/support/LOWF_K_1.dat diff --git a/source/source_estate/test/support/LOWF_K_2.dat b/source/source_estate/unittests/support/LOWF_K_2.dat similarity index 100% rename from source/source_estate/test/support/LOWF_K_2.dat rename to source/source_estate/unittests/support/LOWF_K_2.dat diff --git a/source/source_estate/test/support/LOWF_K_3.dat b/source/source_estate/unittests/support/LOWF_K_3.dat similarity index 100% rename from source/source_estate/test/support/LOWF_K_3.dat rename to source/source_estate/unittests/support/LOWF_K_3.dat diff --git a/source/source_estate/test/support/NOW_SPIN1_CHG.cube b/source/source_estate/unittests/support/NOW_SPIN1_CHG.cube similarity index 100% rename from source/source_estate/test/support/NOW_SPIN1_CHG.cube rename to source/source_estate/unittests/support/NOW_SPIN1_CHG.cube diff --git a/source/source_estate/test/support/OLD1_SPIN1_CHG.cube b/source/source_estate/unittests/support/OLD1_SPIN1_CHG.cube similarity index 100% rename from source/source_estate/test/support/OLD1_SPIN1_CHG.cube rename to source/source_estate/unittests/support/OLD1_SPIN1_CHG.cube diff --git a/source/source_estate/test/support/STRU b/source/source_estate/unittests/support/STRU similarity index 100% rename from source/source_estate/test/support/STRU rename to source/source_estate/unittests/support/STRU diff --git a/source/source_estate/test/support/Si.upf b/source/source_estate/unittests/support/Si.upf similarity index 100% rename from source/source_estate/test/support/Si.upf rename to source/source_estate/unittests/support/Si.upf diff --git a/source/source_estate/test/support/Si_ONCV_PBE-1.0.upf b/source/source_estate/unittests/support/Si_ONCV_PBE-1.0.upf similarity index 100% rename from source/source_estate/test/support/Si_ONCV_PBE-1.0.upf rename to source/source_estate/unittests/support/Si_ONCV_PBE-1.0.upf diff --git a/source/source_estate/test/support/Si_gga_8au_60Ry_2s2p1d.orb b/source/source_estate/unittests/support/Si_gga_8au_60Ry_2s2p1d.orb similarity index 100% rename from source/source_estate/test/support/Si_gga_8au_60Ry_2s2p1d.orb rename to source/source_estate/unittests/support/Si_gga_8au_60Ry_2s2p1d.orb diff --git a/source/source_estate/test/support/WAVEFUNC1.txt b/source/source_estate/unittests/support/WAVEFUNC1.txt similarity index 100% rename from source/source_estate/test/support/WAVEFUNC1.txt rename to source/source_estate/unittests/support/WAVEFUNC1.txt diff --git a/source/source_estate/test/support/chg.cube b/source/source_estate/unittests/support/chg.cube similarity index 100% rename from source/source_estate/test/support/chg.cube rename to source/source_estate/unittests/support/chg.cube diff --git a/source/source_estate/test/support/rho_gamma_ref.dat b/source/source_estate/unittests/support/rho_gamma_ref.dat similarity index 100% rename from source/source_estate/test/support/rho_gamma_ref.dat rename to source/source_estate/unittests/support/rho_gamma_ref.dat diff --git a/source/source_estate/test/support/rho_k_ref.dat b/source/source_estate/unittests/support/rho_k_ref.dat similarity index 100% rename from source/source_estate/test/support/rho_k_ref.dat rename to source/source_estate/unittests/support/rho_k_ref.dat diff --git a/source/source_estate/test/support/si2.STRU b/source/source_estate/unittests/support/si2.STRU similarity index 100% rename from source/source_estate/test/support/si2.STRU rename to source/source_estate/unittests/support/si2.STRU diff --git a/source/source_estate/test/test_charge_moments.cpp b/source/source_estate/unittests/test_charge_moments.cpp similarity index 100% rename from source/source_estate/test/test_charge_moments.cpp rename to source/source_estate/unittests/test_charge_moments.cpp diff --git a/source/source_estate/test/elecstate_base_test.cpp b/source/source_estate/unittests/test_elecstate.cpp similarity index 100% rename from source/source_estate/test/elecstate_base_test.cpp rename to source/source_estate/unittests/test_elecstate.cpp diff --git a/source/source_estate/test/elecstate_energy_test.cpp b/source/source_estate/unittests/test_elecstate_energy.cpp similarity index 100% rename from source/source_estate/test/elecstate_energy_test.cpp rename to source/source_estate/unittests/test_elecstate_energy.cpp diff --git a/source/source_estate/test/elecstate_print_test.cpp b/source/source_estate/unittests/test_elecstate_print.cpp similarity index 98% rename from source/source_estate/test/elecstate_print_test.cpp rename to source/source_estate/unittests/test_elecstate_print.cpp index c2d5bec1743..d2a8e0d058f 100644 --- a/source/source_estate/test/elecstate_print_test.cpp +++ b/source/source_estate/unittests/test_elecstate_print.cpp @@ -145,7 +145,7 @@ TEST_F(ElecStatePrintTest, PrintEtot) for (int i = 0; i < vdw_methods.size(); i++) { inp.vdw_method = vdw_methods[i]; - elecstate::print_etot(ucell.magnet,elecstate, converged, iter, scf_thr, + elecstate::print_etot(ucell.magnet,elecstate, converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, false); } @@ -156,7 +156,7 @@ TEST_F(ElecStatePrintTest, PrintEtot) inp.ks_solver = ks_solvers[i]; testing::internal::CaptureStdout(); - elecstate::print_etot(ucell.magnet,elecstate,converged, iter, scf_thr, + elecstate::print_etot(ucell.magnet,elecstate,converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, print); output = testing::internal::GetCapturedStdout(); @@ -224,7 +224,7 @@ TEST_F(ElecStatePrintTest, PrintEtotColorS2) inp.nspin = 2; GlobalV::MY_RANK = 0; - elecstate::print_etot(ucell.magnet,elecstate,converged, iter, scf_thr, + elecstate::print_etot(ucell.magnet,elecstate,converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, print); delete elecstate.charge; @@ -254,7 +254,7 @@ TEST_F(ElecStatePrintTest, PrintEtotColorS4) inp.noncolin = true; GlobalV::MY_RANK = 0; - elecstate::print_etot(ucell.magnet,elecstate, converged, iter, scf_thr, scf_thr_kin, + elecstate::print_etot(ucell.magnet,elecstate, converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, print); delete elecstate.charge; @@ -283,7 +283,7 @@ TEST_F(ElecStatePrintTest, PrintEtotSDFTPure) inp.ks_solver = "cg"; testing::internal::CaptureStdout(); - elecstate::print_etot(ucell.magnet, elecstate, converged, iter, scf_thr, + elecstate::print_etot(ucell.magnet, elecstate, converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, print); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("CT")); @@ -314,7 +314,7 @@ TEST_F(ElecStatePrintTest, PrintEtotSDFTMixed) inp.ks_solver = "dav"; testing::internal::CaptureStdout(); - elecstate::print_etot(ucell.magnet, elecstate, converged, iter, scf_thr, + elecstate::print_etot(ucell.magnet, elecstate, converged, iter, inp.scf_nmax, scf_thr, scf_thr_kin, duration, inp, two_fermi, pw_diag_thr, avg_iter, print); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("DA")); diff --git a/source/source_estate/test/elecstate_pw_test.cpp b/source/source_estate/unittests/test_elecstate_pw.cpp similarity index 100% rename from source/source_estate/test/elecstate_pw_test.cpp rename to source/source_estate/unittests/test_elecstate_pw.cpp diff --git a/source/source_estate/test/elecstate_fp_energy_test.cpp b/source/source_estate/unittests/test_fp_energy.cpp similarity index 100% rename from source/source_estate/test/elecstate_fp_energy_test.cpp rename to source/source_estate/unittests/test_fp_energy.cpp diff --git a/source/source_estate/test/test_occ_comput.cpp b/source/source_estate/unittests/test_occ_comput.cpp similarity index 100% rename from source/source_estate/test/test_occ_comput.cpp rename to source/source_estate/unittests/test_occ_comput.cpp diff --git a/source/source_estate/test/test_occ_matrix.cpp b/source/source_estate/unittests/test_occ_matrix.cpp similarity index 100% rename from source/source_estate/test/test_occ_matrix.cpp rename to source/source_estate/unittests/test_occ_matrix.cpp diff --git a/source/source_estate/test/test_occ_mixer.cpp b/source/source_estate/unittests/test_occ_mixer.cpp similarity index 100% rename from source/source_estate/test/test_occ_mixer.cpp rename to source/source_estate/unittests/test_occ_mixer.cpp diff --git a/source/source_estate/test/elecstate_occupy_test.cpp b/source/source_estate/unittests/test_occupy.cpp similarity index 100% rename from source/source_estate/test/elecstate_occupy_test.cpp rename to source/source_estate/unittests/test_occupy.cpp diff --git a/source/source_estate/test/test_pcc_0d.cpp b/source/source_estate/unittests/test_pcc_0d.cpp similarity index 100% rename from source/source_estate/test/test_pcc_0d.cpp rename to source/source_estate/unittests/test_pcc_0d.cpp diff --git a/source/source_estate/test/test_pcc_2d.cpp b/source/source_estate/unittests/test_pcc_2d.cpp similarity index 100% rename from source/source_estate/test/test_pcc_2d.cpp rename to source/source_estate/unittests/test_pcc_2d.cpp diff --git a/source/source_estate/test/potentials_base_test.cpp b/source/source_estate/unittests/test_pot_base.cpp similarity index 100% rename from source/source_estate/test/potentials_base_test.cpp rename to source/source_estate/unittests/test_pot_base.cpp diff --git a/source/source_estate/test/test_pot_pcc.cpp b/source/source_estate/unittests/test_pot_pcc.cpp similarity index 100% rename from source/source_estate/test/test_pot_pcc.cpp rename to source/source_estate/unittests/test_pot_pcc.cpp diff --git a/source/source_estate/test/test_pot_sccs.cpp b/source/source_estate/unittests/test_pot_sccs.cpp similarity index 100% rename from source/source_estate/test/test_pot_sccs.cpp rename to source/source_estate/unittests/test_pot_sccs.cpp diff --git a/source/source_estate/test/potential_new_test.cpp b/source/source_estate/unittests/test_potential_new.cpp similarity index 100% rename from source/source_estate/test/potential_new_test.cpp rename to source/source_estate/unittests/test_potential_new.cpp diff --git a/source/source_estate/test/test_sccs_pcc_0d.cpp b/source/source_estate/unittests/test_sccs_pcc_0d.cpp similarity index 100% rename from source/source_estate/test/test_sccs_pcc_0d.cpp rename to source/source_estate/unittests/test_sccs_pcc_0d.cpp diff --git a/source/source_estate/test/test_sccs_pcc_2d.cpp b/source/source_estate/unittests/test_sccs_pcc_2d.cpp similarity index 100% rename from source/source_estate/test/test_sccs_pcc_2d.cpp rename to source/source_estate/unittests/test_sccs_pcc_2d.cpp diff --git a/source/source_estate/test/td_field_test.cpp b/source/source_estate/unittests/test_td_field.cpp similarity index 65% rename from source/source_estate/test/td_field_test.cpp rename to source/source_estate/unittests/test_td_field.cpp index 912eec9c1ab..08b10312d86 100644 --- a/source/source_estate/test/td_field_test.cpp +++ b/source/source_estate/unittests/test_td_field.cpp @@ -4,6 +4,7 @@ #include "source_io/module_parameter/input_parameter.h" #include "gtest/gtest.h" +#include #include #include #include @@ -98,6 +99,67 @@ TEST(TDFieldManagerTest, MixedFieldsSumAndAccumulate) EXPECT_EQ(oscillatory_manager->fields()[1].subdivisions(), 12); } +TEST(TDFieldManagerTest, SubintervalsPreserveFieldAndOriginalGrid) +{ + Input_para input; + input.td_vext = true; + input.td_stype = 1; + input.td_dt = ModuleBase::AU_to_FS; + input.td_tstart = 0; + input.td_tend = 10; + input.td_ttype = std::vector{2}; + input.td_vext_dire = std::vector{1}; + const double omega = 0.02; + input.td_trigo_freq1 = {omega / (2 * ModuleBase::PI * ModuleBase::AU_to_FS)}; + input.td_trigo_freq2 = {0.0}; + input.td_trigo_phase1 = {0.0}; + input.td_trigo_phase2 = {ModuleBase::PI / 2}; + input.td_trigo_amp = {1.0}; + const double amp = ModuleBase::BOHR_TO_A / ModuleBase::Hartree_to_eV; + + for (bool from_file: {false, true}) + { + SCOPED_TRACE(from_file); + std::shared_ptr manager = elecstate::create_td_field_manager(input); + if (from_file) + { + const std::vector> samples = {{0, 0, 0}, {2, 0, 0}, {5, 0, 0}}; + manager->set_A_samples(samples); + } + manager->prepare_sample(0); + manager->prepare_interval(0, 1); + const elecstate::TDFieldState full = manager->field_state(); + const elecstate::TDFieldState left = manager->subinterval(full, 0, 2); + manager->bind_field(left); + const elecstate::TDFieldState right = manager->subinterval(full, 1, 2); + EXPECT_DOUBLE_EQ(left.dt, 0.5); + EXPECT_DOUBLE_EQ(right.dt, 0.5); + EXPECT_DOUBLE_EQ(left.left.x, full.left.x); + EXPECT_DOUBLE_EQ(left.right.x, right.left.x); + EXPECT_DOUBLE_EQ(right.right.x, full.right.x); + const double mid_a = from_file ? 1.0 : -amp * std::sin(omega * 0.5) / omega; + const double mid_e = from_file ? -2.0 : amp * std::cos(omega * 0.5); + EXPECT_NEAR(left.right.x, mid_a, 1e-11); + EXPECT_NEAR(left.electric.x, mid_e, 1e-14); + EXPECT_DOUBLE_EQ(left.propagation.x, (left.left.x + left.right.x) * 0.5); + EXPECT_DOUBLE_EQ(right.propagation.x, (right.left.x + right.right.x) * 0.5); + manager->bind_field(right); + EXPECT_EQ(manager->current_step(), 1); + EXPECT_DOUBLE_EQ(manager->interval_dt_ha(), 0.5); + manager->bind_field(full); + manager->prepare_interval(0, 1); + EXPECT_EQ(manager->current_step(), 1); + EXPECT_DOUBLE_EQ(manager->interval_dt_ha(), 1.0); + EXPECT_DOUBLE_EQ(manager->A_right_ha().x, full.right.x); + EXPECT_DOUBLE_EQ(manager->efield_ha().x, full.electric.x); + manager->prepare_interval(1, 2); + const double end_a = from_file ? 5.0 : -amp * std::sin(2 * omega) / omega; + EXPECT_EQ(manager->current_step(), 2); + EXPECT_DOUBLE_EQ(manager->A_left_ha().x, full.right.x); + EXPECT_NEAR(manager->A_right_ha().x, end_a, 1e-10); + } +} + TEST(TDFieldManagerTest, RestartRequiresCompleteState) { Input_para input; diff --git a/source/source_hamilt/module_sccs/test/CMakeLists.txt b/source/source_hamilt/module_sccs/test/CMakeLists.txt index 3a8e88d9dfe..ad98a0503c2 100644 --- a/source/source_hamilt/module_sccs/test/CMakeLists.txt +++ b/source/source_hamilt/module_sccs/test/CMakeLists.txt @@ -7,9 +7,9 @@ AddTest(TARGET MODULE_HAMILT_sccs_parameters AddTest(TARGET MODULE_HAMILT_sccs_poisson LIBS parameter planewave device base SOURCES test_sccs_lowpass.cpp test_sccs_cav_deriv.cpp test_sccs_coul_0d.cpp test_sccs_coul_2d.cpp test_sccs_pw_coulomb.cpp test_sccs_ion_charge.cpp test_sccs_ion_force.cpp test_sccs_response.cpp test_sccs_functional.cpp - ../../../source_estate/test/test_pot_sccs.cpp - ../../../source_estate/test/test_sccs_pcc_0d.cpp - ../../../source_estate/test/test_sccs_pcc_2d.cpp + ../../../source_estate/unittests/test_pot_sccs.cpp + ../../../source_estate/unittests/test_sccs_pcc_0d.cpp + ../../../source_estate/unittests/test_sccs_pcc_2d.cpp ../../../source_estate/module_pot/pot_sccs.cpp ../../../source_estate/module_pot/sccs_pcc_0d.cpp ../../../source_estate/module_pot/sccs_pcc_2d.cpp diff --git a/source/source_hsolver/CMakeLists.txt b/source/source_hsolver/CMakeLists.txt index e7adc3fb5ad..adca70290f7 100644 --- a/source/source_hsolver/CMakeLists.txt +++ b/source/source_hsolver/CMakeLists.txt @@ -6,23 +6,12 @@ list(APPEND objects diago_bpcg.cpp para_lin_tf.cpp hsolver_pw.cpp - hsolver_pw_tddft.cpp hsolver_lcaopw.cpp diago_iter_assist.cpp hsolver.cpp diago_pxxxgvx.cpp diag_hs_para.cpp diago_params.cpp - linear_bicgstab.cpp - linear_cgs.cpp - linear_gmres.cpp - linear_algebra.cpp - orthonormal.cpp - orthonormal_small.cpp - cn_subspace.cpp - linear_low_rank.cpp - linear_workspace.cpp - hsolver_linear.cpp ) if(ENABLE_LCAO) @@ -94,9 +83,11 @@ if(ENABLE_ELPA) endif() if(BUILD_TESTING) - add_subdirectory(test) + add_subdirectory(unittests) if(ENABLE_MPI) add_subdirectory(kernels/test) endif() message(STATUS "Building tests") endif() + +add_subdirectory(module_linalg) diff --git a/source/source_hsolver/hsolver_pw.h b/source/source_hsolver/hsolver_pw.h index d5cbb772a8c..db6764154c8 100644 --- a/source/source_hsolver/hsolver_pw.h +++ b/source/source_hsolver/hsolver_pw.h @@ -9,7 +9,7 @@ #include #include -class TestHSolverPW; // unit-test fixture, see source_hsolver/test/ +class TestHSolverPW; // unit-test fixture, see source_hsolver/unittests/ namespace hsolver { diff --git a/source/source_hsolver/hsolver_pw_tddft.cpp b/source/source_hsolver/hsolver_pw_tddft.cpp deleted file mode 100644 index e65d7a541f0..00000000000 --- a/source/source_hsolver/hsolver_pw_tddft.cpp +++ /dev/null @@ -1,655 +0,0 @@ -#include "source_hsolver/hsolver_pw_tddft.h" - -#include "source_base/module_device/memory_op.h" -#include "source_base/parallel_device.h" -#include "source_base/timer.h" -#include "source_base/tool_quit.h" -#include "source_basis/module_pw/pw_momentum.h" -#include "source_hsolver/kernels/linear_op.h" - -#include -#include -#include - -namespace hsolver -{ -namespace -{ - -struct LinearMethodName -{ - const char* name; - LinearMethod method; -}; - -constexpr LinearMethodName linear_method_names[] - = {{"bicgstab", LinearMethod::bicgstab}, {"cgs", LinearMethod::cgs}, {"gmres", LinearMethod::gmres}}; - -struct PWPrecondName -{ - const char* name; - PWPreconditioner preconditioner; -}; - -constexpr PWPrecondName pw_precond_names[] = {{"none", PWPreconditioner::none}, - {"kinetic", PWPreconditioner::kinetic}, - {"kinetic_recycle", PWPreconditioner::kinetic_recycle}, - {"kinetic_subspace", PWPreconditioner::kinetic_subspace}}; - -template -class ShiftedHOperator final : public LinearOperator -{ - public: - ShiftedHOperator(const HSOperator& op, const T coefficient, const int dim) : op_(op), coefficient_(coefficient), dim_(dim) - { - } - void apply(const T* x, T* y, const int ld, const int nvec) const override - { - op_.hpsi(x, y, ld, nvec); - linear_op().batch(ld, dim_, nvec, y, x, y, T(1), coefficient_, nullptr, nullptr, nullptr); - } - - private: - const HSOperator& op_; - const T coefficient_; - const int dim_; -}; - -} // namespace - -LinearMethod parse_linear_method(const std::string& name) -{ - for (const LinearMethodName& entry: linear_method_names) - { - if (name == entry.name) - { - return entry.method; - } - } - const std::string message = "Unsupported linear solver: " + name; - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", message); - return LinearMethod::bicgstab; -} - -PWPreconditioner parse_pw_precond(const std::string& name) -{ - for (const PWPrecondName& entry: pw_precond_names) - { - if (name == entry.name) - { - return entry.preconditioner; - } - } - const std::string message = "Unsupported preconditioner: " + name; - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", message); - return PWPreconditioner::kinetic; -} - -template -HSolverPWTDDFT::HSolverPWTDDFT(const ModulePW::PW_Basis_K& basis, - const PWLinearOptions& options, - const diag_comm_info& comm, - std::ostream& log) - : basis_(basis), comm_(comm), options_(options), algebra_(comm), orthonormal_(comm, algebra_), log_(log), band_products_(comm, 9) -{ - initialize(); - log_ << " PW RT-TDDFT orthonormalization: " << orth_method_name(options_.orthonormal) << '\n'; -} - -template -void HSolverPWTDDFT::initialize() -{ - const char* method = nullptr; - for (const LinearMethodName& entry: linear_method_names) - { - if (options_.linear.method == entry.method) - { - method = entry.name; - break; - } - } - if (method == nullptr) - { - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", "Unsupported linear solver."); - return; - } - const char* preconditioner = nullptr; - for (const PWPrecondName& entry: pw_precond_names) - { - if (options_.preconditioner == entry.preconditioner) - { - preconditioner = entry.name; - break; - } - } - if (preconditioner == nullptr) - { - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", "Unsupported preconditioner."); - return; - } - if (options_.linear.method != LinearMethod::gmres) - { - // Ignore the GMRES-only option before creating solver state or reporting effective settings. - options_.linear.reconstruct = false; - } - linear_solver_.reset(new HSolverLinear(options_.linear, comm_)); - std::ostringstream info; - info << " PW RT-TDDFT linear solver: " << method << "; tolerance: " << std::scientific << std::setprecision(6) - << linear_solver_->tolerance() << "; maximum iterations: " << options_.linear.max_iterations - << "; restart: " << options_.linear.restart << '\n' - << " Preconditioner: " << preconditioner << "; CN initial guess: " << options_.cn_init - << "; residual reconstruction: " << options_.linear.reconstruct << '\n'; - log_ << info.str(); -} - -template -void HSolverPWTDDFT::prepare_buffers(const int nbands, const int nbasis) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "prepare_buffers"); - using CtDevice = typename ct::PsiToContainer::type; - const ct::DeviceType device = ct::DeviceTypeToEnum::value; - const int64_t elements = static_cast(nbands) * nbasis; - const int64_t size = std::max(1, elements); - if (rhs_.NumElements() < size || rhs_.data_type() != ct::DataTypeToEnum::value || rhs_.device_type() != device) - { - rhs_ = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); - hpsi_ = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); - } - ModuleBase::timer::end("HSolverPWTDDFT", "prepare_buffers"); -} - -template -void HSolverPWTDDFT::update_precond(const int ik, - const int dim, - const T coefficient, - const ModuleBase::Vector3& momentum_shift) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "update_precond"); - using CtDevice = typename ct::PsiToContainer::type; - const ct::DeviceType device = ct::DeviceTypeToEnum::value; - const int elements = std::max(1, dim); - if (inverse_kinetic_.NumElements() < elements || inverse_kinetic_.data_type() != ct::DataTypeToEnum::value - || inverse_kinetic_.device_type() != device) - { - inverse_kinetic_ = ct::Tensor(ct::DataTypeToEnum::value, device, {elements}); - } - std::vector inverse(dim); - for (int ig = 0; ig < dim; ++ig) - { - const double kinetic = options_.kinetic_enabled ? ModulePW::shifted_kinetic(basis_, ik, ig, momentum_shift) : 0.0; - inverse[ig] = T(1) / (T(1) + coefficient * static_cast(kinetic)); - } - if (dim > 0) - { - base_device::memory::synchronize_memory_op()(inverse_kinetic_.template data(), - inverse.data(), - dim); - } - ModuleBase::timer::end("HSolverPWTDDFT", "update_precond"); -} - -template -bool HSolverPWTDDFT::tracks_state() const -{ - return options_.preconditioner == PWPreconditioner::kinetic_recycle || options_.linear.reconstruct; -} - -template -void HSolverPWTDDFT::prepare_sequence(int nk, int ld, int bands, double dt, int step, int iteration) -{ - if (!tracks_state()) - { - return; - } - const bool reset = states_.size() != static_cast(nk) || dt != sequence_.dt || ld != sequence_.ld || bands != sequence_.bands - || step < sequence_.step || (step == sequence_.step && iteration <= sequence_.iteration); - if (reset) - { - states_.clear(); - states_.resize(nk); - } - sequence_.dt = dt; - sequence_.ld = ld; - sequence_.bands = bands; - sequence_.step = step; - sequence_.iteration = iteration; -} - -template -void HSolverPWTDDFT::invalidate_basis() -{ - for (KPointState& state: states_) - { - state.response.clear(); - state.solve_count = 0; - state.independent_step = -1; - } -} - -template -bool HSolverPWTDDFT::require_audit(int step, KPointState* state) const -{ - if (!options_.linear.reconstruct) - { - return true; - } - constexpr unsigned int audit_period = 16; - const bool required = state->solve_count % audit_period == 0 || state->independent_step == step; - ++state->solve_count; - return required; -} - -template -void HSolverPWTDDFT::retry_kinetic(const LinearOperator& op, - T* current, - const SolveBatch& batch, - LinearSolveResult* result) -{ - const int remaining_iterations = options_.linear.max_iterations - result->iterations; - const LinearSolveControl control{remaining_iterations, false}; - const T* inverse = inverse_kinetic_.template data(); - const LinearLowRank diagonal(algebra_, inverse, batch.dim); - const T* rhs = rhs_.template data(); - LinearSolveResult retry = linear_solver_->solve(op, diagonal, batch.ld, batch.bands, batch.dim, current, rhs, nullptr, true, control); - retry.iterations += result->iterations; - retry.restarts += result->restarts; - retry.operator_calls += result->operator_calls; - retry.operator_columns += result->operator_columns; - retry.true_checks += result->true_checks; - retry.reconstruction_fallbacks += result->reconstruction_fallbacks; - *result = retry; -} - -template -void HSolverPWTDDFT::update_state(KPointState* state, - const SolveDetails& details, - int step, - const SolveBatch& batch, - const T* current) -{ - if (!state) - { - return; - } - if (details.retried || details.linear.reconstruction_fallbacks > 0) - { - state->response.clear(); - } - if (details.linear.reconstruction_fallbacks > 0) - { - state->independent_step = step; - } - if (options_.preconditioner == PWPreconditioner::kinetic_recycle && details.projected - && details.linear.status == LinearSolveStatus::converged && details.linear.reconstruction_fallbacks == 0 && !details.retried) - { - const T* seed = projection_.seed(); - const T* residual = projection_.residual(); - const double tolerance = linear_solver_->tolerance(); - state->response.update(algebra_, batch.ld, batch.dim, batch.bands, current, seed, residual, tolerance, &response_workspace_); - } -} - -template -typename HSolverPWTDDFT::SolveDetails HSolverPWTDDFT::solve_kpoint(const LinearOperator& op, - const T* previous, - T* current, - const SolveBatch& batch, - int step, - int iteration, - KPointState* state) -{ - SolveDetails details; - const T* rhs = rhs_.template data(); - const bool need_projection = (options_.cn_init && iteration == 1) || options_.preconditioner == PWPreconditioner::kinetic_recycle - || options_.preconditioner == PWPreconditioner::kinetic_subspace; - details.projected = need_projection && projection_.prepare(algebra_, batch.ld, batch.dim, batch.bands, previous, rhs); - const T* initial_residual = nullptr; - if (options_.cn_init && iteration == 1 && details.projected) - { - const T* seed = projection_.seed(); - band_products_.copy(batch.ld, batch.dim, batch.bands, seed, current); - initial_residual = projection_.residual(); - details.cn_initial = true; - } - const bool force_check = require_audit(step, state); - const T* inverse = options_.preconditioner == PWPreconditioner::none ? nullptr : inverse_kinetic_.template data(); - LinearLowRank preconditioner(algebra_, inverse, batch.dim); - if (options_.preconditioner == PWPreconditioner::kinetic_subspace && details.projected) - { - const T* image = projection_.image(); - const LinearSmallLU& factor = projection_.factor(); - preconditioner.prepare_subspace(batch.ld, batch.bands, previous, image, factor, &correction_workspace_); - } - else if (options_.preconditioner == PWPreconditioner::kinetic_recycle && state->response.rank() > 0) - { - const int rank = state->response.rank(); - const T* directions = state->response.directions(); - const T* images = state->response.images(); - preconditioner.prepare_response(batch.ld, rank, directions, images, &correction_workspace_); - } - details.coarse_rank = preconditioner.rank(); - details.linear - = linear_solver_->solve(op, preconditioner, batch.ld, batch.bands, batch.dim, current, rhs, initial_residual, force_check); - if (details.linear.status != LinearSolveStatus::converged && details.coarse_rank > 0 - && details.linear.iterations < options_.linear.max_iterations) - { - retry_kinetic(op, current, batch, &details.linear); - details.retried = true; - } - update_state(state, details, step, batch, current); - return details; -} - -template -void HSolverPWTDDFT::report_solve(const SolveDetails& details, int ik, int step, int iteration) const -{ - const LinearSolveResult& result = details.linear; - const int evolution_step = step + 1; - std::ostringstream record; - record << std::scientific << std::setprecision(6) << " PW RT-TDDFT linear solve: evolution_step=" << evolution_step - << " scf_iter=" << iteration << " global_k=" << options_.global_k_indices.at(ik) << '\n' - << " iterations=" << result.iterations << " restarts=" << result.restarts << " operator_calls=" << result.operator_calls - << " operator_columns=" << result.operator_columns << " pre_orth_residual=" << result.max_residual - << " residual_kind=" << (result.reconstructed ? "reconstructed" : "independent") << " true_checks=" << result.true_checks << '\n' - << " reconstruction_fallbacks=" << result.reconstruction_fallbacks << " coarse_rank=" << details.coarse_rank - << " kinetic_retry=" << details.retried << " cn_projected=" << details.projected << " cn_initial=" << details.cn_initial << '\n'; - log_ << record.str(); -} - -template -void HSolverPWTDDFT::solve(HSOperator& op, - const psi::Psi& previous, - psi::Psi* current, - const double dt, - const ModuleBase::Vector3& momentum_shift, - const int istep, - const int iter, - const bool detailed_output) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "solve"); - const int bands = current->get_nbands(); - const int ld = current->get_nbasis(); - const int nk = current->get_nk(); - if (options_.out_stat) - { - orth_norms_.resize(nk); - } - prepare_buffers(bands, ld); - prepare_sequence(nk, ld, bands, dt, istep, iter); - T* rhs = rhs_.template data(); - // H is stored in Rydberg; CN includes the conversion to Hartree. - const T coefficient(0.0, dt / 4.0); - const T rhs_coefficient = -coefficient; - for (int ik = 0; ik < nk; ++ik) - { - op.update_k(ik); - current->fix_k(ik); - previous.fix_k(ik); - const int dim = current->get_ngk(ik); - KPointState* state = tracks_state() ? &states_[ik] : nullptr; - const ShiftedHOperator rhs_op(op, rhs_coefficient, dim); - const ShiftedHOperator lhs_op(op, coefficient, dim); - const T* previous_data = previous.get_pointer(); - T* current_data = current->get_pointer(); - rhs_op.apply(previous_data, rhs, ld, bands); - if (options_.preconditioner != PWPreconditioner::none) - { - update_precond(ik, dim, coefficient, momentum_shift); - } - const SolveBatch batch{ld, dim, bands}; - const SolveDetails details = solve_kpoint(lhs_op, previous_data, current_data, batch, istep, iter, state); - if (detailed_output && log_.good()) - { - report_solve(details, ik, istep, iter); - } - if (details.linear.status != LinearSolveStatus::converged) - { - const LinearSolveResult& result = details.linear; - std::ostringstream message; - const int evolution_step = istep + 1; - message << "PW RT-TDDFT linear solve failed at electronic evolution step " << evolution_step << ", SCF iteration " << iter - << ", global_k=" << options_.global_k_indices.at(ik) << ", band " << result.failed_band << ", after " - << result.iterations << " iterations: " << linear_status_name(result.status) << "; residual = " << result.max_residual; - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", message.str()); - } - correct_orbitals(current_data, ld, dim, bands, ik, istep, iter, detailed_output); - } - ModuleBase::timer::end("HSolverPWTDDFT", "solve"); -} - -template -void HSolverPWTDDFT::cal_band_energy(HSOperator& op, const psi::Psi& current, ModuleBase::matrix* energies) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "cal_band_energy"); - const int nband = current.get_nbands(); - const int ld = current.get_nbasis(); - prepare_buffers(nband, ld); - std::vector expectations(nband); - T* hpsi = hpsi_.template data(); - for (int ik = 0; ik < current.get_nk(); ++ik) - { - op.update_k(ik); - current.fix_k(ik); - op.hpsi(current.get_pointer(), hpsi, ld, nband); - band_products_.dot(ld, current.get_ngk(ik), nband, current.get_pointer(), hpsi, expectations.data()); - for (int band = 0; band < nband; ++band) - { - (*energies)(ik, band) = std::real(expectations[band]); - } - } - ModuleBase::timer::end("HSolverPWTDDFT", "cal_band_energy"); -} - -template -std::vector> HSolverPWTDDFT::cal_eij(HSOperator& op, - const psi::Psi& current, - const int ik) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "cal_eij"); - const int nband = current.get_nbands(); - const int ld = current.get_nbasis(); - const int dim = current.get_ngk(ik); - prepare_buffers(nband, ld); - op.update_k(ik); - current.fix_k(ik); - const T* psi = current.get_pointer(); - T* hpsi = hpsi_.template data(); - op.hpsi(psi, hpsi, ld, nband); - std::vector> result = algebra_.cross(ld, dim, nband, nband, psi, hpsi); - ModuleBase::timer::end("HSolverPWTDDFT", "cal_eij"); - return result; -} - -template -void HSolverPWTDDFT::reset_orth_stats() -{ - if (options_.out_stat) - { - orth_stats_ = TDOrthStats(); - } - warned_events_ = 0; -} - -template -void HSolverPWTDDFT::correct_orbitals(T* current, int ld, int dim, int bands, int ik, int istep, int iter, bool detailed_output) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "correct_orbitals"); - const OrthResult result = orthonormal_.apply(current, ld, dim, bands, options_.orthonormal, options_.out_stat); - record_orth(result, ik, istep, iter); - if (detailed_output && result.gram_checked && log_.good()) - { - const int evolution_step = istep + 1; - std::ostringstream record; - record << std::scientific << std::setprecision(6) << " PW RT-TDDFT orth: evolution_step=" << evolution_step << " scf_iter=" << iter - << " global_k=" << options_.global_k_indices.at(ik) << " requested=" << orth_method_name(options_.orthonormal) - << " orth_before=" << result.before << " orth_after=" << result.after << '\n'; - log_ << record.str(); - } - ModuleBase::timer::end("HSolverPWTDDFT", "correct_orbitals"); -} - -template -void HSolverPWTDDFT::record_orth(const OrthResult& result, int ik, int istep, int iter) -{ - if (result.status == OrthStatus::failed) - { - const char* stage = istep == 0 ? "initialization" : "propagation"; - std::ostringstream message; - const int evolution_step = istep + 1; - message << std::setprecision(16) << " PW RT-TDDFT orbital validation failed (" << stage << "): evolution_step=" << evolution_step - << " scf_iter=" << iter << " global_k=" << options_.global_k_indices.at(ik) - << " requested=" << orth_method_name(options_.orthonormal) << '\n' - << " last_attempted=" << orth_method_name(result.actual) << " passes=" << result.passes - << " fallbacks=" << result.fallbacks << '\n' - << " " << orth_failure_name(result.failure) << "; " << result.reason; - if (result.gram_checked) - { - message << '\n' << " before=" << result.before << " after=" << result.after << " tolerance=" << orth_tolerance(); - } - // stdout is disabled on non-world-root ranks; a failing pool must still report its error. - if (comm_.rank == 0) - { - std::cerr << message.str() << std::endl; - } -#ifdef __MPI - // Let the pool root flush its diagnostic before another rank's exit stops the MPI job. - double diagnostic_written = 1.0; - Parallel_Common::bcast_data(&diagnostic_written, 1, comm_.comm, 0); -#endif - ModuleBase::WARNING_QUIT("HSolverPWTDDFT", message.str()); - } - report_orth_warning(result, ik, istep, iter); - if (options_.out_stat) - { - orth_norms_[ik] = result.norms; - if (result.gram_checked) - { - orth_stats_.before = std::max(orth_stats_.before, result.before); - orth_stats_.after = std::max(orth_stats_.after, result.after); - } - } -} - -template -void HSolverPWTDDFT::report_orth_warning(const OrthResult& result, int ik, int istep, int iter) -{ - if (comm_.rank != 0) - { - return; - } - unsigned int events = 0; - if (result.fallbacks > 0) - { - events |= 1; - } - if (result.rejected > 0) - { - events |= 2; - } - const unsigned int fresh_events = events & ~warned_events_; - if (fresh_events == 0) - { - return; - } - warned_events_ |= events; - const int evolution_step = istep + 1; - std::ostringstream message; - message << std::setprecision(16) << " PW RT-TDDFT orbital warning: evolution_step=" << evolution_step << " scf_iter=" << iter; - message << " global_k=" << options_.global_k_indices.at(ik); - message << " requested=" << orth_method_name(options_.orthonormal) << '\n' - << " before=" << result.before << " after=" << result.after << " tolerance=" << orth_tolerance() << '\n' - << " "; - message << "last_attempted=" << orth_method_name(result.actual) << ". "; - if (fresh_events & 1) - { - message << "A fallback was attempted. "; - } - if (fresh_events & 2) - { - message << "A candidate was rejected. "; - } - message << "The retained state satisfies the tolerance." << '\n' - << " " << result.reason << '\n' - << " Further events of these types in this pool are suppressed for this electronic evolution step."; - const std::string text = message.str(); - std::cerr << text << std::endl; - if (log_.good()) - { - log_ << text << std::endl; - } -} - -template -bool HSolverPWTDDFT::correct_initial(psi::Psi* current, int iter) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "correct_initial"); - bool changed = false; - if (options_.orthonormal != OrthMethod::none) - { - if (options_.out_stat) - { - // Initial diagnostics describe this SCF state, not earlier discarded iterates. - orth_stats_ = TDOrthStats(); - orth_norms_.resize(current->get_nk()); - } - for (int ik = 0; ik < current->get_nk(); ++ik) - { - current->fix_k(ik); - const OrthResult result = orthonormal_.apply(current->get_pointer(), - current->get_nbasis(), - current->get_ngk(ik), - current->get_nbands(), - options_.orthonormal, - options_.out_stat); - record_orth(result, ik, 0, iter); - changed = changed || result.status == OrthStatus::accepted; - } - } - ModuleBase::timer::end("HSolverPWTDDFT", "correct_initial"); - return changed; -} - -template -void HSolverPWTDDFT::check_initial(const psi::Psi& current, int iter) -{ - ModuleBase::timer::start("HSolverPWTDDFT", "check_initial"); - const bool full_gram = options_.orthonormal != OrthMethod::none; - if (options_.out_stat) - { - orth_norms_.resize(current.get_nk()); - } - for (int ik = 0; ik < current.get_nk(); ++ik) - { - current.fix_k(ik); - const OrthResult result = orthonormal_.inspect(current.get_pointer(), - current.get_nbasis(), - current.get_ngk(ik), - current.get_nbands(), - full_gram, - options_.out_stat); - record_orth(result, ik, 0, iter); - } - ModuleBase::timer::end("HSolverPWTDDFT", "check_initial"); -} - -template -double HSolverPWTDDFT::wave_electrons(const ModuleBase::matrix& occupations) const -{ - double electrons = 0.0; - for (std::size_t ik = 0; ik < orth_norms_.size(); ++ik) - { - for (std::size_t band = 0; band < orth_norms_[ik].size(); ++band) - { - electrons += occupations(ik, band) * orth_norms_[ik][band]; - } - } - return electrons; -} - -template class HSolverPWTDDFT, base_device::DEVICE_CPU>; -template class HSolverPWTDDFT, base_device::DEVICE_CPU>; -#if defined(__CUDA) || defined(__ROCM) -template class HSolverPWTDDFT, base_device::DEVICE_GPU>; -template class HSolverPWTDDFT, base_device::DEVICE_GPU>; -#endif -} // namespace hsolver diff --git a/source/source_hsolver/module_linalg/CMakeLists.txt b/source/source_hsolver/module_linalg/CMakeLists.txt new file mode 100644 index 00000000000..d24fac5250f --- /dev/null +++ b/source/source_hsolver/module_linalg/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(hsolver_linalg OBJECT + orb_buffer.cpp + exp_action.cpp + exp_taylor.cpp + exp_lanczos.cpp + hsolver_linear.cpp + linear_bicgstab.cpp + linear_cgs.cpp + linear_gmres.cpp + linear_workspace.cpp + linear_algebra.cpp + linear_low_rank.cpp + cn_subspace.cpp + orthonormal.cpp + orthonormal_small.cpp +) + +if(ENABLE_COVERAGE) + add_coverage(hsolver_linalg) +endif() + +if(BUILD_TESTING) + add_subdirectory(unittests) +endif() diff --git a/source/source_hsolver/cn_subspace.cpp b/source/source_hsolver/module_linalg/cn_subspace.cpp similarity index 91% rename from source/source_hsolver/cn_subspace.cpp rename to source/source_hsolver/module_linalg/cn_subspace.cpp index f11b661836a..640f0b9dc77 100644 --- a/source/source_hsolver/cn_subspace.cpp +++ b/source/source_hsolver/module_linalg/cn_subspace.cpp @@ -1,7 +1,7 @@ -#include "source_hsolver/cn_subspace.h" +#include "source_hsolver/module_linalg/cn_subspace.h" -#include "source_hsolver/kernels/linear_op.h" -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" +#include "source_hsolver/module_linalg/linear_workspace.h" namespace hsolver { diff --git a/source/source_hsolver/cn_subspace.h b/source/source_hsolver/module_linalg/cn_subspace.h similarity index 93% rename from source/source_hsolver/cn_subspace.h rename to source/source_hsolver/module_linalg/cn_subspace.h index 0e822b7c3d2..a7492d30163 100644 --- a/source/source_hsolver/cn_subspace.h +++ b/source/source_hsolver/module_linalg/cn_subspace.h @@ -1,6 +1,6 @@ #ifndef HSOLVER_CN_SUBSPACE_H #define HSOLVER_CN_SUBSPACE_H -#include "source_hsolver/linear_algebra.h" +#include "source_hsolver/module_linalg/linear_algebra.h" namespace hsolver { diff --git a/source/source_hsolver/module_linalg/exp_action.cpp b/source/source_hsolver/module_linalg/exp_action.cpp new file mode 100644 index 00000000000..eb34865d733 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_action.cpp @@ -0,0 +1,49 @@ +#include "source_hsolver/module_linalg/exp_action.h" + +#include "source_hsolver/module_linalg/exp_lanczos.h" +#include "source_hsolver/module_linalg/exp_taylor.h" + +#include +#include + +namespace hsolver +{ +template +ExpAction::ExpAction(const ExpControls& exp_ctrl, const diag_comm_info& comm) : exp_ctrl_(exp_ctrl), algebra_(comm) +{ + using Real = typename T::value_type; + if (exp_ctrl_.rel_tol == 0.0) + { + exp_ctrl_.rel_tol = std::max(1e-10, 100.0 * std::numeric_limits::epsilon()); + } + if (exp_ctrl_.taylor_order < 2 || exp_ctrl_.krylov_max < 2 || !std::isfinite(exp_ctrl_.rel_tol) || exp_ctrl_.rel_tol <= 0) + { + throw std::invalid_argument("Invalid exponential controls."); + } +} + +template +std::unique_ptr> make_exp_action(const ExpControls& exp_ctrl, const diag_comm_info& comm) +{ + if (exp_ctrl.expansion == ExpMethod::taylor) + { + return std::unique_ptr>(new ExpTaylor(exp_ctrl, comm)); + } + return std::unique_ptr>(new ExpLanczos(exp_ctrl, comm)); +} + +template class ExpAction, base_device::DEVICE_CPU>; +template class ExpAction, base_device::DEVICE_CPU>; +template std::unique_ptr, base_device::DEVICE_CPU>> make_exp_action(const ExpControls&, + const diag_comm_info&); +template std::unique_ptr, base_device::DEVICE_CPU>> make_exp_action(const ExpControls&, + const diag_comm_info&); +#if defined(__CUDA) || defined(__ROCM) +template class ExpAction, base_device::DEVICE_GPU>; +template class ExpAction, base_device::DEVICE_GPU>; +template std::unique_ptr, base_device::DEVICE_GPU>> make_exp_action(const ExpControls&, + const diag_comm_info&); +template std::unique_ptr, base_device::DEVICE_GPU>> make_exp_action(const ExpControls&, + const diag_comm_info&); +#endif +} // namespace hsolver diff --git a/source/source_hsolver/module_linalg/exp_action.h b/source/source_hsolver/module_linalg/exp_action.h new file mode 100644 index 00000000000..974deaba102 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_action.h @@ -0,0 +1,74 @@ +#ifndef HSOLVER_EXP_ACTION_H +#define HSOLVER_EXP_ACTION_H + +#include "source_hsolver/hs_operator.h" +#include "source_hsolver/module_linalg/linear_algebra.h" +#include "source_hsolver/module_linalg/orb_buffer.h" + +#include + +namespace hsolver +{ +enum class ExpMethod +{ + taylor, + lanczos +}; + +/** @brief Explicit controls for a frozen Hermitian Hamiltonian exponential. */ +struct ExpControls +{ + ExpMethod expansion = ExpMethod::lanczos; + int taylor_order = 4; + double rel_tol = 0.0; + int krylov_max = 32; +}; + +/** @brief Outcome of an exponential evaluation; retry requests a shorter interval. */ +enum class ExpState +{ + success, + retry, + failed +}; + +/** @brief Error is relative to the input norm and only estimated by Lanczos. */ +struct ExpResult +{ + ExpState state = ExpState::success; + bool has_err_est = false; + double rel_err_est = 0.0; + int order_or_dim = 0; + int bisect_count = 0; + int reorth_count = 0; + int failed_band = -1; + long long hpsi_calls = 0; + long long hpsi_cols = 0; +}; + +/** @brief Apply exp(-i*alpha*H_Ry); caller selects k, buffers must not alias. */ +template +class ExpAction +{ + protected: + ExpControls exp_ctrl_; + LinearAlgebra algebra_; + + public: + ExpAction(const ExpControls& exp_ctrl, const diag_comm_info& comm); + virtual ~ExpAction() = default; + /** @brief Effective relative tolerance after resolving the precision-dependent default. */ + double rel_tol() const + { + return exp_ctrl_.rel_tol; + } + virtual ExpResult apply(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output) = 0; + virtual ExpResult apply_pair(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* half, T* full) + = 0; +}; + +/** @brief Construct a backend without reading global input parameters. */ +template +std::unique_ptr> make_exp_action(const ExpControls& exp_ctrl, const diag_comm_info& comm); +} // namespace hsolver +#endif diff --git a/source/source_hsolver/module_linalg/exp_lanczos.cpp b/source/source_hsolver/module_linalg/exp_lanczos.cpp new file mode 100644 index 00000000000..9c020595748 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_lanczos.cpp @@ -0,0 +1,554 @@ +#include "source_hsolver/module_linalg/exp_lanczos.h" + +#include "source_base/module_container/base/third_party/lapack.h" +#include "source_base/parallel_device.h" +#include "source_base/timer.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" + +#include + +namespace hsolver +{ +namespace +{ +using Wide = std::complex; + +void add_work(ExpResult& total, const ExpResult& part) +{ + total.hpsi_calls += part.hpsi_calls; + total.hpsi_cols += part.hpsi_cols; + total.bisect_count += part.bisect_count; + total.reorth_count += part.reorth_count; + total.order_or_dim = std::max(total.order_or_dim, part.order_or_dim); +} + +ExpResult failed_band(ExpResult result, int band, bool retry) +{ + result.failed_band = band; + result.state = retry ? ExpState::retry : ExpState::failed; + result.has_err_est = false; + return result; +} +} // namespace + +template +ExpLanczos::ExpLanczos(const ExpControls& exp_ctrl, const diag_comm_info& comm) + : ExpAction(exp_ctrl, comm), comm_(comm), work_(comm, 1) +{ +} + +template +int ExpLanczos::batch_size(const OrbLayout& layout) const +{ + // The layout can differ between ranks, but operator column counts must agree. + double rows = std::max(1, layout.ld); +#ifdef __MPI + if (comm_.nproc > 1) + { + std::vector sizes(comm_.nproc, 0.0); + sizes[comm_.rank] = rows; + Parallel_Common::reduce_data(sizes.data(), comm_.nproc, comm_.comm); + rows = *std::max_element(sizes.begin(), sizes.end()); + } +#endif + const double vectors = static_cast(this->exp_ctrl_.krylov_max) + 6.0; + const double bytes_per_band = sizeof(T) * rows * vectors; + const double budget = 256.0 * 1024.0 * 1024.0; + const int memory_limit = static_cast(std::min(64.0, budget / bytes_per_band)); + return std::max(1, std::min(layout.bands, memory_limit)); +} + +template +void ExpLanczos::combine(const OrbLayout& layout, int count, const T* basis, const std::vector& coefficients, T* output) +{ + ModuleBase::timer::start("ExpLanczos", "combine"); + linear_buffer(&coefficients_, coefficients.size()); + T* data = coefficients_.template data(); + base_device::memory::synchronize_memory_op()(data, coefficients.data(), coefficients.size()); + const int dim = layout.npol == 2 ? layout.ld : layout.npw; + const int stride = layout.ld * layout.bands; + linear_op().combine(layout.ld, dim, layout.bands, count, stride, basis, data, output); + ModuleBase::timer::end("ExpLanczos", "combine"); +} + +template +std::vector ExpLanczos::basis_gram(const OrbLayout& layout, int count, const T* basis) +{ + ModuleBase::timer::start("ExpLanczos", "basis_gram"); + const int size = layout.bands * count * count; + linear_buffer(&products_, size); + Wide* data = products_.template data(); + const int dim = layout.npol == 2 ? layout.ld : layout.npw; + const int stride = layout.ld * layout.bands; + linear_op().block_gram(layout.ld, dim, layout.bands, count, stride, basis, data); + std::vector gram(size); + base_device::memory::synchronize_memory_op()(gram.data(), data, size); +#ifdef __MPI + if (comm_.nproc > 1) + { + Parallel_Common::reduce_data(gram.data(), size, comm_.comm); + } +#endif + ModuleBase::timer::end("ExpLanczos", "basis_gram"); + return gram; +} + +template +bool ExpLanczos::diagonalize(const std::vector& diagonal, + const std::vector& off_diagonal, + int band, + int bands, + int count) +{ + ModuleBase::timer::start("ExpLanczos", "diagonalize"); + small_vectors_.assign(count * count, 0.0); + small_values_.resize(count); + const int work_size = std::max(1, 3 * count); + small_work_.resize(work_size); + for (int i = 0; i < count; ++i) + { + small_vectors_[i * count + i] = diagonal[i * bands + band]; + if (i + 1 < count) + { + small_vectors_[(i + 1) * count + i] = off_diagonal[i * bands + band]; + } + } + // Only the real symmetric tridiagonal projection is diagonalized. + const char job = 'V'; + const char upper = 'U'; + int info = 0; + ct::lapackConnector::heev(job, upper, count, small_vectors_.data(), count, small_values_.data(), small_work_.data(), work_size, info); + ModuleBase::timer::end("ExpLanczos", "diagonalize"); + return info == 0; +} + +template +ExpResult ExpLanczos::attempt(const HSOperator& op, + const OrbLayout& layout, + double alpha, + double rel_tol, + const T* input, + T* output, + T* full, + bool reorthogonalize, + bool* lost_orthogonality) +{ + using Real = typename T::value_type; + const int ld = layout.ld; + const int bands = layout.bands; + const int dim = layout.npol == 2 ? ld : layout.npw; + const int stride = ld * bands; + const int limit = this->exp_ctrl_.krylov_max; + const int64_t size = std::max(1, stride); + const double time = full ? 2.0 * std::abs(alpha) : std::abs(alpha); + *lost_orthogonality = false; + ExpResult result; + result.has_err_est = true; + result.reorth_count = reorthogonalize ? 1 : 0; + const int64_t basis_size = size * static_cast(limit); + if (basis_.NumElements() < basis_size) + { + // Avoid holding two large Krylov allocations while growing the workspace. + basis_ = ct::Tensor(); + } + linear_buffer(&basis_, basis_size); + linear_buffer(&image_, size); + linear_buffer(&packed_, size); + linear_buffer(&hpacked_, size); + linear_buffer(&permutation_, bands); + T* q = basis_.template data(); + T* w = image_.template data(); + T* packed = packed_.template data(); + T* hpacked = hpacked_.template data(); + int* map = permutation_.template data(); + base_device::memory::set_memory_op()(output, 0, stride); + if (full) + { + base_device::memory::set_memory_op()(full, 0, stride); + } + base_device::memory::synchronize_memory_op()(q, input, stride); + zero_pad(q, layout); + const std::vector> norms = this->algebra_.dots(ld, dim, bands, 1, stride, q, q); + std::vector scale(bands); + std::vector factors(bands); + std::vector done(bands, false); + std::vector diagonal(static_cast(bands) * limit); + std::vector beta(static_cast(bands) * limit); + std::vector log_bound(bands, 0.0); + std::vector correction_sq(bands, 0.0); + std::vector errors(bands, 0.0); + std::vector active; + active.reserve(bands); + for (int b = 0; b < bands; ++b) + { + if (!std::isfinite(norms[b].real()) || norms[b].real() < 0.0) + { + return failed_band(result, b, false); + } + scale[b] = std::sqrt(norms[b].real()); + done[b] = scale[b] == 0.0; + factors[b] = done[b] ? T(0) : T(1.0 / scale[b]); + } + this->work_.batch(ld, dim, bands, q, q, q, T(1), T(0), factors.data(), nullptr, nullptr); + for (int j = 0; j < limit; ++j) + { + active.clear(); + for (int b = 0; b < bands; ++b) + { + if (!done[b]) + { + active.push_back(b); + } + } + if (active.empty()) + { + return result; + } + const int count = active.size(); + T* column = q + static_cast(j) * stride; + if (count == bands) + { + op.hpsi(column, w, ld, bands); + } + else + { + base_device::memory::synchronize_memory_op()(map, active.data(), count); + linear_op().gather(ld, ld, count, 1, stride, column, packed, map); + op.hpsi(packed, hpacked, ld, count); + base_device::memory::set_memory_op()(w, 0, stride); + linear_op().scatter(ld, ld, count, hpacked, w, map); + } + zero_pad(w, layout); + ++result.hpsi_calls; + result.hpsi_cols += count; + const std::vector> projection = this->algebra_.dots(ld, dim, bands, 1, stride, column, w); + const int m = j + 1; + result.order_or_dim = m; + const int first = std::max(0, j - 1); + const int columns = j - first + 1; + std::vector recurrence(columns * bands, T(0)); + for (int b: active) + { + if (!std::isfinite(std::abs(projection[b]))) + { + return failed_band(result, b, false); + } + diagonal[j * bands + b] = projection[b].real(); + recurrence[(columns - 1) * bands + b] = T(-projection[b].real()); + if (j > 0) + { + recurrence[b] = T(-beta[(j - 1) * bands + b]); + } + } + const T* previous = q + static_cast(first) * stride; + combine(layout, columns, previous, recurrence, w); + if (reorthogonalize) + { + std::vector removed(bands, 0.0); + for (int pass = 0; pass < 2; ++pass) + { + const std::vector> projections = this->algebra_.dots(ld, dim, bands, m, stride, q, w); + std::vector correction(m * bands, T(0)); + for (int i = 0; i < m; ++i) + { + for (int b: active) + { + const Wide value = projections[i * bands + b]; + if (!std::isfinite(std::abs(value))) + { + return failed_band(result, b, false); + } + removed[b] += std::abs(value); + correction[i * bands + b] = T(-value); + } + } + combine(layout, m, q, correction, w); + } + for (int b: active) + { + // ||Q*C|| <= sum_i |C_i| for normalized columns. Accumulate + // a Frobenius bound on the discarded recurrence corrections. + correction_sq[b] += removed[b] * removed[b]; + } + } + const std::vector> residuals = this->algebra_.dots(ld, dim, bands, 1, stride, w, w); + std::vector candidates; + for (int b: active) + { + if (!std::isfinite(residuals[b].real()) || residuals[b].real() < 0.0) + { + return failed_band(result, b, false); + } + const double residual = std::sqrt(residuals[b].real()); + beta[j * bands + b] = residual; + if (residual == 0.0 || time == 0.0) + { + log_bound[b] = -std::numeric_limits::infinity(); + } + else + { + log_bound[b] += std::log(time) + std::log(residual) - std::log(static_cast(m)); + } + // Jawecki et al., Theorem 1: |t|^m product(beta_1,...,beta_m)/m!. + // Duhamel adds |t|*||F|| for the discarded reorthogonalization terms. + errors[b] = std::exp(log_bound[b]) + time * std::sqrt(correction_sq[b]); + if (errors[b] <= rel_tol) + { + candidates.push_back(b); + } + else if (residual <= std::numeric_limits::min()) + { + return failed_band(result, b, true); + } + } + if (!candidates.empty()) + { + const std::vector> gram = basis_gram(layout, m, q); + // The defect bound follows the three-term relation, not Q-adjoint*Q=I. + // Rebuilding for insignificant loss of orthogonality wastes H applications. + // Check the actual output norm separately at the requested precision. + const double roundoff = std::numeric_limits::epsilon(); + const double orth_tol = std::max(std::sqrt(roundoff), 0.1 * rel_tol); + const double norm_tol = std::max(100.0 * m * std::numeric_limits::epsilon(), 0.1 * rel_tol); + for (int b: candidates) + { + double defect = 0.0; + for (int row = 0; row < m; ++row) + { + double row_sum = 0.0; + for (int col = 0; col < m; ++col) + { + const Wide identity = row == col ? Wide(1) : Wide(0); + const double value = std::abs(gram[(col * m + row) * bands + b] - identity); + if (!std::isfinite(value)) + { + return failed_band(result, b, false); + } + row_sum += value; + } + defect = std::max(defect, row_sum); + } + if (defect > orth_tol) + { + *lost_orthogonality = true; + return failed_band(result, b, true); + } + } + std::vector coefficients(m * bands, T(0)); + std::vector full_coefficients; + if (full) + { + full_coefficients.assign(m * bands, T(0)); + } + for (int b: candidates) + { + if (!diagonalize(diagonal, beta, b, bands, m)) + { + return failed_band(result, b, false); + } + std::vector half_values(m, Wide(0)); + std::vector full_values(m, Wide(0)); + for (int k = 0; k < m; ++k) + { + const double weight = scale[b] * small_vectors_[k * m]; + const Wide half_phase = weight * std::exp(Wide(0, -alpha * small_values_[k])); + Wide full_phase(0); + if (full) + { + full_phase = weight * std::exp(Wide(0, -2.0 * alpha * small_values_[k])); + } + for (int i = 0; i < m; ++i) + { + const double component = small_vectors_[k * m + i]; + half_values[i] += component * half_phase; + if (full) + { + full_values[i] += component * full_phase; + } + } + } + for (int i = 0; i < m; ++i) + { + coefficients[i * bands + b] = T(half_values[i]); + if (full) + { + full_coefficients[i * bands + b] = T(full_values[i]); + } + } + } + combine(layout, m, q, coefficients, output); + if (full) + { + combine(layout, m, q, full_coefficients, full); + } + const std::vector> output_norms = this->algebra_.dots(ld, dim, bands, 1, stride, output, output); + std::vector full_norms; + if (full) + { + full_norms = this->algebra_.dots(ld, dim, bands, 1, stride, full, full); + } + for (int b: candidates) + { + const double norm_error = std::abs(std::sqrt(output_norms[b].real()) / scale[b] - 1.0); + double full_error = 0.0; + if (full) + { + full_error = std::abs(std::sqrt(full_norms[b].real()) / scale[b] - 1.0); + } + if (!std::isfinite(norm_error) || !std::isfinite(full_error)) + { + return failed_band(result, b, false); + } + if (norm_error > norm_tol || full_error > norm_tol) + { + *lost_orthogonality = true; + return failed_band(result, b, true); + } + done[b] = true; + result.rel_err_est = std::max(result.rel_err_est, errors[b]); + } + } + bool finished = true; + for (int b = 0; b < bands; ++b) + { + factors[b] = T(0); + if (!done[b]) + { + finished = false; + factors[b] = T(1.0 / beta[j * bands + b]); + result.failed_band = b; + } + } + if (finished) + { + result.failed_band = -1; + return result; + } + if (m < limit) + { + T* next = q + static_cast(m) * stride; + base_device::memory::set_memory_op()(next, 0, stride); + this->work_.batch(ld, dim, bands, next, w, w, T(1), T(0), factors.data(), nullptr, nullptr); + } + } + result.state = ExpState::retry; + result.rel_err_est = *std::max_element(errors.begin(), errors.end()); + return result; +} + +template +ExpResult ExpLanczos::interval(const HSOperator& op, + const OrbLayout& layout, + double alpha, + double rel_tol, + const T* input, + T* output, + T* full, + int depth) +{ + bool lost_orthogonality = false; + ExpResult trial = attempt(op, layout, alpha, rel_tol, input, output, full, false, &lost_orthogonality); + if (lost_orthogonality) + { + const ExpResult previous = trial; + trial = attempt(op, layout, alpha, rel_tol, input, output, full, true, &lost_orthogonality); + add_work(trial, previous); + } + if (trial.state != ExpState::retry) + { + return trial; + } + if (depth == 10) + { + trial.state = ExpState::failed; + return trial; + } + ++trial.bisect_count; + ct::Tensor midpoint; + const int64_t size = static_cast(layout.ld) * layout.bands; + T* middle = output; + T* endpoint = full; + double sub_alpha = alpha; + if (!full) + { + linear_buffer(&midpoint, size); + middle = midpoint.template data(); + endpoint = output; + sub_alpha = alpha / 2.0; + } + const double sub_tol = rel_tol / 2.0; + const int next_depth = depth + 1; + ExpResult left = interval(op, layout, sub_alpha, sub_tol, input, middle, nullptr, next_depth); + add_work(left, trial); + if (left.state != ExpState::success) + { + return left; + } + ExpResult right = interval(op, layout, sub_alpha, sub_tol, middle, endpoint, nullptr, next_depth); + add_work(right, left); + if (right.state == ExpState::success) + { + right.rel_err_est += left.rel_err_est; + } + return right; +} + +template +ExpResult ExpLanczos::evaluate(const HSOperator& op, + const OrbLayout& layout, + double alpha, + const T* input, + T* output, + T* full) +{ + ModuleBase::timer::start("ExpLanczos", "evaluate"); + ExpResult result; + result.has_err_est = true; + const int batch_limit = batch_size(layout); + for (int first = 0; first < layout.bands; first += batch_limit) + { + const int bands = std::min(batch_limit, layout.bands - first); + const OrbLayout batch{layout.ld, layout.npw, layout.npol, bands}; + const int64_t offset = static_cast(first) * layout.ld; + const T* src = input + offset; + T* dst = output + offset; + T* full_dst = full ? full + offset : nullptr; + const ExpResult local = interval(op, batch, alpha, this->exp_ctrl_.rel_tol, src, dst, full_dst, 0); + result.has_err_est = result.has_err_est && local.has_err_est; + add_work(result, local); + result.rel_err_est = std::max(result.rel_err_est, local.rel_err_est); + if (local.state != ExpState::success) + { + result.state = local.state; + result.failed_band = first + local.failed_band; + break; + } + } + ModuleBase::timer::end("ExpLanczos", "evaluate"); + return result; +} + +template +ExpResult ExpLanczos::apply(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output) +{ + return evaluate(op, layout, alpha, input, output, nullptr); +} + +template +ExpResult ExpLanczos::apply_pair(const HSOperator& op, + const OrbLayout& layout, + double alpha, + const T* input, + T* half, + T* full) +{ + return evaluate(op, layout, alpha, input, half, full); +} + +template class ExpLanczos, base_device::DEVICE_CPU>; +template class ExpLanczos, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class ExpLanczos, base_device::DEVICE_GPU>; +template class ExpLanczos, base_device::DEVICE_GPU>; +#endif +} // namespace hsolver diff --git a/source/source_hsolver/module_linalg/exp_lanczos.h b/source/source_hsolver/module_linalg/exp_lanczos.h new file mode 100644 index 00000000000..e1a451f4258 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_lanczos.h @@ -0,0 +1,54 @@ +#ifndef HSOLVER_EXP_LANCZOS_H +#define HSOLVER_EXP_LANCZOS_H +#include "source_hsolver/module_linalg/exp_action.h" +#include "source_hsolver/module_linalg/linear_workspace.h" + +namespace hsolver +{ +template +class ExpLanczos final : public ExpAction +{ + private: + const diag_comm_info comm_; + LinearWorkspace work_; + ct::Tensor basis_; + ct::Tensor image_; + ct::Tensor packed_; + ct::Tensor hpacked_; + ct::Tensor coefficients_; + ct::Tensor products_; + ct::Tensor permutation_; + std::vector small_vectors_; + std::vector small_values_; + std::vector small_work_; + int batch_size(const OrbLayout& layout) const; + void combine(const OrbLayout& layout, int count, const T* basis, const std::vector& coefficients, T* output); + std::vector> basis_gram(const OrbLayout& layout, int count, const T* basis); + bool diagonalize(const std::vector& diagonal, const std::vector& off_diagonal, int band, int bands, int count); + ExpResult attempt(const HSOperator& op, + const OrbLayout& layout, + double alpha, + double rel_tol, + const T* input, + T* output, + T* full, + bool reorthogonalize, + bool* lost_orthogonality); + ExpResult interval(const HSOperator& op, + const OrbLayout& layout, + double alpha, + double rel_tol, + const T* input, + T* output, + T* full, + int depth); + ExpResult evaluate(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output, T* full); + + public: + ExpLanczos(const ExpControls& exp_ctrl, const diag_comm_info& comm); + ExpResult apply(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output) override; + /** @brief Share one Krylov construction for alpha and twice alpha. */ + ExpResult apply_pair(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* half, T* full) override; +}; +} // namespace hsolver +#endif diff --git a/source/source_hsolver/module_linalg/exp_taylor.cpp b/source/source_hsolver/module_linalg/exp_taylor.cpp new file mode 100644 index 00000000000..4acb3108419 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_taylor.cpp @@ -0,0 +1,99 @@ +#include "source_hsolver/module_linalg/exp_taylor.h" + +#include "source_base/timer.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" + +namespace hsolver +{ +template +ExpTaylor::ExpTaylor(const ExpControls& exp_ctrl, const diag_comm_info& comm) : ExpAction(exp_ctrl, comm) +{ +} + +template +ExpResult ExpTaylor::apply(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output) +{ + return evaluate(op, layout, alpha, input, output, nullptr); +} + +template +ExpResult ExpTaylor::apply_pair(const HSOperator& op, + const OrbLayout& layout, + double alpha, + const T* input, + T* half, + T* full) +{ + return evaluate(op, layout, alpha, input, half, full); +} + +template +ExpResult ExpTaylor::evaluate(const HSOperator& op, + const OrbLayout& layout, + double alpha, + const T* input, + T* half, + T* full) +{ + ModuleBase::timer::start("ExpTaylor", "evaluate"); + const int ld = layout.ld; + const int bands = layout.bands; + const int stride = ld * bands; + const int dim = layout.npol == 2 ? ld : layout.npw; + const int64_t count = static_cast(ld) * bands; + linear_buffer(&term_, count); + linear_buffer(&image_, count); + T* term = term_.template data(); + T* image = image_.template data(); + base_device::memory::synchronize_memory_op()(term, input, count); + zero_pad(term, layout); + base_device::memory::synchronize_memory_op()(half, term, count); + if (full) + { + base_device::memory::synchronize_memory_op()(full, term, count); + } + ExpResult result; + result.order_or_dim = this->exp_ctrl_.taylor_order; + // Scale at the longer requested time; half-step weights cannot overflow at high order. + const double series_alpha = full ? 2.0 * alpha : alpha; + for (int k = 1; k <= this->exp_ctrl_.taylor_order; ++k) + { + op.hpsi(term, image, ld, bands); + zero_pad(image, layout); + const T coefficient(0, -series_alpha / k); + linear_op().batch(ld, dim, bands, term, image, image, coefficient, T(0), nullptr, nullptr, nullptr); + const T half_weight = full ? T(std::ldexp(1.0, -k)) : T(1); + linear_op().batch(ld, dim, bands, half, half, term, T(1), half_weight, nullptr, nullptr, nullptr); + if (full) + { + linear_op().batch(ld, dim, bands, full, full, term, T(1), T(1), nullptr, nullptr, nullptr); + } + ++result.hpsi_calls; + result.hpsi_cols += bands; + } + const std::vector> norms = this->algebra_.dots(ld, dim, bands, 1, stride, half, half); + std::vector> full_norms; + if (full) + { + full_norms = this->algebra_.dots(ld, dim, bands, 1, stride, full, full); + } + for (int b = 0; b < bands; ++b) + { + if (!std::isfinite(norms[b].real()) || (full && !std::isfinite(full_norms[b].real()))) + { + result.state = ExpState::failed; + result.failed_band = b; + break; + } + } + ModuleBase::timer::end("ExpTaylor", "evaluate"); + return result; +} + +template class ExpTaylor, base_device::DEVICE_CPU>; +template class ExpTaylor, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class ExpTaylor, base_device::DEVICE_GPU>; +template class ExpTaylor, base_device::DEVICE_GPU>; +#endif +} // namespace hsolver diff --git a/source/source_hsolver/module_linalg/exp_taylor.h b/source/source_hsolver/module_linalg/exp_taylor.h new file mode 100644 index 00000000000..dc0f1014ce1 --- /dev/null +++ b/source/source_hsolver/module_linalg/exp_taylor.h @@ -0,0 +1,21 @@ +#ifndef HSOLVER_EXP_TAYLOR_H +#define HSOLVER_EXP_TAYLOR_H +#include "source_hsolver/module_linalg/exp_action.h" + +namespace hsolver +{ +template +class ExpTaylor final : public ExpAction +{ + private: + ct::Tensor term_; + ct::Tensor image_; + ExpResult evaluate(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* half, T* full); + + public: + ExpTaylor(const ExpControls& exp_ctrl, const diag_comm_info& comm); + ExpResult apply(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* output) override; + ExpResult apply_pair(const HSOperator& op, const OrbLayout& layout, double alpha, const T* input, T* half, T* full) override; +}; +} // namespace hsolver +#endif diff --git a/source/source_hsolver/hsolver_linear.cpp b/source/source_hsolver/module_linalg/hsolver_linear.cpp similarity index 77% rename from source/source_hsolver/hsolver_linear.cpp rename to source/source_hsolver/module_linalg/hsolver_linear.cpp index f86dce35e14..9a90963d534 100644 --- a/source/source_hsolver/hsolver_linear.cpp +++ b/source/source_hsolver/module_linalg/hsolver_linear.cpp @@ -1,4 +1,4 @@ -#include "source_hsolver/hsolver_linear.h" +#include "source_hsolver/module_linalg/hsolver_linear.h" #include "source_base/tool_quit.h" @@ -23,23 +23,23 @@ const char* linear_status_name(const LinearSolveStatus status) } template -HSolverLinear::HSolverLinear(const LinearSolveOptions& options, const diag_comm_info& comm) - : default_control_{options.max_iterations, options.reconstruct} +HSolverLinear::HSolverLinear(const LinearControls& linear_ctrl, const diag_comm_info& comm) + : max_iter_(linear_ctrl.max_iterations), reconstruct_(linear_ctrl.reconstruct) { using Real = typename GetTypeReal::type; const double roundoff_tolerance = 100.0 * std::numeric_limits::epsilon(); - tolerance_ = options.tolerance == 0.0 ? std::max(1e-10, roundoff_tolerance) : options.tolerance; - if (options.method == LinearMethod::bicgstab) + tolerance_ = linear_ctrl.tolerance == 0.0 ? std::max(1e-10, roundoff_tolerance) : linear_ctrl.tolerance; + if (linear_ctrl.solver == LinearMethod::bicgstab) { bicgstab_.reset(new LinearBiCGSTAB(tolerance_, comm)); } - else if (options.method == LinearMethod::cgs) + else if (linear_ctrl.solver == LinearMethod::cgs) { cgs_.reset(new LinearCGS(tolerance_, comm)); } - else if (options.method == LinearMethod::gmres) + else if (linear_ctrl.solver == LinearMethod::gmres) { - gmres_.reset(new LinearGMRES(tolerance_, options, comm)); + gmres_.reset(new LinearGMRES(tolerance_, linear_ctrl.restart, linear_ctrl.max_iterations, comm)); } else { @@ -58,7 +58,7 @@ LinearSolveResult HSolverLinear::solve(const LinearOperator @@ -71,19 +71,20 @@ LinearSolveResult HSolverLinear::solve(const LinearOperatorsolve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, control.max_iterations); + return bicgstab_->solve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, max_iter); } else if (cgs_) { - return cgs_->solve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, control.max_iterations); + return cgs_->solve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, max_iter); } else if (gmres_) { - return gmres_->solve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, force_check, control); + return gmres_->solve(op, preconditioner, ld, nvec, dim, x, b, initial_residual, force_check, max_iter, reconstruct); } else { diff --git a/source/source_hsolver/hsolver_linear.h b/source/source_hsolver/module_linalg/hsolver_linear.h similarity index 82% rename from source/source_hsolver/hsolver_linear.h rename to source/source_hsolver/module_linalg/hsolver_linear.h index 776797db20b..47c43057788 100644 --- a/source/source_hsolver/hsolver_linear.h +++ b/source/source_hsolver/module_linalg/hsolver_linear.h @@ -1,8 +1,8 @@ #ifndef HSOLVER_LINEAR_H #define HSOLVER_LINEAR_H -#include "source_hsolver/linear_bicgstab.h" -#include "source_hsolver/linear_cgs.h" -#include "source_hsolver/linear_gmres.h" +#include "source_hsolver/module_linalg/linear_bicgstab.h" +#include "source_hsolver/module_linalg/linear_cgs.h" +#include "source_hsolver/module_linalg/linear_gmres.h" #include @@ -17,10 +17,11 @@ class HSolverLinear std::unique_ptr> cgs_; std::unique_ptr> gmres_; double tolerance_ = 0.0; - const LinearSolveControl default_control_; + const int max_iter_; + const bool reconstruct_; public: - HSolverLinear(const LinearSolveOptions& options, const diag_comm_info& comm); + HSolverLinear(const LinearControls& linear_ctrl, const diag_comm_info& comm); /** @brief Return the effective tolerance after resolving the precision-dependent default. */ double tolerance() const { @@ -46,7 +47,8 @@ class HSolverLinear const T* b, const T* initial_residual, bool force_check, - const LinearSolveControl& control); + int max_iter, + bool reconstruct); }; } // namespace hsolver #endif diff --git a/source/source_hsolver/kernels/cuda/linear_op.cu b/source/source_hsolver/module_linalg/kernels/cuda/linear_op.cu similarity index 78% rename from source/source_hsolver/kernels/cuda/linear_op.cu rename to source/source_hsolver/module_linalg/kernels/cuda/linear_op.cu index fd59d2d8d29..9a984234f79 100644 --- a/source/source_hsolver/kernels/cuda/linear_op.cu +++ b/source/source_hsolver/module_linalg/kernels/cuda/linear_op.cu @@ -1,4 +1,4 @@ -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" #include #include @@ -407,6 +407,126 @@ void linear_op::native_dots(int ld, int dim, int nve check_launch(); } +namespace +{ +template +__global__ void combine_kernel(int ld, int dim, int count, int stride, int nvec, + const C* basis, const C* coefficients, C* output) +{ + const int i = blockIdx.x * blockDim.x + threadIdx.x; + const int b = blockIdx.y; + if (i < dim) + { + const std::int64_t offset = static_cast(b) * ld + i; + C sum(0); + for (int j = 0; j < count; ++j) + { + sum += basis[static_cast(j) * stride + offset] * coefficients[j * nvec + b]; + } + output[offset] += sum; + } +} + +template +__global__ void scatter_kernel(int ld, int dim, const C* input, C* output, const int* map) +{ + const int i = blockIdx.x * blockDim.x + threadIdx.x; + const int b = blockIdx.y; + if (i < dim) + { + output[static_cast(map[b]) * ld + i] = input[static_cast(b) * ld + i]; + } +} + +template +__global__ void block_gram_kernel(int ld, int dim, int nvec, int count, int stride, + const thrust::complex* basis, thrust::complex* output) +{ + const int b = blockIdx.x % nvec; + const int pair = blockIdx.x / nvec; + const int row = pair % count; + const int col = pair / count; + if (row > col) + { + return; + } + const std::int64_t first = static_cast(row) * stride + static_cast(b) * ld; + const std::int64_t second = static_cast(col) * stride + static_cast(b) * ld; + thrust::complex sum(0); + for (int i = threadIdx.x; i < dim; i += blockDim.x) + { + sum += thrust::conj(thrust::complex(basis[first + i])) * thrust::complex(basis[second + i]); + } + __shared__ double re[linear_threads]; + __shared__ double im[linear_threads]; + const int tid = threadIdx.x; + re[tid] = sum.real(); + im[tid] = sum.imag(); + __syncthreads(); + for (int step = blockDim.x / 2; step > 0; step /= 2) + { + if (tid < step) + { + re[tid] += re[tid + step]; + im[tid] += im[tid + step]; + } + __syncthreads(); + } + if (tid == 0) + { + output[(col * count + row) * nvec + b] = thrust::complex(re[0], im[0]); + if (row != col) + { + output[(row * count + col) * nvec + b] = thrust::complex(re[0], -im[0]); + } + } +} +} // namespace + +template +void linear_op::combine(int ld, int dim, int nvec, int count, int stride, + const T* basis, const T* coefficients, T* output) const +{ + if (dim == 0 || nvec == 0) + { + return; + } + using C = thrust::complex; + const dim3 grid((dim + linear_threads - 1) / linear_threads, nvec); + combine_kernel<<>>(ld, dim, count, stride, nvec, + reinterpret_cast(basis), reinterpret_cast(coefficients), reinterpret_cast(output)); + check_launch(); +} + +template +void linear_op::scatter(int ld, int dim, int nvec, + const T* input, T* output, const int* map) const +{ + if (dim == 0 || nvec == 0) + { + return; + } + using C = thrust::complex; + const dim3 grid((dim + linear_threads - 1) / linear_threads, nvec); + scatter_kernel<<>>(ld, dim, reinterpret_cast(input), reinterpret_cast(output), map); + check_launch(); +} + +template +void linear_op::block_gram(int ld, int dim, int nvec, int count, int stride, + const T* basis, std::complex* output) const +{ + if (nvec == 0 || count == 0) + { + return; + } + using C = thrust::complex; + const int blocks = nvec * count * count; + block_gram_kernel<<>>(ld, dim, nvec, count, stride, reinterpret_cast(basis), + reinterpret_cast*>(output)); + check_launch(); +} + template class linear_op, base_device::DEVICE_GPU>; template class linear_op, base_device::DEVICE_GPU>; diff --git a/source/source_hsolver/kernels/linear_op.cpp b/source/source_hsolver/module_linalg/kernels/linear_op.cpp similarity index 81% rename from source/source_hsolver/kernels/linear_op.cpp rename to source/source_hsolver/module_linalg/kernels/linear_op.cpp index fcaff888ce2..c5b194f1c22 100644 --- a/source/source_hsolver/kernels/linear_op.cpp +++ b/source/source_hsolver/module_linalg/kernels/linear_op.cpp @@ -1,5 +1,6 @@ -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" +#include #include #include #ifdef _OPENMP @@ -291,6 +292,61 @@ void linear_op::native_dots(int ld, int dim, int nvec, int count, int } } +template +void linear_op::combine(int ld, int dim, int nvec, int count, int stride, const T* basis, const T* coefficients, T* output) const +{ +#pragma omp parallel for schedule(static) if (parallel_work(dim, nvec)) + for (int b = 0; b < nvec; ++b) + { + for (int i = 0; i < dim; ++i) + { + const std::int64_t offset = static_cast(b) * ld + i; + T sum(0); + for (int j = 0; j < count; ++j) + { + sum += basis[static_cast(j) * stride + offset] * coefficients[j * nvec + b]; + } + output[offset] += sum; + } + } +} + +template +void linear_op::scatter(int ld, int dim, int nvec, const T* input, T* output, const int* map) const +{ +#pragma omp parallel for schedule(static) if (parallel_work(dim, nvec)) + for (int b = 0; b < nvec; ++b) + { + const std::int64_t source = static_cast(b) * ld; + const std::int64_t destination = static_cast(map[b]) * ld; + std::copy_n(input + source, dim, output + destination); + } +} + +template +void linear_op::block_gram(int ld, int dim, int nvec, int count, int stride, const T* basis, std::complex* output) const +{ +#pragma omp parallel for collapse(2) schedule(static) if (parallel_work(dim, nvec * count)) + for (int col = 0; col < count; ++col) + { + for (int b = 0; b < nvec; ++b) + { + for (int row = 0; row <= col; ++row) + { + const std::int64_t first = static_cast(row) * stride + static_cast(b) * ld; + const std::int64_t second = static_cast(col) * stride + static_cast(b) * ld; + std::complex sum(0); + for (int i = 0; i < dim; ++i) + { + sum += std::conj(std::complex(basis[first + i])) * std::complex(basis[second + i]); + } + output[(col * count + row) * nvec + b] = sum; + output[(row * count + col) * nvec + b] = std::conj(sum); + } + } + } +} + template class linear_op, base_device::DEVICE_CPU>; template class linear_op, base_device::DEVICE_CPU>; diff --git a/source/source_hsolver/kernels/linear_op.h b/source/source_hsolver/module_linalg/kernels/linear_op.h similarity index 79% rename from source/source_hsolver/kernels/linear_op.h rename to source/source_hsolver/module_linalg/kernels/linear_op.h index e6ffe6ff3e7..7f59d8c418d 100644 --- a/source/source_hsolver/kernels/linear_op.h +++ b/source/source_hsolver/module_linalg/kernels/linear_op.h @@ -13,6 +13,12 @@ template class linear_op { public: + /** @brief Add per-band linear combinations of Krylov columns; coefficients are column-major blocks. */ + void combine(int ld, int dim, int nvec, int count, int stride, const T* basis, const T* coefficients, T* output) const; + /** @brief Scatter packed columns to distinct original-band destinations. */ + void scatter(int ld, int dim, int nvec, const T* input, T* output, const int* map) const; + /** @brief Per-band Krylov Gram matrices in double precision, indexed as (column * count + row) * nvec + band. */ + void block_gram(int ld, int dim, int nvec, int count, int stride, const T* basis, std::complex* output) const; /** @brief Skip zero-coefficient columns; a null residual disables the paired residual update. */ void gmres_update(int ld, int dim, int nvec, T* solution, T* residual, const T* direction, const T* image, const T* coefficients) const; /** @brief Batched products accumulated in wavefunction precision. */ @@ -45,6 +51,12 @@ template class linear_op { public: + /** @brief Add per-band linear combinations of Krylov columns; coefficients are column-major blocks. */ + void combine(int ld, int dim, int nvec, int count, int stride, const T* basis, const T* coefficients, T* output) const; + /** @brief Scatter packed columns to distinct original-band destinations. */ + void scatter(int ld, int dim, int nvec, const T* input, T* output, const int* map) const; + /** @brief Per-band Krylov Gram matrices in double precision, indexed as (column * count + row) * nvec + band. */ + void block_gram(int ld, int dim, int nvec, int count, int stride, const T* basis, std::complex* output) const; /** @brief Skip zero-coefficient columns; a null residual disables the paired residual update. */ void gmres_update(int ld, int dim, int nvec, T* solution, T* residual, const T* direction, const T* image, const T* coefficients) const; /** @brief Batched products accumulated in wavefunction precision. */ diff --git a/source/source_hsolver/kernels/rocm/linear_op.hip.cu b/source/source_hsolver/module_linalg/kernels/rocm/linear_op.hip.cu similarity index 78% rename from source/source_hsolver/kernels/rocm/linear_op.hip.cu rename to source/source_hsolver/module_linalg/kernels/rocm/linear_op.hip.cu index e71c038e1e7..27d5ca079bf 100644 --- a/source/source_hsolver/kernels/rocm/linear_op.hip.cu +++ b/source/source_hsolver/module_linalg/kernels/rocm/linear_op.hip.cu @@ -1,4 +1,4 @@ -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" #include #include @@ -407,6 +407,126 @@ void linear_op::native_dots(int ld, int dim, int nve check_launch(); } +namespace +{ +template +__global__ void combine_kernel(int ld, int dim, int count, int stride, int nvec, + const C* basis, const C* coefficients, C* output) +{ + const int i = blockIdx.x * blockDim.x + threadIdx.x; + const int b = blockIdx.y; + if (i < dim) + { + const std::int64_t offset = static_cast(b) * ld + i; + C sum(0); + for (int j = 0; j < count; ++j) + { + sum += basis[static_cast(j) * stride + offset] * coefficients[j * nvec + b]; + } + output[offset] += sum; + } +} + +template +__global__ void scatter_kernel(int ld, int dim, const C* input, C* output, const int* map) +{ + const int i = blockIdx.x * blockDim.x + threadIdx.x; + const int b = blockIdx.y; + if (i < dim) + { + output[static_cast(map[b]) * ld + i] = input[static_cast(b) * ld + i]; + } +} + +template +__global__ void block_gram_kernel(int ld, int dim, int nvec, int count, int stride, + const thrust::complex* basis, thrust::complex* output) +{ + const int b = blockIdx.x % nvec; + const int pair = blockIdx.x / nvec; + const int row = pair % count; + const int col = pair / count; + if (row > col) + { + return; + } + const std::int64_t first = static_cast(row) * stride + static_cast(b) * ld; + const std::int64_t second = static_cast(col) * stride + static_cast(b) * ld; + thrust::complex sum(0); + for (int i = threadIdx.x; i < dim; i += blockDim.x) + { + sum += thrust::conj(thrust::complex(basis[first + i])) * thrust::complex(basis[second + i]); + } + __shared__ double re[linear_threads]; + __shared__ double im[linear_threads]; + const int tid = threadIdx.x; + re[tid] = sum.real(); + im[tid] = sum.imag(); + __syncthreads(); + for (int step = blockDim.x / 2; step > 0; step /= 2) + { + if (tid < step) + { + re[tid] += re[tid + step]; + im[tid] += im[tid + step]; + } + __syncthreads(); + } + if (tid == 0) + { + output[(col * count + row) * nvec + b] = thrust::complex(re[0], im[0]); + if (row != col) + { + output[(row * count + col) * nvec + b] = thrust::complex(re[0], -im[0]); + } + } +} +} // namespace + +template +void linear_op::combine(int ld, int dim, int nvec, int count, int stride, + const T* basis, const T* coefficients, T* output) const +{ + if (dim == 0 || nvec == 0) + { + return; + } + using C = thrust::complex; + const dim3 grid((dim + linear_threads - 1) / linear_threads, nvec); + combine_kernel<<>>(ld, dim, count, stride, nvec, + reinterpret_cast(basis), reinterpret_cast(coefficients), reinterpret_cast(output)); + check_launch(); +} + +template +void linear_op::scatter(int ld, int dim, int nvec, + const T* input, T* output, const int* map) const +{ + if (dim == 0 || nvec == 0) + { + return; + } + using C = thrust::complex; + const dim3 grid((dim + linear_threads - 1) / linear_threads, nvec); + scatter_kernel<<>>(ld, dim, reinterpret_cast(input), reinterpret_cast(output), map); + check_launch(); +} + +template +void linear_op::block_gram(int ld, int dim, int nvec, int count, int stride, + const T* basis, std::complex* output) const +{ + if (nvec == 0 || count == 0) + { + return; + } + using C = thrust::complex; + const int blocks = nvec * count * count; + block_gram_kernel<<>>(ld, dim, nvec, count, stride, reinterpret_cast(basis), + reinterpret_cast*>(output)); + check_launch(); +} + template class linear_op, base_device::DEVICE_GPU>; template class linear_op, base_device::DEVICE_GPU>; diff --git a/source/source_hsolver/linear_algebra.cpp b/source/source_hsolver/module_linalg/linear_algebra.cpp similarity index 99% rename from source/source_hsolver/linear_algebra.cpp rename to source/source_hsolver/module_linalg/linear_algebra.cpp index c4a7aa441c9..5f35a19a2be 100644 --- a/source/source_hsolver/linear_algebra.cpp +++ b/source/source_hsolver/module_linalg/linear_algebra.cpp @@ -1,9 +1,9 @@ -#include "source_hsolver/linear_algebra.h" +#include "source_hsolver/module_linalg/linear_algebra.h" #include "source_base/kernels/math_kernel_op.h" #include "source_base/parallel_device.h" #include "source_base/timer.h" -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" #include #include diff --git a/source/source_hsolver/linear_algebra.h b/source/source_hsolver/module_linalg/linear_algebra.h similarity index 100% rename from source/source_hsolver/linear_algebra.h rename to source/source_hsolver/module_linalg/linear_algebra.h diff --git a/source/source_hsolver/linear_bicgstab.cpp b/source/source_hsolver/module_linalg/linear_bicgstab.cpp similarity index 98% rename from source/source_hsolver/linear_bicgstab.cpp rename to source/source_hsolver/module_linalg/linear_bicgstab.cpp index d3700a74d78..5ba240e92f0 100644 --- a/source/source_hsolver/linear_bicgstab.cpp +++ b/source/source_hsolver/module_linalg/linear_bicgstab.cpp @@ -1,6 +1,6 @@ -#include "source_hsolver/linear_bicgstab.h" +#include "source_hsolver/module_linalg/linear_bicgstab.h" -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" #include diff --git a/source/source_hsolver/linear_bicgstab.h b/source/source_hsolver/module_linalg/linear_bicgstab.h similarity index 97% rename from source/source_hsolver/linear_bicgstab.h rename to source/source_hsolver/module_linalg/linear_bicgstab.h index 2e21510df35..3131c7b10b5 100644 --- a/source/source_hsolver/linear_bicgstab.h +++ b/source/source_hsolver/module_linalg/linear_bicgstab.h @@ -1,6 +1,6 @@ #ifndef MODULE_HSOLVER_LINEAR_BICGSTAB_H_ #define MODULE_HSOLVER_LINEAR_BICGSTAB_H_ -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/linear_workspace.h" namespace hsolver { /** @brief Right-preconditioned BiCGSTAB for independent complex right-hand sides. */ diff --git a/source/source_hsolver/linear_cgs.cpp b/source/source_hsolver/module_linalg/linear_cgs.cpp similarity index 99% rename from source/source_hsolver/linear_cgs.cpp rename to source/source_hsolver/module_linalg/linear_cgs.cpp index f5f0f488f12..1ec12b9047a 100644 --- a/source/source_hsolver/linear_cgs.cpp +++ b/source/source_hsolver/module_linalg/linear_cgs.cpp @@ -1,4 +1,4 @@ -#include "source_hsolver/linear_cgs.h" +#include "source_hsolver/module_linalg/linear_cgs.h" #include diff --git a/source/source_hsolver/linear_cgs.h b/source/source_hsolver/module_linalg/linear_cgs.h similarity index 97% rename from source/source_hsolver/linear_cgs.h rename to source/source_hsolver/module_linalg/linear_cgs.h index d3f671fe660..dc2f96c92ba 100644 --- a/source/source_hsolver/linear_cgs.h +++ b/source/source_hsolver/module_linalg/linear_cgs.h @@ -1,6 +1,6 @@ #ifndef HSOLVER_LINEAR_CGS_H #define HSOLVER_LINEAR_CGS_H -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/linear_workspace.h" namespace hsolver { diff --git a/source/source_hsolver/linear_gmres.cpp b/source/source_hsolver/module_linalg/linear_gmres.cpp similarity index 94% rename from source/source_hsolver/linear_gmres.cpp rename to source/source_hsolver/module_linalg/linear_gmres.cpp index 39471e34a4c..a5772b16505 100644 --- a/source/source_hsolver/linear_gmres.cpp +++ b/source/source_hsolver/module_linalg/linear_gmres.cpp @@ -1,4 +1,4 @@ -#include "source_hsolver/linear_gmres.h" +#include "source_hsolver/module_linalg/linear_gmres.h" #include #include @@ -6,11 +6,11 @@ namespace hsolver { template -LinearGMRES::LinearGMRES(double tolerance, const LinearSolveOptions& options, const diag_comm_info& comm) +LinearGMRES::LinearGMRES(double tolerance, int restart, int max_iter, const diag_comm_info& comm) : tolerance_(tolerance), restart_(0), work_(comm, 2), algebra_(comm) { - const int iteration_limit = std::max(1, options.max_iterations); - restart_ = std::min(options.restart, iteration_limit); + const int iter_limit = std::max(1, max_iter); + restart_ = std::min(restart, iter_limit); if (restart_ <= 0 || restart_ > (std::numeric_limits::max() - 1) / 3) { throw std::invalid_argument("Invalid GMRES restart dimension."); @@ -229,7 +229,7 @@ bool LinearGMRES::cycle(const LinearOperator& op, const LinearOperator& preconditioner, const std::vector& threshold, bool reconstruct, - int max_iterations, + int max_iter, LinearSolveResult* result) { std::vector coeff(bands_); @@ -237,7 +237,7 @@ bool LinearGMRES::cycle(const LinearOperator& op, { return false; } - for (int j = 0; j < restart_ && active_ > 0 && result->iterations < max_iterations; ++j) + for (int j = 0; j < restart_ && active_ > 0 && result->iterations < max_iter; ++j) { T* z = direction(j); T* raw = image(j); @@ -263,7 +263,7 @@ bool LinearGMRES::cycle(const LinearOperator& op, return false; } done[b] = std::abs(g_[b][j + 1]) <= 0.8 * threshold[order_[b]] || norm <= std::numeric_limits::min() || j + 1 == restart_ - || result->iterations == max_iterations; + || result->iterations == max_iter; coeff[b] = done[b] ? T(0) : T(1.0 / norm); if (!done[b]) { @@ -298,11 +298,11 @@ LinearSolveResult LinearGMRES::solve(const LinearOperator& const T* b, const T* initial_residual, bool force_check, - const LinearSolveControl& control) + int max_iter, + bool reconstruct) { const LinearSolveTimer timer("LinearGMRES"); - const int max_iterations = control.max_iterations; - work_.prepare(ld, dim, nvec, x, b, tolerance_, max_iterations); + work_.prepare(ld, dim, nvec, x, b, tolerance_, max_iter); work_.reset_statistics(); ld_ = ld; dim_ = dim; @@ -319,7 +319,6 @@ LinearSolveResult LinearGMRES::solve(const LinearOperator& const double rhs_norm = linear_norm(rhs_norms[i]); threshold[i] = tolerance_ * std::max(1.0, rhs_norm); } - bool reconstruct = control.reconstruct; force_check = force_check || tolerance_ < 100 * std::numeric_limits::epsilon(); LinearSolveResult result; work_.clear(); @@ -339,7 +338,7 @@ LinearSolveResult LinearGMRES::solve(const LinearOperator& bool regular = false; try { - regular = cycle(op, preconditioner, threshold, reconstruct, max_iterations, &result); + regular = cycle(op, preconditioner, threshold, reconstruct, max_iter, &result); result.status = regular ? LinearSolveStatus::max_iterations : LinearSolveStatus::breakdown; } catch (const LinearPreconditionerError&) @@ -414,7 +413,7 @@ LinearSolveResult LinearGMRES::solve(const LinearOperator& return result; } const bool retry_initial = initial_residual && result.restarts == 0; - if (result.iterations >= max_iterations || (result.iterations == start && !retry_initial) || !std::isfinite(result.max_residual)) + if (result.iterations >= max_iter || (result.iterations == start && !retry_initial) || !std::isfinite(result.max_residual)) { return result; } diff --git a/source/source_hsolver/linear_gmres.h b/source/source_hsolver/module_linalg/linear_gmres.h similarity index 87% rename from source/source_hsolver/linear_gmres.h rename to source/source_hsolver/module_linalg/linear_gmres.h index 8b6d3868af8..241e06e4a5b 100644 --- a/source/source_hsolver/linear_gmres.h +++ b/source/source_hsolver/module_linalg/linear_gmres.h @@ -1,7 +1,7 @@ #ifndef HSOLVER_LINEAR_GMRES_H #define HSOLVER_LINEAR_GMRES_H -#include "source_hsolver/linear_algebra.h" -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/linear_algebra.h" +#include "source_hsolver/module_linalg/linear_workspace.h" namespace hsolver { @@ -50,11 +50,11 @@ class LinearGMRES const LinearOperator& preconditioner, const std::vector& threshold, bool reconstruct, - int max_iterations, + int max_iter, LinearSolveResult* result); public: - LinearGMRES(double tolerance, const LinearSolveOptions& options, const diag_comm_info& comm); + LinearGMRES(double tolerance, int restart, int max_iter, const diag_comm_info& comm); /** @brief Use the per-call budget and reconstruction policy; force_check requests an independent final application. */ LinearSolveResult solve(const LinearOperator& op, const LinearOperator& preconditioner, @@ -65,7 +65,8 @@ class LinearGMRES const T* b, const T* initial_residual, bool force_check, - const LinearSolveControl& control); + int max_iter, + bool reconstruct); }; } // namespace hsolver #endif diff --git a/source/source_hsolver/linear_low_rank.cpp b/source/source_hsolver/module_linalg/linear_low_rank.cpp similarity index 87% rename from source/source_hsolver/linear_low_rank.cpp rename to source/source_hsolver/module_linalg/linear_low_rank.cpp index 8bf4f734df4..cbbed22817c 100644 --- a/source/source_hsolver/linear_low_rank.cpp +++ b/source/source_hsolver/module_linalg/linear_low_rank.cpp @@ -1,7 +1,7 @@ -#include "source_hsolver/linear_low_rank.h" +#include "source_hsolver/module_linalg/linear_low_rank.h" -#include "source_hsolver/kernels/linear_op.h" -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" +#include "source_hsolver/module_linalg/linear_workspace.h" namespace hsolver { @@ -83,23 +83,23 @@ void LinearLowRank::prepare_response(int ld, int rank, const T* direc template void LinearLowRank::prepare_subspace(int ld, - int rank, - const T* basis, - const T* images, - const LinearSmallLU& factor, - ct::Tensor* workspace) + int rank, + const T* basis, + const T* images, + const LinearSmallLU& factor, + ct::Tensor* workspace) { prepare(ld, rank, basis, images, basis, &factor, workspace); } template void LinearLowRank::prepare(int ld, - int rank, - const T* z, - const T* w, - const T* test, - const LinearSmallLU* factor, - ct::Tensor* workspace) + int rank, + const T* z, + const T* w, + const T* test, + const LinearSmallLU* factor, + ct::Tensor* workspace) { rank_ = rank; test_ = rank > 0 ? test : nullptr; diff --git a/source/source_hsolver/linear_low_rank.h b/source/source_hsolver/module_linalg/linear_low_rank.h similarity index 96% rename from source/source_hsolver/linear_low_rank.h rename to source/source_hsolver/module_linalg/linear_low_rank.h index ce3eb044950..7c3cc483a4f 100644 --- a/source/source_hsolver/linear_low_rank.h +++ b/source/source_hsolver/module_linalg/linear_low_rank.h @@ -1,7 +1,7 @@ #ifndef HSOLVER_LINEAR_LOW_RANK_H #define HSOLVER_LINEAR_LOW_RANK_H -#include "source_hsolver/linear_algebra.h" -#include "source_hsolver/linear_operator.h" +#include "source_hsolver/module_linalg/linear_algebra.h" +#include "source_hsolver/module_linalg/linear_operator.h" namespace hsolver { diff --git a/source/source_hsolver/linear_operator.h b/source/source_hsolver/module_linalg/linear_operator.h similarity index 100% rename from source/source_hsolver/linear_operator.h rename to source/source_hsolver/module_linalg/linear_operator.h diff --git a/source/source_hsolver/linear_solver_types.h b/source/source_hsolver/module_linalg/linear_solver_types.h similarity index 82% rename from source/source_hsolver/linear_solver_types.h rename to source/source_hsolver/module_linalg/linear_solver_types.h index 030f014682f..2d26f6400f8 100644 --- a/source/source_hsolver/linear_solver_types.h +++ b/source/source_hsolver/module_linalg/linear_solver_types.h @@ -38,22 +38,15 @@ enum class LinearMethod }; /** @brief Numerical policy; tolerance zero selects the precision-aware default. */ -struct LinearSolveOptions +struct LinearControls { - LinearMethod method = LinearMethod::bicgstab; + LinearMethod solver = LinearMethod::bicgstab; double tolerance = 0.0; int max_iterations = 500; int restart = 20; bool reconstruct = false; }; -/** @brief Explicit policy for one solve; does not change the solver's defaults. */ -struct LinearSolveControl -{ - int max_iterations; - bool reconstruct; -}; - const char* linear_status_name(const LinearSolveStatus status); } // namespace hsolver diff --git a/source/source_hsolver/linear_workspace.cpp b/source/source_hsolver/module_linalg/linear_workspace.cpp similarity index 99% rename from source/source_hsolver/linear_workspace.cpp rename to source/source_hsolver/module_linalg/linear_workspace.cpp index fa2e14fe0dc..e4fe906459e 100644 --- a/source/source_hsolver/linear_workspace.cpp +++ b/source/source_hsolver/module_linalg/linear_workspace.cpp @@ -1,9 +1,9 @@ -#include "source_hsolver/linear_workspace.h" +#include "source_hsolver/module_linalg/linear_workspace.h" #include "source_base/module_device/memory_op.h" #include "source_base/parallel_device.h" #include "source_base/timer.h" -#include "source_hsolver/kernels/linear_op.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" #include #include diff --git a/source/source_hsolver/linear_workspace.h b/source/source_hsolver/module_linalg/linear_workspace.h similarity index 97% rename from source/source_hsolver/linear_workspace.h rename to source/source_hsolver/module_linalg/linear_workspace.h index 0b93a0f50ae..7b955f7e484 100644 --- a/source/source_hsolver/linear_workspace.h +++ b/source/source_hsolver/module_linalg/linear_workspace.h @@ -4,8 +4,8 @@ #include "source_base/macros.h" #include "source_base/module_container/ATen/core/tensor.h" #include "source_hsolver/diag_comm_info.h" -#include "source_hsolver/linear_operator.h" -#include "source_hsolver/linear_solver_types.h" +#include "source_hsolver/module_linalg/linear_operator.h" +#include "source_hsolver/module_linalg/linear_solver_types.h" #include #include diff --git a/source/source_hsolver/module_linalg/orb_buffer.cpp b/source/source_hsolver/module_linalg/orb_buffer.cpp new file mode 100644 index 00000000000..4edc782e9ed --- /dev/null +++ b/source/source_hsolver/module_linalg/orb_buffer.cpp @@ -0,0 +1,55 @@ +#include "source_hsolver/module_linalg/orb_buffer.h" + +#include + +namespace hsolver +{ +template +void zero_pad(T* data, const OrbLayout& layout) +{ + const int stride = layout.ld / layout.npol; + if (stride > layout.npw && layout.bands > 0) + { + T* tail = data + layout.npw; + const size_t width = stride - layout.npw; + const size_t columns = static_cast(layout.bands) * layout.npol; + base_device::memory::set_memory_2d_op()(tail, stride, 0, width, columns); + } +} + +template +const T* clean_orbs(const T* input, const OrbLayout& layout, ct::Tensor* scratch) +{ + if (layout.npol == 1) + { + return input; + } + T* data = scratch->template data(); + const size_t count = static_cast(layout.ld) * layout.bands; + if (count > 0) + { + base_device::memory::synchronize_memory_op()(data, input, count); + } + zero_pad(data, layout); + return data; +} + +template void zero_pad, base_device::DEVICE_CPU>(std::complex*, const OrbLayout&); +template void zero_pad, base_device::DEVICE_CPU>(std::complex*, const OrbLayout&); +template const std::complex* clean_orbs, base_device::DEVICE_CPU>(const std::complex*, + const OrbLayout&, + ct::Tensor*); +template const std::complex* clean_orbs, base_device::DEVICE_CPU>(const std::complex*, + const OrbLayout&, + ct::Tensor*); +#if defined(__CUDA) || defined(__ROCM) +template void zero_pad, base_device::DEVICE_GPU>(std::complex*, const OrbLayout&); +template void zero_pad, base_device::DEVICE_GPU>(std::complex*, const OrbLayout&); +template const std::complex* clean_orbs, base_device::DEVICE_GPU>(const std::complex*, + const OrbLayout&, + ct::Tensor*); +template const std::complex* clean_orbs, base_device::DEVICE_GPU>(const std::complex*, + const OrbLayout&, + ct::Tensor*); +#endif +} // namespace hsolver diff --git a/source/source_hsolver/module_linalg/orb_buffer.h b/source/source_hsolver/module_linalg/orb_buffer.h new file mode 100644 index 00000000000..1f6960d832d --- /dev/null +++ b/source/source_hsolver/module_linalg/orb_buffer.h @@ -0,0 +1,28 @@ +#ifndef HSOLVER_ORB_BUFFER_H +#define HSOLVER_ORB_BUFFER_H + +#include "source_base/module_container/ATen/core/tensor.h" +#include "source_base/module_device/memory_op.h" + +namespace hsolver +{ +/** @brief Column-major orbitals; spin components have ld/npol rows each. */ +struct OrbLayout +{ + int ld; + int npw; + int npol; + int bands; +}; + +/** @brief Clear all spin-component tails, including scalar-orbital padding. */ +template +void zero_pad(T* data, const OrbLayout& layout); + +/** @brief Borrow scalar input, or copy spinors into scratch and clear their padding. + * Scratch must have room for ld * bands coefficients; input remains unchanged. + */ +template +const T* clean_orbs(const T* input, const OrbLayout& layout, ct::Tensor* scratch); +} // namespace hsolver +#endif diff --git a/source/source_hsolver/orthonormal.cpp b/source/source_hsolver/module_linalg/orthonormal.cpp similarity index 98% rename from source/source_hsolver/orthonormal.cpp rename to source/source_hsolver/module_linalg/orthonormal.cpp index d4fd9272676..942056a1000 100644 --- a/source/source_hsolver/orthonormal.cpp +++ b/source/source_hsolver/module_linalg/orthonormal.cpp @@ -1,4 +1,4 @@ -#include "source_hsolver/orthonormal.h" +#include "source_hsolver/module_linalg/orthonormal.h" #include "source_base/parallel_device.h" #include "source_base/timer.h" @@ -254,7 +254,7 @@ OrthResult Orthonormal::inspect(const T* input, int ld, int dim, int if (result.failure != OrthFailure::none) { result.status = OrthStatus::failed; - result.reason = "band=" + std::to_string(band); + result.reason = "band=" + std::to_string(band + 1); } } } diff --git a/source/source_hsolver/orthonormal.h b/source/source_hsolver/module_linalg/orthonormal.h similarity index 98% rename from source/source_hsolver/orthonormal.h rename to source/source_hsolver/module_linalg/orthonormal.h index 08deb139749..aea343b2d91 100644 --- a/source/source_hsolver/orthonormal.h +++ b/source/source_hsolver/module_linalg/orthonormal.h @@ -1,7 +1,7 @@ #ifndef HSOLVER_ORTHONORMAL_H #define HSOLVER_ORTHONORMAL_H -#include "source_hsolver/linear_algebra.h" +#include "source_hsolver/module_linalg/linear_algebra.h" #include #include diff --git a/source/source_hsolver/orthonormal_small.cpp b/source/source_hsolver/module_linalg/orthonormal_small.cpp similarity index 90% rename from source/source_hsolver/orthonormal_small.cpp rename to source/source_hsolver/module_linalg/orthonormal_small.cpp index 30d25b305a5..b982b347cba 100644 --- a/source/source_hsolver/orthonormal_small.cpp +++ b/source/source_hsolver/module_linalg/orthonormal_small.cpp @@ -1,7 +1,7 @@ #include "source_base/kernels/math_kernel_op.h" #include "source_base/module_container/base/third_party/lapack.h" #include "source_base/timer.h" -#include "source_hsolver/orthonormal.h" +#include "source_hsolver/module_linalg/orthonormal.h" #include #include @@ -37,10 +37,10 @@ bool cholesky(const std::vector& g, int n, std::vector* c) const char upper = 'U'; const char nonunit = 'N'; int info = 0; - zpotrf_(&upper, &n, c->data(), &n, &info); + ct::lapackConnector::potrf(upper, n, c->data(), n, info); if (info == 0) { - ztrtri_(&upper, &nonunit, &n, c->data(), &n, &info); + ct::lapackConnector::trtri(upper, nonunit, n, c->data(), n, info); } for (int j = 0; j < n; ++j) { @@ -67,7 +67,19 @@ bool lowdin(const std::vector& g, int n, std::vector* c) std::vector rwork(lrwork); std::vector iwork(liwork); int info = 0; - zheevd_(&vectors, &upper, &n, u.data(), &n, values.data(), work.data(), &lwork, rwork.data(), &lrwork, iwork.data(), &liwork, &info); + ct::lapackConnector::heevd(vectors, + upper, + n, + u.data(), + n, + values.data(), + work.data(), + lwork, + rwork.data(), + lrwork, + iwork.data(), + liwork, + info); bool valid = info == 0; for (double value: values) { diff --git a/source/source_hsolver/module_linalg/unittests/CMakeLists.txt b/source/source_hsolver/module_linalg/unittests/CMakeLists.txt new file mode 100644 index 00000000000..3fcadde5a51 --- /dev/null +++ b/source/source_hsolver/module_linalg/unittests/CMakeLists.txt @@ -0,0 +1,34 @@ +abacus_disable_feature_definitions(__CUDA) +abacus_disable_feature_definitions(__ROCM) +abacus_disable_feature_definitions(__EXX) + +set(LINALG_TEST_SOURCES + ../hsolver_linear.cpp + ../linear_bicgstab.cpp + ../linear_cgs.cpp + ../linear_gmres.cpp + ../linear_algebra.cpp + ../cn_subspace.cpp + ../linear_low_rank.cpp + ../linear_workspace.cpp + ../exp_action.cpp + ../exp_lanczos.cpp + ../exp_taylor.cpp + ../orb_buffer.cpp + ../orthonormal.cpp + ../orthonormal_small.cpp +) +AddTest( + TARGET MODULE_HSOLVER_linalg + LIBS parameter base device container + SOURCES test_hsolver_linear.cpp test_cn_subspace.cpp test_linear_low_rank.cpp + test_orthonormal.cpp test_exp_action.cpp ${LINALG_TEST_SOURCES} +) +if(ENABLE_MPI) + add_test( + NAME MODULE_HSOLVER_linalg_parallel + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} + $ ${MPIEXEC_POSTFLAGS} + ) + set_tests_properties(MODULE_HSOLVER_linalg_parallel PROPERTIES PROCESSORS 2 TIMEOUT 120) +endif() diff --git a/source/source_hsolver/test/linear_test_utils.h b/source/source_hsolver/module_linalg/unittests/linear_test_utils.h similarity index 100% rename from source/source_hsolver/test/linear_test_utils.h rename to source/source_hsolver/module_linalg/unittests/linear_test_utils.h diff --git a/source/source_hsolver/test/test_cn_subspace.cpp b/source/source_hsolver/module_linalg/unittests/test_cn_subspace.cpp similarity index 97% rename from source/source_hsolver/test/test_cn_subspace.cpp rename to source/source_hsolver/module_linalg/unittests/test_cn_subspace.cpp index 16fee4d1e10..db79d3be884 100644 --- a/source/source_hsolver/test/test_cn_subspace.cpp +++ b/source/source_hsolver/module_linalg/unittests/test_cn_subspace.cpp @@ -1,6 +1,6 @@ #include "source_base/parallel_device.h" -#include "source_hsolver/cn_subspace.h" -#include "source_hsolver/test/linear_test_utils.h" +#include "source_hsolver/module_linalg/cn_subspace.h" +#include "source_hsolver/module_linalg/unittests/linear_test_utils.h" #include #include diff --git a/source/source_hsolver/module_linalg/unittests/test_exp_action.cpp b/source/source_hsolver/module_linalg/unittests/test_exp_action.cpp new file mode 100644 index 00000000000..af15cdabca0 --- /dev/null +++ b/source/source_hsolver/module_linalg/unittests/test_exp_action.cpp @@ -0,0 +1,267 @@ +#include "source_base/module_container/base/third_party/lapack.h" +#include "source_hsolver/module_linalg/exp_action.h" +#include "source_hsolver/module_linalg/unittests/linear_test_utils.h" + +#include +#include +#include +#include +#include + +namespace +{ +using Wide = std::complex; +using Device = base_device::DEVICE_CPU; + +// A full complex Hermitian matrix, with spin components separated by padding. +template +class DenseExp final : public hsolver::HSOperator +{ + public: + std::vector matrix; + int npol; + mutable int calls = 0; + mutable int cols = 0; + + explicit DenseExp(int spins) : npol(spins) + { + matrix = linear_test::hermitian(6); + } + int row(int i, int ld) const + { + return i / (6 / npol) * (ld / npol) + i % (6 / npol); + } + void update_k(int) override + { + } + void hpsi(const T* x, T* y, int ld, int bands) const override + { + ++calls; + cols += bands; + std::fill_n(y, ld * bands, T(0)); + for (int b = 0; b < bands; ++b) + { + for (int i = 0; i < 6; ++i) + { + for (int j = 0; j < 6; ++j) + { + y[b * ld + row(i, ld)] += matrix[j * 6 + i] * x[b * ld + row(j, ld)]; + } + } + } + } + void spsi(const T*, T*, int, int) const override + { + FAIL() << "PW exponential must not request an overlap operator"; + } +}; + +template +std::vector pack_input(const DenseExp& op, const hsolver::OrbLayout& layout) +{ + std::vector input(layout.ld * layout.bands, T(30, -20)); + for (int b = 0; b < layout.bands; ++b) + { + for (int i = 0; i < 6; ++i) + { + input[b * layout.ld + op.row(i, layout.ld)] = T(std::sin(i + 2 * b + 1), std::cos(2 * i + b)); + } + } + return input; +} + +// Diagonalize the entire matrix, independently of the Krylov approximation. +template +std::vector exact_exp(const std::vector& matrix, const std::vector& input, double alpha) +{ + const int n = 6; + const int lwork = 64; + const char job = 'V'; + const char upper = 'U'; + std::vector vectors(matrix.begin(), matrix.end()); + std::vector work(lwork); + std::vector rwork(3 * n); + std::vector values(n); + int status = 0; + ct::lapackConnector::heev(job, upper, n, vectors.data(), n, values.data(), work.data(), lwork, rwork.data(), status); + EXPECT_EQ(status, 0); + std::vector output(n, Wide(0)); + for (int k = 0; k < n; ++k) + { + Wide weight(0); + for (int i = 0; i < n; ++i) + { + weight += std::conj(vectors[k * n + i]) * input[i]; + } + weight *= std::exp(Wide(0, -alpha * values[k])); + for (int i = 0; i < n; ++i) + { + output[i] += vectors[k * n + i] * weight; + } + } + return output; +} + +template +void check_output(const DenseExp& op, + const hsolver::OrbLayout& layout, + const std::vector& input, + const std::vector& output, + double alpha, + int order, + double tol) +{ + for (int b = 0; b < layout.bands; ++b) + { + std::vector src(6); + for (int i = 0; i < 6; ++i) + { + src[i] = input[b * layout.ld + op.row(i, layout.ld)]; + } + std::vector expected; + if (order == 0) + { + expected = exact_exp(op.matrix, src, alpha); + } + else + { + // Direct dense polynomial in double precision, without batched kernels. + expected = src; + std::vector term = src; + const std::vector matrix(op.matrix.begin(), op.matrix.end()); + for (int k = 1; k <= order; ++k) + { + term = linear_test::multiply(matrix, term, 6, 1); + for (int i = 0; i < 6; ++i) + { + term[i] *= Wide(0, -alpha / k); + expected[i] += term[i]; + } + } + } + double norm_in = 0; + double norm_out = 0; + for (int i = 0; i < 6; ++i) + { + const Wide actual = output[b * layout.ld + op.row(i, layout.ld)]; + EXPECT_NEAR(std::abs(actual - expected[i]), 0.0, tol); + norm_in += std::norm(src[i]); + norm_out += std::norm(actual); + } + if (order == 0) + { + EXPECT_NEAR(norm_out, norm_in, 20 * tol); + } + for (int spin = 0; spin < layout.npol; ++spin) + { + for (int i = layout.npw; i < layout.ld / layout.npol; ++i) + { + EXPECT_EQ(output[b * layout.ld + spin * (layout.ld / layout.npol) + i], T(0)); + } + } + } +} + +template +class ExpTest : public testing::Test +{ +}; +using Precisions = testing::Types; +TYPED_TEST_SUITE(ExpTest, Precisions); + +TYPED_TEST(ExpTest, LanczosMatchesFullExponential) +{ + using T = std::complex; + const double tol = std::is_same::value ? 2e-5 : 2e-10; + for (int npol: {1, 2}) + { + SCOPED_TRACE(npol); + DenseExp op(npol); + const hsolver::OrbLayout layout{10, 6 / npol, npol, 10}; + const std::vector input = pack_input(op, layout); + std::vector output(input.size()); + hsolver::ExpControls exp_ctrl; + std::unique_ptr> exp = hsolver::make_exp_action(exp_ctrl, linear_test::world_comm()); + const hsolver::ExpResult result = exp->apply(op, layout, 0.4, input.data(), output.data()); + ASSERT_EQ(result.state, hsolver::ExpState::success); + EXPECT_TRUE(result.has_err_est); + EXPECT_LE(result.rel_err_est, exp->rel_tol()); + EXPECT_EQ(result.hpsi_calls, op.calls); + EXPECT_EQ(result.hpsi_cols, op.cols); + check_output(op, layout, input, output, 0.4, 0, tol); + } +} + +TYPED_TEST(ExpTest, TaylorPairMatchesBothPolynomials) +{ + using T = std::complex; + const double tol = std::is_same::value ? 2e-6 : 2e-14; + for (int npol: {1, 2}) + { + SCOPED_TRACE(npol); + DenseExp op(npol); + const hsolver::OrbLayout layout{10, 6 / npol, npol, 3}; + const std::vector input = pack_input(op, layout); + std::vector half(input.size()); + std::vector full(input.size()); + hsolver::ExpControls exp_ctrl; + exp_ctrl.expansion = hsolver::ExpMethod::taylor; + exp_ctrl.taylor_order = 6; + std::unique_ptr> exp = hsolver::make_exp_action(exp_ctrl, linear_test::world_comm()); + const hsolver::ExpResult result = exp->apply_pair(op, layout, 0.15, input.data(), half.data(), full.data()); + ASSERT_EQ(result.state, hsolver::ExpState::success); + EXPECT_FALSE(result.has_err_est); + EXPECT_EQ(op.calls, exp_ctrl.taylor_order); + EXPECT_EQ(result.hpsi_calls, op.calls); + EXPECT_EQ(result.hpsi_cols, exp_ctrl.taylor_order * layout.bands); + check_output(op, layout, input, half, 0.15, exp_ctrl.taylor_order, tol); + check_output(op, layout, input, full, 0.3, exp_ctrl.taylor_order, tol); + } +} + +TEST(ExpAction, LanczosSubdividesOrReportsExhaustion) +{ + DenseExp op(1); + const hsolver::OrbLayout layout{8, 6, 1, 2}; + const std::vector input = pack_input(op, layout); + std::vector output(input.size()); + hsolver::ExpControls exp_ctrl; + exp_ctrl.krylov_max = 4; + exp_ctrl.rel_tol = 1e-8; + std::unique_ptr> exp = hsolver::make_exp_action(exp_ctrl, linear_test::world_comm()); + const hsolver::ExpResult result = exp->apply(op, layout, 1.0, input.data(), output.data()); + ASSERT_EQ(result.state, hsolver::ExpState::success); + EXPECT_GT(result.bisect_count, 0); + EXPECT_LE(result.rel_err_est, exp_ctrl.rel_tol); + EXPECT_EQ(result.hpsi_calls, op.calls); + EXPECT_EQ(result.hpsi_cols, op.cols); + check_output(op, layout, input, output, 1.0, 0, 5e-8); + + exp_ctrl.krylov_max = 2; + exp_ctrl.rel_tol = 1e-14; + exp = hsolver::make_exp_action(exp_ctrl, linear_test::world_comm()); + const hsolver::ExpResult failed = exp->apply(op, layout, 1.0, input.data(), output.data()); + EXPECT_EQ(failed.state, hsolver::ExpState::failed); + EXPECT_GT(failed.bisect_count, 0); + EXPECT_GE(failed.failed_band, 0); + EXPECT_LT(failed.failed_band, layout.bands); +} + +TEST(ExpAction, NonfiniteInputReportsOriginalBand) +{ + DenseExp op(2); + const hsolver::OrbLayout layout{10, 3, 2, 10}; + std::vector input = pack_input(op, layout); + input[9 * layout.ld] = Wide(std::numeric_limits::quiet_NaN(), 0); + std::vector output(input.size()); + for (hsolver::ExpMethod method: {hsolver::ExpMethod::lanczos, hsolver::ExpMethod::taylor}) + { + hsolver::ExpControls exp_ctrl; + exp_ctrl.expansion = method; + std::unique_ptr> exp = hsolver::make_exp_action(exp_ctrl, linear_test::world_comm()); + const hsolver::ExpResult result = exp->apply(op, layout, 0.1, input.data(), output.data()); + EXPECT_EQ(result.state, hsolver::ExpState::failed); + EXPECT_EQ(result.failed_band, 9); + } +} +} // namespace diff --git a/source/source_hsolver/test/test_hsolver_linear.cpp b/source/source_hsolver/module_linalg/unittests/test_hsolver_linear.cpp similarity index 91% rename from source/source_hsolver/test/test_hsolver_linear.cpp rename to source/source_hsolver/module_linalg/unittests/test_hsolver_linear.cpp index 14efc6a96d8..f8009bd9ef8 100644 --- a/source/source_hsolver/test/test_hsolver_linear.cpp +++ b/source/source_hsolver/module_linalg/unittests/test_hsolver_linear.cpp @@ -1,7 +1,7 @@ #include "source_base/parallel_device.h" #include "source_base/parallel_global.h" -#include "source_hsolver/hsolver_linear.h" -#include "source_hsolver/test/linear_test_utils.h" +#include "source_hsolver/module_linalg/hsolver_linear.h" +#include "source_hsolver/module_linalg/unittests/linear_test_utils.h" #include #include @@ -121,11 +121,11 @@ TYPED_TEST(LinearSolveTest, DenseReferenceAndReusedBatches) { for (const bool preconditioned: {false, true}) { - hsolver::LinearSolveOptions options; - options.method = method; - options.tolerance = tolerance; - options.restart = 2; - hsolver::HSolverLinear solver(options, comm); + hsolver::LinearControls linear_ctrl; + linear_ctrl.solver = method; + linear_ctrl.tolerance = tolerance; + linear_ctrl.restart = 2; + hsolver::HSolverLinear solver(linear_ctrl, comm); // Shrink, grow, and use zero local rows without replacing the solver. for (const int n: {11, 5, 17, 1}) { @@ -271,11 +271,11 @@ TEST(LinearSolveFailure, ReportsOriginalColumnAndTrueResidual) std::fill(a.begin(), a.end(), T(0)); } DenseOperator op(a, n, start, dim, comm); - hsolver::LinearSolveOptions options; - options.method = method; - options.tolerance = 1e-13; - options.max_iterations = singular ? 10 : 1; - hsolver::HSolverLinear solver(options, comm); + hsolver::LinearControls linear_ctrl; + linear_ctrl.solver = method; + linear_ctrl.tolerance = 1e-13; + linear_ctrl.max_iterations = singular ? 10 : 1; + hsolver::HSolverLinear solver(linear_ctrl, comm); std::vector x(3 * ld, T(0)); std::vector b(3 * ld, T(0)); // Retire column 0; column 2 is swapped forward but failure must still name column 1. @@ -289,7 +289,7 @@ TEST(LinearSolveFailure, ReportsOriginalColumnAndTrueResidual) = singular ? hsolver::LinearSolveStatus::breakdown : hsolver::LinearSolveStatus::max_iterations; EXPECT_EQ(result.status, expected); EXPECT_EQ(result.failed_band, 1); - EXPECT_LE(result.iterations, options.max_iterations); + EXPECT_LE(result.iterations, linear_ctrl.max_iterations); std::vector ax(3 * ld, T(0)); op.apply(x.data(), ax.data(), ld, 3); double residual2 = 0.0; @@ -301,7 +301,7 @@ TEST(LinearSolveFailure, ReportsOriginalColumnAndTrueResidual) Parallel_Common::reduce_data(&residual2, 1, comm.comm); #endif EXPECT_NEAR(result.max_residual, std::sqrt(residual2), 1e-12); - EXPECT_GT(result.max_residual, options.tolerance); + EXPECT_GT(result.max_residual, linear_ctrl.tolerance); } } } @@ -340,23 +340,23 @@ void check_reconstruction(const bool corrupt_initial) b[band * ld + i] = rhs[band * n + start + i]; } } - hsolver::LinearSolveOptions options; - options.method = hsolver::LinearMethod::gmres; + hsolver::LinearControls linear_ctrl; + linear_ctrl.solver = hsolver::LinearMethod::gmres; // Above 100*epsilon in float: exercise reconstructed acceptance, not an automatic audit. - options.tolerance = std::is_same>::value ? 2e-5 : 1e-11; - options.restart = 2; - options.max_iterations = 100; - options.reconstruct = true; + linear_ctrl.tolerance = std::is_same>::value ? 2e-5 : 1e-11; + linear_ctrl.restart = 2; + linear_ctrl.max_iterations = 100; + linear_ctrl.reconstruct = true; DenseOperator op(matrix, n, start, dim, comm); const IdentityOperator identity(dim); - hsolver::HSolverLinear solver(options, comm); + hsolver::HSolverLinear solver(linear_ctrl, comm); const T* initial = corrupt_initial ? bad_residual.data() : nullptr; const hsolver::LinearSolveResult result = solver.solve(op, identity, ld, bands, dim, x.data(), b.data(), initial, corrupt_initial); ASSERT_EQ(result.status, hsolver::LinearSolveStatus::converged); EXPECT_EQ(result.failed_band, -1); EXPECT_GT(result.restarts, 0); EXPECT_GT(result.true_checks, 0); - EXPECT_LE(result.iterations, options.max_iterations); + EXPECT_LE(result.iterations, linear_ctrl.max_iterations); EXPECT_EQ(result.reconstructed, !corrupt_initial); EXPECT_EQ(result.reconstruction_fallbacks, corrupt_initial ? 1 : 0); std::vector ax(ld * bands, T(0)); @@ -369,24 +369,24 @@ void check_reconstruction(const bool corrupt_initial) { error += std::norm(linear_test::Complex(ax[band * ld + i]) - linear_test::Complex(b[band * ld + i])); norm += std::norm(linear_test::Complex(b[band * ld + i])); - EXPECT_LT(std::abs(linear_test::Complex(x[band * ld + i]) - reference[band * n + start + i]), 10 * options.tolerance); + EXPECT_LT(std::abs(linear_test::Complex(x[band * ld + i]) - reference[band * n + start + i]), 10 * linear_ctrl.tolerance); } #ifdef __MPI Parallel_Common::reduce_data(&error, 1, comm.comm); Parallel_Common::reduce_data(&norm, 1, comm.comm); #endif - EXPECT_LE(std::sqrt(error), 1.2 * options.tolerance * std::max(1.0, std::sqrt(norm))); + EXPECT_LE(std::sqrt(error), 1.2 * linear_ctrl.tolerance * std::max(1.0, std::sqrt(norm))); } if (corrupt_initial) { // Recovery shares the total iteration budget rather than starting a fresh allowance. - options.max_iterations = 1; - hsolver::HSolverLinear limited(options, comm); + linear_ctrl.max_iterations = 1; + hsolver::HSolverLinear limited(linear_ctrl, comm); std::fill(x.begin(), x.end(), T(0)); const hsolver::LinearSolveResult exhausted = limited.solve(op, identity, ld, bands, dim, x.data(), b.data(), initial, true); EXPECT_EQ(exhausted.status, hsolver::LinearSolveStatus::max_iterations); EXPECT_EQ(exhausted.failed_band, 1); - EXPECT_EQ(exhausted.iterations, options.max_iterations); + EXPECT_EQ(exhausted.iterations, linear_ctrl.max_iterations); EXPECT_EQ(exhausted.reconstruction_fallbacks, 1); } } diff --git a/source/source_hsolver/test/test_linear_low_rank.cpp b/source/source_hsolver/module_linalg/unittests/test_linear_low_rank.cpp similarity index 97% rename from source/source_hsolver/test/test_linear_low_rank.cpp rename to source/source_hsolver/module_linalg/unittests/test_linear_low_rank.cpp index 6a4d110fba0..4639d920a9f 100644 --- a/source/source_hsolver/test/test_linear_low_rank.cpp +++ b/source/source_hsolver/module_linalg/unittests/test_linear_low_rank.cpp @@ -1,5 +1,5 @@ -#include "source_hsolver/linear_low_rank.h" -#include "source_hsolver/test/linear_test_utils.h" +#include "source_hsolver/module_linalg/linear_low_rank.h" +#include "source_hsolver/module_linalg/unittests/linear_test_utils.h" #include #include diff --git a/source/source_hsolver/test/test_orthonormal.cpp b/source/source_hsolver/module_linalg/unittests/test_orthonormal.cpp similarity index 99% rename from source/source_hsolver/test/test_orthonormal.cpp rename to source/source_hsolver/module_linalg/unittests/test_orthonormal.cpp index 50ff4231d75..d664559b6d1 100644 --- a/source/source_hsolver/test/test_orthonormal.cpp +++ b/source/source_hsolver/module_linalg/unittests/test_orthonormal.cpp @@ -1,4 +1,4 @@ -#include "source_hsolver/orthonormal.h" +#include "source_hsolver/module_linalg/orthonormal.h" #include #include diff --git a/source/source_hsolver/test/CMakeLists.txt b/source/source_hsolver/unittests/CMakeLists.txt similarity index 78% rename from source/source_hsolver/test/CMakeLists.txt rename to source/source_hsolver/unittests/CMakeLists.txt index f98af874b45..d013a06ed42 100644 --- a/source/source_hsolver/test/CMakeLists.txt +++ b/source/source_hsolver/unittests/CMakeLists.txt @@ -2,82 +2,54 @@ abacus_disable_feature_definitions(__CUDA) abacus_disable_feature_definitions(__ROCM) abacus_disable_feature_definitions(__EXX) -set(TD_LINEAR_TEST_SOURCES - ../hsolver_linear.cpp - ../linear_bicgstab.cpp - ../linear_cgs.cpp - ../linear_gmres.cpp - ../linear_algebra.cpp - ../cn_subspace.cpp - ../linear_low_rank.cpp - ../linear_workspace.cpp -) -AddTest( - TARGET MODULE_HSOLVER_linear - LIBS parameter base device container - SOURCES test_hsolver_linear.cpp test_cn_subspace.cpp test_linear_low_rank.cpp ${TD_LINEAR_TEST_SOURCES} -) -AddTest( - TARGET MODULE_HSOLVER_pw_tddft - LIBS parameter base device container psi planewave - SOURCES test_hsolver_pw_tddft.cpp test_orthonormal.cpp ../hsolver_pw_tddft.cpp ../orthonormal.cpp ../orthonormal_small.cpp ${TD_LINEAR_TEST_SOURCES} -) -if(ENABLE_MPI) - add_test( - NAME MODULE_HSOLVER_linear_parallel - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} - $ ${MPIEXEC_POSTFLAGS} - ) - set_tests_properties(MODULE_HSOLVER_linear_parallel PROPERTIES PROCESSORS 2 TIMEOUT 120) -endif() if (ENABLE_MPI) AddTest( TARGET MODULE_HSOLVER_parak2d_test LIBS parameter base device MPI::MPI_CXX - SOURCES parallel_k2d_test.cpp ../parallel_k2d.cpp ../../source_cell/parallel_kpoints.cpp + SOURCES test_parallel_k2d.cpp ../parallel_k2d.cpp ../../source_cell/parallel_kpoints.cpp ) AddTest( TARGET MODULE_HSOLVER_bpcg LIBS parameter base psi device container - SOURCES diago_bpcg_test.cpp ../diago_bpcg.cpp ../para_lin_tf.cpp ../diago_iter_assist.cpp + SOURCES test_diago_bpcg.cpp ../diago_bpcg.cpp ../para_lin_tf.cpp ../diago_iter_assist.cpp ../../source_basis/module_pw/test/test_tool.cpp ) AddTest( TARGET MODULE_HSOLVER_cg LIBS parameter base psi device container - SOURCES diago_cg_test.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_cg.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) AddTest( TARGET MODULE_HSOLVER_cg_float LIBS parameter base psi device container - SOURCES diago_cg_float_test.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_cg_float.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) AddTest( TARGET MODULE_HSOLVER_dav LIBS parameter base psi device - SOURCES diago_david_test.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_david_double.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) AddTest( TARGET MODULE_HSOLVER_dav_float LIBS parameter base psi device - SOURCES diago_david_float_test.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_david_float.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) if(ENABLE_LCAO) AddTest( TARGET MODULE_HSOLVER_cg_real LIBS parameter base psi device container - SOURCES diago_cg_float_test.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_cg_float.cpp ../diago_cg.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) AddTest( TARGET MODULE_HSOLVER_dav_real LIBS parameter base psi device - SOURCES diago_david_real_test.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp + SOURCES test_diago_david_real.cpp ../diago_david.cpp ../diago_iter_assist.cpp ../diag_const_nums.cpp ../../source_basis/module_pw/test/test_tool.cpp ) endif() @@ -101,13 +73,13 @@ if (ENABLE_MPI) AddTest( TARGET MODULE_HSOLVER_LCAO LIBS parameter ELPA::ELPA base genelpa psi device - SOURCES diago_lcao_test.cpp ../diago_elpa.cpp ../diago_elpa_native.cpp ../diago_scalapack.cpp ../diago_lapack.cpp + SOURCES test_diago_lcao.cpp ../diago_elpa.cpp ../diago_elpa_native.cpp ../diago_scalapack.cpp ../diago_lapack.cpp ) else() AddTest( TARGET MODULE_HSOLVER_LCAO LIBS parameter base psi device - SOURCES diago_lcao_test.cpp ../diago_scalapack.cpp ../diago_lapack.cpp + SOURCES test_diago_lcao.cpp ../diago_scalapack.cpp ../diago_lapack.cpp ) endif() @@ -115,7 +87,7 @@ if (ENABLE_MPI) AddTest( TARGET MODULE_HSOLVER_LCAO_PEXSI LIBS parameter PEXSI::PEXSI base psi device pexsi - SOURCES diago_pexsi_test.cpp ../diago_pexsi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp + SOURCES test_diago_pexsi.cpp ../diago_pexsi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp ) endif() endif() @@ -123,7 +95,7 @@ if (ENABLE_MPI) AddTest( TARGET MODULE_HSOLVER_LCAO_cusolver LIBS parameter base psi device - SOURCES diago_lcao_cusolver_test.cpp ../diago_cusolver.cpp ../diago_scalapack.cpp + SOURCES test_diago_cusolver.cpp ../diago_cusolver.cpp ../diago_scalapack.cpp ../kernels/hegvd_op.cpp ../kernels/cuda/diag_cusolver.cu ) @@ -158,7 +130,7 @@ if(ENABLE_MPI) TARGET MODULE_HSOLVER_diago_hs_parallel LIBS parameter ELPA::ELPA base device MPI::MPI_CXX genelpa psi SOURCES - test_diago_hs_para.cpp + test_diag_hs_para.cpp ../diag_hs_para.cpp ../diago_pxxxgvx.cpp ../diago_elpa.cpp @@ -169,7 +141,7 @@ if(ENABLE_MPI) TARGET MODULE_HSOLVER_diago_hs_parallel LIBS parameter base device MPI::MPI_CXX psi SOURCES - test_diago_hs_para.cpp + test_diag_hs_para.cpp ../diag_hs_para.cpp ../diago_pxxxgvx.cpp ../diago_scalapack.cpp @@ -179,7 +151,7 @@ if(ENABLE_MPI) AddTest( TARGET MODULE_HSOLVER_linear_trans LIBS parameter base device MPI::MPI_CXX - SOURCES test_para_linear_trans.cpp ../para_lin_tf.cpp + SOURCES test_para_lin_tf.cpp ../para_lin_tf.cpp ) add_test( diff --git a/source/source_hsolver/test/GammaOnly-Si2-Solution.dat b/source/source_hsolver/unittests/GammaOnly-Si2-Solution.dat similarity index 100% rename from source/source_hsolver/test/GammaOnly-Si2-Solution.dat rename to source/source_hsolver/unittests/GammaOnly-Si2-Solution.dat diff --git a/source/source_hsolver/test/GammaOnly-Si64-Solution.dat b/source/source_hsolver/unittests/GammaOnly-Si64-Solution.dat similarity index 100% rename from source/source_hsolver/test/GammaOnly-Si64-Solution.dat rename to source/source_hsolver/unittests/GammaOnly-Si64-Solution.dat diff --git a/source/source_hsolver/test/H-GammaOnly-Si2.dat b/source/source_hsolver/unittests/H-GammaOnly-Si2.dat similarity index 100% rename from source/source_hsolver/test/H-GammaOnly-Si2.dat rename to source/source_hsolver/unittests/H-GammaOnly-Si2.dat diff --git a/source/source_hsolver/test/H-GammaOnly-Si64.dat b/source/source_hsolver/unittests/H-GammaOnly-Si64.dat similarity index 100% rename from source/source_hsolver/test/H-GammaOnly-Si64.dat rename to source/source_hsolver/unittests/H-GammaOnly-Si64.dat diff --git a/source/source_hsolver/test/H-KPoints-Si2.dat b/source/source_hsolver/unittests/H-KPoints-Si2.dat similarity index 100% rename from source/source_hsolver/test/H-KPoints-Si2.dat rename to source/source_hsolver/unittests/H-KPoints-Si2.dat diff --git a/source/source_hsolver/test/H-KPoints-Si64.dat b/source/source_hsolver/unittests/H-KPoints-Si64.dat similarity index 100% rename from source/source_hsolver/test/H-KPoints-Si64.dat rename to source/source_hsolver/unittests/H-KPoints-Si64.dat diff --git a/source/source_hsolver/test/KPoints-Si2-Solution.dat b/source/source_hsolver/unittests/KPoints-Si2-Solution.dat similarity index 100% rename from source/source_hsolver/test/KPoints-Si2-Solution.dat rename to source/source_hsolver/unittests/KPoints-Si2-Solution.dat diff --git a/source/source_hsolver/test/KPoints-Si64-Solution.dat b/source/source_hsolver/unittests/KPoints-Si64-Solution.dat similarity index 100% rename from source/source_hsolver/test/KPoints-Si64-Solution.dat rename to source/source_hsolver/unittests/KPoints-Si64-Solution.dat diff --git a/source/source_hsolver/test/PEXSI-DM-GammaOnly-Si2.dat b/source/source_hsolver/unittests/PEXSI-DM-GammaOnly-Si2.dat similarity index 100% rename from source/source_hsolver/test/PEXSI-DM-GammaOnly-Si2.dat rename to source/source_hsolver/unittests/PEXSI-DM-GammaOnly-Si2.dat diff --git a/source/source_hsolver/test/PEXSI-H-GammaOnly-Si2.dat b/source/source_hsolver/unittests/PEXSI-H-GammaOnly-Si2.dat similarity index 100% rename from source/source_hsolver/test/PEXSI-H-GammaOnly-Si2.dat rename to source/source_hsolver/unittests/PEXSI-H-GammaOnly-Si2.dat diff --git a/source/source_hsolver/test/PEXSI-S-GammaOnly-Si2.dat b/source/source_hsolver/unittests/PEXSI-S-GammaOnly-Si2.dat similarity index 100% rename from source/source_hsolver/test/PEXSI-S-GammaOnly-Si2.dat rename to source/source_hsolver/unittests/PEXSI-S-GammaOnly-Si2.dat diff --git a/source/source_hsolver/test/S-GammaOnly-Si2.dat b/source/source_hsolver/unittests/S-GammaOnly-Si2.dat similarity index 100% rename from source/source_hsolver/test/S-GammaOnly-Si2.dat rename to source/source_hsolver/unittests/S-GammaOnly-Si2.dat diff --git a/source/source_hsolver/test/S-GammaOnly-Si64.dat b/source/source_hsolver/unittests/S-GammaOnly-Si64.dat similarity index 100% rename from source/source_hsolver/test/S-GammaOnly-Si64.dat rename to source/source_hsolver/unittests/S-GammaOnly-Si64.dat diff --git a/source/source_hsolver/test/S-KPoints-Si2.dat b/source/source_hsolver/unittests/S-KPoints-Si2.dat similarity index 100% rename from source/source_hsolver/test/S-KPoints-Si2.dat rename to source/source_hsolver/unittests/S-KPoints-Si2.dat diff --git a/source/source_hsolver/test/S-KPoints-Si64.dat b/source/source_hsolver/unittests/S-KPoints-Si64.dat similarity index 100% rename from source/source_hsolver/test/S-KPoints-Si64.dat rename to source/source_hsolver/unittests/S-KPoints-Si64.dat diff --git a/source/source_hsolver/test/diago_cg_parallel_test.sh b/source/source_hsolver/unittests/diago_cg_parallel_test.sh similarity index 100% rename from source/source_hsolver/test/diago_cg_parallel_test.sh rename to source/source_hsolver/unittests/diago_cg_parallel_test.sh diff --git a/source/source_hsolver/test/diago_david_parallel_test.sh b/source/source_hsolver/unittests/diago_david_parallel_test.sh similarity index 100% rename from source/source_hsolver/test/diago_david_parallel_test.sh rename to source/source_hsolver/unittests/diago_david_parallel_test.sh diff --git a/source/source_hsolver/test/diago_elpa_utils.h b/source/source_hsolver/unittests/diago_elpa_utils.h similarity index 91% rename from source/source_hsolver/test/diago_elpa_utils.h rename to source/source_hsolver/unittests/diago_elpa_utils.h index 843c53b6a51..60325e38df3 100644 --- a/source/source_hsolver/test/diago_elpa_utils.h +++ b/source/source_hsolver/unittests/diago_elpa_utils.h @@ -1,5 +1,5 @@ #include "source_base/module_external/blacs_connector.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "mpi.h" #include @@ -38,10 +38,10 @@ void process_2d(int &nprows, int &npcols, int &myprow, int &mypcol, int &icontxt } int what = 0, ic = 0; - Cblacs_get(ic, what, &icontxt); - Cblacs_pinfo(&mypnum, &nprocs); - Cblacs_gridmap(&icontxt, usermap, nprows, nprows, npcols); - Cblacs_gridinfo(icontxt, &nprows, &npcols, &myprow, &mypcol); + BlacsConnector::get(ic, what, icontxt); + BlacsConnector::pinfo(mypnum, nprocs); + BlacsConnector::gridmap(icontxt, usermap, nprows, nprows, npcols); + BlacsConnector::gridinfo(icontxt, nprows, npcols, myprow, mypcol); delete[] usermap; } @@ -62,7 +62,7 @@ void distribute_data(T *hmatrix, T *new_matrix, int &nFull, int &nblk, int &na_r int mypnum; MPI_Comm_rank(MPI_COMM_WORLD, &mypnum); int nprows, npcols, myprow, mypcol; - Cblacs_gridinfo(icontxt, &nprows, &npcols, &myprow, &mypcol); + BlacsConnector::gridinfo(icontxt, nprows, npcols, myprow, mypcol); int SENDPROW = 0, SENDPCOL = 0, tag = 0; T *tmp = new T[nblk]; @@ -177,7 +177,7 @@ void lapack_diago(double *hmatrix, double *smatrix, double *e, int &nFull) b[i] = smatrix[i]; } - dsygv_(&itype, &jobz, &uplo, &nFull, a, &nFull, b, &nFull, e, ev, &lwork, &info); + container::lapackConnector::hegv(itype, jobz, uplo, nFull, a, nFull, b, nFull, e, ev, lwork, info); if (info != 0) { std::cout << "ERROR: solvered by LAPACK error, info=" << info << std::endl; @@ -206,7 +206,7 @@ void lapack_diago(std::complex *hmatrix, std::complex *smatrix, b[i] = smatrix[i]; } - zhegv_(&itype, &jobz, &uplo, &nFull, a, &nFull, b, &nFull, e, ev, &lwork, rwork, &info); + container::lapackConnector::hegv(itype, jobz, uplo, nFull, a, nFull, b, nFull, e, ev, lwork, rwork, info); if (info != 0) { std::cout << "ERROR: solvered by LAPACK error, info=" << info << std::endl; diff --git a/source/source_hsolver/test/diago_lcao_parallel_test.sh b/source/source_hsolver/unittests/diago_lcao_parallel_test.sh similarity index 100% rename from source/source_hsolver/test/diago_lcao_parallel_test.sh rename to source/source_hsolver/unittests/diago_lcao_parallel_test.sh diff --git a/source/source_hsolver/test/diago_mock.h b/source/source_hsolver/unittests/diago_mock.h similarity index 100% rename from source/source_hsolver/test/diago_mock.h rename to source/source_hsolver/unittests/diago_mock.h diff --git a/source/source_hsolver/test/diago_pexsi_parallel_test.sh b/source/source_hsolver/unittests/diago_pexsi_parallel_test.sh similarity index 100% rename from source/source_hsolver/test/diago_pexsi_parallel_test.sh rename to source/source_hsolver/unittests/diago_pexsi_parallel_test.sh diff --git a/source/source_hsolver/test/hsolver_pw_sup.h b/source/source_hsolver/unittests/hsolver_pw_sup.h similarity index 100% rename from source/source_hsolver/test/hsolver_pw_sup.h rename to source/source_hsolver/unittests/hsolver_pw_sup.h diff --git a/source/source_hsolver/test/hsolver_supplementary_mock.h b/source/source_hsolver/unittests/hsolver_supplementary_mock.h similarity index 100% rename from source/source_hsolver/test/hsolver_supplementary_mock.h rename to source/source_hsolver/unittests/hsolver_supplementary_mock.h diff --git a/source/source_hsolver/test/parallel_k2d_test.sh b/source/source_hsolver/unittests/parallel_k2d_test.sh similarity index 100% rename from source/source_hsolver/test/parallel_k2d_test.sh rename to source/source_hsolver/unittests/parallel_k2d_test.sh diff --git a/source/source_hsolver/test/test_diago_hs_para.cpp b/source/source_hsolver/unittests/test_diag_hs_para.cpp similarity index 100% rename from source/source_hsolver/test/test_diago_hs_para.cpp rename to source/source_hsolver/unittests/test_diag_hs_para.cpp diff --git a/source/source_hsolver/test/diago_bpcg_test.cpp b/source/source_hsolver/unittests/test_diago_bpcg.cpp similarity index 98% rename from source/source_hsolver/test/diago_bpcg_test.cpp rename to source/source_hsolver/unittests/test_diago_bpcg.cpp index 34bed8b4735..147f75f4b30 100644 --- a/source/source_hsolver/test/diago_bpcg_test.cpp +++ b/source/source_hsolver/unittests/test_diago_bpcg.cpp @@ -1,5 +1,5 @@ #include "source_base/inverse_matrix.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "source_base/parallel_comm.h" #include "source_psi/psi.h" #include "../diago_iter_assist.h" @@ -43,7 +43,7 @@ void lapackEigen(int &npw, std::vector> &hm, double *e, boo double *rwork = new double[3 * npw - 2]; int info = 0; char tmp_c1 = 'V', tmp_c2 = 'U'; - zheev_(&tmp_c1, &tmp_c2, &npw, hm.data(), &npw, e, work2, &lwork, rwork, &info); + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, hm.data(), npw, e, work2, lwork, rwork, info); end = clock(); if (outtime) { std::cout << "Lapack Run time: " << (double)(end - start) / CLOCKS_PER_SEC << " S" << std::endl; diff --git a/source/source_hsolver/test/diago_cg_test.cpp b/source/source_hsolver/unittests/test_diago_cg.cpp similarity index 98% rename from source/source_hsolver/test/diago_cg_test.cpp rename to source/source_hsolver/unittests/test_diago_cg.cpp index 853b51c9f71..34e136f9b19 100644 --- a/source/source_hsolver/test/diago_cg_test.cpp +++ b/source/source_hsolver/unittests/test_diago_cg.cpp @@ -6,7 +6,7 @@ #include "mpi.h" #include "source_base/parallel_comm.h" #include "source_base/inverse_matrix.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "source_basis/module_pw/test/test_tool.h" #include "source_psi/psi.h" @@ -45,7 +45,7 @@ void lapackEigen(int &npw, std::vector> &hm, double *e, boo double *rwork = new double[3 * npw - 2]; int info = 0; char tmp_c1 = 'V', tmp_c2 = 'U'; - zheev_(&tmp_c1, &tmp_c2, &npw, hm.data(), &npw, e, work2, &lwork, rwork, &info); + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, hm.data(), npw, e, work2, lwork, rwork, info); end = clock(); if (outtime) { std::cout << "Lapack Run time: " << (double)(end - start) / CLOCKS_PER_SEC << " S" << std::endl; diff --git a/source/source_hsolver/test/diago_cg_float_test.cpp b/source/source_hsolver/unittests/test_diago_cg_float.cpp similarity index 98% rename from source/source_hsolver/test/diago_cg_float_test.cpp rename to source/source_hsolver/unittests/test_diago_cg_float.cpp index 0651daca593..b6c5eee488e 100644 --- a/source/source_hsolver/test/diago_cg_float_test.cpp +++ b/source/source_hsolver/unittests/test_diago_cg_float.cpp @@ -5,7 +5,7 @@ #include "mpi.h" #include "source_base/parallel_comm.h" #include "source_base/inverse_matrix.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "source_basis/module_pw/test/test_tool.h" #include "source_psi/psi.h" @@ -44,7 +44,7 @@ void lapackEigen(int &npw, std::vector> &hm, float *e, bool float *rwork = new float[3 * npw - 2]; int info = 0; char tmp_c1 = 'V', tmp_c2 = 'U'; - cheev_(&tmp_c1, &tmp_c2, &npw, hm.data(), &npw, e, work2, &lwork, rwork, &info); + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, hm.data(), npw, e, work2, lwork, rwork, info); end = clock(); if (outtime) { std::cout << "Lapack Run time: " << (float)(end - start) / CLOCKS_PER_SEC << " S" << std::endl; diff --git a/source/source_hsolver/test/diago_cg_real_test.cpp b/source/source_hsolver/unittests/test_diago_cg_real.cpp similarity index 97% rename from source/source_hsolver/test/diago_cg_real_test.cpp rename to source/source_hsolver/unittests/test_diago_cg_real.cpp index f1afbd99a45..65d7958fe32 100644 --- a/source/source_hsolver/test/diago_cg_real_test.cpp +++ b/source/source_hsolver/unittests/test_diago_cg_real.cpp @@ -5,7 +5,7 @@ #include "mpi.h" #include "source_base/parallel_comm.h" #include "source_base/inverse_matrix.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "source_basis/module_pw/test/test_tool.h" #include "source_psi/psi.h" @@ -45,11 +45,11 @@ void lapackEigen(int& npw, std::vector& hm, double* e, bool outtime = fa double work_tmp; constexpr int minus_one = -1; - dsyev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, &work_tmp, &minus_one, &info); // get best lwork + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, tmp.data(), npw, e, &work_tmp, minus_one, info); // get best lwork const int lwork = work_tmp; double* work2 = new double[lwork]; - dsyev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, &info); + ct::lapackConnector::heev(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; } diff --git a/source/source_hsolver/test/diago_lcao_cusolver_test.cpp b/source/source_hsolver/unittests/test_diago_cusolver.cpp similarity index 98% rename from source/source_hsolver/test/diago_lcao_cusolver_test.cpp rename to source/source_hsolver/unittests/test_diago_cusolver.cpp index bab49060153..562ff36b7f1 100644 --- a/source/source_hsolver/test/diago_lcao_cusolver_test.cpp +++ b/source/source_hsolver/unittests/test_diago_cusolver.cpp @@ -1,6 +1,6 @@ #include "source_base/matrix_block.h" #include "source_hsolver/diago_scalapack.h" -#include "source_hsolver/test/diago_elpa_utils.h" +#include "source_hsolver/unittests/diago_elpa_utils.h" #include "mpi.h" #include "string.h" @@ -29,7 +29,7 @@ * - hsolver::DiagoScalapack::diag (for Scalapack) * * The 2d block cyclic distribution of H/S matrix is done by - * self-realized functions in source_hsolver/test/diago_elpa_utils.h + * self-realized functions in source_hsolver/unittests/diago_elpa_utils.h */ /// Minimal H(k)/S(k) supplier. The LCAO eigensolvers take the matrix blocks @@ -178,7 +178,7 @@ class DiagoPrepare npcols, mypcol); // the number of column of the new_matrix in each process int ISRC = 0, info; - descinit_(hmtest.desc, &nlocal, &nlocal, &nb2d, &nb2d, &ISRC, &ISRC, &icontxt, &(hmtest.nrow), &info); + ScalapackConnector::descinit(hmtest.desc, nlocal, nlocal, nb2d, nb2d, ISRC, ISRC, icontxt, hmtest.nrow, info); if (info != 0) { printf("Invalid blacs-distribution. Abort!\n"); diff --git a/source/source_hsolver/test/test_diago_david.cpp b/source/source_hsolver/unittests/test_diago_david.cpp similarity index 100% rename from source/source_hsolver/test/test_diago_david.cpp rename to source/source_hsolver/unittests/test_diago_david.cpp diff --git a/source/source_hsolver/test/diago_david_test.cpp b/source/source_hsolver/unittests/test_diago_david_double.cpp similarity index 97% rename from source/source_hsolver/test/diago_david_test.cpp rename to source/source_hsolver/unittests/test_diago_david_double.cpp index 7d4b8cbfea0..9f1153d4438 100644 --- a/source/source_hsolver/test/diago_david_test.cpp +++ b/source/source_hsolver/unittests/test_diago_david_double.cpp @@ -6,7 +6,7 @@ #include "source_psi/psi.h" #include"gtest/gtest.h" #include "source_base/inverse_matrix.h" -#include "source_base/module_external/lapack_connector.h" +#include "source_base/module_container/base/third_party/lapack.h" #include "source_basis/module_pw/test/test_tool.h" #include"mpi.h" @@ -47,7 +47,7 @@ void lapackEigen(int& npw, std::vector>& hm, double* e, boo clock_t start,end; start = clock(); char tmp_c1 = 'V', tmp_c2 = 'U'; - zheev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, rwork, &info); + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, tmp.data(), npw, e, work2, lwork, rwork, info); end = clock(); if(info) { std::cout << "ERROR: Lapack solver, info=" << info <> &hm, float * e, bool clock_t start,end; start = clock(); char tmp_c1 = 'V', tmp_c2 = 'U'; - cheev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, rwork, &info); + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, tmp.data(), npw, e, work2, lwork, rwork, info); end = clock(); if(info) { std::cout << "ERROR: Lapack solver, info=" << info <& hm, double* e, bool outtime = fa double work_tmp; constexpr int minus_one = -1; - dsyev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, &work_tmp, &minus_one, &info); // get best lwork + ct::lapackConnector::heev(tmp_c1, tmp_c2, npw, tmp.data(), npw, e, &work_tmp, minus_one, info); // get best lwork const int lwork = work_tmp; double* work2 = new double[lwork]; - dsyev_(&tmp_c1, &tmp_c2, &npw, tmp.data(), &npw, e, work2, &lwork, &info); + ct::lapackConnector::heev(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; } diff --git a/source/source_hsolver/test/diago_lapack_test.cpp b/source/source_hsolver/unittests/test_diago_lapack.cpp similarity index 99% rename from source/source_hsolver/test/diago_lapack_test.cpp rename to source/source_hsolver/unittests/test_diago_lapack.cpp index f5dead8b518..d12941bfeab 100644 --- a/source/source_hsolver/test/diago_lapack_test.cpp +++ b/source/source_hsolver/unittests/test_diago_lapack.cpp @@ -1,5 +1,5 @@ // Author: Zhang Xiaoyang -// A modified version of diago_lcao_test.cpp +// A modified version of test_diago_lcao.cpp // Remove some useless functions and dependencies. Serialized the full code // and refactored some function. @@ -293,4 +293,4 @@ int main(int argc, char** argv) { return 0; } -} \ No newline at end of file +} diff --git a/source/source_hsolver/test/diago_lcao_test.cpp b/source/source_hsolver/unittests/test_diago_lcao.cpp similarity index 98% rename from source/source_hsolver/test/diago_lcao_test.cpp rename to source/source_hsolver/unittests/test_diago_lcao.cpp index 18b4a30fb0c..0d07ac4c092 100644 --- a/source/source_hsolver/test/diago_lcao_test.cpp +++ b/source/source_hsolver/unittests/test_diago_lcao.cpp @@ -1,7 +1,7 @@ #include "source_base/matrix_block.h" #include "source_hsolver/diago_scalapack.h" #include "source_hsolver/diago_lapack.h" -#include "source_hsolver/test/diago_elpa_utils.h" +#include "source_hsolver/unittests/diago_elpa_utils.h" #include "mpi.h" #include "string.h" @@ -29,7 +29,7 @@ * - hsolver::DiagoScalapack::diag (for Scalapack) * * The 2d block cyclic distribution of H/S matrix is done by - * self-realized functions in source_hsolver/test/diago_elpa_utils.h + * self-realized functions in source_hsolver/unittests/diago_elpa_utils.h */ /// Minimal H(k)/S(k) supplier. The LCAO eigensolvers take the matrix blocks @@ -146,7 +146,7 @@ class DiagoPrepare int npcols; int myprow; int mypcol; - Cblacs_gridinfo(icontxt, &nprows, &npcols, &myprow, &mypcol); + BlacsConnector::gridinfo(icontxt, nprows, npcols, myprow, mypcol); for (int col = 0; col < hmtest.ncol; ++col) { const int global_col = (col / nb2d * npcols + mypcol) * nb2d + col % nb2d; @@ -207,7 +207,7 @@ class DiagoPrepare npcols, mypcol); // the number of column of the new_matrix in each process int ISRC = 0, info; - descinit_(hmtest.desc, &nlocal, &nlocal, &nb2d, &nb2d, &ISRC, &ISRC, &icontxt, &(hmtest.nrow), &info); + ScalapackConnector::descinit(hmtest.desc, nlocal, nlocal, nb2d, nb2d, ISRC, ISRC, icontxt, hmtest.nrow, info); if (info != 0) { printf("Invalid blacs-distribution. Abort!\n"); diff --git a/source/source_hsolver/test/diago_pexsi_test.cpp b/source/source_hsolver/unittests/test_diago_pexsi.cpp similarity index 98% rename from source/source_hsolver/test/diago_pexsi_test.cpp rename to source/source_hsolver/unittests/test_diago_pexsi.cpp index 14b23d05b0d..98b9cde8ca0 100644 --- a/source/source_hsolver/test/diago_pexsi_test.cpp +++ b/source/source_hsolver/unittests/test_diago_pexsi.cpp @@ -6,7 +6,7 @@ #include "source_base/parallel_global.h" #include "source_basis/module_ao/parallel_orbitals.h" #include "source_hsolver/module_pexsi/pexsi_solver.h" -#include "source_hsolver/test/diago_elpa_utils.h" +#include "source_hsolver/unittests/diago_elpa_utils.h" #include #include @@ -133,7 +133,7 @@ class PexsiPrepare mypcol); // the number of column of the new_matrix in each process int ISRC = 0, info; - descinit_(hmtest.desc, &nlocal, &nlocal, &nb2d, &nb2d, &ISRC, &ISRC, &icontxt, &(hmtest.nrow), &info); + ScalapackConnector::descinit(hmtest.desc, nlocal, nlocal, nb2d, nb2d, ISRC, ISRC, icontxt, hmtest.nrow, info); if (info != 0) { printf("Invalid blacs-distribution. Abort!\n"); diff --git a/source/source_hsolver/test/test_hsolver.cpp b/source/source_hsolver/unittests/test_hsolver.cpp similarity index 100% rename from source/source_hsolver/test/test_hsolver.cpp rename to source/source_hsolver/unittests/test_hsolver.cpp diff --git a/source/source_hsolver/test/test_hsolver_pw.cpp b/source/source_hsolver/unittests/test_hsolver_pw.cpp similarity index 100% rename from source/source_hsolver/test/test_hsolver_pw.cpp rename to source/source_hsolver/unittests/test_hsolver_pw.cpp diff --git a/source/source_hsolver/test/test_para_linear_trans.cpp b/source/source_hsolver/unittests/test_para_lin_tf.cpp similarity index 100% rename from source/source_hsolver/test/test_para_linear_trans.cpp rename to source/source_hsolver/unittests/test_para_lin_tf.cpp diff --git a/source/source_hsolver/test/parallel_k2d_test.cpp b/source/source_hsolver/unittests/test_parallel_k2d.cpp similarity index 100% rename from source/source_hsolver/test/parallel_k2d_test.cpp rename to source/source_hsolver/unittests/test_parallel_k2d.cpp diff --git a/source/source_io/CMakeLists.txt b/source/source_io/CMakeLists.txt index 6444267178b..622d2d6b07b 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND objects module_ctrl/ctrl_output_fp.cpp module_ctrl/ctrl_output_pw.cpp module_ctrl/ctrl_output_td.cpp + module_ctrl/ctrl_output_td_pw.cpp module_bessel/bessel_basis.cpp module_output/cal_test.cpp module_dos/cal_dos.cpp @@ -15,6 +16,7 @@ list(APPEND objects module_energy/write_bands.cpp module_energy/write_eig_occ.cpp module_energy/td_eij_io.cpp + module_energy/td_eij_pw.cpp module_bessel/numerical_basis.cpp module_bessel/numerical_basis_overlap.cpp module_bessel/numerical_basis_output.cpp @@ -34,10 +36,12 @@ list(APPEND objects module_current/td_current_io.cpp module_current/td_current_io_comm.cpp module_current/td_current_pw.cpp + module_current/td_spin_pw_io.cpp module_efield/td_efield_io.cpp - module_efield/td_vector_pot_io.cpp + module_efield/td_vecpot_io.cpp module_chgpot/write_libxc_r.cpp module_output/output_log.cpp + module_output/td_conserv_io.cpp module_json/para_json.cpp parse_args.cpp input_help.cpp @@ -172,7 +176,7 @@ if(BUILD_TESTING) add_subdirectory(module_parameter/test) add_subdirectory(module_hs/unittests) add_subdirectory(test_serial) - add_subdirectory(test) + add_subdirectory(unittests) add_subdirectory(module_dos/unittests) endif() diff --git a/source/source_io/module_ctrl/ctrl_output_fp.cpp b/source/source_io/module_ctrl/ctrl_output_fp.cpp index 73e0d679e5b..a57166a82bf 100644 --- a/source/source_io/module_ctrl/ctrl_output_fp.cpp +++ b/source/source_io/module_ctrl/ctrl_output_fp.cpp @@ -225,7 +225,9 @@ void ctrl_output_fp(UnitCell& ucell, const bool output_dipole = inp.esolver_type == "tddft" || should_output; if (inp.out_dipole == 1 && output_dipole) { - for (int is = 0; is < nspin; ++is) + const int dipole_channels = nspin == 4 ? 1 : nspin; + // In a spinor density only channel zero is charge; the other three channels are magnetization. + for (int is = 0; is < dipole_channels; ++is) { std::stringstream ss_dipole; ss_dipole << global_out_dir << "dipole_s" << is + 1 << ".txt"; diff --git a/source/source_io/module_ctrl/ctrl_output_pw.cpp b/source/source_io/module_ctrl/ctrl_output_pw.cpp index 8294d7cbae6..0a3b13120dd 100644 --- a/source/source_io/module_ctrl/ctrl_output_pw.cpp +++ b/source/source_io/module_ctrl/ctrl_output_pw.cpp @@ -27,6 +27,7 @@ void ModuleIO::ctrl_iter_pw(const int istep, const K_Vectors& kv, const ModulePW::PW_Basis_K* pw_wfc, const Input_para& inp, + bool final_output, std::ofstream& ofs_running) { ModuleBase::TITLE("ModuleIO", "ctrl_iter_pw"); @@ -46,7 +47,7 @@ void ModuleIO::ctrl_iter_pw(const int istep, { if (istep % output_frequency == 0) { - if (iter % inp.out_freq_elec == 0 || iter == inp.scf_nmax || conv_esolver) + if (iter % inp.out_freq_elec == 0 || iter == inp.scf_nmax || conv_esolver || final_output) { istep_in = istep; iter_in = iter; @@ -54,7 +55,7 @@ void ModuleIO::ctrl_iter_pw(const int istep, } } } - else if (iter == inp.scf_nmax || conv_esolver) + else if (iter == inp.scf_nmax || conv_esolver || final_output) { out_wfc_flag = true; } @@ -246,10 +247,13 @@ void ModuleIO::ctrl_scf_pw(const int istep, //------------------------------------------------------------------ // 9) write onsite occupations for charge and magnetizations //------------------------------------------------------------------ - if (inp.onsite_radius > 0) - { // float type has not been implemented + const bool spinor_rt = inp.esolver_type == "tddft" && inp.nspin == 4; + // RT writes endpoint magnetic series instead of this static occupation report. + if (inp.onsite_radius > 0 && !spinor_rt) + { + stp.update_psi_d(); auto* onsite_p = projectors::OnsiteProjector::get_instance(); - onsite_p->cal_occupations(reinterpret_cast, Device>*>(stp.template get_psi_t()), + onsite_p->cal_occupations(stp.template get_psi_d(), pelec->wg, inp.nspin); } diff --git a/source/source_io/module_ctrl/ctrl_output_pw.h b/source/source_io/module_ctrl/ctrl_output_pw.h index 9491afbf787..a3c05b0d4b3 100644 --- a/source/source_io/module_ctrl/ctrl_output_pw.h +++ b/source/source_io/module_ctrl/ctrl_output_pw.h @@ -21,6 +21,7 @@ void ctrl_iter_pw(const int istep, const K_Vectors& kv, const ModulePW::PW_Basis_K* pw_wfc, const Input_para& inp, + bool final_output, std::ofstream& ofs_running); // print out information in 'after_scf' in ESolver_KS_PW diff --git a/source/source_io/module_ctrl/ctrl_output_td_pw.cpp b/source/source_io/module_ctrl/ctrl_output_td_pw.cpp new file mode 100644 index 00000000000..d84a88ca85e --- /dev/null +++ b/source/source_io/module_ctrl/ctrl_output_td_pw.cpp @@ -0,0 +1,52 @@ +#include "source_io/module_ctrl/ctrl_output_td_pw.h" + +#include "source_base/constants.h" +#include "source_io/module_current/td_current_pw.h" +#include "source_io/module_current/td_spin_pw_io.h" + +namespace ModuleIO +{ +void ctrl_output_td_pw(const pw::TDVelResultPW& currents, + const pw::TDSpinResultPW& moments, + const pw::CurrentRequest& request, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque, + const std::vector& orbital_fn, + int step, + double dt_ha, + int nspin, + int nkstot, + int rank, + const std::string& directory, + std::ostream& log) +{ + if (rank != 0) + { + return; + } + if (request.charge_total) + { + const int spin_mult = nspin == 2 ? 2 : 1; + const int nk = nkstot / spin_mult; + write_current_pw(currents, step, nk, request.charge_per_k, directory); + } + if (nspin == 4) + { + const double time = step * dt_ha * ModuleBase::AU_to_FS; + write_td_spin_pw(directory, + step, + time, + orbital_fn, + mag_partition, + orbital_dir, + onsite_radius, + calc_torque, + request.spin_current, + moments, + currents, + log); + } +} +} // namespace ModuleIO diff --git a/source/source_io/module_ctrl/ctrl_output_td_pw.h b/source/source_io/module_ctrl/ctrl_output_td_pw.h new file mode 100644 index 00000000000..f996c71dbc0 --- /dev/null +++ b/source/source_io/module_ctrl/ctrl_output_td_pw.h @@ -0,0 +1,28 @@ +#ifndef CTRL_OUTPUT_TD_PW_H +#define CTRL_OUTPUT_TD_PW_H + +#include "source_pw/module_rt/td_obs_pw.h" + +#include +#include + +namespace ModuleIO +{ +/** @brief Write precomputed endpoint observables on the designated output rank. */ +void ctrl_output_td_pw(const pw::TDVelResultPW& currents, + const pw::TDSpinResultPW& moments, + const pw::CurrentRequest& request, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque, + const std::vector& orbital_fn, + int step, + double dt_ha, + int nspin, + int nkstot, + int rank, + const std::string& directory, + std::ostream& log); +} // namespace ModuleIO +#endif diff --git a/source/source_io/module_current/td_current_io.cpp b/source/source_io/module_current/td_current_io.cpp index 22100886e01..609de66ece6 100644 --- a/source/source_io/module_current/td_current_io.cpp +++ b/source/source_io/module_current/td_current_io.cpp @@ -28,6 +28,8 @@ void ModuleIO::write_current(const UnitCell& ucell, ModuleBase::TITLE("ModuleIO", "write_current"); ModuleBase::timer::start("ModuleIO", "write_current"); + // Restart replay is skipped by the caller, so only a fresh run writes step zero. + const std::ios::openmode mode = istep == 0 ? std::ios::out | std::ios::trunc : std::ios::app; if (td_p == nullptr) { ModuleBase::WARNING_QUIT("ModuleIO::write_current", "RT-TDDFT current requires an explicit TD context."); @@ -163,11 +165,13 @@ void ModuleIO::write_current(const UnitCell& ucell, { std::string filename = PARAM.globalv.global_out_dir + "current_tot.txt"; std::ofstream fout; - fout.open(filename, std::ios::app); - fout << std::setprecision(16); - fout << std::scientific; - fout << istep + 1 << " " << current_total[0] / omega << " " << current_total[1] / omega << " " << current_total[2] / omega - << std::endl; + fout.open(filename, mode); + fout << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout << " " << std::setw(19) << current_total[direction] / omega; + } + fout << std::endl; fout.close(); } @@ -190,6 +194,8 @@ void ModuleIO::write_current_eachk(const UnitCell& ucell, ModuleBase::TITLE("ModuleIO", "write_current"); ModuleBase::timer::start("ModuleIO", "write_current"); + // Restart replay is skipped by the caller, so only a fresh run writes step zero. + const std::ios::openmode mode = istep == 0 ? std::ios::out | std::ios::trunc : std::ios::app; if (td_p == nullptr) { ModuleBase::WARNING_QUIT("ModuleIO::write_current", "RT-TDDFT current requires an explicit TD context."); @@ -341,11 +347,13 @@ void ModuleIO::write_current_eachk(const UnitCell& ucell, std::string filename = PARAM.globalv.global_out_dir + "current_s" + std::to_string(is) + "k" + std::to_string(ik + 1) + ".txt"; std::ofstream fout; - fout.open(filename, std::ios::app); - fout << std::setprecision(16); - fout << std::scientific; - fout << istep + 1 << " " << current_ik[0] / omega << " " << current_ik[1] / omega << " " << current_ik[2] / omega - << std::endl; + fout.open(filename, mode); + fout << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout << " " << std::setw(19) << current_ik[direction] / omega; + } + fout << std::endl; fout.close(); } // write end @@ -355,11 +363,13 @@ void ModuleIO::write_current_eachk(const UnitCell& ucell, { std::string filename = PARAM.globalv.global_out_dir + "current_tot.txt"; std::ofstream fout; - fout.open(filename, std::ios::app); - fout << std::setprecision(16); - fout << std::scientific; - fout << istep + 1 << " " << current_total[0] / omega << " " << current_total[1] / omega << " " << current_total[2] / omega - << std::endl; + fout.open(filename, mode); + fout << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout << " " << std::setw(19) << current_total[direction] / omega; + } + fout << std::endl; fout.close(); } diff --git a/source/source_io/module_current/td_current_io_comm.cpp b/source/source_io/module_current/td_current_io_comm.cpp index 9b052451181..b4a66606361 100644 --- a/source/source_io/module_current/td_current_io_comm.cpp +++ b/source/source_io/module_current/td_current_io_comm.cpp @@ -695,6 +695,8 @@ void ModuleIO::write_current(const UnitCell& ucell, { ModuleBase::TITLE("ModuleIO", "write_current"); ModuleBase::timer::start("ModuleIO", "write_current"); + // Restart replay is skipped by the caller, so only a fresh run writes step zero. + const std::ios::openmode mode = istep == 0 ? std::ios::out | std::ios::trunc : std::ios::app; double omega = ucell.omega; std::vector> current_k; @@ -723,11 +725,13 @@ void ModuleIO::write_current(const UnitCell& ucell, std::string filename = PARAM.globalv.global_out_dir + "current_s" + std::to_string(is + 1) + "k" + std::to_string(kpoint_index) + "_comm.txt"; std::ofstream fout; - fout.open(filename, std::ios::app); - fout << std::setprecision(16); - fout << std::scientific; - fout << istep + 1 << " " << current_k[ik][0] / omega << " " << current_k[ik][1] / omega << " " - << current_k[ik][2] / omega << std::endl; + fout.open(filename, mode); + fout << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout << " " << std::setw(19) << current_k[ik][direction] / omega; + } + fout << std::endl; fout.close(); } } @@ -746,11 +750,13 @@ void ModuleIO::write_current(const UnitCell& ucell, { std::string filename = PARAM.globalv.global_out_dir + "current_tot_comm.txt"; std::ofstream fout; - fout.open(filename, std::ios::app); - fout << std::setprecision(16); - fout << std::scientific; - fout << istep + 1 << " " << current_total[0] / omega << " " << current_total[1] / omega << " " << current_total[2] / omega - << std::endl; + fout.open(filename, mode); + fout << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout << " " << std::setw(19) << current_total[direction] / omega; + } + fout << std::endl; fout.close(); } diff --git a/source/source_io/module_current/td_current_pw.cpp b/source/source_io/module_current/td_current_pw.cpp index a9a033aa4f1..2648d6dcc0a 100644 --- a/source/source_io/module_current/td_current_pw.cpp +++ b/source/source_io/module_current/td_current_pw.cpp @@ -1,171 +1,41 @@ -#include "td_current_pw.h" +#include "source_io/module_current/td_current_pw.h" -#include "source_base/module_container/ATen/core/tensor.h" -#include "source_base/module_device/memory_op.h" -#include "source_base/parallel_comm.h" -#include "source_base/parallel_reduce.h" -#include "source_base/timer.h" -#include "source_hamilt/module_xc/xc_functional.h" -#include "source_hsolver/kernels/linear_op.h" +#include "source_base/tool_quit.h" -// Keep operator dependencies local to this implementation file. -#include "source_pw/module_pwdft/op_pw_vel.h" - -#include #include #include #include -#include namespace ModuleIO { -template -PWCurrentResult CurrentPW::calculate(const UnitCell& ucell, - const ModulePW::PW_Basis_K* wfcpw, - psi::Psi, Device>* psi, - const elecstate::ElecState* pelec, - const K_Vectors& kv, - pseudopot_cell_vnl* ppcell, - const int gauge, - const ModuleBase::Vector3& vector_potential) -{ - ModuleBase::timer::start("ModuleIO", "calculate"); - - using Complex = std::complex; - using syncmem_complex_d2h_op = base_device::memory::synchronize_memory_op; - using setmem_complex_op = base_device::memory::set_memory_op; - - double current_total[3] = {0.0, 0.0, 0.0}; - const int nks = wfcpw->nks; - const int max_npw = wfcpw->npwk_max; - const int nbands = psi->get_nbands(); - const int nkstot = kv.get_nkstot(); - const int* isk = kv.isk.data(); - - const int n_npwx = nbands; - - // ============================================================== - // Store Cartesian current components for each k point. - // ============================================================== - const std::int64_t current_elements = 3 * static_cast(nkstot); - std::vector current_k(current_elements, 0.0); - - // Refresh the potential view used by the shared velocity operator. - const FPTYPE* vtau = nullptr; - int vtau_col = 0; - int vtau_row = 0; - if (gauge == 0 && XC_Functional::get_ked_flag()) - { - if (pelec->pot == nullptr) - { - ModuleBase::WARNING_QUIT("calculate", "Missing potential for meta-GGA current."); - } - vtau = pelec->pot->template get_vofk_smooth_data(); - vtau_col = pelec->pot->get_vofk_smooth().nc; - vtau_row = pelec->pot->get_vofk_smooth().nr; - if (vtau_col != wfcpw->nrxx || (wfcpw->nrxx > 0 && (vtau == nullptr || vtau_row != kv.get_spin_mult()))) - { - ModuleBase::WARNING_QUIT("calculate", "Invalid smooth-grid potential for meta-GGA current."); - } - // Preserve the enabled correction on ranks without real-space planes, which still join FFTs. - vtau_row = kv.get_spin_mult(); - } - if (!velocity_) - { - velocity_.reset(new hamilt::Velocity(wfcpw, isk, ppcell, &ucell, true, vtau, vtau_col, vtau_row)); - } - velocity_->set_state(isk, vtau, vtau_col, vtau_row); - - using CtDevice = typename ct::PsiToContainer::type; - const ct::DeviceType device = ct::DeviceTypeToEnum::value; - const std::int64_t component_elements = static_cast(n_npwx) * max_npw; - const std::int64_t velocity_elements = 3 * component_elements; - const std::int64_t velocity_size = std::max(1, velocity_elements); - const int64_t dot_size = std::max(1, n_npwx); - if (vpsi_.NumElements() < velocity_size || vpsi_.data_type() != ct::DataTypeToEnum::value || vpsi_.device_type() != device) - { - vpsi_ = ct::Tensor(ct::DataTypeToEnum::value, device, {velocity_size}); - } - if (dots_.NumElements() < dot_size || dots_.data_type() != ct::DataTypeToEnum::value || dots_.device_type() != device) - { - dots_ = ct::Tensor(ct::DataTypeToEnum::value, device, {dot_size}); - } - Complex* d_vpsi = vpsi_.template data(); - ct::Tensor& dot_buffer = dots_; - band_current_.resize(n_npwx); - std::vector& band_current = band_current_; - - for (int ik = 0; ik < nks; ++ik) - { - psi->fix_k(ik); - Complex* current_psi_ptr = psi->get_pointer(); - const int npw = wfcpw->npwk[ik]; - - if (velocity_elements > 0) - { - setmem_complex_op()(d_vpsi, 0, velocity_elements); - } - - velocity_->init(ik, vector_potential); - velocity_->act(psi, n_npwx, current_psi_ptr, d_vpsi, false); - - for (int id = 0; id < 3; ++id) - { - const Complex* component = d_vpsi + id * component_elements; - hsolver::linear_op().dot(max_npw, npw, n_npwx, current_psi_ptr, component, dot_buffer.data()); - syncmem_complex_d2h_op()(band_current.data(), dot_buffer.data(), n_npwx); - for (int ib = 0; ib < nbands; ++ib) - { - const double contribution = -pelec->wg(ik, ib) * std::real(band_current[ib]); - current_total[id] += contribution; - const std::int64_t current_index = static_cast(kv.ik2iktot[ik]) * 3 + id; - current_k[current_index] += contribution; - } - } - } - - // ============================================================== - // Reduce all current components together across MPI ranks. - // ============================================================== - Parallel_Reduce::reduce_all(current_total, 3); - const std::int64_t max_chunk = std::numeric_limits::max(); - for (std::int64_t offset = 0; offset < current_elements;) - { - const std::int64_t remaining = current_elements - offset; - const int count = static_cast(std::min(max_chunk, remaining)); - double* chunk = current_k.data() + offset; - Parallel_Reduce::reduce_all(chunk, count); - offset += count; - } - - PWCurrentResult result; - for (int d = 0; d < 3; ++d) - { - result.total[d] = current_total[d] / ucell.omega; - } - for (double& value: current_k) - { - value /= ucell.omega; - } - result.per_k = std::move(current_k); - ModuleBase::timer::end("ModuleIO", "calculate"); - return result; -} - -void write_pw_current(const PWCurrentResult& current, +void write_current_pw(const pw::TDVelResultPW& current, const int istep, const int nk_per_spin, const bool out_current_k, const std::string& out_dir) { + // The initial endpoint starts a new series; later endpoints append. + const std::ios::openmode mode = istep == 0 ? std::ios::out | std::ios::trunc : std::ios::app; // Always write the total current when this routine is enabled. std::string filename_tot = out_dir + "current_tot.txt"; std::ofstream fout_tot; - fout_tot.open(filename_tot, std::ios::app); - fout_tot << std::setprecision(16) << std::scientific; - fout_tot << istep + 1 << " " << current.total[0] << " " << current.total[1] << " " << current.total[2] << std::endl; + fout_tot.open(filename_tot, mode); + if (!fout_tot) + { + ModuleBase::WARNING_QUIT("write_current_pw", "Cannot open " + filename_tot); + } + fout_tot << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (double value: current.total) + { + fout_tot << " " << std::setw(19) << value; + } + fout_tot << std::endl; fout_tot.close(); + if (!fout_tot) + { + ModuleBase::WARNING_QUIT("write_current_pw", "Failed to write " + filename_tot); + } // Optionally write the contribution from each k point. if (out_current_k) @@ -178,42 +48,25 @@ void write_pw_current(const PWCurrentResult& current, std::string filename_k = out_dir + "current_s" + std::to_string(is) + "k" + std::to_string(k_idx) + ".txt"; std::ofstream fout_k; - fout_k.open(filename_k, std::ios::app); - fout_k << std::setprecision(16) << std::scientific; + fout_k.open(filename_k, mode); + if (!fout_k) + { + ModuleBase::WARNING_QUIT("write_current_pw", "Cannot open " + filename_k); + } const std::int64_t offset = static_cast(ik) * 3; - fout_k << istep + 1 << " " << current.per_k[offset] << " " << current.per_k[offset + 1] << " " << current.per_k[offset + 2] - << std::endl; + fout_k << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(12); + for (int direction = 0; direction < 3; ++direction) + { + fout_k << " " << std::setw(19) << current.per_k[offset + direction]; + } + fout_k << std::endl; fout_k.close(); + if (!fout_k) + { + ModuleBase::WARNING_QUIT("write_current_pw", "Failed to write " + filename_k); + } } } } -template -void CurrentPW::write(const int istep, - const UnitCell& ucell, - const ModulePW::PW_Basis_K* wfcpw, - psi::Psi, Device>* psi, - const elecstate::ElecState* pelec, - const K_Vectors& kv, - pseudopot_cell_vnl* ppcell, - const int gauge, - const ModuleBase::Vector3& A_right_ha, - const bool out_current_k, - const std::string& out_dir, - const int world_rank) -{ - const PWCurrentResult result = calculate(ucell, wfcpw, psi, pelec, kv, ppcell, gauge, A_right_ha); - if (world_rank == 0) - { - const int nk_per_spin = kv.get_nkstot() / kv.get_spin_mult(); - write_pw_current(result, istep, nk_per_spin, out_current_k, out_dir); - } -} - -template class CurrentPW; -template class CurrentPW; -#if defined(__CUDA) || defined(__ROCM) -template class CurrentPW; -template class CurrentPW; -#endif } // namespace ModuleIO diff --git a/source/source_io/module_current/td_current_pw.h b/source/source_io/module_current/td_current_pw.h index c240cef8746..e97fe1045ff 100644 --- a/source/source_io/module_current/td_current_pw.h +++ b/source/source_io/module_current/td_current_pw.h @@ -1,65 +1,13 @@ #ifndef TD_CURRENT_PW_H #define TD_CURRENT_PW_H -#include "source_cell/klist.h" -#include "source_cell/unitcell.h" -#include "source_estate/elecstate.h" -#include "source_psi/psi.h" -#include "source_pw/module_pwdft/op_pw_vel.h" -#include "source_pw/module_pwdft/vnl_pw.h" +#include "source_pw/module_rt/td_obs_pw.h" -#include #include namespace ModuleIO { -/** @brief Reduced current densities in Hartree atomic units. */ -struct PWCurrentResult -{ - ModuleBase::Vector3 total; - std::vector per_k; -}; - -/** @brief Write already reduced current densities; performs no collective operations. */ -void write_pw_current(const PWCurrentResult& current, - const int istep, - const int nk_per_spin, - const bool out_current_k, - const std::string& out_dir); - -/** @brief Persistent one-k-point current workspace for a propagation run. */ -template -class CurrentPW -{ - private: - std::unique_ptr> velocity_; - ct::Tensor vpsi_; - ct::Tensor dots_; - std::vector> band_current_; - - public: - /** @brief Compute globally reduced current densities without file output. */ - PWCurrentResult calculate(const UnitCell& ucell, - const ModulePW::PW_Basis_K* wfcpw, - psi::Psi, Device>* psi, - const elecstate::ElecState* pelec, - const K_Vectors& kv, - pseudopot_cell_vnl* ppcell, - const int gauge, - const ModuleBase::Vector3& A_right_ha); - /** @brief Evaluate and write the current using native wavefunctions. */ - void write(const int istep, - const UnitCell& ucell, - const ModulePW::PW_Basis_K* wfcpw, - psi::Psi, Device>* psi, - const elecstate::ElecState* pelec, - const K_Vectors& kv, - pseudopot_cell_vnl* ppcell, - const int gauge, - const ModuleBase::Vector3& vector_potential, - const bool out_current_k, - const std::string& out_dir, - const int world_rank); -}; +/** @brief Write reduced charge currents on the output rank; performs no collectives. */ +void write_current_pw(const pw::TDVelResultPW& current, int istep, int nk_per_spin, bool out_current_k, const std::string& out_dir); } // namespace ModuleIO #endif diff --git a/source/source_io/module_current/td_spin_pw_io.cpp b/source/source_io/module_current/td_spin_pw_io.cpp new file mode 100644 index 00000000000..4dbfe79a04e --- /dev/null +++ b/source/source_io/module_current/td_spin_pw_io.cpp @@ -0,0 +1,183 @@ +#include "source_io/module_current/td_spin_pw_io.h" + +#include "source_base/tool_quit.h" + +#include +#include +#include +#include +#include +#include + +namespace ModuleIO +{ +namespace +{ +std::ofstream open_series(const std::string& path, int step, const std::string& header, std::ostream& log) +{ + const std::ios::openmode mode = step == 0 ? std::ios::out : std::ios::app; + std::ofstream output(path.c_str(), mode); + if (!output) + { + ModuleBase::WARNING_QUIT("write_td_spin_pw", "Cannot open " + path); + } + if (step == 0) + { + output << header << '\n'; + char cwd[PATH_MAX]; + std::string full_path = path; + if (!path.empty() && path[0] != '/' && getcwd(cwd, sizeof(cwd)) != nullptr) + { + full_path = std::string(cwd) + "/" + path; + } + log << "Write file: " << full_path << '\n'; + } + return output; +} + +void finish_series(std::ofstream* output) +{ + output->flush(); + if (!output->good()) + { + ModuleBase::WARNING_QUIT("write_td_spin_pw", "Failed to write magnetic time series."); + } +} + +void write_endpoint(std::ostream& output, int step, double time_fs) +{ + // Internal step zero is the initial state at time zero, displayed as step one. + output << std::right << std::setw(6) << step + 1 << " " << std::fixed << std::setprecision(6) << std::setw(10) << time_fs; + output << std::scientific << std::setprecision(12); +} + +void write_atoms(std::ofstream* output, int step, double time, const std::vector& values) +{ + for (size_t atom = 0; atom < values.size() / 3; ++atom) + { + write_endpoint(*output, step, time); + *output << " " << std::setw(6) << atom + 1; + for (int a = 0; a < 3; ++a) + { + *output << " " << std::setw(19) << values[3 * atom + a]; + } + *output << '\n'; + } + finish_series(output); +} +} // namespace + +void write_td_spin_pw(const std::string& directory, + int step, + double time_fs, + const std::vector& orbitals, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque, + bool spin_current, + const pw::TDSpinResultPW& spin, + const pw::TDVelResultPW& current, + std::ostream& log) +{ + if (mag_partition != "none") + { + std::string header = "# method=" + mag_partition + "; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign"; + if (mag_partition == "onsite") + { + std::ostringstream radius; + radius << std::scientific << std::setprecision(12) << onsite_radius; + header += "\n# onsite_radius(Bohr)=" + radius.str() + "; projector=q(k+G+A); atom_phase_cancels"; + for (int it = 0; it < orbitals.size(); ++it) + { + header += "\n# orbital=" + orbital_dir + orbitals[it]; + } + } + std::ostringstream total_columns; + total_columns << std::left << std::setw(6) << "#step" << " " << std::right << std::setw(10) << "time_fs"; + for (const char* label: {"Mx", "My", "Mz", "M_norm", "M_abs_integral", "N_elec"}) + { + total_columns << " " << std::setw(19) << label; + } + std::ostringstream atom_columns; + atom_columns << std::left << std::setw(6) << "#step" << " " << std::right << std::setw(10) << "time_fs" + << " " << std::setw(6) << "atom"; + for (const char* label: {"Mx", "My", "Mz"}) + { + atom_columns << " " << std::setw(19) << label; + } + const std::string total_header = header + '\n' + total_columns.str(); + const std::string atom_header = header + '\n' + atom_columns.str(); + const std::string total_path = directory + "mag_tot.txt"; + const std::string atom_path = directory + "mag_atom.txt"; + std::ofstream total = open_series(total_path, step, total_header, log); + std::ofstream atoms = open_series(atom_path, step, atom_header, log); + write_endpoint(total, step, time_fs); + double norm = 0.0; + for (double value: spin.mag) + { + total << " " << std::setw(19) << value; + norm += value * value; + } + total << " " << std::setw(19) << std::sqrt(norm) << " " << std::setw(19) << spin.mag_abs << " " << std::setw(19) + << spin.electrons << '\n'; + finish_series(&total); + write_atoms(&atoms, step, time_fs, spin.atom_mag); + } + if (calc_torque) + { + std::ostringstream total_columns; + total_columns << std::left << std::setw(6) << "#step" << " " << std::right << std::setw(10) << "time_fs"; + for (const char* label: {"tau_xc_x", "tau_xc_y", "tau_xc_z", "tau_soc_x", "tau_soc_y", "tau_soc_z"}) + { + total_columns << " " << std::setw(19) << label; + } + std::ostringstream atom_columns; + atom_columns << std::left << std::setw(6) << "#step" << " " << std::right << std::setw(10) << "time_fs" + << " " << std::setw(6) << "atom"; + for (const char* label: {"tau_soc_x", "tau_soc_y", "tau_soc_z"}) + { + atom_columns << " " << std::setw(19) << label; + } + const std::string total_header = "# torque=dS/dt; S=M/2; unit=hbar/Hartree_atomic_time\n" + total_columns.str(); + const std::string atom_header = "# SOC_pseudopotential_atom_decomposition; unit=hbar/Hartree_atomic_time\n" + "# not_the_derivative_of_atomic_moments\n" + + atom_columns.str(); + const std::string total_path = directory + "torque_tot.txt"; + const std::string atom_path = directory + "torque_atom.txt"; + std::ofstream total = open_series(total_path, step, total_header, log); + std::ofstream atoms = open_series(atom_path, step, atom_header, log); + write_endpoint(total, step, time_fs); + for (double value: spin.xc) + { + total << " " << std::setw(19) << value; + } + for (double value: spin.soc) + { + total << " " << std::setw(19) << value; + } + total << '\n'; + finish_series(&total); + write_atoms(&atoms, step, time_fs, spin.atom_soc); + } + if (spin_current) + { + std::ostringstream columns; + columns << std::left << std::setw(6) << "#step" << " " << std::right << std::setw(10) << "time_fs"; + for (const char* label: {"Jxx", "Jxy", "Jxz", "Jyx", "Jyy", "Jyz", "Jzx", "Jzy", "Jzz"}) + { + columns << " " << std::setw(19) << label; + } + const std::string header = "# S=M/2; unit=hbar/(Bohr^2*Hartree_atomic_time); flow_index_first\n" + columns.str(); + const std::string path = directory + "spincur_tot.txt"; + std::ofstream output = open_series(path, step, header, log); + write_endpoint(output, step, time_fs); + for (double value: current.spin) + { + output << " " << std::setw(19) << value; + } + output << '\n'; + finish_series(&output); + } +} +} // namespace ModuleIO diff --git a/source/source_io/module_current/td_spin_pw_io.h b/source/source_io/module_current/td_spin_pw_io.h new file mode 100644 index 00000000000..d2fa021c823 --- /dev/null +++ b/source/source_io/module_current/td_spin_pw_io.h @@ -0,0 +1,27 @@ +#ifndef TD_SPIN_PW_IO_H +#define TD_SPIN_PW_IO_H +#include "source_pw/module_rt/td_obs_pw.h" + +#include +#include +namespace ModuleIO +{ +/** + * @brief Write globally reduced endpoint data on the designated output rank only. + * @param step Zero-based internal electronic step, written as step + 1. + * @param time_fs Physical time in fs, written with six decimal places; the initial state is at zero. + */ +void write_td_spin_pw(const std::string& directory, + int step, + double time_fs, + const std::vector& orbitals, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque, + bool spin_current, + const pw::TDSpinResultPW& spin, + const pw::TDVelResultPW& current, + std::ostream& log); +} // namespace ModuleIO +#endif diff --git a/source/source_io/module_dipole/dipole_io.h b/source/source_io/module_dipole/dipole_io.h index c38f5f93b7c..8ac8f72a1a7 100644 --- a/source/source_io/module_dipole/dipole_io.h +++ b/source/source_io/module_dipole/dipole_io.h @@ -9,13 +9,14 @@ namespace ModuleIO { +/** @brief Write aligned electronic dipoles; precision counts significant digits. */ void write_dipole(const UnitCell& ucell, const double* rho, const ModulePW::PW_Basis* rhopw, const int& istep, const std::string& fn, std::ofstream& ofs_running, - const int& precision = 11); + const int& precision = 13); } // namespace ModuleIO diff --git a/source/source_io/module_dipole/write_dipole.cpp b/source/source_io/module_dipole/write_dipole.cpp index 74020c0492e..19fb6bdcea6 100644 --- a/source/source_io/module_dipole/write_dipole.cpp +++ b/source/source_io/module_dipole/write_dipole.cpp @@ -1,6 +1,8 @@ #include "source_base/parallel_reduce.h" #include "source_io/module_dipole/dipole_io.h" +#include + namespace ModuleIO { @@ -40,7 +42,7 @@ void print_dipole_moment(std::ofstream& ofs_running, const std::string& name, do // - istep: current time step // - fn: output file name // - ofs_running: output stream for logging -// - precision: floating-point precision for output +// - precision: number of significant digits for output void write_dipole(const UnitCell& ucell, const double* rho, const ModulePW::PW_Basis* rhopw, @@ -67,10 +69,10 @@ void write_dipole(const UnitCell& ucell, ofs_running << " Write dipole data to file: " << fn << std::endl; - // Validate grid dimensions to prevent division by zero - if (rhopw->nx == 0 || rhopw->ny == 0 || rhopw->nz == 0 || rhopw->nxyz == 0 || rhopw->nplane == 0) + // Empty local FFT partitions contribute zero but must still join the subsequent reduction. + if (rhopw->nx == 0 || rhopw->ny == 0 || rhopw->nz == 0 || rhopw->nxyz == 0 || (rhopw->nplane == 0 && rhopw->nrxx != 0)) { - ModuleBase::WARNING_QUIT("ModuleIO::write_dipole", "Invalid grid parameters: nx, ny, nz, nxyz, or nplane is zero"); + ModuleBase::WARNING_QUIT("ModuleIO::write_dipole", "Invalid global grid dimensions or inconsistent local plane count"); } // Accumulate the electronic first moment in fractional coordinates. @@ -118,8 +120,12 @@ void write_dipole(const UnitCell& ucell, print_dipole_moment(ofs_running, "Electronic dipole moment", dipole_elec[0], dipole_elec[1], dipole_elec[2]); // Write to file: step index and three dipole components - ofs << std::setprecision(precision) << istep + 1 << " " << dipole_elec[0] << " " << dipole_elec[1] << " " << dipole_elec[2] - << std::endl; + ofs << std::right << std::setw(6) << istep + 1 << std::scientific << std::setprecision(precision - 1); + for (int direction = 0; direction < 3; ++direction) + { + ofs << " " << std::setw(19) << dipole_elec[direction]; + } + ofs << std::endl; // Calculate ionic dipole moment // Accumulate Z_v * taud, then transform to Cartesian coordinates. diff --git a/source/source_io/module_dm/test/write_dmk_test.cpp b/source/source_io/module_dm/test/write_dmk_test.cpp index 4d6a2a8f1bc..8a2998c58c0 100644 --- a/source/source_io/module_dm/test/write_dmk_test.cpp +++ b/source/source_io/module_dm/test/write_dmk_test.cpp @@ -8,7 +8,7 @@ #include "source_io/module_dm/write_dmk.h" #include "source_base/global_variable.h" -#include "../../test/prepare_unitcell.h" +#include "../../unittests/prepare_unitcell.h" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/source/source_io/module_efield/td_efield_io.cpp b/source/source_io/module_efield/td_efield_io.cpp index 7e081639664..289ec6dd9e0 100644 --- a/source/source_io/module_efield/td_efield_io.cpp +++ b/source/source_io/module_efield/td_efield_io.cpp @@ -1,4 +1,4 @@ -#include "td_efield_io.h" +#include "source_io/module_efield/td_efield_io.h" #include "source_base/constants.h" #include "source_base/tool_quit.h" @@ -11,7 +11,7 @@ namespace { -std::string td_field_output_path(const std::string& output_dir, const std::size_t field_index) +std::string field_out_path(const std::string& output_dir, const std::size_t field_index) { std::stringstream path; path << output_dir << "efield_" << field_index + 1 << ".txt"; @@ -23,7 +23,7 @@ std::string td_field_output_path(const std::string& output_dir, const std::size_ namespace ModuleIO { -void prepare_td_field_output(const std::string& output_dir, const std::size_t field_count, const bool restart) +void prep_td_field_out(const std::string& output_dir, const std::size_t field_count, const bool restart) { // A restart continues an existing time series. A fresh calculation opens // every configured file with `out`, which truncates any previous series. @@ -34,29 +34,34 @@ void prepare_td_field_output(const std::string& output_dir, const std::size_t fi for (std::size_t field_index = 0; field_index < field_count; ++field_index) { - const std::string output_path = td_field_output_path(output_dir, field_index); + const std::string output_path = field_out_path(output_dir, field_index); std::ofstream output(output_path.c_str(), std::ofstream::out); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::prepare_td_field_output", "Cannot prepare electric-field file " + output_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::prep_td_field_out", "Cannot prepare electric-field file " + output_path + "!"); } } } -void prepare_td_field_output(const std::string& output_dir, const elecstate::TDFieldManager& manager, const bool restart) +void prep_td_field_out(const std::string& output_dir, const elecstate::TDFieldManager& manager, const bool restart) { if (!manager.file_source()) { - prepare_td_field_output(output_dir, manager.fields().size(), restart); + prep_td_field_out(output_dir, manager.fields().size(), restart); } if (!restart) { std::ofstream output((output_dir + "efield_total.txt").c_str()); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::prepare_td_field_output", "Cannot prepare efield_total.txt."); + ModuleBase::WARNING_QUIT("ModuleIO::prep_td_field_out", "Cannot prepare efield_total.txt."); } - output << "# time(fs) Ex(V/Angstrom) Ey(V/Angstrom) Ez(V/Angstrom); "; + output << std::left << std::setw(10) << "# time(fs)" << std::right; + for (const char* label: {"Ex(V/Angstrom)", "Ey(V/Angstrom)", "Ez(V/Angstrom)"}) + { + output << " " << std::setw(19) << label; + } + output << " # "; if (manager.file_source()) { output << "endpoint finite differences\n"; @@ -68,19 +73,21 @@ void prepare_td_field_output(const std::string& output_dir, const elecstate::TDF } } -void write_td_field_values(const elecstate::TDFieldManager& manager, const std::string& output_dir) +void write_td_field(const elecstate::TDFieldManager& manager, const std::string& output_dir) { + const double time_fs = manager.current_step() * manager.dt_ha() * ModuleBase::AU_to_FS; // Keep the complete time series, including zero fields outside the analytic window. { std::ofstream output((output_dir + "efield_total.txt").c_str(), std::ofstream::app); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::write_td_field_values", "Cannot append efield_total.txt."); + ModuleBase::WARNING_QUIT("ModuleIO::write_td_field", "Cannot append efield_total.txt."); } - output << std::scientific << std::setprecision(16) << manager.current_step() * manager.dt_ha() * ModuleBase::AU_to_FS; + output << std::right << std::fixed << std::setprecision(6) << std::setw(10) << time_fs; + output << std::scientific << std::setprecision(12); for (int direction = 0; direction < 3; ++direction) { - output << '\t' << manager.efield_ha()[direction] * ModuleBase::Hartree_to_eV / ModuleBase::BOHR_TO_A; + output << " " << std::setw(19) << manager.efield_ha()[direction] * ModuleBase::Hartree_to_eV / ModuleBase::BOHR_TO_A; } output << '\n'; } @@ -93,16 +100,17 @@ void write_td_field_values(const elecstate::TDFieldManager& manager, const std:: for (std::size_t field_index = 0; field_index < field_values.size(); ++field_index) { // Keep one file per input occurrence even when directions repeat. - const std::string output_path = td_field_output_path(output_dir, field_index); + const std::string output_path = field_out_path(output_dir, field_index); std::ofstream output(output_path.c_str(), std::ofstream::app); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::write_td_field_values", "Cannot append electric-field file " + output_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::write_td_field", "Cannot append electric-field file " + output_path + "!"); } // Convert only at the user-visible output boundary: time to fs and the // electric field to V/Angstrom. - output << manager.current_step() * manager.dt_ha() * ModuleBase::AU_to_FS << "\t" - << field_values[field_index] * ModuleBase::Hartree_to_eV / ModuleBase::BOHR_TO_A << std::endl; + output << std::right << std::fixed << std::setprecision(6) << std::setw(10) << time_fs << " " << std::scientific + << std::setprecision(12) << std::setw(19) << field_values[field_index] * ModuleBase::Hartree_to_eV / ModuleBase::BOHR_TO_A + << std::endl; } } diff --git a/source/source_io/module_efield/td_efield_io.h b/source/source_io/module_efield/td_efield_io.h index 6c6b83ac3e5..474b2a7e701 100644 --- a/source/source_io/module_efield/td_efield_io.h +++ b/source/source_io/module_efield/td_efield_io.h @@ -19,18 +19,20 @@ namespace ModuleIO * @param field_count Number of configured time-dependent electric fields. * @param restart Whether the calculation continues from an MD/RT-TDDFT restart. */ -void prepare_td_field_output(const std::string& output_dir, std::size_t field_count, bool restart); +void prep_td_field_out(const std::string& output_dir, std::size_t field_count, bool restart); /** @brief Prepare total endpoint E and, for analytic fields, the configured waveform files. */ -void prepare_td_field_output(const std::string& output_dir, const elecstate::TDFieldManager& manager, bool restart); +void prep_td_field_out(const std::string& output_dir, const elecstate::TDFieldManager& manager, bool restart); /** * @brief Append the current electric-field samples to their output files. + * Times are written in fs with six decimal places, starting at physical time zero. + * Field components use scientific notation with twelve decimal places; columns are right-aligned. * * @param manager Time-dependent electric-field state for the current electronic step. * @param output_dir Output directory including its trailing path separator. */ -void write_td_field_values(const elecstate::TDFieldManager& manager, const std::string& output_dir); +void write_td_field(const elecstate::TDFieldManager& manager, const std::string& output_dir); } // namespace ModuleIO diff --git a/source/source_io/module_efield/td_vector_pot_io.cpp b/source/source_io/module_efield/td_vecpot_io.cpp similarity index 54% rename from source/source_io/module_efield/td_vector_pot_io.cpp rename to source/source_io/module_efield/td_vecpot_io.cpp index 9de3561f481..c8ff3db213e 100644 --- a/source/source_io/module_efield/td_vector_pot_io.cpp +++ b/source/source_io/module_efield/td_vecpot_io.cpp @@ -1,4 +1,4 @@ -#include "td_vector_pot_io.h" +#include "source_io/module_efield/td_vecpot_io.h" #include "source_base/tool_quit.h" @@ -13,15 +13,19 @@ namespace const char* VECTOR_POT_FILENAME = "vector_pot.txt"; -std::string vector_pot_path(const std::string& directory) +std::string vecpot_path(const std::string& directory) { return directory + VECTOR_POT_FILENAME; } -void write_vector_pot_header(std::ofstream& output) +void wr_vecpot_header(std::ofstream& output) { - output << std::left << std::setw(8) << "#istep" << std::setw(15) << "A_x" << std::setw(15) << "A_y" << std::setw(15) << "A_z" - << "# endpoint values, Hartree atomic units" << std::endl; + output << std::left << std::setw(6) << "#istep" << std::right; + for (const char* label: {"A_x", "A_y", "A_z"}) + { + output << " " << std::setw(19) << label; + } + output << " # endpoint values, Hartree atomic units" << std::endl; } bool is_blank_or_comment(const std::string& line) @@ -35,13 +39,13 @@ bool is_blank_or_comment(const std::string& line) namespace ModuleIO { -std::vector> read_td_vector_pot(const std::string& input_dir) +std::vector> read_td_vecpot(const std::string& input_dir) { - const std::string input_path = vector_pot_path(input_dir); + const std::string input_path = vecpot_path(input_dir); std::ifstream input(input_path.c_str()); if (!input) { - ModuleBase::WARNING_QUIT("ModuleIO::read_td_vector_pot", "Cannot open vector-potential file " + input_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::read_td_vecpot", "Cannot open vector-potential file " + input_path + "!"); } std::vector> vector_potentials; @@ -60,7 +64,7 @@ std::vector> read_td_vector_pot(const std::string& i ModuleBase::Vector3 vector_pot; if (!(row >> step_label >> vector_pot[0] >> vector_pot[1] >> vector_pot[2])) { - ModuleBase::WARNING_QUIT("ModuleIO::read_td_vector_pot", + ModuleBase::WARNING_QUIT("ModuleIO::read_td_vecpot", "Invalid vector-potential data on line " + std::to_string(line_number) + " of " + input_path + "!"); } row >> std::ws; @@ -68,12 +72,12 @@ std::vector> read_td_vector_pot(const std::string& i { if (!std::isfinite(vector_pot[direction])) { - ModuleBase::WARNING_QUIT("ModuleIO::read_td_vector_pot", "Non-finite vector potential in " + input_path); + ModuleBase::WARNING_QUIT("ModuleIO::read_td_vecpot", "Non-finite vector potential in " + input_path); } } if (!row.eof()) { - ModuleBase::WARNING_QUIT("ModuleIO::read_td_vector_pot", + ModuleBase::WARNING_QUIT("ModuleIO::read_td_vecpot", "Unexpected vector-potential data on line " + std::to_string(line_number) + " of " + input_path + "!"); } vector_potentials.push_back(vector_pot); @@ -81,28 +85,28 @@ std::vector> read_td_vector_pot(const std::string& i if (vector_potentials.empty()) { - ModuleBase::WARNING_QUIT("ModuleIO::read_td_vector_pot", "No vector-potential data found in " + input_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::read_td_vecpot", "No vector-potential data found in " + input_path + "!"); } return vector_potentials; } -void check_td_vector_pot_paths(const std::string& input_dir, const std::string& output_dir) +void check_td_vecpot_paths(const std::string& input_dir, const std::string& output_dir) { struct stat input_state; struct stat output_state; - const std::string input_path = vector_pot_path(input_dir); - const std::string output_path = vector_pot_path(output_dir); + const std::string input_path = vecpot_path(input_dir); + const std::string output_path = vecpot_path(output_dir); // Different paths can name the same file through symbolic or hard links; compare file identity before writing. if (stat(input_path.c_str(), &input_state) == 0 && stat(output_path.c_str(), &output_state) == 0 && input_state.st_dev == output_state.st_dev && input_state.st_ino == output_state.st_ino) { - ModuleBase::WARNING_QUIT("ModuleIO::check_td_vector_pot_paths", "Vector-potential output would overwrite its input file."); + ModuleBase::WARNING_QUIT("ModuleIO::check_td_vecpot_paths", "Vector-potential output would overwrite its input file."); } } -void prepare_td_vector_pot_output(const std::string& output_dir, const bool restart) +void prep_td_vecpot_out(const std::string& output_dir, const bool restart) { - const std::string output_path = vector_pot_path(output_dir); + const std::string output_path = vecpot_path(output_dir); if (restart) { std::ifstream existing(output_path.c_str(), std::ifstream::binary | std::ifstream::ate); @@ -115,24 +119,24 @@ void prepare_td_vector_pot_output(const std::string& output_dir, const bool rest std::ofstream output(output_path.c_str(), std::ofstream::out); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::prepare_td_vector_pot_output", "Cannot prepare vector-potential file " + output_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::prep_td_vecpot_out", "Cannot prepare vector-potential file " + output_path + "!"); } - write_vector_pot_header(output); + wr_vecpot_header(output); } -void write_td_vector_pot(const std::string& output_dir, const int electronic_step, const ModuleBase::Vector3& vector_pot) +void write_td_vecpot(const std::string& output_dir, const int electronic_step, const ModuleBase::Vector3& vector_pot) { - const std::string output_path = vector_pot_path(output_dir); + const std::string output_path = vecpot_path(output_dir); std::ofstream output(output_path.c_str(), std::ofstream::app); if (!output) { - ModuleBase::WARNING_QUIT("ModuleIO::write_td_vector_pot", "Cannot append vector-potential file " + output_path + "!"); + ModuleBase::WARNING_QUIT("ModuleIO::write_td_vecpot", "Cannot append vector-potential file " + output_path + "!"); } - output << std::left << std::setw(8) << electronic_step + 1; + output << std::right << std::setw(6) << electronic_step + 1 << std::scientific << std::setprecision(12); for (int direction = 0; direction < 3; ++direction) { - output << std::scientific << std::setprecision(16) << std::setw(25) << vector_pot[direction]; + output << " " << std::setw(19) << vector_pot[direction]; } output << std::endl; } diff --git a/source/source_io/module_efield/td_vector_pot_io.h b/source/source_io/module_efield/td_vecpot_io.h similarity index 68% rename from source/source_io/module_efield/td_vector_pot_io.h rename to source/source_io/module_efield/td_vecpot_io.h index d61400fd663..7247fdf34c3 100644 --- a/source/source_io/module_efield/td_vector_pot_io.h +++ b/source/source_io/module_efield/td_vecpot_io.h @@ -1,5 +1,5 @@ -#ifndef TD_VECTOR_POT_IO_H -#define TD_VECTOR_POT_IO_H +#ifndef TD_VECPOT_IO_H +#define TD_VECPOT_IO_H #include "source_base/vector3.h" @@ -15,10 +15,10 @@ namespace ModuleIO * @param input_dir Input directory including its trailing path separator. * @return Vector potentials in atomic units, ordered by file row. */ -std::vector> read_td_vector_pot(const std::string& input_dir); +std::vector> read_td_vecpot(const std::string& input_dir); /** @brief Reject output that aliases the input file, including symbolic and hard links. */ -void check_td_vector_pot_paths(const std::string& input_dir, const std::string& output_dir); +void check_td_vecpot_paths(const std::string& input_dir, const std::string& output_dir); /** * @brief Prepare the vector-potential output file for an RT-TDDFT calculation. @@ -26,7 +26,7 @@ void check_td_vector_pot_paths(const std::string& input_dir, const std::string& * @param output_dir Output directory including its trailing path separator. * @param restart Whether the calculation continues from an MD/RT-TDDFT restart. */ -void prepare_td_vector_pot_output(const std::string& output_dir, bool restart); +void prep_td_vecpot_out(const std::string& output_dir, bool restart); /** * @brief Append one Cartesian vector-potential sample. @@ -35,7 +35,7 @@ void prepare_td_vector_pot_output(const std::string& output_dir, bool restart); * @param electronic_step Zero-based electronic-step index. * @param vector_pot Cartesian vector potential in atomic units. */ -void write_td_vector_pot(const std::string& output_dir, int electronic_step, const ModuleBase::Vector3& vector_pot); +void write_td_vecpot(const std::string& output_dir, int electronic_step, const ModuleBase::Vector3& vector_pot); } // namespace ModuleIO diff --git a/source/source_io/module_energy/td_eij_io.cpp b/source/source_io/module_energy/td_eij_io.cpp index 77c7377f7b4..6448fa672f3 100644 --- a/source/source_io/module_energy/td_eij_io.cpp +++ b/source/source_io/module_energy/td_eij_io.cpp @@ -51,4 +51,5 @@ void print_eij(const std::complex* eij, ofs.flags(original_flags); ofs.precision(original_precision); } + } // namespace ModuleIO diff --git a/source/source_io/module_energy/td_eij_pw.cpp b/source/source_io/module_energy/td_eij_pw.cpp new file mode 100644 index 00000000000..8f824845d81 --- /dev/null +++ b/source/source_io/module_energy/td_eij_pw.cpp @@ -0,0 +1,127 @@ +#include "source_io/module_energy/td_eij_pw.h" + +#include "source_base/parallel_device.h" +#include "source_base/timer.h" +#include "source_io/module_energy/td_eij_io.h" + +#include +#include +#include + +namespace ModuleIO +{ +template +void print_eij_pw(hsolver::HSOperator& op, + hsolver::TDOrbOps& orbitals, + psi::Psi& current, + const K_Vectors& kv, + int nspin, + int step, + int iter, + double threshold, + std::ostream& log) +{ + ModuleBase::timer::start("ModuleIO", "print_eij_pw"); + + const int original_k = current.get_current_k(); + const int nband = current.get_nbands(); + const size_t elements = static_cast(nband) * nband; + const int nk = kv.get_nkstot() / (nspin == 2 ? 2 : 1); + const Parallel_Kpoints& pools = kv.para_k; + const bool main_rank = pools.my_pool == 0 && pools.rank_in_pool == 0; + + for (int global_k = 0; global_k < kv.get_nkstot(); ++global_k) + { + const int physical_k = global_k % nk; + const int spin = global_k / nk; + int owner = 0; + int local_k = global_k; +#ifdef __MPI + owner = pools.whichpool[physical_k]; + local_k = physical_k - pools.startk_pool[owner] + spin * pools.nks_pool[owner]; +#endif + + std::vector> eij; + if (pools.my_pool == owner) + { + eij = orbitals.cal_eij(op, current, local_k); + } + +#ifdef __MPI + // Each pool already has the full matrix; transfer only one copy to the main log. + if (owner != 0 && pools.rank_in_pool == 0 && (main_rank || pools.my_pool == owner)) + { + if (main_rank) + { + eij.resize(elements); + } + MPI_Comm world = MPI_COMM_WORLD; + const int source = pools.get_startpro_pool(owner); + const size_t max_count = std::numeric_limits::max(); + for (size_t offset = 0; offset < elements; offset += max_count) + { + const int count = static_cast(std::min(max_count, elements - offset)); + if (main_rank) + { + Parallel_Common::recv_data(eij.data() + offset, count, source, 0, world, MPI_STATUS_IGNORE); + } + else + { + Parallel_Common::send_data(eij.data() + offset, count, 0, 0, world); + } + } + } +#endif + + if (main_rank) + { + const EijOutputInfo output{threshold, step + 1, iter, physical_k + 1, nspin, spin + 1}; + print_eij(eij.data(), nband, nband, output, log); + } + } + + current.fix_k(original_k); + op.update_k(original_k); + + ModuleBase::timer::end("ModuleIO", "print_eij_pw"); +} + +template void print_eij_pw(hsolver::HSOperator, base_device::DEVICE_CPU>&, + hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + psi::Psi, base_device::DEVICE_CPU>&, + const K_Vectors&, + int, + int, + int, + double, + std::ostream&); +template void print_eij_pw(hsolver::HSOperator, base_device::DEVICE_CPU>&, + hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + psi::Psi, base_device::DEVICE_CPU>&, + const K_Vectors&, + int, + int, + int, + double, + std::ostream&); +#if defined(__CUDA) || defined(__ROCM) +template void print_eij_pw(hsolver::HSOperator, base_device::DEVICE_GPU>&, + hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + psi::Psi, base_device::DEVICE_GPU>&, + const K_Vectors&, + int, + int, + int, + double, + std::ostream&); +template void print_eij_pw(hsolver::HSOperator, base_device::DEVICE_GPU>&, + hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + psi::Psi, base_device::DEVICE_GPU>&, + const K_Vectors&, + int, + int, + int, + double, + std::ostream&); +#endif +} // namespace ModuleIO diff --git a/source/source_io/module_energy/td_eij_pw.h b/source/source_io/module_energy/td_eij_pw.h new file mode 100644 index 00000000000..ca917c3fba1 --- /dev/null +++ b/source/source_io/module_energy/td_eij_pw.h @@ -0,0 +1,25 @@ +#ifndef TD_EIJ_PW_H +#define TD_EIJ_PW_H + +#include "source_cell/klist.h" +#include "source_pw/module_rt/td_orbital_ops.h" + +#include + +namespace ModuleIO +{ +/** @brief Collect and print Eij from an already bound endpoint Hamiltonian. + * All ranks participate; both k-point cursors are restored before returning. + */ +template +void print_eij_pw(hsolver::HSOperator& op, + hsolver::TDOrbOps& orbitals, + psi::Psi& current, + const K_Vectors& kv, + int nspin, + int step, + int iter, + double threshold, + std::ostream& log); +} // namespace ModuleIO +#endif diff --git a/source/source_io/module_output/td_conserv_io.cpp b/source/source_io/module_output/td_conserv_io.cpp new file mode 100644 index 00000000000..0e896aca95b --- /dev/null +++ b/source/source_io/module_output/td_conserv_io.cpp @@ -0,0 +1,51 @@ +#include "source_io/module_output/td_conserv_io.h" + +#include "source_base/global_function.h" + +#include + +namespace ModuleIO +{ +void print_conserv(const pw::TDConserv& values, + double npsi0, + double nrho0, + int step, + bool full_gram, + const std::string& orth, + std::ofstream& log) +{ + if (!log.good()) + { + return; + } + + const char* stage = step == 0 ? "initial state" : "propagation"; + const int evolve_step = step + 1; + const double delta_wave = values.npsi - npsi0; + const double delta_rho = values.nrho - nrho0; + const std::ios::fmtflags saved_flags = log.flags(); + const std::streamsize saved_prec = log.precision(); + log << " PW RT-TDDFT conservation: evolution step " << evolve_step << ", " << stage << ", " << orth << '\n'; + log << std::right << std::fixed << std::setprecision(10); + ModuleBase::GlobalFunc::OUT(log, "Npsi", values.npsi); + ModuleBase::GlobalFunc::OUT(log, "Nrho", values.nrho); + + log << std::scientific << std::setprecision(6); + ModuleBase::GlobalFunc::OUT(log, "dNpsi", delta_wave); + ModuleBase::GlobalFunc::OUT(log, "dNrho", delta_rho); + if (full_gram) + { + if (step == 0) + { + ModuleBase::GlobalFunc::OUT(log, "initial_orth_error", values.orth_after); + } + else + { + ModuleBase::GlobalFunc::OUT(log, "orth_before_step_max", values.orth_before); + ModuleBase::GlobalFunc::OUT(log, "orth_after_step_max", values.orth_after); + } + } + log.flags(saved_flags); + log.precision(saved_prec); +} +} // namespace ModuleIO diff --git a/source/source_io/module_output/td_conserv_io.h b/source/source_io/module_output/td_conserv_io.h new file mode 100644 index 00000000000..0f40e687506 --- /dev/null +++ b/source/source_io/module_output/td_conserv_io.h @@ -0,0 +1,20 @@ +#ifndef TD_CONSERV_IO_H +#define TD_CONSERV_IO_H + +#include "source_pw/module_rt/td_conserv_pw.h" + +#include +#include + +namespace ModuleIO +{ +/** @brief Print endpoint conservation relative to the caller's initial counts. */ +void print_conserv(const pw::TDConserv& values, + double npsi0, + double nrho0, + int step, + bool full_gram, + const std::string& orth, + std::ofstream& log); +} // namespace ModuleIO +#endif diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index 75be1fba4b8..672afba6478 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -316,10 +316,15 @@ struct Input_para // ============== #Parameters (9.rt-tddft) =========================== double td_dt = -1.0; ///< time step for propagation + int td_max_halvings = 0; ///< Maximum depth of PW real-time interval bisection; zero disables retries. + int td_scf_nmax = 100; ///< SCF limit per real-time propagation attempt, independent of initial-state SCF. int estep_per_md = 1; ///< number of electronic steps per MD step std::string lin_solver = "gmres"; ///< linear solver for real-time propagation std::string td_orthonormal = "cholesky"; ///< Orthonormalization for PW real-time propagation. bool td_out_stat = false; ///< Output PW real-time conservation diagnostics. + std::string td_out_mag = "voronoi"; ///< RT-TDDFT spinor magnetic moment partition. + bool td_out_torque = false; ///< Output XC and SOC spin angular momentum torques. + bool td_out_spincur = false; ///< Output the macroscopic spin angular momentum current. int lin_gmres_restart = 20; ///< Maximum Arnoldi steps per GMRES cycle. bool td_cn_init = true; ///< CN subspace initial guess and residual reuse. bool lin_reconstruct = true; ///< Explicit GMRES residual reconstruction with periodic audits. @@ -335,6 +340,10 @@ struct Input_para double td_print_eij = -1.0; ///< threshold to output Eij elements int td_edm = 0; ///< 0: new edm method 1: old edm method int propagator = 0; ///< method of propagator + std::string td_exp_method = "lanczos"; ///< PW ETRS exponential backend. + int td_exp_order = 4; ///< Fixed Taylor polynomial order. + double td_exp_thr = 0.0; ///< Zero selects the precision-dependent exponential tolerance. + int td_exp_krylov_dim = 32; ///< Maximum Lanczos dimension before frozen-operator subdivision. int td_stype = 0; ///< type of space domain 0 : length gauge 1: velocity gauge std::vector td_ttype = {0}; ///< type of time domain ///< 0 Gauss type function. diff --git a/source/source_io/module_parameter/read_inp_estruc.cpp b/source/source_io/module_parameter/read_inp_estruc.cpp index 8867fb9e268..777dbdbfe78 100644 --- a/source/source_io/module_parameter/read_inp_estruc.cpp +++ b/source/source_io/module_parameter/read_inp_estruc.cpp @@ -444,15 +444,22 @@ The other way is only available when compiling with LIBXC, and it allows for sup item.annotation = "Noncollinear GGA gradient method: 0 original, 1 local axis, 2 regularized mapped-density LCA"; item.category = "Electronic structure"; item.type = "Integer"; - item.description = R"(Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations. -* 0: preserves the original algorithm (default). -* 1: uses the local magnetization magnitude instead of the global quantization axis in the built-in GGA gradient correction. For LIBXC functionals, 0 and 1 are equivalent. -* 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the FFT gradients of these mapped spin densities. The potential reverses this same discrete energy graph: apply the FFT divergence to each spin-channel flux, then apply the local-map Jacobian. Density/sigma clipping branches and the GGA metric stress derivative use the same mapped densities. This changes the finite-grid functional relative to projecting the four density-channel gradients; converged energies can therefore change. -For r = |m| and x = r/eta, S_eta = eta*x^3*(3*x^2 - 8*x + 6) for r < eta, and S_eta = r otherwise. The regularization is part of the functional definition, including its first and second derivatives. -Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior.)"; - item.default_value = "0"; + item.description = R"(Selects the local spin mapping for LDA/GGA functionals in magnetic `nspin=4` calculations. +* `0`: In the built-in GGA gradient correction, constructs spin densities using the local magnetization magnitude, with its sign determined by the projection onto the global quantization axis when that axis is enabled. Otherwise, uses the unsigned magnitude. +* `1`: Always uses the unsigned local magnetization magnitude in the built-in GGA gradient correction, independent of the global quantization axis. For Libxc functionals, `0` and `1` are equivalent. +* `2`: Uses the regularized spin densities $\rho_{\pm}=\frac{|n+\rho_{\mathrm{core}}|\pm\min(S_{\eta}(r),|n+\rho_{\mathrm{core}}|)}{2}$, where $n$ is the valence electron density, $\rho_{\mathrm{core}}$ is the NLCC core density, and $r=|\boldsymbol{m}|$. With $x=r/\eta$ and fixed $\eta=10^{-3}\,\mathrm{electrons}/\mathrm{bohr}^{3}$, the $C^2$ mapping is $S_{\eta}(r)=\eta x^3(3x^2-8x+6)$ for $r\lt\eta$, and $S_{\eta}(r)=r$ otherwise. GGA gradients use these mapped densities. This regularization affects both LDA and GGA and can change energies and magnetic responses. + +When omitted, the value is `2` for `esolver_type=tddft` and `0` otherwise. Explicit values are preserved.)"; + item.default_value = "`2` for `esolver_type=tddft`; `0` otherwise"; + item.unit = ""; item.domain.set_choices({"0", "1", "2"}); read_sync_int(input.gga_grad); + item.reset_value = [](const Input_Item& item, Parameter& para) { + if (!item.is_read() && para.inp.esolver_type == "tddft") + { + para.input.gga_grad = 2; + } + }; this->add_item(item); } { @@ -780,7 +787,7 @@ Note: If gamma_only is set to 1, the KPT file will be overwritten. So make sure item.annotation = "number of electron iterations"; item.category = "Electronic structure"; item.type = "Integer"; - item.description = "This variable indicates the maximal iteration number for electronic iterations."; + item.description = "Maximum number of electronic self-consistency iterations. In PW and LCAO RT-TDDFT, this controls initial-state calculations; real-time propagation uses the independent `td_scf_nmax` limit."; item.default_value = "100"; item.unit = ""; read_sync_int(input.scf_nmax); diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 2d60bdc7aaa..bbbcbe7e0f2 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -888,20 +888,30 @@ void ReadInput::item_dftu() } { Input_Item item("onsite_radius"); - item.annotation = "radius of the sphere for onsite projection (Bohr)"; + item.domain.set_rule("value>0"); + item.domain.set_active_when("onsite_radius!=0"); + item.annotation = "cutoff radius of onsite projection orbitals (Bohr)"; item.category = "DFT+U correction"; item.type = "Real"; - item.description = R"(* The onsite_radius parameter facilitates modulation of the single-zeta portion of numerical atomic orbitals used for DFT+U projections. -* The modulation algorithm applies a smooth truncation to the orbital tail followed by normalization. A representative profile is $f(r)=\frac{1}{2}\left[1+\operatorname{erf}\!\left(\frac{r_c-r}{\sigma}\right)\right]$, where $r_c$ is the cutoff radius and $\sigma=\gamma r_c$ controls smoothness.)"; - item.default_value = "3.0"; + item.description = R"(Cutoff radius for numerical atomic orbitals used in onsite projections. +* Controls the localized projections for `dft_plus_u=1` and spin constraints (`sc_mag_switch=true`) in PW and LCAO calculations. +* Enables onsite population analysis in ordinary PW calculations when set to a positive value. +* Controls atomic magnetic moment projections for `nspin=4` PW RT-TDDFT with `td_out_mag=onsite`. + +When omitted, the value is `3.0` for `dft_plus_u=1`, `sc_mag_switch=true`, or `nspin=4` PW RT-TDDFT with `td_out_mag=onsite`; otherwise it is `0.0`. Explicit values must be positive. + +Provide numerical atomic orbital files through `NUMERICAL_ORBITAL` in `STRU`, with their directory specified by `orbital_dir`. Projected magnetic moments depend on the chosen orbitals and radius.)"; + item.default_value = "`3.0` for `dft_plus_u=1`, `sc_mag_switch=true`, or `nspin=4` PW RT-TDDFT with `td_out_mag=onsite`; `0.0` otherwise"; item.unit = "Bohr"; - item.set_availability("dft_plus_u==1"); + item.set_availability("basis_type in [pw, lcao]"); read_sync_double(input.onsite_radius); item.reset_value = [](const Input_Item& item, Parameter& para) { - if ((para.input.dft_plus_u == 1 || para.input.sc_mag_switch) && para.input.onsite_radius == 0.0) + if (!item.is_read()) { - // autoset onsite_radius to 3.0 as default, this default value comes from the systematic atomic magnetism test - para.input.onsite_radius = 3.0; + const bool rt_onsite = para.inp.basis_type == "pw" && para.inp.esolver_type == "tddft" + && para.inp.nspin == 4 && para.inp.td_out_mag == "onsite"; + const bool use_onsite = para.inp.dft_plus_u == 1 || para.inp.sc_mag_switch || rt_onsite; + para.input.onsite_radius = use_onsite ? 3.0 : 0.0; } }; this->add_item(item); diff --git a/source/source_io/module_parameter/read_inp_out.cpp b/source/source_io/module_parameter/read_inp_out.cpp index 880234ed6da..1755de440c0 100644 --- a/source/source_io/module_parameter/read_inp_out.cpp +++ b/source/source_io/module_parameter/read_inp_out.cpp @@ -1654,9 +1654,16 @@ In molecular dynamics calculations, the output frequency is controlled by out_fr item.annotation = "output dipole or not"; item.category = "Real-Time TDDFT (Common)"; item.type = "Boolean"; - item.description = R"(Controls electric-dipole output. In RT-TDDFT, each enabled spin channel is written to `OUT.{suffix}/dipole_s[spin].txt` using a one-based spin number. Every row contains the one-based electronic-step index followed by the Cartesian electronic-dipole components $P_x$, $P_y$, and $P_z$ in atomic units. The running log additionally reports the electronic, ionic, and total dipoles and the norm of the total dipole. -* `True`: Output the electric dipole information. -* `False`: Do not output the electric dipole information.)"; + item.description = R"(Output the electronic dipole moment to `OUT.{suffix}/dipole_s[spin].txt`. In Hartree atomic units, + +$$\boldsymbol{P}(t)=-\int_{\Omega}\boldsymbol{r}\,\rho(\boldsymbol{r},t)\,\mathrm{d}^3r,$$ + +where the integral is over the simulation cell and $\rho$ is the electron number density. For `nspin=2`, the two spin channels are written separately; for `nspin=1` or `4`, a single file contains the dipole of the total electron density. + +Each row contains the step index followed by $P_x$, $P_y$, and $P_z$. The running log additionally reports the ionic and combined dipoles. + +* `True`: Enable dipole output. +* `False`: Disable dipole output.)"; item.default_value = "False"; item.unit = ""; read_sync_bool(input.out_dipole); @@ -1667,10 +1674,17 @@ In molecular dynamics calculations, the output frequency is controlled by out_fr item.annotation = "output current or not"; item.category = "Real-Time TDDFT (Common)"; item.type = "Integer"; - item.description = R"(Controls the current-density output method for RT-TDDFT. Each row contains the one-based electronic-step index followed by $J_x$, $J_y$, and $J_z$ in atomic units; the initial ground state is step 1 and subsequent steps increase by one. -* `0`: Do not output current. -* `1`: Available for PW and LCAO. PW evaluates the occupied-state expectation values of the velocity operator, using plane-wave momentum and nonlocal-projector derivatives; in the velocity gauge these are evaluated at the vector-potential-shifted momentum. In the length gauge, a kinetic-energy-density functional also contributes its velocity term. LCAO explicitly constructs the velocity operator from the momentum, vector-potential, and KB nonlocal-pseudopotential terms using two-center and spherical-grid integrals: $\hat{v}_{\alpha}=-\mathrm{i}\nabla_{\alpha}+A_{\alpha}(t)+\mathrm{i}\left[\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}},r_{\alpha}\right]$, where $\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}}=\mathrm{e}^{-\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}\hat{V}_{\mathrm{NL}}^{\mathrm{KB}}\mathrm{e}^{\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}$. $\boldsymbol{A}(t)$ is nonzero only for the velocity gauge (`td_stype=1`); otherwise $\boldsymbol{A}(t)=0$. Other nonlocal Hamiltonian terms, such as EXX, are not included explicitly. The total current is written to `OUT.{suffix}/current_tot.txt`. -* `2`: Available only for LCAO. Use the full Hamiltonian to construct the generalized velocity matrix in a nonorthogonal NAO basis, $\widetilde{v}_{\alpha}=\partial_{\alpha}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{\alpha}S$. This includes all contributions available in the real-space Hamiltonian matrix when enabled. This method is more general but more expensive. The total current is written to `OUT.{suffix}/current_tot_comm.txt`.)"; + item.description = R"(Output the RT-TDDFT charge current density. In Hartree atomic units, + +$$\boldsymbol{J}(t)=-\frac{1}{\Omega}\sum_{n\boldsymbol{k}}f_{n\boldsymbol{k}}\operatorname{Re}\Braket{\psi_{n\boldsymbol{k}}(t)|\hat{\boldsymbol{v}}(t)|\psi_{n\boldsymbol{k}}(t)},$$ + +where $\Omega$ is the cell volume, $f_{n\boldsymbol{k}}$ includes occupations and k-point weights, and $\hat{\boldsymbol{v}}$ is the velocity operator. + +* `0`: Disable current output. +* `1`: Available for PW and LCAO. Evaluate the velocity from momentum and nonlocal pseudopotential contributions, including coupling to the vector potential in the velocity gauge. Other nonlocal terms, such as exact exchange, are not included. Write the total current to `OUT.{suffix}/current_tot.txt`. +* `2`: Available only for LCAO. Construct the velocity matrix from the full Hamiltonian in the nonorthogonal atomic-orbital basis: $\widetilde{v}_{\alpha}=\partial_{k_{\alpha}}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{k_{\alpha}}S$, where $H$, $S$, and $\mathcal{R}_{\alpha}$ are the Hamiltonian, overlap, and position matrices in k space. This automatically includes nonlocal contributions present in the Hamiltonian, including exact exchange. Write the total current to `OUT.{suffix}/current_tot_comm.txt`. + +Each row contains the step index followed by $J_x$, $J_y$, and $J_z$.)"; item.default_value = "0"; item.unit = ""; item.set_availability("basis_type in [pw, lcao] and esolver_type==tddft"); @@ -1683,7 +1697,7 @@ In molecular dynamics calculations, the output frequency is controlled by out_fr item.category = "Real-Time TDDFT (Common)"; item.type = "Boolean"; item.description = R"(Controls whether RT-TDDFT current density is also resolved by spin and k-point. PW supports `out_current=1`; LCAO supports `out_current=1` or `2`. The total-current file is always written when current output is enabled. -* `True`: In addition to the total, `out_current=1` writes `OUT.{suffix}/current_s[spin]k[kpoint].txt`; `out_current=2` writes `OUT.{suffix}/current_s[spin]k[kpoint]_comm.txt`. Both use one-based spin and k-point numbers, with k-points numbered independently within each spin channel. Rows follow the step numbering, atomic units, precision, and append convention described in `out_current`. These weighted contributions sum to the total current. +* `True`: In addition to the total, `out_current=1` writes `OUT.{suffix}/current_s[spin]k[kpoint].txt`; `out_current=2` writes `OUT.{suffix}/current_s[spin]k[kpoint]_comm.txt`. These weighted contributions sum to the total current. * `False`: Output only `current_tot.txt` for `out_current=1` or `current_tot_comm.txt` for `out_current=2`.)"; item.default_value = "False"; item.unit = ""; @@ -1696,7 +1710,7 @@ In molecular dynamics calculations, the output frequency is controlled by out_fr item.annotation = "output electric fields"; item.category = "Real-Time TDDFT (Common)"; item.type = "Boolean"; - item.description = R"(Controls time-dependent electric-field output in `OUT.{suffix}/`. `efield_total.txt` contains time in fs followed by the total-field components $E_x$, $E_y$, and $E_z$ in V/Angstrom. Each configured analytic field is additionally written to `efield_[index].txt`, containing time in fs and the field value in V/Angstrom. The one-based index follows the occurrence order in `td_ttype` and `td_vext_dire`; fields assigned to the same direction remain in separate files. Output is written on active electronic steps. Fresh calculations overwrite the output; runs with `md_restart=True` append to it. + item.description = R"(Controls time-dependent electric-field output in `OUT.{suffix}/`. `efield_total.txt` contains time in fs followed by the total-field components $E_x$, $E_y$, and $E_z$ in V/Angstrom. Each configured analytic field is additionally written to `efield_[index].txt`, containing time in fs and the field value in V/Angstrom. The index follows the occurrence order in `td_ttype` and `td_vext_dire`; fields assigned to the same direction remain in separate files. Output is written on active electronic steps. Fresh calculations overwrite the output; runs with `md_restart=True` append to it. * `True`: Output electric-field values. * `False`: Do not output electric-field values.)"; item.default_value = "False"; @@ -1710,7 +1724,7 @@ In molecular dynamics calculations, the output frequency is controlled by out_fr item.annotation = "output endpoint vector potentials"; item.category = "Real-Time TDDFT (Common)"; item.type = "Boolean"; - item.description = R"(Controls vector-potential output to `OUT.{suffix}/vector_pot.txt`. Each row contains the one-based electronic-step index followed by $A_x$, $A_y$, and $A_z$ in Hartree atomic units. The file can be used as input for `init_vecpot` with the same `td_dt`. Fresh calculations overwrite the output; runs with `md_restart=True` append to it. + item.description = R"(Controls vector-potential output to `OUT.{suffix}/vector_pot.txt`. Each row contains the step index followed by $A_x$, $A_y$, and $A_z$ in Hartree atomic units. The file can be used as input for `init_vecpot` with the same `td_dt`. Fresh calculations overwrite the output; runs with `md_restart=True` append to it. * `True`: Output the vector potential. * `False`: Do not output the vector potential.)"; item.default_value = "False"; diff --git a/source/source_io/module_parameter/read_inp_tddft.cpp b/source/source_io/module_parameter/read_inp_tddft.cpp index 484aedf8331..8a7d8f28274 100644 --- a/source/source_io/module_parameter/read_inp_tddft.cpp +++ b/source/source_io/module_parameter/read_inp_tddft.cpp @@ -7,56 +7,13 @@ #include #include #include -#include +#include namespace ModuleIO { namespace { -int parse_td_integer(const Input_Item& item) -{ - std::size_t consumed = 0; - try - { - if (item.str_values.size() == 1) - { - const int value = std::stoi(item.str_values[0], &consumed); - if (consumed == item.str_values[0].size()) - { - return value; - } - } - } - catch (const std::exception&) - { - } - const std::string message = item.label + " must be a positive integer."; - ModuleBase::WARNING_QUIT("ReadInput", message); - return 0; -} - -std::vector parse_supersine_steps(const Input_Item& item, const int default_step) -{ - const std::vector tokens - = item.is_read() ? item.str_values : std::vector(1, "default"); - std::vector values; - for (const std::string& token: tokens) - { - if (token == "default") - { - values.push_back(default_step); - } - else - { - std::vector parsed; - parse_expression(std::vector(1, token), parsed); - values.insert(values.end(), parsed.begin(), parsed.end()); - } - } - return values; -} - struct FieldParameterRule { const char* name; @@ -78,10 +35,6 @@ void check_td_efield_parameters(const Input_para& input) ModuleBase::WARNING_QUIT("ReadInput", "td_ttype and td_vext_dire must contain the same number of fields."); } - if (input.td_stype < 0 || input.td_stype > 2) - { - ModuleBase::WARNING_QUIT("ReadInput", "td_stype must be 0, 1, or 2."); - } for (const int direction: input.td_vext_dire) { if (direction < 1 || direction > 3) @@ -197,6 +150,7 @@ void ReadInput::item_rt_tddft() // Please preserve this ordering when adding new parameters. { Input_Item item("td_orthonormal"); + item.domain.set_choices({"cholesky", "lowdin", "newton_schulz", "none"}); item.annotation = "orthonormalization method for PW real-time propagation"; item.category = "Real-Time TDDFT (PW)"; item.type = "String"; @@ -206,18 +160,11 @@ void ReadInput::item_rt_tddft() * `newton_schulz`: Newton-Schulz iteration for a Gram matrix close to the identity. Starting from $\boldsymbol{C}_0=\boldsymbol{I}$, approximate $\boldsymbol{S}^{-1/2}$ using $\boldsymbol{C}_{j+1}=\boldsymbol{C}_j(3\boldsymbol{I}-\boldsymbol{S}\boldsymbol{C}_j^2)/2$. * `none`: Disable orthonormalization. -[NOTE] Orthonormalization is applied after the Crank-Nicolson linear solve and uses an orthogonality tolerance independent of `lin_thr`. With orthonormalization enabled, the propagated Gram matrix must differ from the identity by at most `1e-6` (single precision) or `1e-12` (double precision) per element; unsuccessful corrections stop the calculation. Wavefunctions within this tolerance are left unchanged. Nonfinite or nonpositive orbital norms are rejected even with `none`.)"; +[NOTE] Orthonormalization is applied after each wavefunction propagation. With orthonormalization enabled, the propagated Gram matrix must differ from the identity by at most `1e-6` (single precision) or `1e-12` (double precision) per element; unsuccessful corrections stop the calculation. Wavefunctions within this tolerance are left unchanged. Nonfinite or nonpositive orbital norms are rejected even with `none`.)"; item.default_value = "cholesky"; item.unit = ""; item.set_availability("basis_type==pw and esolver_type==tddft"); read_sync_string(input.td_orthonormal); - item.check_value = [](const Input_Item& item, const Parameter& para) { - const std::string& method = para.inp.td_orthonormal; - if (method != "none" && method != "cholesky" && method != "lowdin" && method != "newton_schulz") - { - ModuleBase::WARNING_QUIT("ReadInput", "td_orthonormal must be cholesky, lowdin, newton_schulz or none."); - } - }; this->add_item(item); } { @@ -225,7 +172,7 @@ void ReadInput::item_rt_tddft() item.annotation = "output PW real-time conservation diagnostics"; item.category = "Real-Time TDDFT (PW)"; item.type = "Boolean"; - item.description = R"(Write wavefunction and density electron counts, their changes from the initial state, and orthogonality errors to the running log after each electronic evolution step. Electron counts describe the end-of-step state; orthogonality errors before and after correction are separate maxima over all SCF iterations and k points within that step. Orthogonality errors are omitted when `td_orthonormal=none`. + item.description = R"(Write wavefunction and density electron counts, their changes from the initial state, and orthogonality errors to the running log after each electronic evolution step. Electron counts describe the end-of-step state; orthogonality errors before and after correction are separate maxima over all SCF iterations and k points within that step. When half-step retries are enabled, only accepted substeps contribute to these maxima. Orthogonality errors are omitted when `td_orthonormal=none`. [NOTE] Enabling this output adds density integration and diagnostic communication.)"; item.default_value = "false"; @@ -234,8 +181,92 @@ void ReadInput::item_rt_tddft() read_sync_bool(input.td_out_stat); this->add_item(item); } + { + Input_Item item("td_max_halvings"); + const std::string depth_rule = "value>=0 and value<" + std::to_string(std::numeric_limits::digits); + item.domain.set_rule(depth_rule); + item.annotation = "maximum depth of PW real-time half-step retries"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Integer"; + item.description = R"(Maximum number of recursive halvings of an electronic propagation interval when self-consistency fails. Zero disables retries. Each full-step or subdivided trial uses at most `td_scf_nmax` iterations. The smallest internal time step is `td_dt / 2^td_max_halvings`; output times and the physical field profile retain the original `td_dt` grid. A value of 3 allows internal steps down to `td_dt / 8`.)"; + item.default_value = "0"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft"); + read_sync_int(input.td_max_halvings); + this->add_item(item); + } + { + Input_Item item("td_scf_nmax"); + item.domain.set_rule("value>=2"); + item.annotation = "SCF iteration limit per real-time propagation attempt"; + item.category = "Real-Time TDDFT (Common)"; + item.type = "Integer"; + item.description = R"(Maximum number of self-consistency iterations for each real-time propagation step in PW and LCAO calculations. Must be an integer of at least 2. Convergence can end the iterations early. In PW calculations, when `td_max_halvings` is positive, the limit applies independently to each full-step or subdivided trial. This parameter is independent of `scf_nmax`.)"; + item.default_value = "100"; + item.unit = ""; + item.set_availability("esolver_type==tddft and basis_type in [pw, lcao]"); + read_sync_int(input.td_scf_nmax); + this->add_item(item); + } + { + Input_Item item("td_out_mag"); + item.domain.set_choices({"voronoi", "onsite", "none"}); + item.annotation = "RT-TDDFT spinor magnetic moment output"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "String"; + item.description = R"(Write total and atomic magnetic moments to `mag_tot.txt` and `mag_atom.txt` at every step. +* `voronoi`: Integrate magnetization over periodic nearest-atom regions, including vacuum. +* `onsite`: Project onto the smoothed single-zeta numerical atomic orbitals. `onsite_radius` controls their cutoff. +* `none`: Disable these two files. + +Total moments always come from the magnetization density. Atomic onsite moments need not sum to the total. Moments follow the ABACUS Pauli convention in Bohr magnetons.)"; + item.default_value = "voronoi"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and nspin==4"); + read_sync_string(input.td_out_mag); + this->add_item(item); + } + { + Input_Item item("td_out_torque"); + item.annotation = "output PW spin angular momentum torques"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Boolean"; + item.description = R"(Write total exchange-correlation and SOC torques to `torque_tot.txt` and the atomic SOC contributions to `torque_atom.txt` at every step. In Hartree atomic units, + +$$\boldsymbol{\tau}_{\mathrm{xc}}=\mathrm{i}\sum_{n\boldsymbol{k}}f_{n\boldsymbol{k}}\Braket{\psi_{n\boldsymbol{k}}|\left[\hat{V}_{\mathrm{xc}},\hat{\boldsymbol{S}}\right]|\psi_{n\boldsymbol{k}}},$$ + +$$\boldsymbol{\tau}_{\mathrm{SOC}}=\mathrm{i}\sum_{n\boldsymbol{k}}f_{n\boldsymbol{k}}\Braket{\psi_{n\boldsymbol{k}}|\left[\hat{V}_{\mathrm{SOC}},\hat{\boldsymbol{S}}\right]|\psi_{n\boldsymbol{k}}}.$$ + +Here $\hat{\boldsymbol{S}}=\boldsymbol{\sigma}/2$, with $\boldsymbol{\sigma}$ the Pauli matrices, and $f_{n\boldsymbol{k}}$ includes occupations and k-point weights. $\hat{V}_{\mathrm{xc}}$ is the spin-dependent exchange-correlation potential, and $\hat{V}_{\mathrm{SOC}}$ is the SOC part of the nonlocal pseudopotential. + +The torques describe changes in spin angular momentum $\boldsymbol{S}=\boldsymbol{M}/2$, where $\boldsymbol{M}$ follows the ABACUS Pauli convention. Atomic SOC contributions use the corresponding atomic pseudopotential terms.)"; + item.default_value = "false"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and nspin==4"); + read_sync_bool(input.td_out_torque); + this->add_item(item); + } + { + Input_Item item("td_out_spincur"); + item.annotation = "output PW spin angular momentum current"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Boolean"; + item.description = R"(Write the nine macroscopic spin angular momentum current components to `spincur_tot.txt` at every step. In Hartree atomic units, + +$$J_i^a=\frac{1}{2\Omega}\sum_{n\boldsymbol{k}}f_{n\boldsymbol{k}}\Braket{\psi_{n\boldsymbol{k}}|\left\{\hat{v}_i,\hat{S}_a\right\}|\psi_{n\boldsymbol{k}}},\qquad \hat{S}_a=\frac{\sigma_a}{2}.$$ + +Here $\Omega$ is the cell volume, $f_{n\boldsymbol{k}}$ includes occupations and k-point weights, $\sigma_a$ is a Pauli matrix, and $\hat{v}_i$ is the velocity operator including the nonlocal pseudopotential contribution. + +Components are ordered $xx,xy,xz,yx,yy,yz,zx,zy,zz$, with flow direction first and spin polarization second.)"; + item.default_value = "false"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and nspin==4"); + read_sync_bool(input.td_out_spincur); + this->add_item(item); + } { Input_Item item("lin_solver"); + item.domain.set_choices({"bicgstab", "cgs", "gmres"}); item.annotation = "linear solver for real-time propagation"; item.category = "Real-Time TDDFT (PW)"; item.type = "String"; @@ -247,18 +278,13 @@ void ReadInput::item_rt_tddft() The initial ground-state diagonalization is controlled by `ks_solver`.)"; item.default_value = "gmres"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft"); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0"); read_sync_string(input.lin_solver); - item.check_value = [](const Input_Item&, const Parameter& para) { - if (para.inp.lin_solver != "bicgstab" && para.inp.lin_solver != "cgs" && para.inp.lin_solver != "gmres") - { - ModuleBase::WARNING_QUIT("ReadInput", "lin_solver must be bicgstab, cgs or gmres."); - } - }; this->add_item(item); } { Input_Item item("lin_precond"); + item.domain.set_choices({"kinetic", "kinetic_recycle", "kinetic_subspace", "none"}); item.annotation = "right preconditioner for PW real-time propagation"; item.category = "Real-Time TDDFT (PW)"; item.type = "String"; @@ -271,19 +297,13 @@ The initial ground-state diagonalization is controlled by `ks_solver`.)"; Preconditioning changes the convergence rate, while `lin_thr` still controls the residual of the original equation.)"; item.default_value = "kinetic_recycle"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft"); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0"); read_sync_string(input.lin_precond); - item.check_value = [](const Input_Item&, const Parameter& para) { - if (para.inp.lin_precond != "kinetic" && para.inp.lin_precond != "none" - && para.inp.lin_precond != "kinetic_recycle" && para.inp.lin_precond != "kinetic_subspace") - { - ModuleBase::WARNING_QUIT("ReadInput", "lin_precond must be none, kinetic, kinetic_recycle or kinetic_subspace."); - } - }; this->add_item(item); } { Input_Item item("lin_thr"); + item.domain.set_rule("value>=0"); item.annotation = "residual tolerance of the linear solver"; item.category = "Real-Time TDDFT (PW)"; item.type = "Real"; @@ -294,32 +314,8 @@ Preconditioning changes the convergence rate, while `lin_thr` still controls the All methods check the residual at the end of the linear solve, before orthonormalization. GMRES can use explicit residual reconstruction with periodic independent checks when `lin_reconstruct` is enabled. Subsequent orthonormalization uses a separate orthogonality tolerance and does not guarantee that the corrected wavefunctions satisfy the same linear residual tolerance.)"; item.default_value = "0"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft"); - item.read_value = [](const Input_Item& item, Parameter& para) { - std::size_t consumed = 0; - try - { - if (item.str_values.size() == 1) - { - para.input.lin_thr = std::stod(item.str_values[0], &consumed); - if (consumed == item.str_values[0].size()) - { - return; - } - } - } - catch (const std::exception&) - { - } - ModuleBase::WARNING_QUIT("ReadInput", "lin_thr must be a nonnegative finite real number."); - }; - sync_double(input.lin_thr); - item.check_value = [](const Input_Item&, const Parameter& para) { - if (!std::isfinite(para.inp.lin_thr) || para.inp.lin_thr < 0.0) - { - ModuleBase::WARNING_QUIT("ReadInput", "lin_thr must be a nonnegative finite real number."); - } - }; + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0"); + read_sync_double(input.lin_thr); this->add_item(item); } { @@ -328,14 +324,11 @@ All methods check the residual at the end of the linear solve, before orthonorma item.annotation = "maximum iterations per linear solve"; item.category = "Real-Time TDDFT (PW)"; item.type = "Integer"; - item.description = "Positive maximum number of iterations for each PW real-time linear solve. Failure to converge stops the calculation. The number of self-consistency iterations is controlled separately by `scf_nmax`."; + item.description = "Positive maximum number of iterations for each PW real-time linear solve. Failure to converge stops the calculation. Initial-state self-consistency uses `scf_nmax`; real-time self-consistency uses `td_scf_nmax`."; item.default_value = "500"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft"); - item.read_value = [](const Input_Item& item, Parameter& para) { - para.input.lin_maxiter = parse_td_integer(item); - }; - sync_int(input.lin_maxiter); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0"); + read_sync_int(input.lin_maxiter); this->add_item(item); } { @@ -347,11 +340,8 @@ All methods check the residual at the end of the linear solve, before orthonorma item.description = "Positive maximum Arnoldi dimension per GMRES cycle. `lin_maxiter` limits the total iterations across all cycles."; item.default_value = "20"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft and lin_solver==gmres"); - item.read_value = [](const Input_Item& item, Parameter& para) { - para.input.lin_gmres_restart = parse_td_integer(item); - }; - sync_int(input.lin_gmres_restart); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0 and lin_solver==gmres"); + read_sync_int(input.lin_gmres_restart); this->add_item(item); } { @@ -362,7 +352,7 @@ All methods check the residual at the end of the linear solve, before orthonorma item.description = R"(Project the Crank-Nicolson equation $\boldsymbol{L}\boldsymbol{x}=\boldsymbol{b}$ onto the previous-time wavefunction subspace to initialize the first propagation solve of each time step. With those wavefunctions as the columns of $\boldsymbol{U}$, the projected initial guess is $\boldsymbol{x}_0=\boldsymbol{U}(\boldsymbol{U}^{\dagger}\boldsymbol{L}\boldsymbol{U})^{-1}\boldsymbol{U}^{\dagger}\boldsymbol{b}$. Evaluate and reuse the initial residual $\boldsymbol{r}_0=\boldsymbol{b}-\boldsymbol{L}\boldsymbol{x}_0$ using the stored subspace operator images $\boldsymbol{L}\boldsymbol{U}$, without an additional Hamiltonian application. Available with all linear solvers and preconditioners; later self-consistency iterations retain their current wavefunction guess.)"; item.default_value = "true"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft"); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0"); read_sync_bool(input.td_cn_init); this->add_item(item); } @@ -378,26 +368,20 @@ Use an internal tolerance of 0.8 times the effective `lin_thr` and independently Only effective for `lin_solver=gmres`; ignored otherwise.)"; item.default_value = "true"; item.unit = ""; - item.set_availability("basis_type==pw and esolver_type==tddft and lin_solver==gmres"); + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==0 and lin_solver==gmres"); read_sync_bool(input.lin_reconstruct); this->add_item(item); } { Input_Item item("estep_per_md"); + item.domain.set_rule("value>0"); item.annotation = "steps of force change"; item.category = "Real-Time TDDFT (Common)"; item.type = "Integer"; item.description = "The number of electronic propagation steps between two ionic steps."; item.default_value = "1"; item.unit = ""; - item.read_value = [](const Input_Item& item, Parameter& para) { - para.input.estep_per_md = parse_td_integer(item); - if (para.input.estep_per_md <= 0) - { - ModuleBase::WARNING_QUIT("ReadInput", "estep_per_md must be a positive integer."); - } - }; - sync_int(input.estep_per_md); + read_sync_int(input.estep_per_md); this->add_item(item); } // real time TDDFT @@ -416,19 +400,8 @@ Only effective for `lin_solver=gmres`; ignored otherwise.)"; GlobalV::ofs_running << "td_dt don't exist, set td_dt with md_dt" << std::endl; para.input.td_dt = para.input.mdp.md_dt / para.input.estep_per_md; } - if (para.input.td_dt <= 0.0) - { - ModuleBase::WARNING_QUIT("ReadInput", "td_dt must be greater than zero."); - } }; - item.read_value = [](const Input_Item& item, Parameter& para) { - para.input.td_dt = doublevalue; - if (para.input.td_dt <= 0.0) - { - ModuleBase::WARNING_QUIT("ReadInput", "td_dt must be greater than zero."); - } - }; - sync_double(input.td_dt); + read_sync_double(input.td_dt); this->add_item(item); } { @@ -450,7 +423,7 @@ Only effective for `lin_solver=gmres`; ignored otherwise.)"; item.annotation = "print eij or not"; item.category = "Real-Time TDDFT (Common)"; item.type = "Real"; - item.description = R"(Controls output of the propagated-state Hamiltonian matrix elements $E_{ij}=\Braket{\psi_i | \hat{H} | \psi_j}$ to the running log. The printed band indices $i$ and $j$ are one-based global indices. Both the threshold and the printed matrix elements are in Ry. + item.description = R"(Controls output of the propagated-state Hamiltonian matrix elements $E_{ij}=\Braket{\psi_i | \hat{H} | \psi_j}$ to the running log. The printed band indices $i$ and $j$ are global indices. Both the threshold and the printed matrix elements are in Ry. * $\lt 0$: Disable the output. * $\geqslant 0$: Print an element when either $\left|\operatorname{Re}E_{ij}\right|$ or $\left|\operatorname{Im}E_{ij}\right|$ is greater than or equal to `td_print_eij`.)"; item.default_value = "-1"; @@ -461,22 +434,83 @@ Only effective for `lin_solver=gmres`; ignored otherwise.)"; } { Input_Item item("td_propagator"); + item.domain.add_requirement("basis_type==pw and esolver_type==tddft", "td_propagator in [0, 2]"); item.annotation = "method of propagator"; - item.category = "Real-Time TDDFT (LCAO)"; + item.category = "Real-Time TDDFT (Common)"; item.type = "Integer"; - item.description = R"(Method used to propagate the electronic states in a nonorthogonal LCAO basis. The formulas below use Hartree atomic units, with $S$, $H$, and $\Delta t=\mathtt{td\_dt}$ evaluated as required by each approximation. -* `0`: Crank-Nicolson through an explicitly constructed evolution matrix, $U=\left[S+\mathrm{i}H\Delta t/2\right]^{-1}\left[S-\mathrm{i}H\Delta t/2\right]$. + item.description = R"(Method used to propagate the electronic states. The formulas below use Hartree atomic units, with $\Delta t$ denoting the electronic propagation time step and $S$ the LCAO overlap matrix. The Hamiltonian $H$ and overlap matrix $S$ are evaluated as required by each approximation. + +For a plane-wave (PW) basis: +* `0`: Crank-Nicolson, $\left[I+\mathrm{i}H\Delta t/2\right]\psi(t+\Delta t)=\left[I-\mathrm{i}H\Delta t/2\right]\psi(t)$. The linear system uses the same midpoint Hamiltonian on both sides. +* `2`: Enforced time-reversal symmetry (ETRS), $U(t+\Delta t,t)=\exp\left[-\mathrm{i}H(t+\Delta t)\Delta t/2\right]\exp\left[-\mathrm{i}H(t)\Delta t/2\right]$. Select the exponential algorithm with `td_exp_method`. + +For a nonorthogonal LCAO basis: +* `0`: Crank-Nicolson, $U=\left[S+\mathrm{i}H\Delta t/2\right]^{-1}\left[S-\mathrm{i}H\Delta t/2\right]$. The evolution matrix is constructed explicitly and applied to the wavefunctions. * `1`: Fourth-order Taylor approximation to the exponential. With $\mathcal{A}=-\mathrm{i}S^{-1}H\Delta t$, $U=I+\mathcal{A}+\mathcal{A}^2/2+\mathcal{A}^3/6+\mathcal{A}^4/24$. -* `2`: Enforced time-reversal symmetry (ETRS), $U(t+\Delta t,t)=\exp\left[-\mathrm{i}S^{-1}H(t+\Delta t)\Delta t/2\right]\exp\left[-\mathrm{i}S^{-1}H(t)\Delta t/2\right]$. In the implementation, each exponential is replaced by the fourth-order Taylor polynomial from method `1` evaluated with a half time step. -* `3`: Crank-Nicolson by directly solving $\left[S+\mathrm{i}H\Delta t/2\right]\psi(t+\Delta t)=\left[S-\mathrm{i}H\Delta t/2\right]\psi(t)$. +* `2`: Enforced time-reversal symmetry (ETRS), $U(t+\Delta t,t)=\exp\left[-\mathrm{i}S^{-1}H(t+\Delta t)\Delta t/2\right]\exp\left[-\mathrm{i}S^{-1}H(t)\Delta t/2\right]$. Each exponential uses the fourth-order Taylor approximation from method `1` with a half time step. +* `3`: Crank-Nicolson, $\left[S+\mathrm{i}H\Delta t/2\right]\psi(t+\Delta t)=\left[S-\mathrm{i}H\Delta t/2\right]\psi(t)$. The linear system is solved directly. -[NOTE] GPU execution currently supports only method `0` in both single-GPU and multi-GPU solver configurations. CPU execution supports methods `0` through `3`.)"; +[NOTE] PW supports methods `0` and `2` on CPU and GPU. LCAO supports methods `0` through `3` on CPU and only method `0` on GPU.)"; item.default_value = "0"; item.unit = ""; - item.set_availability("basis_type==lcao and esolver_type==tddft"); + item.set_availability("(basis_type==pw or basis_type==lcao) and esolver_type==tddft"); read_sync_int(input.propagator); this->add_item(item); } + { + Input_Item item("td_exp_method"); + item.domain.set_choices({"lanczos", "taylor"}); + item.annotation = "exponential algorithm for PW ETRS"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "String"; + item.description = R"(Algorithm used to evaluate $\exp(-\mathrm{i}\tau\boldsymbol{H})\boldsymbol{\psi}$ for Enforced time-reversal symmetry (ETRS) propagation with a plane-wave basis. The Hamiltonian $\boldsymbol{H}$ is held fixed over the evolution interval $\tau$. The formulas below use Hartree atomic units. +* `lanczos`: Adaptive Lanczos approximation with automatic reorthogonalization when needed. The estimated error relative to the input wavefunction norm is controlled by `td_exp_thr`, and the maximum Krylov dimension by `td_exp_krylov_dim`. The half-step and full-step predictor share a Krylov basis. If the error target cannot be met within the maximum dimension, the frozen-Hamiltonian interval is subdivided internally. +* `taylor`: Fixed-order Taylor approximation, $\exp(-\mathrm{i}\tau\boldsymbol{H})\boldsymbol{\psi}\approx\sum_{k=0}^{p}(-\mathrm{i}\tau\boldsymbol{H})^k\boldsymbol{\psi}/k!$, where the order $p$ is specified by `td_exp_order`.)"; + item.default_value = "lanczos"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==2"); + read_sync_string(input.td_exp_method); + this->add_item(item); + } + { + Input_Item item("td_exp_order"); + item.domain.set_rule("value>=2"); + item.annotation = "Taylor polynomial order for PW ETRS"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Integer"; + item.description = "Taylor polynomial order $p$ used by `td_exp_method=taylor`. Must be an integer of at least 2."; + item.default_value = "4"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==2 and td_exp_method==taylor"); + read_sync_int(input.td_exp_order); + this->add_item(item); + } + { + Input_Item item("td_exp_thr"); + item.domain.set_rule("value>=0"); + item.annotation = "relative exponential error target for PW Lanczos"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Real"; + item.description = R"(Target for the estimated error in each Lanczos exponential calculation, relative to the input wavefunction norm. Must be nonnegative and finite. Zero selects $\max(10^{-10},100\epsilon)$, where $\epsilon$ is machine epsilon for the wavefunction precision, giving `1e-10` in double precision and approximately `1.19209e-5` in single precision. A positive value specifies the target directly.)"; + item.default_value = "0"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==2 and td_exp_method==lanczos"); + read_sync_double(input.td_exp_thr); + this->add_item(item); + } + { + Input_Item item("td_exp_krylov_dim"); + item.domain.set_rule("value>=2"); + item.annotation = "maximum Lanczos dimension for PW ETRS"; + item.category = "Real-Time TDDFT (PW)"; + item.type = "Integer"; + item.description = "Maximum number of Krylov basis vectors used in each Lanczos exponential calculation. Must be an integer of at least 2. Larger values increase wavefunction storage and orthogonalization work."; + item.default_value = "32"; + item.unit = ""; + item.set_availability("basis_type==pw and esolver_type==tddft and td_propagator==2 and td_exp_method==lanczos"); + read_sync_int(input.td_exp_krylov_dim); + this->add_item(item); + } { Input_Item item("td_vext"); item.annotation = "add extern potential or not"; @@ -509,6 +543,7 @@ Only effective for `lin_solver=gmres`; ignored otherwise.)"; } { Input_Item item("td_stype"); + item.domain.add_requirement("init_vecpot==false", "td_stype in [0, 1, 2]"); item.annotation = "type of electric field in space domain"; item.category = "Real-Time TDDFT (Common)"; item.type = "Integer"; @@ -699,7 +734,7 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually item.annotation = "t1 of Trapezoid type electric field"; item.category = "Real-Time TDDFT (Common)"; item.type = "Vector of Real"; - item.description = R"(Electronic step defining the end of the linear rise, $t_1=\mathtt{td\_trape\_t1}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy `td_trape_t1 <= td_trape_t2 <= td_trape_t3`. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; + item.description = R"(Electronic step defining the end of the linear rise, $t_1=\mathtt{td\_trape\_t1}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy $\mathtt{td\_trape\_t1}\leqslant\mathtt{td\_trape\_t2}\leqslant\mathtt{td\_trape\_t3}$. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; item.default_value = "1875"; item.unit = ""; item.set_availability("td_ttype contains 1"); @@ -714,7 +749,7 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually item.annotation = "t2 of Trapezoid type electric field"; item.category = "Real-Time TDDFT (Common)"; item.type = "Vector of Real"; - item.description = R"(Electronic step defining the end of the plateau, $t_2=\mathtt{td\_trape\_t2}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy `td_trape_t1 <= td_trape_t2 <= td_trape_t3`. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; + item.description = R"(Electronic step defining the end of the plateau, $t_2=\mathtt{td\_trape\_t2}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy $\mathtt{td\_trape\_t1}\leqslant\mathtt{td\_trape\_t2}\leqslant\mathtt{td\_trape\_t3}$. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; item.default_value = "5625"; item.unit = ""; item.set_availability("td_ttype contains 1"); @@ -729,7 +764,7 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually item.annotation = "t3 of Trapezoid type electric field"; item.category = "Real-Time TDDFT (Common)"; item.type = "Vector of Real"; - item.description = R"(Electronic step defining the end of the linear fall, $t_3=\mathtt{td\_trape\_t3}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy `td_trape_t1 <= td_trape_t2 <= td_trape_t3`. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; + item.description = R"(Electronic step defining the end of the linear fall, $t_3=\mathtt{td\_trape\_t3}\Delta t$. The value must be a nonnegative integer; integer-valued real inputs such as `2.0` are accepted. Each field must satisfy $\mathtt{td\_trape\_t1}\leqslant\mathtt{td\_trape\_t2}\leqslant\mathtt{td\_trape\_t3}$. Supply exactly one value for each `td_ttype 1` occurrence, in occurrence order.)"; item.default_value = "7500"; item.unit = ""; item.set_availability("td_ttype contains 1"); @@ -929,7 +964,15 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually item.unit = ""; item.set_availability("td_ttype contains 4"); item.reset_value = [](const Input_Item& item, Parameter& para) { - para.input.td_supsine_tstart = parse_supersine_steps(item, para.input.td_tstart); + std::vector tokens = item.is_read() ? item.str_values : std::vector(1, "default"); + for (std::string& token: tokens) + { + if (token == "default") + { + token = std::to_string(para.input.td_tstart); + } + } + parse_expression(tokens, para.input.td_supsine_tstart); }; item.get_final_value = [](Input_Item& item, const Parameter&) { item.final_value << (item.is_read() ? longstring(item.str_values) : "default"); @@ -947,7 +990,15 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually item.unit = ""; item.set_availability("td_ttype contains 4"); item.reset_value = [](const Input_Item& item, Parameter& para) { - para.input.td_supsine_tend = parse_supersine_steps(item, para.input.td_tend); + std::vector tokens = item.is_read() ? item.str_values : std::vector(1, "default"); + for (std::string& token: tokens) + { + if (token == "default") + { + token = std::to_string(para.input.td_tend); + } + } + parse_expression(tokens, para.input.td_supsine_tend); }; item.get_final_value = [](Input_Item& item, const Parameter&) { item.final_value << (item.is_read() ? longstring(item.str_values) : "default"); @@ -957,6 +1008,8 @@ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually } { Input_Item item("init_vecpot"); + item.domain.add_requirement("init_vecpot==true", + "esolver_type==tddft and ((basis_type==pw and td_stype==1) or (basis_type==lcao and td_stype in [1, 2]))"); item.annotation = "read endpoint vector potentials from file"; item.category = "Real-Time TDDFT (Common)"; item.type = "Boolean"; @@ -969,16 +1022,6 @@ The file takes precedence over analytic waveforms, independently of `td_vext`, ` item.unit = ""; item.set_availability("esolver_type==tddft and ((basis_type==pw and td_stype==1) or (basis_type==lcao and td_stype in [1, 2]))"); read_sync_bool(input.init_vecpot); - item.check_value = [](const Input_Item&, const Parameter& para) { - const Input_para& inp = para.inp; - const bool supported = inp.esolver_type == "tddft" - && ((inp.basis_type == "pw" && inp.td_stype == 1) - || (inp.basis_type == "lcao" && (inp.td_stype == 1 || inp.td_stype == 2))); - if (inp.init_vecpot && !supported) - { - ModuleBase::WARNING_QUIT("ReadInput", "init_vecpot requires PW velocity gauge or LCAO velocity/hybrid gauge RT-TDDFT."); - } - }; this->add_item(item); } { diff --git a/source/source_io/test/CMakeLists.txt b/source/source_io/unittests/CMakeLists.txt similarity index 85% rename from source/source_io/test/CMakeLists.txt rename to source/source_io/unittests/CMakeLists.txt index ef8609a0afb..d80b96b75bb 100644 --- a/source/source_io/test/CMakeLists.txt +++ b/source/source_io/unittests/CMakeLists.txt @@ -6,7 +6,7 @@ abacus_disable_feature_definitions(__EXX) AddTest( TARGET MODULE_IO_write_bands LIBS parameter base device symmetry - SOURCES write_bands_test.cpp ../module_energy/write_bands.cpp + SOURCES test_write_bands.cpp ../module_energy/write_bands.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) @@ -55,7 +55,7 @@ abacus_copy_test_files( AddTest( TARGET MODULE_IO_input_test_para LIBS parameter base device io_input - SOURCES read_input_ptest.cpp + SOURCES test_read_input_parallel.cpp ) add_test(NAME MODULE_IO_input_test_para_4 @@ -66,7 +66,7 @@ add_test(NAME MODULE_IO_input_test_para_4 AddTest( TARGET MODULE_IO_read_exit_file_test LIBS parameter base device - SOURCES read_exit_file_test.cpp + SOURCES test_read_exit_file.cpp ) add_test(NAME MODULE_IO_read_exit_file_test_para_4 @@ -77,27 +77,27 @@ add_test(NAME MODULE_IO_read_exit_file_test_para_4 AddTest( TARGET MODULE_IO_output_test LIBS parameter base device - SOURCES output_test.cpp + SOURCES test_output.cpp ) AddTest( TARGET MODULE_IO_td_efield_io_test LIBS parameter base device - SOURCES td_efield_io_test.cpp ../module_efield/td_efield_io.cpp + SOURCES test_td_efield_io.cpp ../module_efield/td_efield_io.cpp ../../source_estate/module_pot/td_field.cpp ../../source_estate/module_pot/td_field_profiles.cpp ../../source_estate/module_pot/td_field_manager.cpp ) AddTest( - TARGET MODULE_IO_td_vector_pot_io_test + TARGET MODULE_IO_td_vecpot_io_test LIBS parameter base device - SOURCES td_vector_pot_io_test.cpp ../module_efield/td_vector_pot_io.cpp + SOURCES test_td_vecpot_io.cpp ../module_efield/td_vecpot_io.cpp ) AddTest( TARGET MODULE_IO_write_eig_occ_test LIBS parameter base device symmetry - SOURCES write_eig_occ_test.cpp ../module_energy/write_eig_occ.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp + SOURCES test_write_eig_occ.cpp ../module_energy/write_eig_occ.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/cif_io.cpp ../../source_cell/reciprocal_grid.cpp ) @@ -106,13 +106,13 @@ AddTest( AddTest( TARGET MODULE_IO_print_info LIBS parameter base device symmetry cell_info - SOURCES print_info_test.cpp ../module_output/print_info.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp + SOURCES test_print_info.cpp ../module_output/print_info.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) AddTest( TARGET MODULE_IO_write_wfc_nao LIBS parameter base psi device - SOURCES write_wfc_nao_test.cpp ../module_wf/write_wfc_nao.cpp ../../source_basis/module_ao/parallel_orbitals.cpp + SOURCES test_write_wfc_nao.cpp ../module_wf/write_wfc_nao.cpp ../../source_basis/module_ao/parallel_orbitals.cpp ) abacus_copy_test_files(write_wfc_nao_para.sh) @@ -125,31 +125,31 @@ add_test(NAME MODULE_IO_write_wfc_nao_para AddTest( TARGET MODULE_IO_write_orb_info LIBS parameter base device cell_info - SOURCES write_orb_info_test.cpp ../module_output/write_orb_info.cpp + SOURCES test_write_orb_info.cpp ../module_output/write_orb_info.cpp ) AddTest( TARGET MODULE_IO_parse_args LIBS parameter base device io_input - SOURCES parse_args_test.cpp ../parse_args.cpp ../input_help.cpp + SOURCES test_parse_args.cpp ../parse_args.cpp ../input_help.cpp ) AddTest( TARGET MODULE_IO_input_help_test LIBS parameter base device io_input - SOURCES input_help_test.cpp ../input_help.cpp + SOURCES test_input_help.cpp ../input_help.cpp ) AddTest( TARGET MODULE_IO_bessel_basis_test LIBS parameter base device - SOURCES bessel_basis_test.cpp ../module_bessel/bessel_basis.cpp + SOURCES test_bessel_basis.cpp ../module_bessel/bessel_basis.cpp ) AddTest( TARGET MODULE_IO_output_log_test LIBS parameter base device - SOURCES ../module_output/output_log.cpp outputlog_test.cpp ../../source_basis/module_pw/test/test_tool.cpp + SOURCES ../module_output/output_log.cpp test_output_log.cpp ../../source_basis/module_pw/test/test_tool.cpp ) if(ENABLE_LCAO) @@ -157,7 +157,7 @@ AddTest( TARGET MODULE_IO_to_qo_test LIBS parameter base device numerical_atomic_orbitals nao_smoothgen container orb SOURCES - to_qo_test.cpp + test_to_qo.cpp ../module_qo/to_qo_kernel.cpp ../module_qo/to_qo_mpi.cpp ../module_qo/to_qo_structures.cpp @@ -171,7 +171,7 @@ endif() AddTest( TARGET MODULE_IO_read_wfc_pw_test LIBS parameter base device planewave - SOURCES read_wfc_pw_test.cpp ../module_wf/read_wfc_pw.cpp ../../source_basis/module_pw/test/test_tool.cpp + SOURCES test_read_wfc_pw.cpp ../module_wf/read_wfc_pw.cpp ../../source_basis/module_pw/test/test_tool.cpp ) add_test(NAME MODULE_IO_read_wfc_pw_test_parallel @@ -182,7 +182,7 @@ add_test(NAME MODULE_IO_read_wfc_pw_test_parallel AddTest( TARGET MODULE_IO_read_wf2rho_pw_test LIBS parameter base device planewave psi symmetry - SOURCES read_wf2rho_pw_test.cpp ../module_wf/read_wfc_pw.cpp ../module_wf/read_wf2rho_pw.cpp ../../source_basis/module_pw/test/test_tool.cpp ../../source_estate/module_charge/charge.cpp ../../source_estate/module_charge/chg_tools.cpp ../../source_estate/module_charge/chg_parallel.cpp ../module_wf/write_wfc_pw.cpp + SOURCES test_read_wf2rho_pw.cpp ../module_wf/read_wfc_pw.cpp ../module_wf/read_wf2rho_pw.cpp ../../source_basis/module_pw/test/test_tool.cpp ../../source_estate/module_charge/charge.cpp ../../source_estate/module_charge/chg_tools.cpp ../../source_estate/module_charge/chg_parallel.cpp ../module_wf/write_wfc_pw.cpp ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) @@ -196,7 +196,7 @@ if(ENABLE_LCAO) AddTest( TARGET MODULE_IO_numerical_basis_test LIBS parameter base device numerical_atomic_orbitals nao_smoothgen container orb - SOURCES numerical_basis_test.cpp + SOURCES test_numerical_basis.cpp ../module_bessel/numerical_basis_jyjy.cpp ../../source_lcao/center2orb.cpp ) @@ -206,7 +206,7 @@ endif() AddTest( TARGET MODULE_IO_mulliken_test LIBS parameter base device - SOURCES output_mulliken_test.cpp output_mulliken_mock.cpp ../module_mulliken/output_mulliken.cpp + SOURCES test_output_mulliken.cpp output_mulliken_mock.cpp ../module_mulliken/output_mulliken.cpp ../../source_cell/cell_index.cpp ../../source_basis/module_ao/parallel_orbitals.cpp ) @@ -215,7 +215,7 @@ AddTest( #AddTest( # TARGET MODULE_IO_read_wfc_lcao_test # LIBS parameter base device -# SOURCES read_wfc_lcao_test.cpp ../read_wfc_lcao.cpp +# SOURCES test_read_wfc_lcao.cpp ../read_wfc_lcao.cpp #) #add_test(NAME MODULE_IO_read_wfc_lcao_test_parallel @@ -228,7 +228,7 @@ AddTest( AddTest( TARGET MODULE_IO_orb_io_test LIBS parameter base device - SOURCES orb_io_test.cpp + SOURCES test_orb_io.cpp ) add_test(NAME MODULE_IO_orb_io_test_parallel @@ -261,7 +261,7 @@ endif() AddTest( TARGET MODULE_IO_read_wfc_nao_test LIBS parameter base device - SOURCES read_wfc_nao_test.cpp ../module_wf/read_wfc_nao.cpp ../module_wf/write_wfc_nao.cpp ../../source_psi/psi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp + SOURCES test_read_wfc_nao.cpp ../module_wf/read_wfc_nao.cpp ../module_wf/write_wfc_nao.cpp ../../source_psi/psi.cpp ../../source_basis/module_ao/parallel_orbitals.cpp ) add_test( @@ -275,7 +275,7 @@ AddTest( TARGET MODULE_IO_restart_exx_csr_test LIBS parameter base device SOURCES - restart_exx_csr_test.cpp + test_restart_exx_csr.cpp ../module_restart/restart_exx_csr.cpp ../module_hs/hs_sparse_io.cpp ../module_hs/lat_r_csr.cpp @@ -285,5 +285,5 @@ endif() AddTest( TARGET MODULE_IO_write_elf_logic_test - SOURCES write_elf_logic_test.cpp + SOURCES test_write_elf_logic.cpp ) diff --git a/source/source_io/test/INPUTs b/source/source_io/unittests/INPUTs similarity index 100% rename from source/source_io/test/INPUTs rename to source/source_io/unittests/INPUTs diff --git a/source/source_io/test/dos_test.h b/source/source_io/unittests/dos_test.h similarity index 100% rename from source/source_io/test/dos_test.h rename to source/source_io/unittests/dos_test.h diff --git a/source/source_io/test/for_testing_klist.h b/source/source_io/unittests/for_testing_klist.h similarity index 100% rename from source/source_io/test/for_testing_klist.h rename to source/source_io/unittests/for_testing_klist.h diff --git a/source/source_io/test/output_mulliken_mock.cpp b/source/source_io/unittests/output_mulliken_mock.cpp similarity index 100% rename from source/source_io/test/output_mulliken_mock.cpp rename to source/source_io/unittests/output_mulliken_mock.cpp diff --git a/source/source_io/test/prepare_unitcell.h b/source/source_io/unittests/prepare_unitcell.h similarity index 100% rename from source/source_io/test/prepare_unitcell.h rename to source/source_io/unittests/prepare_unitcell.h diff --git a/source/source_io/test/support/BesselBasis_UnitTest_C4_AtomType0.html b/source/source_io/unittests/support/BesselBasis_UnitTest_C4_AtomType0.html similarity index 100% rename from source/source_io/test/support/BesselBasis_UnitTest_C4_AtomType0.html rename to source/source_io/unittests/support/BesselBasis_UnitTest_C4_AtomType0.html diff --git a/source/source_io/test/support/DMK_nspin1 b/source/source_io/unittests/support/DMK_nspin1 similarity index 100% rename from source/source_io/test/support/DMK_nspin1 rename to source/source_io/unittests/support/DMK_nspin1 diff --git a/source/source_io/test/support/DMK_nspin2 b/source/source_io/unittests/support/DMK_nspin2 similarity index 100% rename from source/source_io/test/support/DMK_nspin2 rename to source/source_io/unittests/support/DMK_nspin2 diff --git a/source/source_io/test/support/INPUT b/source/source_io/unittests/support/INPUT similarity index 100% rename from source/source_io/test/support/INPUT rename to source/source_io/unittests/support/INPUT diff --git a/source/source_io/test/support/INPUT.diago_proc_full b/source/source_io/unittests/support/INPUT.diago_proc_full similarity index 100% rename from source/source_io/test/support/INPUT.diago_proc_full rename to source/source_io/unittests/support/INPUT.diago_proc_full diff --git a/source/source_io/test/support/INPUT.diago_proc_subset b/source/source_io/unittests/support/INPUT.diago_proc_subset similarity index 100% rename from source/source_io/test/support/INPUT.diago_proc_subset rename to source/source_io/unittests/support/INPUT.diago_proc_subset diff --git a/source/source_io/test/support/INPUT.plumed b/source/source_io/unittests/support/INPUT.plumed similarity index 100% rename from source/source_io/test/support/INPUT.plumed rename to source/source_io/unittests/support/INPUT.plumed diff --git a/source/source_io/test/support/INPUT.td_field_mixed b/source/source_io/unittests/support/INPUT.td_field_mixed similarity index 100% rename from source/source_io/test/support/INPUT.td_field_mixed rename to source/source_io/unittests/support/INPUT.td_field_mixed diff --git a/source/source_io/test/support/KPT b/source/source_io/unittests/support/KPT similarity index 100% rename from source/source_io/test/support/KPT rename to source/source_io/unittests/support/KPT diff --git a/source/source_io/test/support/QO_ovlpR_0.dat b/source/source_io/unittests/support/QO_ovlpR_0.dat similarity index 100% rename from source/source_io/test/support/QO_ovlpR_0.dat rename to source/source_io/unittests/support/QO_ovlpR_0.dat diff --git a/source/source_io/test/support/SK_nspin1 b/source/source_io/unittests/support/SK_nspin1 similarity index 100% rename from source/source_io/test/support/SK_nspin1 rename to source/source_io/unittests/support/SK_nspin1 diff --git a/source/source_io/test/support/SK_nspin2 b/source/source_io/unittests/support/SK_nspin2 similarity index 100% rename from source/source_io/test/support/SK_nspin2 rename to source/source_io/unittests/support/SK_nspin2 diff --git a/source/source_io/test/support/SR.csr b/source/source_io/unittests/support/SR.csr similarity index 100% rename from source/source_io/test/support/SR.csr rename to source/source_io/unittests/support/SR.csr diff --git a/source/source_io/test/support/STRU b/source/source_io/unittests/support/STRU similarity index 100% rename from source/source_io/test/support/STRU rename to source/source_io/unittests/support/STRU diff --git a/source/source_io/test/support/Si.upf b/source/source_io/unittests/support/Si.upf similarity index 100% rename from source/source_io/test/support/Si.upf rename to source/source_io/unittests/support/Si.upf diff --git a/source/source_io/test/support/WINPUT b/source/source_io/unittests/support/WINPUT similarity index 100% rename from source/source_io/test/support/WINPUT rename to source/source_io/unittests/support/WINPUT diff --git a/source/source_io/test/support/charge-density.dat b/source/source_io/unittests/support/charge-density.dat similarity index 100% rename from source/source_io/test/support/charge-density.dat rename to source/source_io/unittests/support/charge-density.dat diff --git a/source/source_io/test/support/dm_nao.txt b/source/source_io/unittests/support/dm_nao.txt similarity index 100% rename from source/source_io/test/support/dm_nao.txt rename to source/source_io/unittests/support/dm_nao.txt diff --git a/source/source_io/test/support/dmk1_nao.txt b/source/source_io/unittests/support/dmk1_nao.txt similarity index 100% rename from source/source_io/test/support/dmk1_nao.txt rename to source/source_io/unittests/support/dmk1_nao.txt diff --git a/source/source_io/test/support/istate.info b/source/source_io/unittests/support/istate.info similarity index 100% rename from source/source_io/test/support/istate.info rename to source/source_io/unittests/support/istate.info diff --git a/source/source_io/test/support/kpoints b/source/source_io/unittests/support/kpoints similarity index 100% rename from source/source_io/test/support/kpoints rename to source/source_io/unittests/support/kpoints diff --git a/source/source_io/test/support/sc.json b/source/source_io/unittests/support/sc.json similarity index 100% rename from source/source_io/test/support/sc.json rename to source/source_io/unittests/support/sc.json diff --git a/source/source_io/test/support/wf_nao.txt b/source/source_io/unittests/support/wf_nao.txt similarity index 100% rename from source/source_io/test/support/wf_nao.txt rename to source/source_io/unittests/support/wf_nao.txt diff --git a/source/source_io/test/support/wfs1_nao.txt b/source/source_io/unittests/support/wfs1_nao.txt similarity index 100% rename from source/source_io/test/support/wfs1_nao.txt rename to source/source_io/unittests/support/wfs1_nao.txt diff --git a/source/source_io/test/support/wfs1k1_nao.txt b/source/source_io/unittests/support/wfs1k1_nao.txt similarity index 100% rename from source/source_io/test/support/wfs1k1_nao.txt rename to source/source_io/unittests/support/wfs1k1_nao.txt diff --git a/source/source_io/test/support/wfs1k1_pw.dat b/source/source_io/unittests/support/wfs1k1_pw.dat similarity index 100% rename from source/source_io/test/support/wfs1k1_pw.dat rename to source/source_io/unittests/support/wfs1k1_pw.dat diff --git a/source/source_io/test/support/wfs1k2_nao.txt b/source/source_io/unittests/support/wfs1k2_nao.txt similarity index 100% rename from source/source_io/test/support/wfs1k2_nao.txt rename to source/source_io/unittests/support/wfs1k2_nao.txt diff --git a/source/source_io/test/support/wfs1k3_nao.txt b/source/source_io/unittests/support/wfs1k3_nao.txt similarity index 100% rename from source/source_io/test/support/wfs1k3_nao.txt rename to source/source_io/unittests/support/wfs1k3_nao.txt diff --git a/source/source_io/test/support/wfs1k4_nao.txt b/source/source_io/unittests/support/wfs1k4_nao.txt similarity index 100% rename from source/source_io/test/support/wfs1k4_nao.txt rename to source/source_io/unittests/support/wfs1k4_nao.txt diff --git a/source/source_io/test/support/wfs2_nao.txt b/source/source_io/unittests/support/wfs2_nao.txt similarity index 100% rename from source/source_io/test/support/wfs2_nao.txt rename to source/source_io/unittests/support/wfs2_nao.txt diff --git a/source/source_io/test/bessel_basis_test.cpp b/source/source_io/unittests/test_bessel_basis.cpp similarity index 100% rename from source/source_io/test/bessel_basis_test.cpp rename to source/source_io/unittests/test_bessel_basis.cpp diff --git a/source/source_io/test/input_help_test.cpp b/source/source_io/unittests/test_input_help.cpp similarity index 100% rename from source/source_io/test/input_help_test.cpp rename to source/source_io/unittests/test_input_help.cpp diff --git a/source/source_io/test/numerical_basis_test.cpp b/source/source_io/unittests/test_numerical_basis.cpp similarity index 100% rename from source/source_io/test/numerical_basis_test.cpp rename to source/source_io/unittests/test_numerical_basis.cpp diff --git a/source/source_io/test/orb_io_test.cpp b/source/source_io/unittests/test_orb_io.cpp similarity index 100% rename from source/source_io/test/orb_io_test.cpp rename to source/source_io/unittests/test_orb_io.cpp diff --git a/source/source_io/test/output_test.cpp b/source/source_io/unittests/test_output.cpp similarity index 100% rename from source/source_io/test/output_test.cpp rename to source/source_io/unittests/test_output.cpp diff --git a/source/source_io/test/outputlog_test.cpp b/source/source_io/unittests/test_output_log.cpp similarity index 100% rename from source/source_io/test/outputlog_test.cpp rename to source/source_io/unittests/test_output_log.cpp diff --git a/source/source_io/test/output_mulliken_test.cpp b/source/source_io/unittests/test_output_mulliken.cpp similarity index 100% rename from source/source_io/test/output_mulliken_test.cpp rename to source/source_io/unittests/test_output_mulliken.cpp diff --git a/source/source_io/test/parse_args_test.cpp b/source/source_io/unittests/test_parse_args.cpp similarity index 100% rename from source/source_io/test/parse_args_test.cpp rename to source/source_io/unittests/test_parse_args.cpp diff --git a/source/source_io/test/print_info_test.cpp b/source/source_io/unittests/test_print_info.cpp similarity index 100% rename from source/source_io/test/print_info_test.cpp rename to source/source_io/unittests/test_print_info.cpp diff --git a/source/source_io/test/read_exit_file_test.cpp b/source/source_io/unittests/test_read_exit_file.cpp similarity index 100% rename from source/source_io/test/read_exit_file_test.cpp rename to source/source_io/unittests/test_read_exit_file.cpp diff --git a/source/source_io/test/test_read_input.cmake b/source/source_io/unittests/test_read_input.cmake similarity index 100% rename from source/source_io/test/test_read_input.cmake rename to source/source_io/unittests/test_read_input.cmake diff --git a/source/source_io/test/test_read_input.cpp b/source/source_io/unittests/test_read_input.cpp similarity index 100% rename from source/source_io/test/test_read_input.cpp rename to source/source_io/unittests/test_read_input.cpp diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/unittests/test_read_input_parallel.cpp similarity index 99% rename from source/source_io/test/read_input_ptest.cpp rename to source/source_io/unittests/test_read_input_parallel.cpp index 2f57e82b2d7..3c8ce4c54bd 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/unittests/test_read_input_parallel.cpp @@ -15,7 +15,7 @@ #include "source_basis/module_pw/test/test_tool.h" // #endif /************************************************ - * unit test of read_input_test.cpp + * unit test of read_input.cpp ***********************************************/ /** diff --git a/source/source_io/test/read_wf2rho_pw_test.cpp b/source/source_io/unittests/test_read_wf2rho_pw.cpp similarity index 100% rename from source/source_io/test/read_wf2rho_pw_test.cpp rename to source/source_io/unittests/test_read_wf2rho_pw.cpp diff --git a/source/source_io/test/read_wfc_lcao_test.cpp b/source/source_io/unittests/test_read_wfc_lcao.cpp similarity index 100% rename from source/source_io/test/read_wfc_lcao_test.cpp rename to source/source_io/unittests/test_read_wfc_lcao.cpp diff --git a/source/source_io/test/read_wfc_nao_test.cpp b/source/source_io/unittests/test_read_wfc_nao.cpp similarity index 100% rename from source/source_io/test/read_wfc_nao_test.cpp rename to source/source_io/unittests/test_read_wfc_nao.cpp diff --git a/source/source_io/test/read_wfc_pw_test.cpp b/source/source_io/unittests/test_read_wfc_pw.cpp similarity index 100% rename from source/source_io/test/read_wfc_pw_test.cpp rename to source/source_io/unittests/test_read_wfc_pw.cpp diff --git a/source/source_io/test/restart_exx_csr_test.cpp b/source/source_io/unittests/test_restart_exx_csr.cpp similarity index 100% rename from source/source_io/test/restart_exx_csr_test.cpp rename to source/source_io/unittests/test_restart_exx_csr.cpp diff --git a/source/source_io/test/test_spin_tag.cpp b/source/source_io/unittests/test_spin_tag.cpp similarity index 100% rename from source/source_io/test/test_spin_tag.cpp rename to source/source_io/unittests/test_spin_tag.cpp diff --git a/source/source_io/test/td_efield_io_test.cpp b/source/source_io/unittests/test_td_efield_io.cpp similarity index 85% rename from source/source_io/test/td_efield_io_test.cpp rename to source/source_io/unittests/test_td_efield_io.cpp index 25c3afc1856..6c91a43393f 100644 --- a/source/source_io/test/td_efield_io_test.cpp +++ b/source/source_io/unittests/test_td_efield_io.cpp @@ -92,14 +92,14 @@ TEST_F(TDEFieldIOTest, FreshCalculationTruncatesAndUsesOneBasedFiles) } std::shared_ptr manager = create_manager({2.0, 3.0}); - ModuleIO::prepare_td_field_output(output_prefix_, manager->fields().size(), false); + ModuleIO::prep_td_field_out(output_prefix_, manager->fields().size(), false); EXPECT_TRUE(read_samples(1).empty()); EXPECT_TRUE(read_samples(2).empty()); manager->prepare_sample(0); - ModuleIO::write_td_field_values(*manager, output_prefix_); + ModuleIO::write_td_field(*manager, output_prefix_); manager->prepare_sample(1); - ModuleIO::write_td_field_values(*manager, output_prefix_); + ModuleIO::write_td_field(*manager, output_prefix_); const std::vector> samples_1 = read_samples(1); const std::vector> samples_2 = read_samples(2); @@ -109,8 +109,9 @@ TEST_F(TDEFieldIOTest, FreshCalculationTruncatesAndUsesOneBasedFiles) EXPECT_DOUBLE_EQ(samples_2[0].first, 0.0); EXPECT_NEAR(samples_1[0].second, 2.0, 1.0e-12); EXPECT_NEAR(samples_2[0].second, 3.0, 1.0e-12); - EXPECT_NEAR(samples_1[1].first, ModuleBase::AU_to_FS, 1.0e-7); - EXPECT_NEAR(samples_2[1].first, ModuleBase::AU_to_FS, 1.0e-7); + // One atomic time unit is rounded to six decimal places in fs. + EXPECT_DOUBLE_EQ(samples_1[1].first, 0.024189); + EXPECT_DOUBLE_EQ(samples_2[1].first, 0.024189); std::ifstream zero_based_file(output_path(0).c_str()); EXPECT_FALSE(zero_based_file.good()); @@ -124,10 +125,10 @@ TEST_F(TDEFieldIOTest, RestartPreservesExistingSamples) } std::shared_ptr manager = create_manager({4.0}); - ModuleIO::prepare_td_field_output(output_prefix_, manager->fields().size(), true); + ModuleIO::prep_td_field_out(output_prefix_, manager->fields().size(), true); const int next_step = manager->current_step() + 1; manager->prepare_sample(next_step); - ModuleIO::write_td_field_values(*manager, output_prefix_); + ModuleIO::write_td_field(*manager, output_prefix_); const std::vector> samples = read_samples(1); ASSERT_EQ(samples.size(), 2U); @@ -146,11 +147,11 @@ TEST_F(TDEFieldIOTest, ReportsOutputOpenFailures) const std::string invalid_directory = blocking_path_ + "/"; std::shared_ptr manager = create_manager({4.0}); - EXPECT_EXIT(ModuleIO::prepare_td_field_output(invalid_directory, manager->fields().size(), false), testing::ExitedWithCode(1), ""); + EXPECT_EXIT(ModuleIO::prep_td_field_out(invalid_directory, manager->fields().size(), false), testing::ExitedWithCode(1), ""); const int next_step = manager->current_step() + 1; manager->prepare_sample(next_step); - EXPECT_EXIT(ModuleIO::write_td_field_values(*manager, invalid_directory), testing::ExitedWithCode(1), ""); + EXPECT_EXIT(ModuleIO::write_td_field(*manager, invalid_directory), testing::ExitedWithCode(1), ""); } } // namespace diff --git a/source/source_io/test/td_vector_pot_io_test.cpp b/source/source_io/unittests/test_td_vecpot_io.cpp similarity index 66% rename from source/source_io/test/td_vector_pot_io_test.cpp rename to source/source_io/unittests/test_td_vecpot_io.cpp index 1deb83ca133..7de31704065 100644 --- a/source/source_io/test/td_vector_pot_io_test.cpp +++ b/source/source_io/unittests/test_td_vecpot_io.cpp @@ -1,4 +1,4 @@ -#include "source_io/module_efield/td_vector_pot_io.h" +#include "source_io/module_efield/td_vecpot_io.h" #include "gtest/gtest.h" #include @@ -9,7 +9,7 @@ namespace { -class TDVectorPotIOTest : public testing::Test +class TDVecpotIOTest : public testing::Test { protected: void SetUp() override @@ -39,28 +39,28 @@ class TDVectorPotIOTest : public testing::Test return lines; } - const std::string output_prefix_ = "td_vector_pot_io_test_"; + const std::string output_prefix_ = "td_vecpot_io_test_"; const std::string output_path_ = output_prefix_ + "vector_pot.txt"; }; -TEST_F(TDVectorPotIOTest, FreshCalculationTruncatesAndWritesHeader) +TEST_F(TDVecpotIOTest, FreshCalculationTruncatesAndWritesHeader) { { std::ofstream output(output_path_.c_str()); output << "old data\n"; } - ModuleIO::prepare_td_vector_pot_output(output_prefix_, false); - ModuleIO::write_td_vector_pot(output_prefix_, 0, ModuleBase::Vector3(1.0, 2.0, 3.0)); - ModuleIO::write_td_vector_pot(output_prefix_, 1, ModuleBase::Vector3(4.0, 5.0, 6.0)); + ModuleIO::prep_td_vecpot_out(output_prefix_, false); + ModuleIO::write_td_vecpot(output_prefix_, 0, ModuleBase::Vector3(1.0, 2.0, 3.0)); + ModuleIO::write_td_vecpot(output_prefix_, 1, ModuleBase::Vector3(4.0, 5.0, 6.0)); const std::vector lines = read_lines(); ASSERT_EQ(lines.size(), 3U); EXPECT_EQ(lines[0].find("#istep"), 0U); - EXPECT_EQ(lines[1].find("1"), 0U); - EXPECT_EQ(lines[2].find("2"), 0U); + EXPECT_EQ(lines[1].substr(0, 6), " 1"); + EXPECT_EQ(lines[2].substr(0, 6), " 2"); - const std::vector> vector_potentials = ModuleIO::read_td_vector_pot(output_prefix_); + const std::vector> vector_potentials = ModuleIO::read_td_vecpot(output_prefix_); ASSERT_EQ(vector_potentials.size(), 2U); EXPECT_DOUBLE_EQ(vector_potentials[0][0], 1.0); EXPECT_DOUBLE_EQ(vector_potentials[0][1], 2.0); @@ -70,7 +70,7 @@ TEST_F(TDVectorPotIOTest, FreshCalculationTruncatesAndWritesHeader) EXPECT_DOUBLE_EQ(vector_potentials[1][2], 6.0); } -TEST_F(TDVectorPotIOTest, RestartPreservesExistingSamples) +TEST_F(TDVecpotIOTest, RestartPreservesExistingSamples) { { std::ofstream output(output_path_.c_str()); @@ -78,19 +78,19 @@ TEST_F(TDVectorPotIOTest, RestartPreservesExistingSamples) output << "7 1.0 2.0 3.0\n"; } - ModuleIO::prepare_td_vector_pot_output(output_prefix_, true); - ModuleIO::write_td_vector_pot(output_prefix_, 7, ModuleBase::Vector3(4.0, 5.0, 6.0)); + ModuleIO::prep_td_vecpot_out(output_prefix_, true); + ModuleIO::write_td_vecpot(output_prefix_, 7, ModuleBase::Vector3(4.0, 5.0, 6.0)); const std::vector lines = read_lines(); ASSERT_EQ(lines.size(), 3U); EXPECT_EQ(lines[0], "#istep A_x A_y A_z"); EXPECT_EQ(lines[1], "7 1.0 2.0 3.0"); - EXPECT_EQ(lines[2].find("8"), 0U); + EXPECT_EQ(lines[2].substr(0, 6), " 8"); } -TEST_F(TDVectorPotIOTest, RestartCreatesHeaderForMissingOrEmptyFile) +TEST_F(TDVecpotIOTest, RestartCreatesHeaderForMissingOrEmptyFile) { - ModuleIO::prepare_td_vector_pot_output(output_prefix_, true); + ModuleIO::prep_td_vecpot_out(output_prefix_, true); std::vector lines = read_lines(); ASSERT_EQ(lines.size(), 1U); EXPECT_EQ(lines[0].find("#istep"), 0U); @@ -98,13 +98,13 @@ TEST_F(TDVectorPotIOTest, RestartCreatesHeaderForMissingOrEmptyFile) { std::ofstream output(output_path_.c_str(), std::ofstream::out); } - ModuleIO::prepare_td_vector_pot_output(output_prefix_, true); + ModuleIO::prep_td_vecpot_out(output_prefix_, true); lines = read_lines(); ASSERT_EQ(lines.size(), 1U); EXPECT_EQ(lines[0].find("#istep"), 0U); } -TEST_F(TDVectorPotIOTest, ReaderSkipsBlankAndCommentLinesAndIgnoresLabels) +TEST_F(TDVecpotIOTest, ReaderSkipsBlankAndCommentLinesAndIgnoresLabels) { { std::ofstream output(output_path_.c_str()); @@ -114,7 +114,7 @@ TEST_F(TDVectorPotIOTest, ReaderSkipsBlankAndCommentLinesAndIgnoresLabels) output << "42 4.5 5.5 -6.5\n"; } - const std::vector> vector_potentials = ModuleIO::read_td_vector_pot(output_prefix_); + const std::vector> vector_potentials = ModuleIO::read_td_vecpot(output_prefix_); ASSERT_EQ(vector_potentials.size(), 2U); EXPECT_DOUBLE_EQ(vector_potentials[0][0], 1.5); EXPECT_DOUBLE_EQ(vector_potentials[0][1], -2.5); @@ -124,25 +124,25 @@ TEST_F(TDVectorPotIOTest, ReaderSkipsBlankAndCommentLinesAndIgnoresLabels) EXPECT_DOUBLE_EQ(vector_potentials[1][2], -6.5); } -TEST_F(TDVectorPotIOTest, ReaderRejectsEmptyAndMalformedFiles) +TEST_F(TDVecpotIOTest, ReaderRejectsEmptyAndMalformedFiles) { { std::ofstream output(output_path_.c_str()); output << "# no samples\n"; } - EXPECT_EXIT(ModuleIO::read_td_vector_pot(output_prefix_), testing::ExitedWithCode(1), ""); + EXPECT_EXIT(ModuleIO::read_td_vecpot(output_prefix_), testing::ExitedWithCode(1), ""); { std::ofstream output(output_path_.c_str(), std::ofstream::out); output << "1 2.0 invalid 4.0\n"; } - EXPECT_EXIT(ModuleIO::read_td_vector_pot(output_prefix_), testing::ExitedWithCode(1), ""); + EXPECT_EXIT(ModuleIO::read_td_vecpot(output_prefix_), testing::ExitedWithCode(1), ""); { std::ofstream output(output_path_.c_str(), std::ofstream::out); output << "1 2.0 3.0 4.0 extra\n"; } - EXPECT_EXIT(ModuleIO::read_td_vector_pot(output_prefix_), testing::ExitedWithCode(1), ""); + EXPECT_EXIT(ModuleIO::read_td_vecpot(output_prefix_), testing::ExitedWithCode(1), ""); } } // namespace diff --git a/source/source_io/test/to_qo_test.cpp b/source/source_io/unittests/test_to_qo.cpp similarity index 100% rename from source/source_io/test/to_qo_test.cpp rename to source/source_io/unittests/test_to_qo.cpp diff --git a/source/source_io/test/write_bands_test.cpp b/source/source_io/unittests/test_write_bands.cpp similarity index 100% rename from source/source_io/test/write_bands_test.cpp rename to source/source_io/unittests/test_write_bands.cpp diff --git a/source/source_io/test/write_eig_occ_test.cpp b/source/source_io/unittests/test_write_eig_occ.cpp similarity index 100% rename from source/source_io/test/write_eig_occ_test.cpp rename to source/source_io/unittests/test_write_eig_occ.cpp diff --git a/source/source_io/test/write_elf_logic_test.cpp b/source/source_io/unittests/test_write_elf_logic.cpp similarity index 100% rename from source/source_io/test/write_elf_logic_test.cpp rename to source/source_io/unittests/test_write_elf_logic.cpp diff --git a/source/source_io/test/write_orb_info_test.cpp b/source/source_io/unittests/test_write_orb_info.cpp similarity index 100% rename from source/source_io/test/write_orb_info_test.cpp rename to source/source_io/unittests/test_write_orb_info.cpp diff --git a/source/source_io/test/write_wfc_nao_test.cpp b/source/source_io/unittests/test_write_wfc_nao.cpp similarity index 100% rename from source/source_io/test/write_wfc_nao_test.cpp rename to source/source_io/unittests/test_write_wfc_nao.cpp diff --git a/source/source_io/test/tmp_mocks.cpp b/source/source_io/unittests/tmp_mocks.cpp similarity index 100% rename from source/source_io/test/tmp_mocks.cpp rename to source/source_io/unittests/tmp_mocks.cpp diff --git a/source/source_io/test/write_wfc_nao_para.sh b/source/source_io/unittests/write_wfc_nao_para.sh similarity index 100% rename from source/source_io/test/write_wfc_nao_para.sh rename to source/source_io/unittests/write_wfc_nao_para.sh diff --git a/source/source_psi/setup_psi_pw.cpp b/source/source_psi/setup_psi_pw.cpp index cb56267631a..a07296676fb 100644 --- a/source/source_psi/setup_psi_pw.cpp +++ b/source/source_psi/setup_psi_pw.cpp @@ -116,14 +116,27 @@ void Setup_Psi_pw::before_runner(const UnitCell& ucell, template void Setup_Psi_pw::update_psi_d_impl() { - if (this->psi_d != nullptr && this->precision_type_ == PrecisionType::ComplexFloat) - { - delete this->get_psi_d(); - } - if (this->precision_type_ == PrecisionType::ComplexFloat) { - this->psi_d = static_cast(new psi::Psi, Device>(*this->get_psi_t())); + const psi::Psi* native = this->get_psi_t(); + psi::Psi, Device>* mirror = this->get_psi_d(); + if (mirror == nullptr) + { + this->psi_d = new psi::Psi, Device>(*native); + } + else if (mirror->get_nk() != native->get_nk() || mirror->get_nbands() != native->get_nbands() + || mirror->get_nbasis() != native->get_nbasis() || mirror->get_ngk_pointer() != native->get_ngk_pointer()) + { + // Preserve the object address borrowed by onsite projectors even when storage changes. + *mirror = psi::Psi, Device>(*native); + } + else + { + const T* source = native->get_pointer() - native->get_psi_bias(); + std::complex* destination = mirror->get_pointer() - mirror->get_psi_bias(); + base_device::memory::cast_memory_op, T, Device, Device>()(destination, source, native->size()); + mirror->fix_k(native->get_current_k()); + } } else { @@ -251,19 +264,13 @@ void Setup_Psi_pw::sync_cpu() template void Setup_Psi_pw::castmem_d2h_impl(std::complex* dst, const std::complex* src, const std::size_t size) { - base_device::memory::cast_memory_op, std::complex, base_device::DEVICE_CPU, Device>()( - dst, - src, - size); + base_device::memory::cast_memory_op, std::complex, base_device::DEVICE_CPU, Device>()(dst, src, size); } template void Setup_Psi_pw::castmem_d2h_impl(std::complex* dst, const std::complex* src, const std::size_t size) { - base_device::memory::cast_memory_op, std::complex, base_device::DEVICE_CPU, Device>()( - dst, - src, - size); + base_device::memory::cast_memory_op, std::complex, base_device::DEVICE_CPU, Device>()(dst, src, size); } template @@ -313,21 +320,19 @@ void Setup_Psi_pw::clean() template class psi::PSIPrepare, base_device::DEVICE_CPU>; template class psi::PSIPrepare, base_device::DEVICE_CPU>; -template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_CPU>( - const UnitCell&, - const K_Vectors&, - const Structure_Factor&, - const ModulePW::PW_Basis_K&, - const int&, - const Input_para&); - -template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_CPU>( - const UnitCell&, - const K_Vectors&, - const Structure_Factor&, - const ModulePW::PW_Basis_K&, - const int&, - const Input_para&); +template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_CPU>(const UnitCell&, + const K_Vectors&, + const Structure_Factor&, + const ModulePW::PW_Basis_K&, + const int&, + const Input_para&); + +template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_CPU>(const UnitCell&, + const K_Vectors&, + const Structure_Factor&, + const ModulePW::PW_Basis_K&, + const int&, + const Input_para&); template void Setup_Psi_pw::init_impl, base_device::DEVICE_CPU>( hamilt::Hamilt, base_device::DEVICE_CPU>*); @@ -363,21 +368,19 @@ template void Setup_Psi_pw::castmem_d2h_impl, base_device:: template class psi::PSIPrepare, base_device::DEVICE_GPU>; template class psi::PSIPrepare, base_device::DEVICE_GPU>; -template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_GPU>( - const UnitCell&, - const K_Vectors&, - const Structure_Factor&, - const ModulePW::PW_Basis_K&, - const int&, - const Input_para&); - -template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_GPU>( - const UnitCell&, - const K_Vectors&, - const Structure_Factor&, - const ModulePW::PW_Basis_K&, - const int&, - const Input_para&); +template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_GPU>(const UnitCell&, + const K_Vectors&, + const Structure_Factor&, + const ModulePW::PW_Basis_K&, + const int&, + const Input_para&); + +template void Setup_Psi_pw::before_runner_impl, base_device::DEVICE_GPU>(const UnitCell&, + const K_Vectors&, + const Structure_Factor&, + const ModulePW::PW_Basis_K&, + const int&, + const Input_para&); template void Setup_Psi_pw::init_impl, base_device::DEVICE_GPU>( hamilt::Hamilt, base_device::DEVICE_GPU>*); diff --git a/source/source_pw/CMakeLists.txt b/source/source_pw/CMakeLists.txt index 0efea3ccb93..a4adc51e172 100644 --- a/source/source_pw/CMakeLists.txt +++ b/source/source_pw/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(module_pwdft) add_subdirectory(module_ofdft) add_subdirectory(module_stodft) add_subdirectory(module_dfpt) +add_subdirectory(module_rt) diff --git a/source/source_pw/module_proj/onsite_proj.h b/source/source_pw/module_proj/onsite_proj.h index fcfe8553b14..f9618c427bc 100644 --- a/source/source_pw/module_proj/onsite_proj.h +++ b/source/source_pw/module_proj/onsite_proj.h @@ -18,6 +18,14 @@ namespace projectors { public: + /** @brief Own an independent projector and its workspaces. */ + OnsiteProjector() = default; + ~OnsiteProjector(); + OnsiteProjector(const OnsiteProjector&) = delete; + OnsiteProjector& operator=(const OnsiteProjector&) = delete; + OnsiteProjector(OnsiteProjector&&) = delete; + OnsiteProjector& operator=(OnsiteProjector&&) = delete; + /** * @brief initialize the radial projector for real-space projection involving operators * @@ -71,6 +79,13 @@ namespace projectors const int nspin_in); int get_size_becp() const { return size_becp; } + /** @brief Extend this projector's radial table to cover shifted momenta. */ + void ensure_range(double momentum, double dq); + /** @brief Invalidate position-dependent overlap projectors without changing radial channels. */ + void invalidate_proj(); + /** @brief Project endpoint spin-component columns without printing static occupations. */ + void overlap_td(int ik, int columns, const std::complex* psi, int stride, + const ModuleBase::Vector3& vector_potential); std::complex* get_becp() const { return becp; } std::complex* get_h_becp() const { return h_becp; } std::complex* get_tab_atomic() const { return tab_atomic_; } @@ -102,20 +117,19 @@ namespace projectors const double* wg_ik) const; private: - OnsiteProjector(){}; - ~OnsiteProjector(); + void overlap_impl(int columns, const std::complex* psi, int stride, + const ModuleBase::Vector3& vector_potential); Device* ctx = {}; base_device::DEVICE_CPU* cpu_ctx = {}; base_device::AbacusDevice_t device = {}; - static OnsiteProjector *instance; hamilt::Onsite_Proj_tools* fs_tools = nullptr; std::complex* tab_atomic_ = nullptr; std::complex* becp = nullptr; // nbands * nkb // save becp in CPU memory, only used when Device is GPU - std::complex* h_becp; + std::complex* h_becp = nullptr; int size_becp = 0; int size_vproj = 0; @@ -175,4 +189,4 @@ namespace projectors }; }// namespace projectors -#endif // MODULEHAMILTPW_ONSITEPROJECTOR_H \ No newline at end of file +#endif // MODULEHAMILTPW_ONSITEPROJECTOR_H diff --git a/source/source_pw/module_proj/onsite_proj_init.cpp b/source/source_pw/module_proj/onsite_proj_init.cpp index e2c0a4fe411..5b84d7f4a87 100644 --- a/source/source_pw/module_proj/onsite_proj_init.cpp +++ b/source/source_pw/module_proj/onsite_proj_init.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "source_base/module_out/orb_io.h" #include "source_pw/module_proj/onsite_proj.h" @@ -141,7 +142,7 @@ void projectors::OnsiteProjector::init(const std::string& orbital_dir } } - this->init_proj(PARAM.inp.orbital_dir, + this->init_proj(orbital_dir, orb_files, nproj, lproj, @@ -209,6 +210,10 @@ void projectors::OnsiteProjector::init_proj(const std::string& orbita continue; } std::ifstream ifs(orbital_dir + orb_files[it]); + if (!ifs) + { + ModuleBase::WARNING_QUIT("OnsiteProjector", "Cannot open orbital file: " + orbital_dir + orb_files[it]); + } std::string elem = ""; double ecut = -1.0; int nr_ = -1; @@ -216,6 +221,10 @@ void projectors::OnsiteProjector::init_proj(const std::string& orbita std::vector nzeta; // number of radials for each l std::vector> radials; // radials arranged in serial ModuleIO::read_abacus_orb(ifs, elem, ecut, nr_, dr_, nzeta, radials); + if (nr_ < 2 || !(dr_ > 0.0) || radials.empty()) + { + ModuleBase::WARNING_QUIT("OnsiteProjector", "Invalid orbital radial grid."); + } #ifdef __DEBUG assert(elem != ""); assert(ecut != -1.0); @@ -227,16 +236,20 @@ void projectors::OnsiteProjector::init_proj(const std::string& orbita dr = (dr == -1.0) ? dr_ : dr; for(int ip = 0; ip < nproj_it; ++ip) { + if (!(onsite_r[idx] > 0.0) || onsite_r[idx] >= (nr_ - 1) * dr_) + { + ModuleBase::WARNING_QUIT("OnsiteProjector", "onsite_radius must lie inside the orbital radial grid."); + } int l = lproj[idx]; int izeta = iproj[idx]; int irad = 0; irad = std::accumulate(nzeta.begin(), nzeta.begin() + l, irad); irad += izeta; std::vector temp = radials[irad]; - rgrid.resize(nr); + rgrid.resize(nr_); std::iota(rgrid.begin(), rgrid.end(), 0); std::for_each(rgrid.begin(), rgrid.end(), [dr](double& r_i) { r_i *= dr; }); - smoothgen(nr, rgrid.data(), temp.data(), onsite_r[idx], projs[idx]); + smoothgen(nr_, rgrid.data(), temp.data(), onsite_r[idx], projs[idx]); it2iproj[it][ip] = idx; ++idx; } @@ -253,6 +266,27 @@ void projectors::OnsiteProjector::init_proj(const std::string& orbita } // explicit method instantiation +template +void projectors::OnsiteProjector::ensure_range(double momentum, double dq) +{ + // Four extra samples cover the radial interpolation stencil at the largest shifted momentum. + const int required = static_cast(std::ceil(momentum / dq)) + 4; + if (required <= tab.getBound3()) + { + return; + } + std::vector counts(ntype); + for (int it = 0; it < ntype; ++it) + { + counts[it] = it2iproj[it].size(); + } + const int capacity = std::max(required + 100, static_cast(std::ceil(1.25 * tab.getBound3()))); + const int npol = ucell->get_npol(); + RadialProjection::build_sbt_tab(counts, rgrid, projs, lproj, capacity, dq, ucell->omega, npol, tab, nhtol); + fs_tools->refresh_table(); +} + +template void projectors::OnsiteProjector::ensure_range(double, double); template void projectors::OnsiteProjector::init( const std::string&, @@ -277,6 +311,7 @@ void projectors::OnsiteProjector::init_proj( const std::vector&); #if ((defined __CUDA) || (defined __ROCM)) +template void projectors::OnsiteProjector::ensure_range(double, double); template void projectors::OnsiteProjector::init( const std::string&, diff --git a/source/source_pw/module_proj/onsite_proj_overlap.cpp b/source/source_pw/module_proj/onsite_proj_overlap.cpp index 79776c7496e..c94c6b1e56a 100644 --- a/source/source_pw/module_proj/onsite_proj_overlap.cpp +++ b/source/source_pw/module_proj/onsite_proj_overlap.cpp @@ -29,27 +29,9 @@ void projectors::OnsiteProjector::overlap_proj_psi( const int ld_psi) { ModuleBase::timer::start("OnsiteProj", "overlap"); - // notes on refactor for DCU calculation - // the npm here is nbands(occ) * npol, for calling cal_becp, the npol should be divided. - int npol = this->ucell->get_npol(); - if(this->becp == nullptr || this->size_becp < npm*this->tot_nproj) - { - this->size_becp = npm*this->tot_nproj; - resmem_complex_op()(this->becp, this->size_becp); - if(this->device == base_device::GpuDevice ) - { - resmem_complex_h_op()(this->h_becp, this->size_becp); - } - else - { - this->h_becp = this->becp; - } - } - this->fs_tools->cal_becp(ik_, npm/npol, this->becp, ppsi, ld_psi > 0 ? ld_psi : this->npwx_); // in cal_becp, npm should be the one not multiplied by npol - if(this->device == base_device::GpuDevice) - { - syncmem_complex_d2h_op()(h_becp, this->becp, this->size_becp); - } + const int stride = ld_psi > 0 ? ld_psi : npwx_; + const ModuleBase::Vector3 zero; + overlap_impl(npm, ppsi, stride, zero); ModuleBase::timer::end("OnsiteProj", "overlap"); } @@ -107,7 +89,50 @@ void projectors::OnsiteProjector::cal_occupations( ModuleBase::timer::end("OnsiteProj", "cal_occupation"); } -// explicit method instantiation +template +void projectors::OnsiteProjector::invalidate_proj() +{ + if (fs_tools != nullptr) + { + fs_tools->invalidate_proj(); + } +} + +template +void projectors::OnsiteProjector::overlap_td(int ik, int columns, + const std::complex* psi, int stride, + const ModuleBase::Vector3& vector_potential) +{ + tabulate_atomic(ik); + overlap_impl(columns, psi, stride, vector_potential); +} + +template +void projectors::OnsiteProjector::overlap_impl(int columns, + const std::complex* psi, int stride, + const ModuleBase::Vector3& vector_potential) +{ + const int count = columns * tot_nproj; + if (count > size_becp || becp == nullptr) + { + size_becp = count; + resmem_complex_op()(becp, std::max(1, count)); + if (device == base_device::GpuDevice) + { + resmem_complex_h_op()(h_becp, std::max(1, count)); + } + else + { + h_becp = becp; + } + } + const int bands = columns / ucell->get_npol(); + fs_tools->cal_becp(ik_, bands, becp, psi, stride, vector_potential, h_becp); +} + +template void projectors::OnsiteProjector::invalidate_proj(); +template void projectors::OnsiteProjector::overlap_td( + int, int, const std::complex*, int, const ModuleBase::Vector3&); template void projectors::OnsiteProjector::tabulate_atomic( const int, const char); @@ -123,6 +148,9 @@ void projectors::OnsiteProjector::cal_occupatio const int); #if ((defined __CUDA) || (defined __ROCM)) +template void projectors::OnsiteProjector::invalidate_proj(); +template void projectors::OnsiteProjector::overlap_td( + int, int, const std::complex*, int, const ModuleBase::Vector3&); template void projectors::OnsiteProjector::tabulate_atomic( const int, const char); diff --git a/source/source_pw/module_proj/onsite_proj_tools.h b/source/source_pw/module_proj/onsite_proj_tools.h index facbb9faf14..e88cc374c54 100644 --- a/source/source_pw/module_proj/onsite_proj_tools.h +++ b/source/source_pw/module_proj/onsite_proj_tools.h @@ -63,6 +63,17 @@ class Onsite_Proj_tools * @brief calculate the becp = for all beta functions */ void cal_becp(int ik, int npm, std::complex* becp_in = nullptr, const std::complex* ppsi_in = nullptr, int npwx = 0); + /** @brief Gauge-covariant projection at the explicit endpoint vector potential (inverse Bohr). + * @param host_becp Optional caller-owned host buffer for the pool-reduced overlaps; may be nullptr. + */ + void cal_becp(int ik, int npm, std::complex* becp_in, + const std::complex* ppsi_in, int npwx, + const ModuleBase::Vector3& vector_potential, + std::complex* host_becp); + /** @brief Invalidate projectors after resizing the borrowed radial interpolation table. */ + void refresh_table(); + /** @brief Rebuild overlap projectors on the next call after atomic coordinates change. */ + void invalidate_proj(); /** * @brief calculate the dbecp_{ij} = for all beta functions * stress_{ij} = -1/omega \sum_{n,k}f_{nk} \sum_I \sum_{lm,l'm'}D_{l,l'}^{I} becp * dbecp_{ij} also calculated @@ -147,6 +158,7 @@ class Onsite_Proj_tools int deeq_nc_dims[4] = {0, 0, 0, 0}; int current_ik = -1; + ModuleBase::Vector3 current_a_; int max_nh = 0; int max_npw = 0; @@ -213,6 +225,7 @@ class Onsite_Proj_tools /// becp and dbecp: std::complex* dbecp = nullptr; // nbands * nkb (for stress) or nbands * nkb * 3 (for force) std::complex* becp = nullptr; // nbands * nkb + std::vector> host_becp_; /// @brief rename the operators for CPU/GPU device using gemm_op = ModuleBase::gemm_op, Device>; diff --git a/source/source_pw/module_proj/onsite_proj_tools_becp.cpp b/source/source_pw/module_proj/onsite_proj_tools_becp.cpp index 170f1ecb931..d9ae7a18105 100644 --- a/source/source_pw/module_proj/onsite_proj_tools_becp.cpp +++ b/source/source_pw/module_proj/onsite_proj_tools_becp.cpp @@ -1,13 +1,14 @@ -#include "source_pw/module_proj/onsite_proj_tools.h" - #include "source_base/math_polyint.h" #include "source_base/math_ylmreal.h" #include "source_base/parallel_reduce.h" #include "source_base/timer.h" #include "source_base/tool_title.h" #include "source_io/module_parameter/parameter.h" +#include "source_pw/module_proj/onsite_proj_tools.h" #include "source_pw/module_pwdft/nonlocal_maths.h" +#include + // cal_becp // starts from vkb (nkb, ng) table // it should be merely the multiplication of matrix (vkb, ng) * (ng, nbands) -> (vkb, nbands) @@ -18,24 +19,61 @@ // because the atom selection task is operator-specific. template void hamilt::Onsite_Proj_tools::cal_becp(int ik, - int npm, - std::complex* becp_in, - const std::complex* ppsi_in, - int npwx) + int npm, + std::complex* becp_in, + const std::complex* ppsi_in, + int npwx) +{ + const ModuleBase::Vector3 zero; + cal_becp(ik, npm, becp_in, ppsi_in, npwx, zero, nullptr); +} + +template +void hamilt::Onsite_Proj_tools::refresh_table() +{ + // Resizing the radial table changes both its device storage and every projector interpolated from it. + invalidate_proj(); + if (this->device == base_device::GpuDevice) + { + resmem_var_op()(d_vq_tab, this->tabtpr->getSize()); + } +} + +template +void hamilt::Onsite_Proj_tools::invalidate_proj() +{ + // Coordinate updates change atomic phases even when the k point and A are unchanged. + current_ik = -1; +} + +template +void hamilt::Onsite_Proj_tools::cal_becp(int ik, + int npm, + std::complex* becp_in, + const std::complex* ppsi_in, + int npwx, + const ModuleBase::Vector3& vector_potential, + std::complex* host_becp) { ModuleBase::TITLE("Onsite_Proj_tools", "cal_becp"); ModuleBase::timer::start("Onsite_Proj_tools", "cal_becp"); const int npol = this->ucell_->get_npol(); - const std::complex* ppsi = ppsi_in == nullptr ? &(this->psi_[0](ik, 0, 0)) : ppsi_in; const int npw = this->wfc_basis_->npwk[ik]; + const std::complex* ppsi = ppsi_in; + if (npw > 0 && ppsi == nullptr) + { + ppsi = &(this->psi_[0](ik, 0, 0)); + } if (becp_in == nullptr && this->becp == nullptr) { resmem_complex_op()(becp, this->nbands * npol * this->nkb); } std::complex* becp_tmp = becp_in == nullptr ? this->becp : becp_in; const int size_becp_act = npm * npol * this->nkb; - if (ik != this->current_ik) // different ik, need to recalculate vkb + // Coordinates and radial-table changes invalidate current_ik explicitly; k and A are checked on each call. + const bool changed_a = (vector_potential - current_a_).norm2() != 0.0; + if (npw > 0 && (ik != this->current_ik || changed_a)) { const int size_becp = this->nbands * npol * this->nkb; if (this->becp == nullptr) @@ -50,6 +88,20 @@ void hamilt::Onsite_Proj_tools::cal_becp(int ik, // calculate G+K this->g_plus_k = maths.cal_gk(ik, this->wfc_basis_); + if (vector_potential.norm2() != 0.0) + { + const double tpiba = this->ucell_->tpiba; + for (int ig = 0; ig < npw; ++ig) + { + const ModuleBase::Vector3 q = this->wfc_basis_->getgpluskcar(ik, ig) + vector_potential / tpiba; + g_plus_k[3 * ig] = q.x; + g_plus_k[3 * ig + 1] = q.y; + g_plus_k[3 * ig + 2] = q.z; + const double norm = q.norm(); + g_plus_k[3 * npw + ig] = norm * tpiba; + g_plus_k[4 * npw + ig] = norm < 1e-8 ? 0.0 : tpiba / norm; + } + } FPTYPE *gk = g_plus_k.data(), *vq_tb = this->tabtpr->ptr; // vq_tb has dimension (ntype, nproj, GlobalV::NQX) @@ -151,6 +203,7 @@ void hamilt::Onsite_Proj_tools::cal_becp(int ik, } } this->current_ik = ik; + this->current_a_ = vector_potential; } // DEBUG: ONCE YOU CHECK vkb VALUES, YOU UNCOMMENT THE FOLLOWING LINE // for (int i = 0; i < vkb_size; i++) @@ -168,32 +221,52 @@ void hamilt::Onsite_Proj_tools::cal_becp(int ik, const char transa = 'C'; const char transb = 'N'; int npm_npol = npm * npol; - gemm_op()(transa, - transb, - this->nkb, - npm_npol, // nbands(occ)*npol - npw, - &ModuleBase::ONE, - this->ppcell_vkb, - npw, - ppsi, - npwx > 0 ? npwx : this->max_npw, - &ModuleBase::ZERO, - becp_tmp, - this->nkb); + if (npw == 0) + { + // An empty local PW partition contributes zero but must still join the pool reduction below. + setmem_complex_op()(becp_tmp, 0, size_becp_act); + } + else + { + gemm_op()(transa, + transb, + this->nkb, + npm_npol, // nbands(occ)*npol + npw, + &ModuleBase::ONE, + this->ppcell_vkb, + npw, + ppsi, + npwx > 0 ? npwx : this->max_npw, + &ModuleBase::ZERO, + becp_tmp, + this->nkb); + } if (this->device == base_device::GpuDevice) { - std::complex* h_becp = nullptr; - resmem_complex_h_op()(h_becp, size_becp_act); - syncmem_complex_d2h_op()(h_becp, becp_tmp, size_becp_act); - Parallel_Reduce::reduce_pool(h_becp, size_becp_act); - syncmem_complex_h2d_op()(becp_tmp, h_becp, size_becp_act); - delmem_complex_h_op()(h_becp); + if (host_becp == nullptr) + { + host_becp_.resize(size_becp_act); + host_becp = host_becp_.data(); + } + if (size_becp_act > 0) + { + syncmem_complex_d2h_op()(host_becp, becp_tmp, size_becp_act); + } + Parallel_Reduce::reduce_pool(host_becp, size_becp_act); + if (size_becp_act > 0) + { + syncmem_complex_h2d_op()(becp_tmp, host_becp, size_becp_act); + } } else { Parallel_Reduce::reduce_pool(becp_tmp, size_becp_act); + if (host_becp != nullptr && host_becp != becp_tmp && size_becp_act > 0) + { + std::copy(becp_tmp, becp_tmp + size_becp_act, host_becp); + } } // DEBUG: ONCE YOU CHECK becp VALUES, YOU UNCOMMENT THE FOLLOWING LINE // std::cout << "ik: " << ik << std::endl; @@ -205,12 +278,34 @@ void hamilt::Onsite_Proj_tools::cal_becp(int ik, } // explicit method instantiation -template -void hamilt::Onsite_Proj_tools::cal_becp( - int, int, std::complex*, const std::complex*, int); +template void hamilt::Onsite_Proj_tools::cal_becp(int, + int, + std::complex*, + const std::complex*, + int, + const ModuleBase::Vector3&, + std::complex*); +template void hamilt::Onsite_Proj_tools::refresh_table(); +template void hamilt::Onsite_Proj_tools::invalidate_proj(); +template void hamilt::Onsite_Proj_tools::cal_becp(int, + int, + std::complex*, + const std::complex*, + int); #if ((defined __CUDA) || (defined __ROCM)) -template -void hamilt::Onsite_Proj_tools::cal_becp( - int, int, std::complex*, const std::complex*, int); +template void hamilt::Onsite_Proj_tools::cal_becp(int, + int, + std::complex*, + const std::complex*, + int, + const ModuleBase::Vector3&, + std::complex*); +template void hamilt::Onsite_Proj_tools::refresh_table(); +template void hamilt::Onsite_Proj_tools::invalidate_proj(); +template void hamilt::Onsite_Proj_tools::cal_becp(int, + int, + std::complex*, + const std::complex*, + int); #endif diff --git a/source/source_pw/module_pwdft/CMakeLists.txt b/source/source_pw/module_pwdft/CMakeLists.txt index 2b0af1ec744..fbe33d10327 100644 --- a/source/source_pw/module_pwdft/CMakeLists.txt +++ b/source/source_pw/module_pwdft/CMakeLists.txt @@ -5,16 +5,12 @@ list( hamilt_pw.cpp pw_hybrid_nscf.cpp pw_hybrid_source.cpp - td_history_pw.cpp - td_pw.cpp op_pw_ekin.cpp - op_pw_ekin_td.cpp op_pw_veff.cpp projector_gradient.cpp velocity_workspace.cpp nonlocal_workspace.cpp op_pw_nl.cpp - op_pw_nl_td.cpp op_pw_meta.cpp op_pw_vel.cpp op_pw.cpp @@ -95,7 +91,7 @@ endif() if(BUILD_TESTING) if(ENABLE_MPI) - add_subdirectory(test) + add_subdirectory(unittests) add_subdirectory(kernels/test) endif() endif() diff --git a/source/source_pw/module_pwdft/hamilt_pw.cpp b/source/source_pw/module_pwdft/hamilt_pw.cpp index d3d284643f5..8b4a23de6cd 100644 --- a/source/source_pw/module_pwdft/hamilt_pw.cpp +++ b/source/source_pw/module_pwdft/hamilt_pw.cpp @@ -1,19 +1,19 @@ #include "hamilt_pw.h" #include "op_pw_ekin.h" -#include "op_pw_ekin_td.h" #include "op_pw_exx.h" #include "op_pw_meta.h" #include "op_pw_nl.h" -#include "op_pw_nl_td.h" #include "op_pw_proj.h" #include "op_pw_veff.h" #include "source_base/global_function.h" #include "source_base/global_variable.h" #include "source_base/parallel_reduce.h" +#include "source_estate/module_pot/pot_pcc.h" #include "source_hamilt/module_xc/general_exx_info.h" // for General_Exx_Info type #include "source_io/module_parameter/parameter.h" -#include "source_estate/module_pot/pot_pcc.h" +#include "source_pw/module_rt/op_pw_ekin_td.h" +#include "source_pw/module_rt/op_pw_nl_td.h" namespace hamilt { @@ -43,8 +43,7 @@ HamiltPW::HamiltPW(elecstate::Potential* pot_in, if (PARAM.inp.t_in_h) { // Operator* ekinetic = new Ekinetic> - Operator* ekinetic - = new Ekinetic>(tpiba2, gk2, wfc_basis->nks, wfc_basis->npwk_max); + Operator* ekinetic = new Ekinetic>(tpiba2, gk2, wfc_basis->nks, wfc_basis->npwk_max); if (this->ops == nullptr) { this->ops = ekinetic; @@ -87,7 +86,10 @@ HamiltPW::HamiltPW(elecstate::Potential* pot_in, { pot_register_in.push_back("surchem"); } - if (input.imp_sol == 2) { pot_register_in.push_back("sccs"); } + if (input.imp_sol == 2) + { + pot_register_in.push_back("sccs"); + } if (input.assume_isolated == "pcc_0d") { pot_register_in.push_back("pcc"); @@ -172,11 +174,8 @@ HamiltPW::HamiltPW(elecstate::Potential* pot_in, } if (PARAM.inp.sc_mag_switch || PARAM.inp.dft_plus_u) { - Operator* onsite_proj = new OnsiteProj>(isk, - ucell, - p_dftu, - PARAM.inp.sc_mag_switch, - (PARAM.inp.dft_plus_u > 0)); + Operator* onsite_proj + = new OnsiteProj>(isk, ucell, p_dftu, PARAM.inp.sc_mag_switch, (PARAM.inp.dft_plus_u > 0)); this->ops->add(onsite_proj); } if (exx_info && exx_info->cal_exx) @@ -214,7 +213,7 @@ HamiltPW::~HamiltPW() } template -void HamiltPW::bind_td_state(const Real* veff, const Real* vofk, const ModuleBase::Vector3& A_ha) +void HamiltPW::bind_td_state(const Real* veff, const ModuleBase::Vector3& A_ha) { Operator* op = this->ops; while (op != nullptr) @@ -223,10 +222,6 @@ void HamiltPW::bind_td_state(const Real* veff, const Real* vofk, cons { static_cast>*>(op)->set_veff(veff); } - else if (op->get_cal_type() == calculation_type::pw_meta) - { - static_cast>*>(op)->set_vk(vofk); - } else if (op->get_cal_type() == calculation_type::pw_ekinetic_td) { static_cast*>(op)->set_A_ha(A_ha); @@ -234,7 +229,8 @@ void HamiltPW::bind_td_state(const Real* veff, const Real* vofk, cons else if (op->get_cal_type() == calculation_type::pw_nonlocal) { TDNonlocalPW* td_nonlocal = dynamic_cast*>(op); - if (td_nonlocal != nullptr) td_nonlocal->set_A_ha(A_ha); + if (td_nonlocal != nullptr) + td_nonlocal->set_A_ha(A_ha); } op = op->next_op; } @@ -279,17 +275,7 @@ void HamiltPW::sPsi(const T* psi_in, // psi if (nbands == 1) { int inc = 1; - gemv_op()(transa, - npw, - this->ppcell->nkb, - &one, - this->vkb, - this->ppcell->vkbnc, - psi_in, - inc, - &zero, - becp, - inc); + gemv_op()(transa, npw, this->ppcell->nkb, &one, this->vkb, this->ppcell->vkbnc, psi_in, inc, &zero, becp, inc); } else { @@ -326,7 +312,7 @@ void HamiltPW::sPsi(const T* psi_in, // psi const int nh = atoms->ncpp.nh; T* qqc = nullptr; resmem_complex_op()(qqc, nh * nh, "Hamilt::qqc"); - std::vector qqc_host(nh*nh); + std::vector qqc_host(nh * nh); const double* qq_now_host = &this->ppcell->qq_nt.ptr[it * this->ppcell->nhm * this->ppcell->nhm]; for (int i = 0; i < nh; i++) @@ -366,17 +352,7 @@ void HamiltPW::sPsi(const T* psi_in, // psi if (nbands == 1) { const int inc = 1; - gemv_op()(transa, - npw, - this->ppcell->nkb, - &one, - this->vkb, - this->ppcell->vkbnc, - ps, - inc, - &one, - spsi, - inc); + gemv_op()(transa, npw, this->ppcell->nkb, &one, this->vkb, this->ppcell->vkbnc, ps, inc, &one, spsi, inc); } else { diff --git a/source/source_pw/module_pwdft/hamilt_pw.h b/source/source_pw/module_pwdft/hamilt_pw.h index 72158eadaf4..d7d93a9c8bd 100644 --- a/source/source_pw/module_pwdft/hamilt_pw.h +++ b/source/source_pw/module_pwdft/hamilt_pw.h @@ -43,7 +43,7 @@ class HamiltPW : public Hamilt /** @brief Bind local-potential buffers and Hartree vector potential for the same operation. * @note The caller must keep the buffers alive and restore endpoint state after propagation. */ - void bind_td_state(const Real* veff, const Real* vofk, const ModuleBase::Vector3& A_ha); + void bind_td_state(const Real* veff, const ModuleBase::Vector3& A_ha); void sPsi(const T* psi_in, // psi T* spsi, // spsi diff --git a/source/source_pw/module_pwdft/nonlocal_workspace.cpp b/source/source_pw/module_pwdft/nonlocal_workspace.cpp index 5530baef6a5..297f25e26ff 100644 --- a/source/source_pw/module_pwdft/nonlocal_workspace.cpp +++ b/source/source_pw/module_pwdft/nonlocal_workspace.cpp @@ -48,6 +48,7 @@ void NonlocalWorkspace::project(const T* vkb, const T* psi, const int const T zero(0, 0); if (npw == 0) { + // Empty PW partitions still supply zero coefficients to the collective projector reduction. const size_t count = static_cast(nkb) * bands; Zero()(becp_, 0, count); } @@ -115,6 +116,22 @@ void NonlocalWorkspace::apply(const UnitCell& cell, const pseudopot_c const size_t count = static_cast(nbasis) * bands / npol; Zero()(hpsi, 0, count); } + // Here bands counts spin-component columns, while nbasis includes all components of one orbital. + project_contract(cell, pp, basis, spin, bands, nbasis, npol, npw, vkb, psi); + if (pp.nkb > 0 && bands > 0 && npw > 0) + { + this->back_project(vkb, hpsi, npw, pp.vkbnc, nbasis / npol, pp.nkb, bands); + } + ModuleBase::timer::end("NonlocalWorkspace", "apply"); +} + + +template +void NonlocalWorkspace::project_contract(const UnitCell& cell, const pseudopot_cell_vnl& pp, + const ModulePW::PW_Basis_K& basis, int spin, + int bands, int nbasis, int npol, int npw, + const T* vkb, const T* psi) +{ if (pp.nkb > 0 && bands > 0) { const size_t count = static_cast(pp.nkb) * bands; @@ -144,15 +161,9 @@ void NonlocalWorkspace::apply(const UnitCell& cell, const pseudopot_c } } #endif - if (npw > 0) - { - this->contract(cell, pp, spin, npol, bands); - this->back_project(vkb, hpsi, npw, pp.vkbnc, nbasis / npol, pp.nkb, bands); - } + this->contract(cell, pp, spin, npol, bands); } - ModuleBase::timer::end("NonlocalWorkspace", "apply"); } - template class NonlocalWorkspace, base_device::DEVICE_CPU>; template class NonlocalWorkspace, base_device::DEVICE_CPU>; #if defined(__CUDA) || defined(__ROCM) diff --git a/source/source_pw/module_pwdft/nonlocal_workspace.h b/source/source_pw/module_pwdft/nonlocal_workspace.h index 5a659645353..6ff8ab467dc 100644 --- a/source/source_pw/module_pwdft/nonlocal_workspace.h +++ b/source/source_pw/module_pwdft/nonlocal_workspace.h @@ -37,6 +37,16 @@ class NonlocalWorkspace /** @brief Borrow the most recently computed projection coefficients. */ T* get_becp() const { return becp_; } + + /** @brief Project and contract on every pool rank, including empty PW partitions; bands counts spin-component columns. + * B uses [column][projector] and DB [projector][column]; both borrowed arrays are pool-reduced and valid until the next operation. + */ + void project_contract(const UnitCell& cell, const pseudopot_cell_vnl& pp, + const ModulePW::PW_Basis_K& basis, int spin, + int bands, int nbasis, int npol, int npw, + const T* vkb, const T* psi); + const T* projections() const { return becp_; } + const T* contracted() const { return ps_; } }; } // namespace hamilt #endif diff --git a/source/source_pw/module_pwdft/op_pw_meta.h b/source/source_pw/module_pwdft/op_pw_meta.h index 533eba97d1e..bb9ffbc21b3 100644 --- a/source/source_pw/module_pwdft/op_pw_meta.h +++ b/source/source_pw/module_pwdft/op_pw_meta.h @@ -53,8 +53,6 @@ class Meta> : public OperatorPW } const int * get_isk() const {return this->isk;} const Real* get_vk() const {return this->vk;} - /** @brief Select the borrowed endpoint or midpoint kinetic-energy-density potential. */ - void set_vk(const Real* potential) { this->vk = potential; } int get_vk_row() const {return this->vk_row;} int get_vk_col() const {return this->vk_col;} const ModulePW::PW_Basis_K* get_wfcpw() const diff --git a/source/source_pw/module_pwdft/op_pw_vel.cpp b/source/source_pw/module_pwdft/op_pw_vel.cpp index 4038442bbee..980720da9a0 100644 --- a/source/source_pw/module_pwdft/op_pw_vel.cpp +++ b/source/source_pw/module_pwdft/op_pw_vel.cpp @@ -281,12 +281,8 @@ void Velocity::act(const psi::Psi, Device>* ModuleBase::gemm_op()('C', 'N', nkb3, n_npwx, npw, &one, gradvkb_d, max_npw, psi0, max_npw, &zero, becp2_, nkb3); } - if (npol != 1) - { - ModuleBase::WARNING_QUIT("Velocity", "Non-collinear velocity is not supported."); - } // deeq stores energies in Ry; velocity uses Hartree atomic units like p. - this->contraction_.contract(*this->ucell, *this->ppcell, this->isk[this->ik], n_npwx, FPTYPE(0.5), *this->wfcpw, becp1_); + this->contraction_.contract(*this->ucell, *this->ppcell, this->isk[this->ik], n_npwx, npol, FPTYPE(0.5), *this->wfcpw, becp1_); if (npw == 0) { diff --git a/source/source_pw/module_pwdft/op_pw_vel.h b/source/source_pw/module_pwdft/op_pw_vel.h index 1c5096e2389..8730d89d1c3 100644 --- a/source/source_pw/module_pwdft/op_pw_vel.h +++ b/source/source_pw/module_pwdft/op_pw_vel.h @@ -30,14 +30,6 @@ class Velocity void init(const int ik_in); /** @brief Refresh momentum and projectors with a Hartree-unit vector potential. */ void init(const int ik_in, const ModuleBase::Vector3& vector_potential); - /** @brief Refresh borrowed spin and meta-GGA potential views before reuse. */ - void set_state(const int* isk, const FPTYPE* vtau, const int cols, const int rows) - { - this->isk = isk; - vtau_ = vtau; - vtau_col_ = cols; - vtau_row_ = rows; - } /** * @brief calculate \hat{v}|\psi> diff --git a/source/source_pw/module_pwdft/setup_pot.cpp b/source/source_pw/module_pwdft/setup_pot.cpp index 52761bb5270..4d4fd83e631 100644 --- a/source/source_pw/module_pwdft/setup_pot.cpp +++ b/source/source_pw/module_pwdft/setup_pot.cpp @@ -18,6 +18,7 @@ void pw::setup_pot(const int istep, pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi* kspw_psi, // electronic wave functions + psi::Psi, Device>* onsite_psi, // persistent double-precision mirror hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod @@ -67,12 +68,14 @@ void pw::setup_pot(const int istep, //---------------------------------------------------------- //! 4) Onsite projectors //---------------------------------------------------------- - if (inp.onsite_radius > 0) + const bool spinor_rt = inp.esolver_type == "tddft" && inp.nspin == 4; + // The RT observer owns endpoint projection setup, including spinor precision conversion. + if (inp.onsite_radius > 0 && !spinor_rt) { auto* onsite_p = projectors::OnsiteProjector::get_instance(); onsite_p->init(inp.orbital_dir, &ucell, - *(kspw_psi), + *onsite_psi, kv, *(pw_wfc), sf, @@ -125,6 +128,7 @@ template void pw::setup_pot, base_device::DEVICE_CPU>( pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi, base_device::DEVICE_CPU>* kspw_psi, // electronic wave functions + psi::Psi, base_device::DEVICE_CPU>* onsite_psi, hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod @@ -144,6 +148,7 @@ template void pw::setup_pot, base_device::DEVICE_CPU>( pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi, base_device::DEVICE_CPU>* kspw_psi, // electronic wave functions + psi::Psi, base_device::DEVICE_CPU>* onsite_psi, hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod @@ -164,6 +169,7 @@ template void pw::setup_pot, base_device::DEVICE_GPU>( pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi, base_device::DEVICE_GPU>* kspw_psi, // electronic wave functions + psi::Psi, base_device::DEVICE_GPU>* onsite_psi, hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod @@ -182,6 +188,7 @@ template void pw::setup_pot, base_device::DEVICE_GPU>( pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi, base_device::DEVICE_GPU>* kspw_psi, // electronic wave functions + psi::Psi, base_device::DEVICE_GPU>* onsite_psi, hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod diff --git a/source/source_pw/module_pwdft/setup_pot.h b/source/source_pw/module_pwdft/setup_pot.h index 6842159e261..d865f163b07 100644 --- a/source/source_pw/module_pwdft/setup_pot.h +++ b/source/source_pw/module_pwdft/setup_pot.h @@ -25,6 +25,7 @@ void setup_pot(const int istep, pseudopot_cell_vnl &ppcell, // non-local pseudopotentials VSep* vsep_cell, // U-1/2 method psi::Psi* kspw_psi, // electronic wave functions + psi::Psi, Device>* onsite_psi, // persistent double-precision mirror hamilt::HamiltBase* p_hamilt, // hamiltonian ModulePW::PW_Basis_K *pw_wfc, // pw for wfc const ModulePW::PW_Basis *pw_rhod, // pw for rhod diff --git a/source/source_pw/module_pwdft/td_history_pw.h b/source/source_pw/module_pwdft/td_history_pw.h deleted file mode 100644 index 5ebfdd90550..00000000000 --- a/source/source_pw/module_pwdft/td_history_pw.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef TD_HISTORY_PW_H -#define TD_HISTORY_PW_H - -#include "source_base/module_container/ATen/core/tensor.h" -#include "source_estate/module_pot/potential_new.h" -#include "source_psi/psi.h" - -#include - -namespace pw -{ - -/** @brief Non-owning device pointers to the smooth local potentials. */ -template -struct TDPotentialView -{ - const Real* veff; - const Real* vofk; -}; - -/** @brief Converged time-step history and predictor-corrector potential storage. */ -template -class TDHistoryPW -{ - public: - /** @brief Prepare storage after the potential grids have been updated. */ - void prepare(const elecstate::Potential& potential, const bool needs_ked); - - /** @brief Use the current potential for the predictor, then average with the saved potential. */ - TDPotentialView::type> prop_pot(elecstate::Potential& potential, - const bool needs_ked, - const bool corrector); - - /** @brief Save the converged state; the caller owns the convergence decision. */ - void save(const psi::Psi& current, elecstate::Potential& potential, const bool needs_ked); - - /** @brief Access the fixed origin of every corrector solve in the next step. */ - const psi::Psi& previous() const; - - private: - using Real = typename GetTypeReal::type; - std::unique_ptr> previous_; - ct::Tensor veff_prev_; - ct::Tensor veff_mid_; - ct::Tensor vofk_prev_; - ct::Tensor vofk_mid_; -}; - -} // namespace pw -#endif diff --git a/source/source_pw/module_pwdft/test/CMakeLists.txt b/source/source_pw/module_pwdft/unittests/CMakeLists.txt similarity index 98% rename from source/source_pw/module_pwdft/test/CMakeLists.txt rename to source/source_pw/module_pwdft/unittests/CMakeLists.txt index 91e0ce07bcc..6404f938a7e 100644 --- a/source/source_pw/module_pwdft/test/CMakeLists.txt +++ b/source/source_pw/module_pwdft/unittests/CMakeLists.txt @@ -3,13 +3,14 @@ abacus_disable_feature_definitions(__CUDA) abacus_disable_feature_definitions(__ROCM) abacus_disable_feature_definitions(__EXX) + addtest( TARGET MODULE_PW_pwdft_soc LIBS parameter SOURCES - soc_test.cpp + test_soc.cpp ../soc.cpp ../../../source_base/global_variable.cpp ../../../source_base/global_function.cpp @@ -35,7 +36,7 @@ addtest( base device SOURCES - dftu_base_test.cpp + test_dftu_base.cpp ../dftu_base.cpp ../dftu_base_io.cpp ../dftu_base_io_read.cpp @@ -83,7 +84,7 @@ addtest( device planewave SOURCES - structure_factor_test.cpp + test_stru_fac.cpp ../stru_fac.cpp ../../../source_cell/unitcell.cpp ../../../source_cell/unitcell_index.cpp diff --git a/source/source_pw/module_pwdft/test/dftu_base_test.cpp b/source/source_pw/module_pwdft/unittests/test_dftu_base.cpp similarity index 100% rename from source/source_pw/module_pwdft/test/dftu_base_test.cpp rename to source/source_pw/module_pwdft/unittests/test_dftu_base.cpp diff --git a/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp b/source/source_pw/module_pwdft/unittests/test_dftu_pw_tools.cpp similarity index 100% rename from source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp rename to source/source_pw/module_pwdft/unittests/test_dftu_pw_tools.cpp diff --git a/source/source_pw/module_pwdft/test/test_pw_hybrid_source.cpp b/source/source_pw/module_pwdft/unittests/test_pw_hybrid_source.cpp similarity index 100% rename from source/source_pw/module_pwdft/test/test_pw_hybrid_source.cpp rename to source/source_pw/module_pwdft/unittests/test_pw_hybrid_source.cpp diff --git a/source/source_pw/module_pwdft/test/soc_test.cpp b/source/source_pw/module_pwdft/unittests/test_soc.cpp similarity index 100% rename from source/source_pw/module_pwdft/test/soc_test.cpp rename to source/source_pw/module_pwdft/unittests/test_soc.cpp diff --git a/source/source_pw/module_pwdft/test/structure_factor_test.cpp b/source/source_pw/module_pwdft/unittests/test_stru_fac.cpp similarity index 100% rename from source/source_pw/module_pwdft/test/structure_factor_test.cpp rename to source/source_pw/module_pwdft/unittests/test_stru_fac.cpp diff --git a/source/source_pw/module_pwdft/velocity_workspace.cpp b/source/source_pw/module_pwdft/velocity_workspace.cpp index c7147c5594e..f9e2c7a7486 100644 --- a/source/source_pw/module_pwdft/velocity_workspace.cpp +++ b/source/source_pw/module_pwdft/velocity_workspace.cpp @@ -33,6 +33,7 @@ void VelocityWorkspace::contract(const UnitCell& cell, const pseudopot_cell_vnl& pp, const int spin, const int bands, + const int npol, const Real scale, const ModulePW::PW_Basis_K& basis, Complex* buffer) @@ -65,6 +66,7 @@ void VelocityWorkspace::contract(const UnitCell& cell, base_device::memory::set_memory_op()(output, 0, projection_elements); for (int component = 0; component < 4; ++component) { + // The ordinary overlap is packed separately from the three interleaved gradient overlaps. int sum = 0; int atom = 0; const int stride = component == 0 ? pp.nkb : 3 * pp.nkb; @@ -73,24 +75,45 @@ void VelocityWorkspace::contract(const UnitCell& cell, Complex* component_output = output + component * count; for (int type = 0; type < cell.ntype; ++type) { - nonlocal_pw_op()(nullptr, - cell.atoms[type].na, - bands, - cell.atoms[type].ncpp.nh, - sum, - atom, - spin, - stride, - pp.deeq.getBound2(), - pp.deeq.getBound3(), - pp.deeq.getBound4(), - pp.template get_deeq_data(), - component_output, - input); + // Both kernels advance sum and atom by reference. + if (npol == 2) + { + nonlocal_pw_op()(nullptr, + cell.atoms[type].na, + bands, + cell.atoms[type].ncpp.nh, + sum, + atom, + stride, + pp.deeq_nc.getBound2(), + pp.deeq_nc.getBound3(), + pp.deeq_nc.getBound4(), + pp.template get_deeq_nc_data(), + component_output, + input); + } + else + { + nonlocal_pw_op()(nullptr, + cell.atoms[type].na, + bands, + cell.atoms[type].ncpp.nh, + sum, + atom, + spin, + stride, + pp.deeq.getBound2(), + pp.deeq.getBound3(), + pp.deeq.getBound4(), + pp.template get_deeq_data(), + component_output, + input); + } } } if (scale != Real(1)) { + // Velocity contractions convert the Ry-valued D matrix to Hartree without changing the Hamiltonian's storage. const Complex factor(scale, 0); const std::int64_t max_chunk = std::numeric_limits::max(); for (std::int64_t offset = 0; offset < projection_elements;) diff --git a/source/source_pw/module_pwdft/velocity_workspace.h b/source/source_pw/module_pwdft/velocity_workspace.h index 7dd2665f63b..85a9b79d94d 100644 --- a/source/source_pw/module_pwdft/velocity_workspace.h +++ b/source/source_pw/module_pwdft/velocity_workspace.h @@ -22,11 +22,12 @@ class VelocityWorkspace /** @brief Reserve four input and four output projector blocks. */ Complex* prepare(const std::int64_t count); - /** @brief Reduce projections and contract D on their native device. */ + /** @brief Reduce four projection blocks and contract D on their native device; bands counts spin-component columns. */ void contract(const UnitCell& cell, const pseudopot_cell_vnl& pp, const int spin, const int bands, + const int npol, const Real scale, const ModulePW::PW_Basis_K& basis, Complex* buffer); diff --git a/source/source_pw/module_pwdft/vnl_pw.cpp b/source/source_pw/module_pwdft/vnl_pw.cpp index 233e0590bca..90a74bbcd8c 100644 --- a/source/source_pw/module_pwdft/vnl_pw.cpp +++ b/source/source_pw/module_pwdft/vnl_pw.cpp @@ -169,9 +169,10 @@ void pseudopot_cell_vnl::init(const UnitCell& ucell, resmem_cd_op()(c_deeq_nc, PARAM.inp.nspin * ucell.nat * this->nhm * this->nhm); resmem_cd_op()(c_qq_so, ntype * 4 * this->nhm * this->nhm); } + // Forces use double precision even when propagation uses float. + resmem_zd_op()(z_deeq_nc, PARAM.inp.nspin * ucell.nat * this->nhm * this->nhm); if (PARAM.globalv.has_double_data) { - resmem_zd_op()(z_deeq_nc, PARAM.inp.nspin * ucell.nat * this->nhm * this->nhm); resmem_zd_op()(z_qq_so, ntype * 4 * this->nhm * this->nhm); } resmem_dd_op()(d_deeq, PARAM.inp.nspin * ucell.nat * this->nhm * this->nhm); @@ -192,9 +193,9 @@ void pseudopot_cell_vnl::init(const UnitCell& ucell, resmem_ch_op()(c_deeq_nc, PARAM.inp.nspin * ucell.nat * this->nhm * this->nhm, "VNL::c_deeq_nc"); resmem_ch_op()(c_qq_so, ntype * 4 * this->nhm * this->nhm, "VNL::c_qq_so"); } + this->z_deeq_nc = this->deeq_nc.ptr; if (PARAM.globalv.has_double_data) { - this->z_deeq_nc = this->deeq_nc.ptr; this->z_qq_so = this->qq_so.ptr; } this->d_deeq = this->deeq.ptr; diff --git a/source/source_pw/module_pwdft/vnl_pw_deeq.cpp b/source/source_pw/module_pwdft/vnl_pw_deeq.cpp index 54ad733b274..681fa9dc414 100644 --- a/source/source_pw/module_pwdft/vnl_pw_deeq.cpp +++ b/source/source_pw/module_pwdft/vnl_pw_deeq.cpp @@ -1,14 +1,14 @@ -#include "vnl_pw.h" - -#include "source_io/module_parameter/parameter.h" #include "source_base/global_function.h" #include "source_base/global_variable.h" #include "source_base/math_ylmreal.h" -#include "source_base/timer.h" -#include "source_base/module_external/blas_connector.h" +#include "source_base/module_container/base/third_party/blas.h" #include "source_base/module_device/device.h" +#include "source_base/module_external/blas_connector.h" #include "source_base/parallel_reduce.h" +#include "source_base/timer.h" +#include "source_io/module_parameter/parameter.h" #include "source_pw/module_pwdft/kernels/vnl_op.h" +#include "vnl_pw.h" #include @@ -35,9 +35,7 @@ * @param rho_basis plane-wave basis for charge density FFT * @param cell unit cell (read-only, but passed by reference for compatibility) */ -void pseudopot_cell_vnl::cal_effective_D(const ModuleBase::matrix& veff, - const ModulePW::PW_Basis* rho_basis, - UnitCell& cell) +void pseudopot_cell_vnl::cal_effective_D(const ModuleBase::matrix& veff, const ModulePW::PW_Basis* rho_basis, UnitCell& cell) { ModuleBase::TITLE("pseudopot_cell_vnl", "cal_effective_D"); @@ -144,33 +142,19 @@ void pseudopot_cell_vnl::cal_effective_D(const ModuleBase::matrix& veff, { if (PARAM.globalv.has_float_data) { - castmem_d2s_h2d_op()(this->s_deeq, - this->deeq.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); - castmem_z2c_h2d_op()(this->c_deeq_nc, - this->deeq_nc.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); - } - if (PARAM.globalv.has_double_data) - { - syncmem_z2z_h2d_op()(this->z_deeq_nc, - this->deeq_nc.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + castmem_d2s_h2d_op()(this->s_deeq, this->deeq.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + castmem_z2c_h2d_op()(this->c_deeq_nc, this->deeq_nc.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); } - syncmem_d2d_h2d_op()(this->d_deeq, - this->deeq.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + // Keep the double-precision force view current in single-precision runs. + syncmem_z2z_h2d_op()(this->z_deeq_nc, this->deeq_nc.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + syncmem_d2d_h2d_op()(this->d_deeq, this->deeq.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); } else { if (PARAM.globalv.has_float_data) { - castmem_d2s_h2h_op()(this->s_deeq, - this->deeq.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); - castmem_z2c_h2h_op()(this->c_deeq_nc, - this->deeq_nc.ptr, - PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + castmem_d2s_h2h_op()(this->s_deeq, this->deeq.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); + castmem_z2c_h2h_op()(this->c_deeq_nc, this->deeq_nc.ptr, PARAM.inp.nspin * cell.nat * this->nhm * this->nhm); } // There's no need to synchronize double precision pointers while in a CPU environment. } @@ -263,23 +247,23 @@ void pseudopot_cell_vnl::newq(const ModuleBase::matrix& veff, const ModulePW::PW double* aux_ptr = reinterpret_cast(aux.c); BlasConnector::gemm(transb, - transa, - natom, - nij, - complex_npw, - fact, - aux_ptr, - complex_npw, - qg_ptr, - complex_npw, - zero, - deeaux.c, - nij); + transa, + natom, + nij, + complex_npw, + fact, + aux_ptr, + complex_npw, + qg_ptr, + complex_npw, + zero, + deeaux.c, + nij); // I'm not sure if this is correct for gamma_only if (rho_basis->gamma_only && rho_basis->ig_gge0 >= 0) { const double neg = -1.0; - dger_(&nij, &natom, &neg, qg_ptr, &complex_npw, aux_ptr, &complex_npw, deeaux.c, &nij); + container::BlasConnector::ger(nij, natom, neg, qg_ptr, complex_npw, aux_ptr, complex_npw, deeaux.c, nij); } for (int ia = 0; ia < natom; ia++) @@ -304,15 +288,15 @@ void pseudopot_cell_vnl::newq(const ModuleBase::matrix& veff, const ModulePW::PW } #ifdef __MPI - Parallel_Reduce::reduce_pool(deeq.ptr,deeq.getSize()); + Parallel_Reduce::reduce_pool(deeq.ptr, deeq.getSize()); #endif } /** * @brief Rotate deeq into deeq_nc for spin-orbit coupling case. * - * Uses the SOC rotation coefficients soc.fcoef to transform - * the spin-diagonal deeq into the full 2x2 spinor deeq_nc. + * Uses the SOC rotation coefficients soc.fcoef to transform the scalar + * and magnetic (x, y, z) components of deeq into the full 2x2 spinor deeq_nc. * * @param iat atom index * @param cell unit cell @@ -338,28 +322,24 @@ void pseudopot_cell_vnl::newd_so(const int& iat, UnitCell& cell) { for (int lh = 0; lh < upf->nh; lh++) { + const std::complex spin_uu = soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 0, is2, lh, jh); + const std::complex spin_dd = soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 1, is2, lh, jh); + const std::complex scalar_term = deeq(0, iat, kh, lh) * (spin_uu + spin_dd); + if (PARAM.globalv.domag) { - deeq_nc(ijs, iat, ih, jh) - += deeq(0, iat, kh, lh) - * (soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 0, is2, lh, jh) - + soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 1, is2, lh, jh)) - + deeq(1, iat, kh, lh) - * (soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 1, is2, lh, jh) - + soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 0, is2, lh, jh)) - + ModuleBase::NEG_IMAG_UNIT * deeq(2, iat, kh, lh) - * (soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 1, is2, lh, jh) - - soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 0, is2, lh, jh)) - + deeq(3, iat, kh, lh) - * (soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 0, is2, lh, jh) - - soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 1, is2, lh, jh)); + const std::complex spin_ud = soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 1, is2, lh, jh); + const std::complex spin_du = soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 0, is2, lh, jh); + const std::complex mag_x_term = deeq(1, iat, kh, lh) * (spin_ud + spin_du); + const std::complex mag_y_term + = ModuleBase::NEG_IMAG_UNIT * deeq(2, iat, kh, lh) * (spin_ud - spin_du); + const std::complex mag_z_term = deeq(3, iat, kh, lh) * (spin_uu - spin_dd); + + deeq_nc(ijs, iat, ih, jh) += scalar_term + mag_x_term + mag_y_term + mag_z_term; } else { - deeq_nc(ijs, iat, ih, jh) - += deeq(0, iat, kh, lh) - * (soc.fcoef(it, is1, 0, ih, kh) * soc.fcoef(it, 0, is2, lh, jh) - + soc.fcoef(it, is1, 1, ih, kh) * soc.fcoef(it, 1, is2, lh, jh)); + deeq_nc(ijs, iat, ih, jh) += scalar_term; } } } diff --git a/source/source_pw/module_rt/CMakeLists.txt b/source/source_pw/module_rt/CMakeLists.txt new file mode 100644 index 00000000000..50ed81fef19 --- /dev/null +++ b/source/source_pw/module_rt/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(module_rt_pw OBJECT + cn_solver_pw.cpp + td_orbital_ops.cpp + td_prop_pw.cpp + td_hamilt_pw.cpp + prop_cn_pw.cpp + prop_etrs_pw.cpp + td_history_pw.cpp + td_conserv_pw.cpp + td_endpoint_pw.cpp + td_pw.cpp + td_vel_pw.cpp + td_spin_pw.cpp + op_pw_ekin_td.cpp + op_pw_nl_td.cpp +) + +if(ENABLE_COVERAGE) + add_coverage(module_rt_pw) +endif() + +if(BUILD_TESTING) + add_subdirectory(unittests) +endif() diff --git a/source/source_pw/module_rt/cn_solver_pw.cpp b/source/source_pw/module_rt/cn_solver_pw.cpp new file mode 100644 index 00000000000..b3844e5cf9c --- /dev/null +++ b/source/source_pw/module_rt/cn_solver_pw.cpp @@ -0,0 +1,453 @@ +#include "source_pw/module_rt/cn_solver_pw.h" + +#include "source_base/module_device/memory_op.h" +#include "source_base/parallel_device.h" +#include "source_base/timer.h" +#include "source_base/tool_quit.h" +#include "source_basis/module_pw/pw_momentum.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" +#include "source_hsolver/module_linalg/orb_buffer.h" + +#include +#include +#include + +namespace hsolver +{ +namespace +{ + +struct LinearMethodName +{ + const char* name; + LinearMethod method; +}; + +constexpr LinearMethodName linear_method_names[] + = {{"bicgstab", LinearMethod::bicgstab}, {"cgs", LinearMethod::cgs}, {"gmres", LinearMethod::gmres}}; + +struct PWPrecondName +{ + const char* name; + PWPreconditioner preconditioner; +}; + +constexpr PWPrecondName pw_precond_names[] = {{"none", PWPreconditioner::none}, + {"kinetic", PWPreconditioner::kinetic}, + {"kinetic_recycle", PWPreconditioner::kinetic_recycle}, + {"kinetic_subspace", PWPreconditioner::kinetic_subspace}}; + +template +class ShiftedHOperator final : public LinearOperator +{ + public: + ShiftedHOperator(const HSOperator& op, const T coefficient, const int dim, const int npw, const int npol) + : op_(op), coefficient_(coefficient), dim_(dim), npw_(npw), npol_(npol) + { + } + void apply(const T* x, T* y, const int ld, const int nvec) const override + { + op_.hpsi(x, y, ld, nvec); + // Keep H zero on padding so the shifted operator retains only its identity term there. + if (npol_ == 2) + { + const OrbLayout layout{ld, npw_, npol_, nvec}; + zero_pad(y, layout); + } + linear_op().batch(ld, dim_, nvec, y, x, y, T(1), coefficient_, nullptr, nullptr, nullptr); + } + + private: + const HSOperator& op_; + const T coefficient_; + const int dim_; + const int npw_; + const int npol_; +}; + +} // namespace + +LinearMethod parse_linear_method(const std::string& name) +{ + for (const LinearMethodName& entry: linear_method_names) + { + if (name == entry.name) + { + return entry.method; + } + } + const std::string message = "Unsupported linear solver: " + name; + ModuleBase::WARNING_QUIT("CNSolverPW", message); + return LinearMethod::bicgstab; +} + +PWPreconditioner parse_pw_precond(const std::string& name) +{ + for (const PWPrecondName& entry: pw_precond_names) + { + if (name == entry.name) + { + return entry.preconditioner; + } + } + const std::string message = "Unsupported preconditioner: " + name; + ModuleBase::WARNING_QUIT("CNSolverPW", message); + return PWPreconditioner::kinetic; +} + +template +CNSolverPW::CNSolverPW(const ModulePW::PW_Basis_K& basis, + const CNControls& cn_ctrl, + int npol, + const std::vector& global_k, + const diag_comm_info& comm, + std::ostream& log) + : basis_(basis), comm_(comm), cn_ctrl_(cn_ctrl), npol_(npol), global_k_(global_k), algebra_(comm), log_(log) +{ + initialize(); +} + +template +void CNSolverPW::initialize() +{ + const char* method = nullptr; + for (const LinearMethodName& entry: linear_method_names) + { + if (cn_ctrl_.linear.solver == entry.method) + { + method = entry.name; + break; + } + } + if (method == nullptr) + { + ModuleBase::WARNING_QUIT("CNSolverPW", "Unsupported linear solver."); + return; + } + const char* preconditioner = nullptr; + for (const PWPrecondName& entry: pw_precond_names) + { + if (cn_ctrl_.preconditioner == entry.preconditioner) + { + preconditioner = entry.name; + break; + } + } + if (preconditioner == nullptr) + { + ModuleBase::WARNING_QUIT("CNSolverPW", "Unsupported preconditioner."); + return; + } + if (cn_ctrl_.linear.solver != LinearMethod::gmres) + { + // Ignore the GMRES-only option before creating solver state or reporting effective settings. + cn_ctrl_.linear.reconstruct = false; + } + linear_solver_.reset(new HSolverLinear(cn_ctrl_.linear, comm_)); + std::ostringstream info; + info << " PW RT-TDDFT linear solver: " << method << "; tolerance: " << std::scientific << std::setprecision(6) + << linear_solver_->tolerance() << "; maximum iterations: " << cn_ctrl_.linear.max_iterations + << "; restart: " << cn_ctrl_.linear.restart << '\n' + << " Preconditioner: " << preconditioner << "; CN initial guess: " << cn_ctrl_.cn_init + << "; residual reconstruction: " << cn_ctrl_.linear.reconstruct << '\n'; + log_ << info.str(); +} + +template +void CNSolverPW::prepare_buffers(const int nbands, const int nbasis) +{ + ModuleBase::timer::start("CNSolverPW", "prepare_buffers"); + using CtDevice = typename ct::PsiToContainer::type; + const ct::DeviceType device = ct::DeviceTypeToEnum::value; + const int64_t elements = static_cast(nbands) * nbasis; + const int64_t size = std::max(1, elements); + if (rhs_.NumElements() < size || rhs_.data_type() != ct::DataTypeToEnum::value || rhs_.device_type() != device) + { + rhs_ = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); + clean_ = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); + } + ModuleBase::timer::end("CNSolverPW", "prepare_buffers"); +} + +template +void CNSolverPW::update_precond(const int ik, + const int dim, + const T coefficient, + const ModuleBase::Vector3& momentum_shift) +{ + ModuleBase::timer::start("CNSolverPW", "update_precond"); + using CtDevice = typename ct::PsiToContainer::type; + const ct::DeviceType device = ct::DeviceTypeToEnum::value; + const int elements = std::max(1, dim); + if (inverse_kinetic_.NumElements() < elements || inverse_kinetic_.data_type() != ct::DataTypeToEnum::value + || inverse_kinetic_.device_type() != device) + { + inverse_kinetic_ = ct::Tensor(ct::DataTypeToEnum::value, device, {elements}); + } + std::vector inverse(dim, T(1)); + for (int ig = 0; ig < dim; ++ig) + { + // The two spin components share the same kinetic diagonal; padding keeps an identity preconditioner. + const int physical_g = npol_ == 2 ? ig % basis_.npwk_max : ig; + if (physical_g >= basis_.npwk[ik]) + { + continue; + } + const double kinetic = cn_ctrl_.kinetic_enabled ? ModulePW::shifted_kinetic(basis_, ik, physical_g, momentum_shift) : 0.0; + inverse[ig] = T(1) / (T(1) + coefficient * static_cast(kinetic)); + } + if (dim > 0) + { + base_device::memory::synchronize_memory_op()(inverse_kinetic_.template data(), + inverse.data(), + dim); + } + ModuleBase::timer::end("CNSolverPW", "update_precond"); +} + +template +bool CNSolverPW::tracks_state() const +{ + return cn_ctrl_.preconditioner == PWPreconditioner::kinetic_recycle || cn_ctrl_.linear.reconstruct; +} + +template +void CNSolverPW::prepare_sequence(int nk, int ld, int bands, double dt, int step, int iteration) +{ + if (!tracks_state()) + { + return; + } + const bool reset = states_.size() != static_cast(nk) || dt != sequence_.dt || ld != sequence_.ld || bands != sequence_.bands + || step < sequence_.step || (step == sequence_.step && iteration <= sequence_.iteration); + if (reset) + { + states_.clear(); + states_.resize(nk); + } + sequence_.dt = dt; + sequence_.ld = ld; + sequence_.bands = bands; + sequence_.step = step; + sequence_.iteration = iteration; +} + +template +void CNSolverPW::invalidate_basis() +{ + for (KPointState& state: states_) + { + state.response.clear(); + state.solve_count = 0; + state.independent_step = -1; + } +} + +template +bool CNSolverPW::require_audit(int step, KPointState* state) const +{ + if (!cn_ctrl_.linear.reconstruct) + { + return true; + } + constexpr unsigned int audit_period = 16; + const bool required = state->solve_count % audit_period == 0 || state->independent_step == step; + ++state->solve_count; + return required; +} + +template +void CNSolverPW::retry_kinetic(const LinearOperator& op, + T* current, + const BatchLayout& batch, + LinearSolveResult* result) +{ + const int remaining_iter = cn_ctrl_.linear.max_iterations - result->iterations; + const T* inverse = inverse_kinetic_.template data(); + const LinearLowRank diagonal(algebra_, inverse, batch.dim); + const T* rhs = rhs_.template data(); + LinearSolveResult retry + = linear_solver_->solve(op, diagonal, batch.ld, batch.bands, batch.dim, current, rhs, nullptr, true, remaining_iter, false); + retry.iterations += result->iterations; + retry.restarts += result->restarts; + retry.operator_calls += result->operator_calls; + retry.operator_columns += result->operator_columns; + retry.true_checks += result->true_checks; + retry.reconstruction_fallbacks += result->reconstruction_fallbacks; + *result = retry; +} + +template +void CNSolverPW::update_state(KPointState* state, + const SolveDetails& details, + int step, + const BatchLayout& batch, + const T* current) +{ + if (!state) + { + return; + } + if (details.retried || details.linear.reconstruction_fallbacks > 0) + { + state->response.clear(); + } + if (details.linear.reconstruction_fallbacks > 0) + { + state->independent_step = step; + } + if (cn_ctrl_.preconditioner == PWPreconditioner::kinetic_recycle && details.projected + && details.linear.status == LinearSolveStatus::converged && details.linear.reconstruction_fallbacks == 0 && !details.retried) + { + const T* seed = projection_.seed(); + const T* residual = projection_.residual(); + const double tolerance = linear_solver_->tolerance(); + state->response.update(algebra_, batch.ld, batch.dim, batch.bands, current, seed, residual, tolerance, &response_workspace_); + } +} + +template +typename CNSolverPW::SolveDetails CNSolverPW::solve_kpoint(const LinearOperator& op, + const T* previous, + T* current, + const BatchLayout& batch, + int step, + int iteration, + KPointState* state) +{ + SolveDetails details; + const T* rhs = rhs_.template data(); + const bool need_projection = (cn_ctrl_.cn_init && iteration == 1) || cn_ctrl_.preconditioner == PWPreconditioner::kinetic_recycle + || cn_ctrl_.preconditioner == PWPreconditioner::kinetic_subspace; + details.projected = need_projection && projection_.prepare(algebra_, batch.ld, batch.dim, batch.bands, previous, rhs); + const T* initial_residual = nullptr; + if (cn_ctrl_.cn_init && iteration == 1 && details.projected) + { + const T* seed = projection_.seed(); + if (batch.dim > 0) + { + base_device::memory::synchronize_memory_2d_op()(current, batch.ld, seed, batch.ld, batch.dim, batch.bands); + } + initial_residual = projection_.residual(); + details.cn_initial = true; + } + const bool force_check = require_audit(step, state); + const T* inverse = cn_ctrl_.preconditioner == PWPreconditioner::none ? nullptr : inverse_kinetic_.template data(); + LinearLowRank preconditioner(algebra_, inverse, batch.dim); + if (cn_ctrl_.preconditioner == PWPreconditioner::kinetic_subspace && details.projected) + { + const T* image = projection_.image(); + const LinearSmallLU& factor = projection_.factor(); + preconditioner.prepare_subspace(batch.ld, batch.bands, previous, image, factor, &correction_workspace_); + } + else if (cn_ctrl_.preconditioner == PWPreconditioner::kinetic_recycle && state->response.rank() > 0) + { + const int rank = state->response.rank(); + const T* directions = state->response.directions(); + const T* images = state->response.images(); + preconditioner.prepare_response(batch.ld, rank, directions, images, &correction_workspace_); + } + details.coarse_rank = preconditioner.rank(); + details.linear + = linear_solver_->solve(op, preconditioner, batch.ld, batch.bands, batch.dim, current, rhs, initial_residual, force_check); + if (details.linear.status != LinearSolveStatus::converged && details.coarse_rank > 0 + && details.linear.iterations < cn_ctrl_.linear.max_iterations) + { + retry_kinetic(op, current, batch, &details.linear); + details.retried = true; + } + update_state(state, details, step, batch, current); + return details; +} + +template +void CNSolverPW::report_solve(const SolveDetails& details, int ik, int step, int iteration) const +{ + const LinearSolveResult& result = details.linear; + const int evolution_step = step + 1; + std::ostringstream record; + record << std::scientific << std::setprecision(6) << " PW RT-TDDFT linear solve: evolution_step=" << evolution_step + << " scf_iter=" << iteration << " global_k=" << global_k_.at(ik) + 1 << '\n' + << " iterations=" << result.iterations << " restarts=" << result.restarts << " operator_calls=" << result.operator_calls + << " operator_columns=" << result.operator_columns << " pre_orth_residual=" << result.max_residual + << " residual_kind=" << (result.reconstructed ? "reconstructed" : "independent") << " true_checks=" << result.true_checks << '\n' + << " reconstruction_fallbacks=" << result.reconstruction_fallbacks << " coarse_rank=" << details.coarse_rank + << " kinetic_retry=" << details.retried << " cn_projected=" << details.projected << " cn_initial=" << details.cn_initial << '\n'; + log_ << record.str(); +} + +template +void CNSolverPW::solve(HSOperator& op, + const psi::Psi& previous, + psi::Psi* current, + const double dt, + const ModuleBase::Vector3& momentum_shift, + const int istep, + const int iter, + const bool detailed_output) +{ + ModuleBase::timer::start("CNSolverPW", "solve"); + const int bands = current->get_nbands(); + const int ld = current->get_nbasis(); + const int nk = current->get_nk(); + prepare_buffers(bands, ld); + prepare_sequence(nk, ld, bands, dt, istep, iter); + T* rhs = rhs_.template data(); + // H is stored in Rydberg; CN includes the conversion to Hartree. + const T coefficient(0.0, dt / 4.0); + const T rhs_coefficient = -coefficient; + for (int ik = 0; ik < nk; ++ik) + { + op.update_k(ik); + current->fix_k(ik); + previous.fix_k(ik); + const int npw = current->get_ngk(ik); + // A spinor spans both npwx-strided blocks, including their explicitly zeroed padding. + const int dim = npol_ == 2 ? ld : npw; + KPointState* state = tracks_state() ? &states_[ik] : nullptr; + const ShiftedHOperator rhs_op(op, rhs_coefficient, dim, npw, npol_); + const ShiftedHOperator lhs_op(op, coefficient, dim, npw, npol_); + const OrbLayout layout{ld, npw, npol_, bands}; + const T* previous_data = clean_orbs(previous.get_pointer(), layout, &clean_); + T* current_data = current->get_pointer(); + if (npol_ == 2) + { + zero_pad(current_data, layout); + } + rhs_op.apply(previous_data, rhs, ld, bands); + if (cn_ctrl_.preconditioner != PWPreconditioner::none) + { + update_precond(ik, dim, coefficient, momentum_shift); + } + const BatchLayout batch{ld, dim, bands}; + const SolveDetails details = solve_kpoint(lhs_op, previous_data, current_data, batch, istep, iter, state); + if (detailed_output && log_.good()) + { + report_solve(details, ik, istep, iter); + } + if (details.linear.status != LinearSolveStatus::converged) + { + const LinearSolveResult& result = details.linear; + std::ostringstream message; + const int evolution_step = istep + 1; + std::string band_label = "unknown"; + if (result.failed_band >= 0) + { + band_label = std::to_string(result.failed_band + 1); + } + message << "PW RT-TDDFT linear solve failed at electronic evolution step " << evolution_step << ", SCF iteration " << iter + << ", global_k=" << global_k_.at(ik) + 1 << ", band " << band_label << ", after " << result.iterations + << " iterations: " << linear_status_name(result.status) << "; residual = " << result.max_residual; + ModuleBase::WARNING_QUIT("CNSolverPW", message.str()); + } + } + ModuleBase::timer::end("CNSolverPW", "solve"); +} + +template class CNSolverPW, base_device::DEVICE_CPU>; +template class CNSolverPW, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class CNSolverPW, base_device::DEVICE_GPU>; +template class CNSolverPW, base_device::DEVICE_GPU>; +#endif +} // namespace hsolver diff --git a/source/source_hsolver/hsolver_pw_tddft.h b/source/source_pw/module_rt/cn_solver_pw.h similarity index 55% rename from source/source_hsolver/hsolver_pw_tddft.h rename to source/source_pw/module_rt/cn_solver_pw.h index 53f882c1915..06609d8fdd2 100644 --- a/source/source_hsolver/hsolver_pw_tddft.h +++ b/source/source_pw/module_rt/cn_solver_pw.h @@ -1,13 +1,12 @@ -#ifndef HSOLVER_PW_TDDFT_H -#define HSOLVER_PW_TDDFT_H +#ifndef HSOLVER_CN_SOLVER_PW_H +#define HSOLVER_CN_SOLVER_PW_H #include "source_base/matrix.h" #include "source_basis/module_pw/pw_basis_k.h" -#include "source_hsolver/cn_subspace.h" #include "source_hsolver/hs_operator.h" -#include "source_hsolver/hsolver_linear.h" -#include "source_hsolver/linear_low_rank.h" -#include "source_hsolver/orthonormal.h" +#include "source_hsolver/module_linalg/cn_subspace.h" +#include "source_hsolver/module_linalg/hsolver_linear.h" +#include "source_hsolver/module_linalg/linear_low_rank.h" #include "source_psi/psi.h" #include @@ -25,37 +24,30 @@ enum class PWPreconditioner kinetic_subspace }; -/** @brief Numerical and propagation options, resolved once at the input boundary. */ -struct PWLinearOptions +/** @brief Crank-Nicolson linear solve and preconditioner controls. */ +struct CNControls { - OrthMethod orthonormal = OrthMethod::cholesky; - LinearSolveOptions linear; + LinearControls linear; PWPreconditioner preconditioner = PWPreconditioner::kinetic; bool cn_init = false; bool kinetic_enabled = true; - bool out_stat = false; - std::vector global_k_indices; ///< Required zero-based global index for every local k point. }; LinearMethod parse_linear_method(const std::string& name); -/** @brief Independent maxima over all SCF iterations and local k points in one electronic step. - * Values are replicated within each pool and reduced across pools for step-end output. - * The before and after maxima need not come from the same correction. - */ -struct TDOrthStats -{ - double before = 0.0; - double after = 0.0; -}; PWPreconditioner parse_pw_precond(const std::string& name); -/** @brief PW Crank-Nicolson solves and endpoint Hamiltonian expectations. */ +/** @brief PW Crank-Nicolson numerical solves with fixed previous-step orbitals. */ template -class HSolverPWTDDFT +class CNSolverPW { public: - /** @brief Configure propagation using typed, explicit solver options. */ - HSolverPWTDDFT(const ModulePW::PW_Basis_K& basis, const PWLinearOptions& options, const diag_comm_info& comm, std::ostream& log); + /** @brief Configure propagation with explicit numerical controls and orbital layout. */ + CNSolverPW(const ModulePW::PW_Basis_K& basis, + const CNControls& cn_ctrl, + int npol, + const std::vector& global_k, + const diag_comm_info& comm, + std::ostream& log); /** @brief Invalidate basis-dependent history and restart independent residual checks without releasing buffers. * Call on every rank in the pool after changing the basis or its distribution, including @@ -63,19 +55,6 @@ class HSolverPWTDDFT * updates and ionic motion at fixed basis do not require this notification. */ void invalidate_basis(); - /** @brief Reset diagnostics without invalidating preconditioner history. */ - void reset_orth_stats(); - /** @brief Correct initial orbitals when needed; return whether this pool changed any orbital. */ - bool correct_initial(psi::Psi* current, int iter); - /** @brief Check the converged initial state once; finite orthogonality errors are diagnostic only. */ - void check_initial(const psi::Psi& current, int iter); - /** @brief Occupation-weighted electron count for the local k-point pool. */ - double wave_electrons(const ModuleBase::matrix& occupations) const; - const TDOrthStats& orth_stats() const - { - return orth_stats_; - } - /** @brief Propagate from the fixed previous step, retaining the current iterate as the initial guess. * @param dt Electronic time step in Hartree atomic units. * @param momentum_shift Propagation vector potential in Hartree atomic units (inverse Bohr). @@ -91,12 +70,6 @@ class HSolverPWTDDFT const int iter, const bool detailed_output); - /** @brief Evaluate band expectations after the caller restores the endpoint Hamiltonian. */ - void cal_band_energy(HSOperator& op, const psi::Psi& current, ModuleBase::matrix* energies); - - /** @brief Return the pool-reduced, column-major Psi-adjoint H Psi for one local k point. */ - std::vector> cal_eij(HSOperator& op, const psi::Psi& current, const int ik); - private: using Real = typename GetTypeReal::type; struct KPointState @@ -113,7 +86,7 @@ class HSolverPWTDDFT int ld = -1; int bands = -1; }; - struct SolveBatch + struct BatchLayout { int ld; int dim; @@ -129,20 +102,17 @@ class HSolverPWTDDFT }; const ModulePW::PW_Basis_K& basis_; const diag_comm_info comm_; - PWLinearOptions options_; + CNControls cn_ctrl_; + const int npol_; + const std::vector global_k_; + ct::Tensor clean_; LinearAlgebra algebra_; - Orthonormal orthonormal_; - TDOrthStats orth_stats_; - std::vector> orth_norms_; std::ostream& log_; - unsigned int warned_events_ = 0; CNSubspace projection_; std::vector states_; SequenceState sequence_; std::unique_ptr> linear_solver_; - LinearWorkspace band_products_; ct::Tensor rhs_; - ct::Tensor hpsi_; ct::Tensor inverse_kinetic_; ct::Tensor response_workspace_; ct::Tensor correction_workspace_; @@ -154,18 +124,15 @@ class HSolverPWTDDFT SolveDetails solve_kpoint(const LinearOperator& op, const T* previous, T* current, - const SolveBatch& batch, + const BatchLayout& batch, int step, int iteration, KPointState* state); - void retry_kinetic(const LinearOperator& op, T* current, const SolveBatch& batch, LinearSolveResult* result); - void update_state(KPointState* state, const SolveDetails& details, int step, const SolveBatch& batch, const T* current); + void retry_kinetic(const LinearOperator& op, T* current, const BatchLayout& batch, LinearSolveResult* result); + void update_state(KPointState* state, const SolveDetails& details, int step, const BatchLayout& batch, const T* current); void report_solve(const SolveDetails& details, int ik, int step, int iteration) const; void prepare_buffers(const int nbands, const int nbasis); void update_precond(const int ik, const int dim, const T coefficient, const ModuleBase::Vector3& momentum_shift); - void correct_orbitals(T* current, int ld, int dim, int bands, int ik, int istep, int iter, bool detailed_output); - void record_orth(const OrthResult& result, int ik, int istep, int iter); - void report_orth_warning(const OrthResult& result, int ik, int istep, int iter); }; } // namespace hsolver diff --git a/source/source_pw/module_pwdft/op_pw_ekin_td.cpp b/source/source_pw/module_rt/op_pw_ekin_td.cpp similarity index 98% rename from source/source_pw/module_pwdft/op_pw_ekin_td.cpp rename to source/source_pw/module_rt/op_pw_ekin_td.cpp index f604ea3d9c0..602e41bf0c8 100644 --- a/source/source_pw/module_pwdft/op_pw_ekin_td.cpp +++ b/source/source_pw/module_rt/op_pw_ekin_td.cpp @@ -1,4 +1,4 @@ -#include "source_pw/module_pwdft/op_pw_ekin_td.h" +#include "source_pw/module_rt/op_pw_ekin_td.h" #include "source_base/module_device/memory_op.h" #include "source_base/timer.h" diff --git a/source/source_pw/module_pwdft/op_pw_ekin_td.h b/source/source_pw/module_rt/op_pw_ekin_td.h similarity index 89% rename from source/source_pw/module_pwdft/op_pw_ekin_td.h rename to source/source_pw/module_rt/op_pw_ekin_td.h index a02663a5011..e0d06b73dfd 100644 --- a/source/source_pw/module_pwdft/op_pw_ekin_td.h +++ b/source/source_pw/module_rt/op_pw_ekin_td.h @@ -1,9 +1,9 @@ #ifndef OP_PW_EKIN_TD_H #define OP_PW_EKIN_TD_H -#include "op_pw.h" #include "source_base/module_container/ATen/core/tensor.h" #include "source_basis/module_pw/pw_basis_k.h" +#include "source_pw/module_pwdft/op_pw.h" namespace hamilt { @@ -16,7 +16,10 @@ class TDEkineticPW : public OperatorPW public: /** @brief Bind the vector potential in Hartree atomic units before init(). */ - void set_A_ha(const ModuleBase::Vector3& A) { A_ha_ = A; } + void set_A_ha(const ModuleBase::Vector3& A) + { + A_ha_ = A; + } TDEkineticPW(const ModulePW::PW_Basis_K* wfc_basis_in); virtual ~TDEkineticPW(); diff --git a/source/source_pw/module_pwdft/op_pw_nl_td.cpp b/source/source_pw/module_rt/op_pw_nl_td.cpp similarity index 98% rename from source/source_pw/module_pwdft/op_pw_nl_td.cpp rename to source/source_pw/module_rt/op_pw_nl_td.cpp index a2856e3b68a..08b2953a15a 100644 --- a/source/source_pw/module_pwdft/op_pw_nl_td.cpp +++ b/source/source_pw/module_rt/op_pw_nl_td.cpp @@ -1,4 +1,4 @@ -#include "op_pw_nl_td.h" +#include "source_pw/module_rt/op_pw_nl_td.h" #include "source_base/timer.h" #include "source_base/tool_quit.h" diff --git a/source/source_pw/module_pwdft/op_pw_nl_td.h b/source/source_pw/module_rt/op_pw_nl_td.h similarity index 97% rename from source/source_pw/module_pwdft/op_pw_nl_td.h rename to source/source_pw/module_rt/op_pw_nl_td.h index ad3756c6057..9e8b35ac116 100644 --- a/source/source_pw/module_pwdft/op_pw_nl_td.h +++ b/source/source_pw/module_rt/op_pw_nl_td.h @@ -1,8 +1,8 @@ #ifndef OP_PW_NL_TD_H #define OP_PW_NL_TD_H -#include "op_pw.h" #include "source_pw/module_pwdft/nonlocal_workspace.h" +#include "source_pw/module_pwdft/op_pw.h" #include "source_pw/module_pwdft/vnl_pw.h" namespace hamilt diff --git a/source/source_pw/module_rt/prop_cn_pw.cpp b/source/source_pw/module_rt/prop_cn_pw.cpp new file mode 100644 index 00000000000..92a5b2d0312 --- /dev/null +++ b/source/source_pw/module_rt/prop_cn_pw.cpp @@ -0,0 +1,64 @@ +#include "source_pw/module_rt/prop_cn_pw.h" + +#include "source_base/kernels/math_kernel_op.h" + +namespace pw +{ +template +CNPropPW::CNPropPW(const ModulePW::PW_Basis_K& basis, + const hsolver::CNControls& cn_ctrl, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log) + : solver_(basis, cn_ctrl, npol, global_k, comm, log) +{ +} + +template +void CNPropPW::invalidate_basis() +{ + solver_.invalidate_basis(); +} + +template +void CNPropPW::evolve(TDHamiltPW& hamilt, + const TDHistoryPW& history, + elecstate::Potential& potential, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) +{ + using Real = typename T::value_type; + const Real* veff = potential.template get_veff_smooth_data(); + if (scf_iter > 1) + { + const ModuleBase::matrix& shape = potential.get_veff_smooth(); + const int size = shape.nr * shape.nc; + hsolver::linear_buffer(&veff_mid_, size); + Real* buffer = veff_mid_.template data(); + const Real* previous = history.left_potential(); + ModuleBase::vector_add_vector_op()(size, buffer, previous, Real(0.5), veff, Real(0.5)); + veff = buffer; + } + + ModuleBase::Vector3 vecpot_ha(0, 0, 0); + if (field.gauge() == 1) + { + vecpot_ha = field.A_prop_ha(); + } + + hamilt.bind(veff, vecpot_ha); + const psi::Psi& previous = history.previous(); + const double dt = field.interval_dt_ha(); + solver_.solve(hamilt, previous, current, dt, vecpot_ha, elec_step, scf_iter, log_detail); +} +template class CNPropPW, base_device::DEVICE_CPU>; +template class CNPropPW, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class CNPropPW, base_device::DEVICE_GPU>; +template class CNPropPW, base_device::DEVICE_GPU>; +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/prop_cn_pw.h b/source/source_pw/module_rt/prop_cn_pw.h new file mode 100644 index 00000000000..2c3b8a745ed --- /dev/null +++ b/source/source_pw/module_rt/prop_cn_pw.h @@ -0,0 +1,39 @@ +#ifndef PW_PROP_CN_PW_H +#define PW_PROP_CN_PW_H +#include "source_pw/module_rt/cn_solver_pw.h" +#include "source_pw/module_rt/td_prop_pw.h" + +namespace pw +{ +template +class CNPropPW final : public PWProp +{ + private: + hsolver::CNSolverPW solver_; + ct::Tensor veff_mid_; + + public: + CNPropPW(const ModulePW::PW_Basis_K& basis, + const hsolver::CNControls& cn_ctrl, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log); + void begin_trial() override + { + } + void discard_trial() override + { + } + void invalidate_basis() override; + void evolve(TDHamiltPW& hamilt, + const TDHistoryPW& history, + elecstate::Potential& potential, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) override; +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/prop_etrs_pw.cpp b/source/source_pw/module_rt/prop_etrs_pw.cpp new file mode 100644 index 00000000000..5fbe94452fc --- /dev/null +++ b/source/source_pw/module_rt/prop_etrs_pw.cpp @@ -0,0 +1,150 @@ +#include "source_pw/module_rt/prop_etrs_pw.h" + +#include "source_base/parallel_device.h" +#include "source_base/tool_quit.h" + +#include +#include + +namespace pw +{ +template +ETRSPropPW::ETRSPropPW(const hsolver::ExpControls& exp_ctrl, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log) + : pool_comm_(comm), npol_(npol), global_k_(global_k), log_(log) +{ + exponential_ = hsolver::make_exp_action(exp_ctrl, comm); + log_ << " PW RT-TDDFT propagator: ETRS; exponential: "; + if (exp_ctrl.expansion == hsolver::ExpMethod::taylor) + { + log_ << "taylor; order=" << exp_ctrl.taylor_order << "; predictor=shared powers\n"; + } + else + { + const double rel_tol = exponential_->rel_tol(); + log_ << "lanczos; tolerance=" << rel_tol << "; maximum dimension=" << exp_ctrl.krylov_max << '\n'; + } +} + +template +void ETRSPropPW::begin_trial() +{ + half_ready_ = false; +} + +template +void ETRSPropPW::discard_trial() +{ + half_ready_ = false; +} + +template +void ETRSPropPW::invalidate_basis() +{ + half_ready_ = false; +} + +template +void ETRSPropPW::report(const hsolver::ExpResult& result, int ik, int elec_step, int scf_iter, bool log_detail) const +{ + std::ostringstream text; + text << " PW ETRS exponential: step=" << elec_step << " scf_iter=" << scf_iter << " global_k=" << global_k_.at(ik) + 1 + << " order_or_dimension=" << result.order_or_dim << " operator_calls=" << result.hpsi_calls + << " operator_columns=" << result.hpsi_cols << " subdivisions=" << result.bisect_count + << " reorthogonalizations=" << result.reorth_count; + if (result.has_err_est) + { + text << " estimated_error=" << result.rel_err_est; + } + if (log_detail) + { + log_ << text.str() << '\n'; + } + if (result.state != hsolver::ExpState::success) + { + text << " failed_band=" << result.failed_band + 1 << "; reduce td_dt or adjust exponential controls."; + const std::string message = text.str(); + // stdout is disabled on non-world-root ranks; report from the failing pool. + if (pool_comm_.rank == 0) + { + std::cerr << message << std::endl; + } +#ifdef __MPI + // Flush the pool root's diagnostic before any peer can terminate the MPI job. + double diag_sent = 1.0; + Parallel_Common::bcast_data(&diag_sent, 1, pool_comm_.comm, 0); +#endif + ModuleBase::WARNING_QUIT("ETRSPropPW", message); + } +} + +template +void ETRSPropPW::evolve(TDHamiltPW& hamilt, + const TDHistoryPW& history, + elecstate::Potential& potential, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) +{ + using Real = typename T::value_type; + const bool predictor = scf_iter == 1; + const psi::Psi& previous = history.previous(); + const int ld = current->get_nbasis(); + const int bands = current->get_nbands(); + const int64_t stride = static_cast(ld) * bands; + if (predictor) + { + const int64_t size = stride * current->get_nk(); + if (half_psi_.NumElements() < size) + { + // Release obsolete storage before allocating a larger half-step buffer. + half_psi_ = ct::Tensor(); + } + hsolver::linear_buffer(&half_psi_, size); + left_gen_ = history.generation(); + hamilt.bind(history.left_potential(), field.A_left_ha()); + } + else + { + if (!half_ready_ || left_gen_ != history.generation()) + { + ModuleBase::WARNING_QUIT("ETRSPropPW", "Missing left half-step for the current trial."); + } + const Real* endpoint = potential.template get_veff_smooth_data(); + hamilt.bind(endpoint, field.A_right_ha()); + } + const double alpha = field.interval_dt_ha() / 4.0; + for (int ik = 0; ik < current->get_nk(); ++ik) + { + hamilt.update_k(ik); + current->fix_k(ik); + previous.fix_k(ik); + const hsolver::OrbLayout layout{ld, current->get_ngk(ik), npol_, bands}; + T* output = current->get_pointer(); + T* half = half_psi_.template data() + ik * stride; + hsolver::ExpResult result; + if (predictor) + { + const T* input = previous.get_pointer(); + result = exponential_->apply_pair(hamilt, layout, alpha, input, half, output); + } + else + { + result = exponential_->apply(hamilt, layout, alpha, half, output); + } + report(result, ik, elec_step, scf_iter, log_detail); + } + half_ready_ = true; +} +template class ETRSPropPW, base_device::DEVICE_CPU>; +template class ETRSPropPW, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class ETRSPropPW, base_device::DEVICE_GPU>; +template class ETRSPropPW, base_device::DEVICE_GPU>; +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/prop_etrs_pw.h b/source/source_pw/module_rt/prop_etrs_pw.h new file mode 100644 index 00000000000..2e06f9dc0c2 --- /dev/null +++ b/source/source_pw/module_rt/prop_etrs_pw.h @@ -0,0 +1,42 @@ +#ifndef PW_PROP_ETRS_PW_H +#define PW_PROP_ETRS_PW_H +#include "source_hsolver/diag_comm_info.h" +#include "source_hsolver/module_linalg/exp_action.h" +#include "source_pw/module_rt/td_prop_pw.h" + +namespace pw +{ +template +class ETRSPropPW final : public PWProp +{ + private: + const hsolver::diag_comm_info pool_comm_; + std::unique_ptr> exponential_; + ct::Tensor half_psi_; + const int npol_; + const std::vector global_k_; + std::ostream& log_; + bool half_ready_ = false; + unsigned long long left_gen_ = 0; + void report(const hsolver::ExpResult& result, int ik, int elec_step, int scf_iter, bool log_detail) const; + + public: + ETRSPropPW(const hsolver::ExpControls& exp_ctrl, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log); + void begin_trial() override; + void discard_trial() override; + void invalidate_basis() override; + void evolve(TDHamiltPW& hamilt, + const TDHistoryPW& history, + elecstate::Potential& potential, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) override; +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_conserv_pw.cpp b/source/source_pw/module_rt/td_conserv_pw.cpp new file mode 100644 index 00000000000..e3a06794e88 --- /dev/null +++ b/source/source_pw/module_rt/td_conserv_pw.cpp @@ -0,0 +1,46 @@ +#include "source_pw/module_rt/td_conserv_pw.h" + +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" + +namespace pw +{ +TDConserv cal_td_conserv(double local_npsi, + const Charge& charge, + double omega, + int pool_rank, + double orth_before, + double orth_after, + bool full_gram) +{ + ModuleBase::timer::start("pw", "cal_td_conserv"); + TDConserv result; + // Orbital norms are replicated within each k-point pool. + if (pool_rank == 0) + { + result.npsi = local_npsi; + } + Parallel_Reduce::reduce_all(result.npsi); + + const int density_spins = charge.nspin == 2 ? 2 : 1; + for (int spin = 0; spin < density_spins; ++spin) + { + for (int ir = 0; ir < charge.nrxx; ++ir) + { + result.nrho += charge.rho[spin][ir]; + } + } + result.nrho *= omega / charge.rhopw->nxyz; + Parallel_Reduce::reduce_pool(result.nrho); + + double maxima[] = {orth_before, orth_after}; + if (full_gram) + { + Parallel_Reduce::reduce_max(maxima, 2); + } + result.orth_before = maxima[0]; + result.orth_after = maxima[1]; + ModuleBase::timer::end("pw", "cal_td_conserv"); + return result; +} +} // namespace pw diff --git a/source/source_pw/module_rt/td_conserv_pw.h b/source/source_pw/module_rt/td_conserv_pw.h new file mode 100644 index 00000000000..8354e779502 --- /dev/null +++ b/source/source_pw/module_rt/td_conserv_pw.h @@ -0,0 +1,26 @@ +#ifndef TD_CONSERV_PW_H +#define TD_CONSERV_PW_H + +#include "source_estate/module_charge/charge.h" + +namespace pw +{ +/** @brief Globally reduced electron counts and orthogonality errors. */ +struct TDConserv +{ + double npsi = 0.0; + double nrho = 0.0; + double orth_before = 0.0; + double orth_after = 0.0; +}; + +/** @brief Count each k-point pool once and integrate the charge channels. */ +TDConserv cal_td_conserv(double local_npsi, + const Charge& charge, + double omega, + int pool_rank, + double orth_before, + double orth_after, + bool full_gram); +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_endpoint_pw.cpp b/source/source_pw/module_rt/td_endpoint_pw.cpp new file mode 100644 index 00000000000..c8008398519 --- /dev/null +++ b/source/source_pw/module_rt/td_endpoint_pw.cpp @@ -0,0 +1,192 @@ +#include "source_pw/module_rt/td_endpoint_pw.h" + +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" +#include "source_estate/elecstate_tools.h" +#include "source_estate/module_charge/chg_symm.h" +#include "source_hamilt/hamilt_hs_adapter.h" + +namespace pw +{ +template +void orth_init_pw(hsolver::TDOrbOps& orbitals, + hsolver::HSOperator& op, + psi::Psi& current, + elecstate::ElecStatePW& estate, + Charge& charge, + UnitCell& cell, + const ModulePW::PW_Basis& rhod, + int nspin, + int nbands, + int iter, + bool do_orth) +{ + ModuleBase::timer::start("pw", "orth_init_pw"); + // Padding remains zero even when physical orbital corrections are disabled. + orbitals.zero_padding(¤t); + if (do_orth) + { + int changed = orbitals.orth_initial(¤t, iter); + // Occupations and density construction contain collectives across pools. + Parallel_Reduce::reduce_all(changed); + if (changed > 0) + { + orbitals.cal_band_energy(op, current, &estate.ekb); + elecstate::calculate_weights(estate.ekb, + estate.wg, + estate.klist, + estate.eferm, + estate.f_en, + estate.nelec_spin, + nbands, + estate.skip_weights); + elecstate::calEBand(estate.ekb, estate.wg, estate.f_en); + + estate.psiToRho(current); + module_charge::symmetrize_rho(nspin, charge, &rhod, cell.symm); + } + } + ModuleBase::timer::end("pw", "orth_init_pw"); +} + +template +void rebuild_td_end(psi::Psi& current, + elecstate::ElecStatePW& estate, + Charge& charge, + UnitCell& cell, + hamilt::HamiltPW& hamilt, + hsolver::TDOrbOps& orbitals, + const ModulePW::PW_Basis_K& basis, + const ModulePW::PW_Basis& rhod, + const ModuleBase::Vector3& vecpot, + int nspin, + int imp_sol, + bool sc_mag, + int dft_u, + const std::string& assume_iso) +{ + ModuleBase::timer::start("pw", "rebuild_td_end"); + // Discard a mixed trial density while keeping the final orbitals and occupations. + estate.psiToRho(current); + module_charge::symmetrize_rho(nspin, charge, &rhod, cell.symm); + charge.save_rho_before_sum_band(); + estate.pot->update_from_charge(&charge, &cell); + + using Real = typename GetTypeReal::type; + const Real* veff = estate.pot->template get_veff_smooth_data(); + hamilt.bind_td_state(veff, vecpot); + hamilt::HamiltHSOperator op(&hamilt, &basis); + orbitals.cal_band_energy(op, current, &estate.ekb); + elecstate::calEBand(estate.ekb, estate.wg, estate.f_en); + estate.f_en.deband = estate.cal_delta_eband(cell); + estate.f_en.descf = 0.0; + + // Do not reuse a force correction from an earlier self-consistent endpoint. + estate.vnew_exist = false; + estate.cal_energies(2, imp_sol, sc_mag, dft_u, assume_iso); + ModuleBase::timer::end("pw", "rebuild_td_end"); +} + +template void orth_init_pw(hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + hsolver::HSOperator, base_device::DEVICE_CPU>&, + psi::Psi, base_device::DEVICE_CPU>&, + elecstate::ElecStatePW, base_device::DEVICE_CPU>&, + Charge&, + UnitCell&, + const ModulePW::PW_Basis&, + int, + int, + int, + bool); +template void rebuild_td_end(psi::Psi, base_device::DEVICE_CPU>&, + elecstate::ElecStatePW, base_device::DEVICE_CPU>&, + Charge&, + UnitCell&, + hamilt::HamiltPW, base_device::DEVICE_CPU>&, + hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + const ModulePW::PW_Basis_K&, + const ModulePW::PW_Basis&, + const ModuleBase::Vector3&, + int, + int, + bool, + int, + const std::string&); +template void orth_init_pw(hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + hsolver::HSOperator, base_device::DEVICE_CPU>&, + psi::Psi, base_device::DEVICE_CPU>&, + elecstate::ElecStatePW, base_device::DEVICE_CPU>&, + Charge&, + UnitCell&, + const ModulePW::PW_Basis&, + int, + int, + int, + bool); +template void rebuild_td_end(psi::Psi, base_device::DEVICE_CPU>&, + elecstate::ElecStatePW, base_device::DEVICE_CPU>&, + Charge&, + UnitCell&, + hamilt::HamiltPW, base_device::DEVICE_CPU>&, + hsolver::TDOrbOps, base_device::DEVICE_CPU>&, + const ModulePW::PW_Basis_K&, + const ModulePW::PW_Basis&, + const ModuleBase::Vector3&, + int, + int, + bool, + int, + const std::string&); +#if defined(__CUDA) || defined(__ROCM) +template void orth_init_pw(hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + hsolver::HSOperator, base_device::DEVICE_GPU>&, + psi::Psi, base_device::DEVICE_GPU>&, + elecstate::ElecStatePW, base_device::DEVICE_GPU>&, + Charge&, + UnitCell&, + const ModulePW::PW_Basis&, + int, + int, + int, + bool); +template void rebuild_td_end(psi::Psi, base_device::DEVICE_GPU>&, + elecstate::ElecStatePW, base_device::DEVICE_GPU>&, + Charge&, + UnitCell&, + hamilt::HamiltPW, base_device::DEVICE_GPU>&, + hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + const ModulePW::PW_Basis_K&, + const ModulePW::PW_Basis&, + const ModuleBase::Vector3&, + int, + int, + bool, + int, + const std::string&); +template void orth_init_pw(hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + hsolver::HSOperator, base_device::DEVICE_GPU>&, + psi::Psi, base_device::DEVICE_GPU>&, + elecstate::ElecStatePW, base_device::DEVICE_GPU>&, + Charge&, + UnitCell&, + const ModulePW::PW_Basis&, + int, + int, + int, + bool); +template void rebuild_td_end(psi::Psi, base_device::DEVICE_GPU>&, + elecstate::ElecStatePW, base_device::DEVICE_GPU>&, + Charge&, + UnitCell&, + hamilt::HamiltPW, base_device::DEVICE_GPU>&, + hsolver::TDOrbOps, base_device::DEVICE_GPU>&, + const ModulePW::PW_Basis_K&, + const ModulePW::PW_Basis&, + const ModuleBase::Vector3&, + int, + int, + bool, + int, + const std::string&); +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/td_endpoint_pw.h b/source/source_pw/module_rt/td_endpoint_pw.h new file mode 100644 index 00000000000..babf5046f6e --- /dev/null +++ b/source/source_pw/module_rt/td_endpoint_pw.h @@ -0,0 +1,41 @@ +#ifndef TD_ENDPOINT_PW_H +#define TD_ENDPOINT_PW_H + +#include "source_estate/elecstate_pw.h" +#include "source_pw/module_rt/td_orbital_ops.h" +#include "source_pw/module_pwdft/hamilt_pw.h" + +namespace pw +{ +/** @brief Clean initial orbitals and rebuild occupations and density if orthogonalization changes them. */ +template +void orth_init_pw(hsolver::TDOrbOps& orbitals, + hsolver::HSOperator& op, + psi::Psi& current, + elecstate::ElecStatePW& estate, + Charge& charge, + UnitCell& cell, + const ModulePW::PW_Basis& rhod, + int nspin, + int nbands, + int iter, + bool do_orth); + +/** @brief Rebuild an accepted endpoint from its orbitals while retaining all occupations. */ +template +void rebuild_td_end(psi::Psi& current, + elecstate::ElecStatePW& estate, + Charge& charge, + UnitCell& cell, + hamilt::HamiltPW& hamilt, + hsolver::TDOrbOps& orbitals, + const ModulePW::PW_Basis_K& basis, + const ModulePW::PW_Basis& rhod, + const ModuleBase::Vector3& vecpot, + int nspin, + int imp_sol, + bool sc_mag, + int dft_u, + const std::string& assume_iso); +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_hamilt_pw.cpp b/source/source_pw/module_rt/td_hamilt_pw.cpp new file mode 100644 index 00000000000..cccf6bddf99 --- /dev/null +++ b/source/source_pw/module_rt/td_hamilt_pw.cpp @@ -0,0 +1,39 @@ +#include "source_pw/module_rt/td_hamilt_pw.h" + +namespace pw +{ +template +TDHamiltPW::TDHamiltPW(hamilt::HamiltPW& hamilt, const ModulePW::PW_Basis_K& basis) + : hamilt_(hamilt), op_(&hamilt, &basis) +{ +} +template +void TDHamiltPW::bind(const Real* veff, const ModuleBase::Vector3& vecpot_ha) +{ + veff_ = veff; + vecpot_ha_ = vecpot_ha; + hamilt_.bind_td_state(veff_, vecpot_ha_); +} +template +void TDHamiltPW::update_k(int ik) +{ + hamilt_.bind_td_state(veff_, vecpot_ha_); + op_.update_k(ik); +} +template +void TDHamiltPW::hpsi(const T* x, T* hx, int ld, int bands) const +{ + op_.hpsi(x, hx, ld, bands); +} +template +void TDHamiltPW::spsi(const T* x, T* sx, int ld, int bands) const +{ + op_.spsi(x, sx, ld, bands); +} +template class TDHamiltPW, base_device::DEVICE_CPU>; +template class TDHamiltPW, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class TDHamiltPW, base_device::DEVICE_GPU>; +template class TDHamiltPW, base_device::DEVICE_GPU>; +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/td_hamilt_pw.h b/source/source_pw/module_rt/td_hamilt_pw.h new file mode 100644 index 00000000000..ec0ea87fb5d --- /dev/null +++ b/source/source_pw/module_rt/td_hamilt_pw.h @@ -0,0 +1,28 @@ +#ifndef PW_TD_HAMILT_PW_H +#define PW_TD_HAMILT_PW_H +#include "source_hamilt/hamilt_hs_adapter.h" +#include "source_pw/module_pwdft/hamilt_pw.h" + +namespace pw +{ +/** @brief A call-scoped PW sample; every k update refreshes shifted projectors. */ +template +class TDHamiltPW final : public hsolver::HSOperator +{ + private: + using Real = typename T::value_type; + hamilt::HamiltPW& hamilt_; + hamilt::HamiltHSOperator op_; + const Real* veff_ = nullptr; + ModuleBase::Vector3 vecpot_ha_; + + public: + TDHamiltPW(hamilt::HamiltPW& hamilt, const ModulePW::PW_Basis_K& basis); + /** @brief Select a potential sample whose storage outlives its applications. */ + void bind(const Real* veff, const ModuleBase::Vector3& vecpot_ha); + void update_k(int ik) override; + void hpsi(const T* x, T* hx, int ld, int bands) const override; + void spsi(const T* x, T* sx, int ld, int bands) const override; +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_pwdft/td_history_pw.cpp b/source/source_pw/module_rt/td_history_pw.cpp similarity index 51% rename from source/source_pw/module_pwdft/td_history_pw.cpp rename to source/source_pw/module_rt/td_history_pw.cpp index 7e981682939..7809e5451f9 100644 --- a/source/source_pw/module_pwdft/td_history_pw.cpp +++ b/source/source_pw/module_rt/td_history_pw.cpp @@ -1,6 +1,5 @@ -#include "source_pw/module_pwdft/td_history_pw.h" +#include "source_pw/module_rt/td_history_pw.h" -#include "source_base/kernels/math_kernel_op.h" #include "source_base/module_device/memory_op.h" #include "source_base/timer.h" #include "source_base/tool_quit.h" @@ -13,7 +12,7 @@ namespace { template -void prepare_pair(const ModuleBase::matrix& potential, ct::Tensor* previous, ct::Tensor* midpoint) +void prepare_potential(const ModuleBase::matrix& potential, ct::Tensor* previous) { using CtDevice = typename ct::PsiToContainer::type; const ct::DeviceType device = ct::DeviceTypeToEnum::value; @@ -21,68 +20,64 @@ void prepare_pair(const ModuleBase::matrix& potential, ct::Tensor* previous, ct: if (previous->NumElements() < size || previous->data_type() != ct::DataTypeToEnum::value || previous->device_type() != device) { *previous = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); - *midpoint = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); } } template -const Real* average_potential(const ModuleBase::matrix& shape, const Real* current, const ct::Tensor& previous, ct::Tensor* midpoint) +void save_potential(const ModuleBase::matrix& shape, const Real* current, ct::Tensor* previous) { const int size = shape.nr * shape.nc; - if (size == 0) + if (size > 0) { - return current; + base_device::memory::synchronize_memory_op()(previous->template data(), current, size); } - Real* buffer = midpoint->template data(); - ModuleBase::vector_add_vector_op()(size, buffer, previous.template data(), Real(0.5), current, Real(0.5)); - return buffer; } -template -void save_potential(const ModuleBase::matrix& shape, const Real* current, ct::Tensor* previous) +} // namespace + +TDElecSnap capture_td(const elecstate::fenergy& energy, const ModuleBase::matrix& eigenvalues, const Charge& charge) { - const int size = shape.nr * shape.nc; - if (size > 0) + TDElecSnap state; + state.energy = energy; + state.eigenvalues = eigenvalues; + state.density.resize(charge.nspin * charge.nrxx); + for (int spin = 0; spin < charge.nspin; ++spin) { - base_device::memory::synchronize_memory_op()(previous->template data(), current, size); + std::copy(charge.rho[spin], charge.rho[spin] + charge.nrxx, state.density.begin() + spin * charge.nrxx); } + return state; } -} // namespace +void restore_td(const TDElecSnap& state, elecstate::fenergy& energy, ModuleBase::matrix& eigenvalues, Charge& charge) +{ + ModuleBase::timer::start("pw", "restore_td"); + energy = state.energy; + eigenvalues = state.eigenvalues; + for (int spin = 0; spin < charge.nspin; ++spin) + { + const double* density = state.density.data() + spin * charge.nrxx; + std::copy(density, density + charge.nrxx, charge.rho[spin]); + } + charge.save_rho_before_sum_band(); + ModuleBase::timer::end("pw", "restore_td"); +} template -void TDHistoryPW::prepare(const elecstate::Potential& potential, const bool needs_ked) +void TDHistoryPW::prepare(const elecstate::Potential& potential) { ModuleBase::timer::start("TDHistoryPW", "prepare"); - prepare_pair(potential.get_veff_smooth(), &veff_prev_, &veff_mid_); - if (needs_ked) - { - prepare_pair(potential.get_vofk_smooth(), &vofk_prev_, &vofk_mid_); - } + prepare_potential(potential.get_veff_smooth(), &veff_prev_); ModuleBase::timer::end("TDHistoryPW", "prepare"); } template -TDPotentialView::type> TDHistoryPW::prop_pot(elecstate::Potential& potential, - const bool needs_ked, - const bool corrector) +const typename GetTypeReal::type* TDHistoryPW::left_potential() const { - ModuleBase::timer::start("TDHistoryPW", "prop_pot"); - TDPotentialView view{potential.template get_veff_smooth_data(), potential.template get_vofk_smooth_data()}; - if (corrector) - { - view.veff = average_potential(potential.get_veff_smooth(), view.veff, veff_prev_, &veff_mid_); - if (needs_ked) - { - view.vofk = average_potential(potential.get_vofk_smooth(), view.vofk, vofk_prev_, &vofk_mid_); - } - } - ModuleBase::timer::end("TDHistoryPW", "prop_pot"); - return view; + return veff_prev_.template data(); } template -void TDHistoryPW::save(const psi::Psi& current, elecstate::Potential& potential, const bool needs_ked) +void TDHistoryPW::save(const psi::Psi& current, elecstate::Potential& potential) { ModuleBase::timer::start("TDHistoryPW", "save"); if (!previous_) @@ -90,11 +85,8 @@ void TDHistoryPW::save(const psi::Psi& current, elecstate: previous_.reset(new psi::Psi(current)); } *previous_ = current; + ++generation_; save_potential(potential.get_veff_smooth(), potential.template get_veff_smooth_data(), &veff_prev_); - if (needs_ked) - { - save_potential(potential.get_vofk_smooth(), potential.template get_vofk_smooth_data(), &vofk_prev_); - } ModuleBase::timer::end("TDHistoryPW", "save"); } @@ -103,7 +95,7 @@ const psi::Psi& TDHistoryPW::previous() const { if (!previous_) { - ModuleBase::WARNING_QUIT("TDHistoryPW", "No converged state has been saved for propagation."); + ModuleBase::WARNING_QUIT("TDHistoryPW", "No endpoint state has been saved for propagation."); } return *previous_; } diff --git a/source/source_pw/module_rt/td_history_pw.h b/source/source_pw/module_rt/td_history_pw.h new file mode 100644 index 00000000000..f9066b4fe0c --- /dev/null +++ b/source/source_pw/module_rt/td_history_pw.h @@ -0,0 +1,59 @@ +#ifndef TD_HISTORY_PW_H +#define TD_HISTORY_PW_H + +#include "source_base/module_container/ATen/core/tensor.h" +#include "source_estate/fp_energy.h" +#include "source_estate/module_charge/charge.h" +#include "source_estate/module_pot/potential_new.h" +#include "source_psi/psi.h" + +#include +#include + +namespace pw +{ + +/** @brief Electronic data at an accepted endpoint; orbitals and potential stay in TDHistoryPW. */ +struct TDElecSnap +{ + elecstate::fenergy energy; + ModuleBase::matrix eigenvalues; + std::vector density; +}; + +/** @brief Copy energy, band expectations and density without advancing orbital history. */ +TDElecSnap capture_td(const elecstate::fenergy& energy, const ModuleBase::matrix& eigenvalues, const Charge& charge); + +/** @brief Restore electronic data on the unchanged density grid and refresh its mixing backup. */ +void restore_td(const TDElecSnap& state, elecstate::fenergy& energy, ModuleBase::matrix& eigenvalues, Charge& charge); + +/** @brief Accepted endpoint wavefunctions and potential snapshots. */ +template +class TDHistoryPW +{ + public: + /** @brief Prepare storage after the potential grids have been updated. */ + void prepare(const elecstate::Potential& potential); + + /** @brief Borrow the immutable accepted left-endpoint potential. */ + const typename GetTypeReal::type* left_potential() const; + unsigned long long generation() const + { + return generation_; + } + + /** @brief Save the accepted endpoint; the caller owns the convergence decision. */ + void save(const psi::Psi& current, elecstate::Potential& potential); + + /** @brief Access the fixed origin of every corrector solve in the next step. */ + const psi::Psi& previous() const; + + private: + using Real = typename GetTypeReal::type; + std::unique_ptr> previous_; + ct::Tensor veff_prev_; + unsigned long long generation_ = 0; +}; + +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_obs_pw.h b/source/source_pw/module_rt/td_obs_pw.h new file mode 100644 index 00000000000..baaa91e87db --- /dev/null +++ b/source/source_pw/module_rt/td_obs_pw.h @@ -0,0 +1,37 @@ +#ifndef TD_OBS_PW_H +#define TD_OBS_PW_H + +#include +#include + +namespace pw +{ +/** @brief Independent requests; all ranks must use the same choices. */ +struct CurrentRequest +{ + bool charge_total = false; + bool charge_per_k = false; + bool spin_current = false; +}; + +/** @brief Globally reduced currents; unrequested arrays stay zero or empty. */ +struct TDVelResultPW +{ + std::array total{}; ///< Electron charge current per volume, in Hartree atomic units. + std::vector per_k; ///< Same units, [global k including spin][Cartesian direction]. + std::array spin{}; ///< Spin angular momentum flux, [flow][spin], hbar/(Bohr^2*atomic time). +}; + +/** @brief Endpoint observables replicated on all ranks after the appropriate reductions. */ +struct TDSpinResultPW +{ + std::array mag{}; ///< ABACUS Pauli moment in mu_B; no electron minus sign. + double mag_abs = 0.0; ///< Integral of the magnetization magnitude, in mu_B. + double electrons = 0.0; ///< Valence electron count; excludes the NLCC core density. + std::vector atom_mag; ///< [atom][Cartesian direction], in mu_B. + std::array xc{}; ///< Rate of spin angular momentum S=M/2, hbar/atomic time. + std::array soc{}; ///< Same units as xc. + std::vector atom_soc; ///< Pseudopotential atom decomposition, [atom][direction]. +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_orbital_ops.cpp b/source/source_pw/module_rt/td_orbital_ops.cpp new file mode 100644 index 00000000000..278211f1bc1 --- /dev/null +++ b/source/source_pw/module_rt/td_orbital_ops.cpp @@ -0,0 +1,322 @@ +#include "source_pw/module_rt/td_orbital_ops.h" + +#include "source_base/parallel_device.h" +#include "source_base/timer.h" +#include "source_base/tool_quit.h" +#include "source_hsolver/module_linalg/orb_buffer.h" + +#include +#include +#include + +namespace hsolver +{ +template +TDOrbOps::TDOrbOps(int npol, + OrthMethod orth_method, + bool out_stat, + const std::vector& global_k, + const diag_comm_info& comm, + std::ostream& log) + : comm_(comm), npol_(npol), orth_method_(orth_method), out_stat_(out_stat), global_k_(global_k), algebra_(comm), + orthonormal_(comm, algebra_), log_(log), band_products_(comm, 9) +{ + log_ << " PW RT-TDDFT orthonormalization: " << orth_method_name(orth_method_) << '\n'; +} + +template +void TDOrbOps::prepare_buffers(int nbands, int nbasis) +{ + const int64_t size = static_cast(nbands) * nbasis; + linear_buffer(&clean_, size); + linear_buffer(&hpsi_, size); +} + +template +void TDOrbOps::correct(psi::Psi* current, int step, int iter, bool detailed_output) +{ + if (out_stat_) + { + orth_norms_.resize(current->get_nk()); + } + zero_padding(current); + for (int ik = 0; ik < current->get_nk(); ++ik) + { + current->fix_k(ik); + const int ld = current->get_nbasis(); + const int dim = npol_ == 2 ? ld : current->get_ngk(ik); + const int bands = current->get_nbands(); + T* data = current->get_pointer(); + correct_orbitals(data, ld, dim, bands, ik, step, iter, detailed_output); + } +} + +template +void TDOrbOps::cal_band_energy(HSOperator& op, const psi::Psi& current, ModuleBase::matrix* energies) +{ + ModuleBase::timer::start("TDOrbOps", "cal_band_energy"); + const int nband = current.get_nbands(); + const int ld = current.get_nbasis(); + prepare_buffers(nband, ld); + std::vector expectations(nband); + T* hpsi = hpsi_.template data(); + for (int ik = 0; ik < current.get_nk(); ++ik) + { + op.update_k(ik); + current.fix_k(ik); + const int npw = current.get_ngk(ik); + const int dim = npol_ == 2 ? ld : npw; + const OrbLayout layout{ld, npw, npol_, nband}; + const T* data = clean_orbs(current.get_pointer(), layout, &clean_); + op.hpsi(data, hpsi, ld, nband); + if (npol_ == 2) + { + zero_pad(hpsi, layout); + } + band_products_.dot(ld, dim, nband, data, hpsi, expectations.data()); + for (int band = 0; band < nband; ++band) + { + (*energies)(ik, band) = std::real(expectations[band]); + } + } + ModuleBase::timer::end("TDOrbOps", "cal_band_energy"); +} + +template +std::vector> TDOrbOps::cal_eij(HSOperator& op, const psi::Psi& current, const int ik) +{ + ModuleBase::timer::start("TDOrbOps", "cal_eij"); + const int nband = current.get_nbands(); + const int ld = current.get_nbasis(); + const int npw = current.get_ngk(ik); + const int dim = npol_ == 2 ? ld : npw; + prepare_buffers(nband, ld); + op.update_k(ik); + current.fix_k(ik); + const OrbLayout layout{ld, npw, npol_, nband}; + const T* psi = clean_orbs(current.get_pointer(), layout, &clean_); + T* hpsi = hpsi_.template data(); + op.hpsi(psi, hpsi, ld, nband); + if (npol_ == 2) + { + zero_pad(hpsi, layout); + } + std::vector> result = algebra_.cross(ld, dim, nband, nband, psi, hpsi); + ModuleBase::timer::end("TDOrbOps", "cal_eij"); + return result; +} + +template +void TDOrbOps::reset_orth_stats() +{ + if (out_stat_) + { + orth_stats_ = TDOrthStats(); + } + warned_events_ = 0; +} + +template +void TDOrbOps::correct_orbitals(T* current, int ld, int dim, int bands, int ik, int istep, int iter, bool detailed_output) +{ + ModuleBase::timer::start("TDOrbOps", "correct_orbitals"); + const OrthResult result = orthonormal_.apply(current, ld, dim, bands, orth_method_, out_stat_); + record_orth(result, ik, istep, iter); + if (detailed_output && result.gram_checked && log_.good()) + { + const int evolution_step = istep + 1; + std::ostringstream record; + record << std::scientific << std::setprecision(6) << " PW RT-TDDFT orth: evolution_step=" << evolution_step << " scf_iter=" << iter + << " global_k=" << global_k_.at(ik) + 1 << " requested=" << orth_method_name(orth_method_) + << " orth_before=" << result.before << " orth_after=" << result.after << '\n'; + log_ << record.str(); + } + ModuleBase::timer::end("TDOrbOps", "correct_orbitals"); +} + +template +void TDOrbOps::record_orth(const OrthResult& result, int ik, int istep, int iter) +{ + if (result.status == OrthStatus::failed) + { + const char* stage = istep == 0 ? "initialization" : "propagation"; + std::ostringstream message; + const int evolution_step = istep + 1; + message << std::setprecision(16) << " PW RT-TDDFT orbital validation failed (" << stage << "): evolution_step=" << evolution_step + << " scf_iter=" << iter << " global_k=" << global_k_.at(ik) + 1 << " requested=" << orth_method_name(orth_method_) << '\n' + << " last_attempted=" << orth_method_name(result.actual) << " passes=" << result.passes + << " fallbacks=" << result.fallbacks << '\n' + << " " << orth_failure_name(result.failure) << "; " << result.reason; + if (result.gram_checked) + { + message << '\n' << " before=" << result.before << " after=" << result.after << " tolerance=" << orth_tolerance(); + } + // stdout is disabled on non-world-root ranks; a failing pool must still report its error. + if (comm_.rank == 0) + { + std::cerr << message.str() << std::endl; + } +#ifdef __MPI + // Let the pool root flush its diagnostic before another rank's exit stops the MPI job. + double diagnostic_written = 1.0; + Parallel_Common::bcast_data(&diagnostic_written, 1, comm_.comm, 0); +#endif + ModuleBase::WARNING_QUIT("TDOrbOps", message.str()); + } + report_orth_warning(result, ik, istep, iter); + if (out_stat_) + { + orth_norms_[ik] = result.norms; + if (result.gram_checked) + { + orth_stats_.before = std::max(orth_stats_.before, result.before); + orth_stats_.after = std::max(orth_stats_.after, result.after); + } + } +} + +template +void TDOrbOps::report_orth_warning(const OrthResult& result, int ik, int istep, int iter) +{ + if (comm_.rank != 0) + { + return; + } + unsigned int events = 0; + if (result.fallbacks > 0) + { + events |= 1; + } + if (result.rejected > 0) + { + events |= 2; + } + const unsigned int fresh_events = events & ~warned_events_; + if (fresh_events == 0) + { + return; + } + warned_events_ |= events; + const int evolution_step = istep + 1; + std::ostringstream message; + message << std::setprecision(16) << " PW RT-TDDFT orbital warning: evolution_step=" << evolution_step << " scf_iter=" << iter; + message << " global_k=" << global_k_.at(ik) + 1; + message << " requested=" << orth_method_name(orth_method_) << '\n' + << " before=" << result.before << " after=" << result.after << " tolerance=" << orth_tolerance() << '\n' + << " "; + message << "last_attempted=" << orth_method_name(result.actual) << ". "; + if (fresh_events & 1) + { + message << "A fallback was attempted. "; + } + if (fresh_events & 2) + { + message << "A candidate was rejected. "; + } + message << "The retained state satisfies the tolerance." << '\n' + << " " << result.reason << '\n' + << " Further events of these types in this pool are suppressed for this electronic evolution step."; + const std::string text = message.str(); + std::cerr << text << std::endl; + if (log_.good()) + { + log_ << text << std::endl; + } +} + +template +void TDOrbOps::zero_padding(psi::Psi* current) +{ + ModuleBase::timer::start("TDOrbOps", "zero_padding"); + if (npol_ != 2) + { + ModuleBase::timer::end("TDOrbOps", "zero_padding"); + return; + } + const int old_k = current->get_current_k(); + for (int ik = 0; ik < current->get_nk(); ++ik) + { + current->fix_k(ik); + const int npw = current->get_ngk(ik); + const int ld = current->get_nbasis(); + const int bands = current->get_nbands(); + const OrbLayout layout{ld, npw, npol_, bands}; + zero_pad(current->get_pointer(), layout); + } + current->fix_k(old_k); + ModuleBase::timer::end("TDOrbOps", "zero_padding"); +} + +template +bool TDOrbOps::orth_initial(psi::Psi* current, int iter) +{ + ModuleBase::timer::start("TDOrbOps", "orth_initial"); + bool changed = false; + if (orth_method_ != OrthMethod::none) + { + if (out_stat_) + { + // Initial diagnostics describe this SCF state, not earlier discarded iterates. + orth_stats_ = TDOrthStats(); + orth_norms_.resize(current->get_nk()); + } + for (int ik = 0; ik < current->get_nk(); ++ik) + { + current->fix_k(ik); + const int dim = npol_ == 2 ? current->get_nbasis() : current->get_ngk(ik); + const OrthResult result + = orthonormal_.apply(current->get_pointer(), current->get_nbasis(), dim, current->get_nbands(), orth_method_, out_stat_); + record_orth(result, ik, 0, iter); + changed = changed || result.status == OrthStatus::accepted; + } + } + ModuleBase::timer::end("TDOrbOps", "orth_initial"); + return changed; +} + +template +void TDOrbOps::check_initial(const psi::Psi& current, int iter) +{ + ModuleBase::timer::start("TDOrbOps", "check_initial"); + const bool full_gram = orth_method_ != OrthMethod::none; + const int ld = current.get_nbasis(); + const int bands = current.get_nbands(); + prepare_buffers(bands, ld); + if (out_stat_) + { + orth_norms_.resize(current.get_nk()); + } + for (int ik = 0; ik < current.get_nk(); ++ik) + { + current.fix_k(ik); + const int npw = current.get_ngk(ik); + const int dim = npol_ == 2 ? ld : npw; + const OrbLayout layout{ld, npw, npol_, bands}; + const T* data = clean_orbs(current.get_pointer(), layout, &clean_); + const OrthResult result = orthonormal_.inspect(data, current.get_nbasis(), dim, current.get_nbands(), full_gram, out_stat_); + record_orth(result, ik, 0, iter); + } + ModuleBase::timer::end("TDOrbOps", "check_initial"); +} + +template +double TDOrbOps::wave_electrons(const ModuleBase::matrix& occupations) const +{ + double electrons = 0.0; + for (std::size_t ik = 0; ik < orth_norms_.size(); ++ik) + { + for (std::size_t band = 0; band < orth_norms_[ik].size(); ++band) + { + electrons += occupations(ik, band) * orth_norms_[ik][band]; + } + } + return electrons; +} + +template class TDOrbOps, base_device::DEVICE_CPU>; +template class TDOrbOps, base_device::DEVICE_CPU>; +#if defined(__CUDA) || defined(__ROCM) +template class TDOrbOps, base_device::DEVICE_GPU>; +template class TDOrbOps, base_device::DEVICE_GPU>; +#endif +} // namespace hsolver diff --git a/source/source_pw/module_rt/td_orbital_ops.h b/source/source_pw/module_rt/td_orbital_ops.h new file mode 100644 index 00000000000..a78aa1f891c --- /dev/null +++ b/source/source_pw/module_rt/td_orbital_ops.h @@ -0,0 +1,80 @@ +#ifndef HSOLVER_TD_ORBITAL_OPS_H +#define HSOLVER_TD_ORBITAL_OPS_H +#include "source_base/matrix.h" +#include "source_hsolver/hs_operator.h" +#include "source_hsolver/module_linalg/linear_workspace.h" +#include "source_hsolver/module_linalg/orthonormal.h" +#include "source_psi/psi.h" + +#include + +namespace hsolver +{ +/** @brief Independent orthogonality maxima over accepted trial iterations and local k points. */ +struct TDOrthStats +{ + double before = 0.0; + double after = 0.0; +}; + +template +class TDOrbOps +{ + private: + const diag_comm_info comm_; + const int npol_; + const OrthMethod orth_method_; + const bool out_stat_; + const std::vector global_k_; + ct::Tensor clean_; + ct::Tensor hpsi_; + LinearAlgebra algebra_; + Orthonormal orthonormal_; + TDOrthStats orth_stats_; + std::vector> orth_norms_; + std::ostream& log_; + unsigned int warned_events_ = 0; + LinearWorkspace band_products_; + void prepare_buffers(int nbands, int nbasis); + void correct_orbitals(T* current, int ld, int dim, int bands, int ik, int istep, int iter, bool detailed_output); + void record_orth(const OrthResult& result, int ik, int istep, int iter); + void report_orth_warning(const OrthResult& result, int ik, int istep, int iter); + + public: + /** @brief Configure common orbital processing independently of a propagator. */ + TDOrbOps(int npol, + OrthMethod orth_method, + bool out_stat, + const std::vector& global_k, + const diag_comm_info& comm, + std::ostream& log); + /** @brief Apply common postprocessing to a completed predictor or corrector. */ + void correct(psi::Psi* current, int step, int iter, bool detailed_output); + /** @brief Reset diagnostics without invalidating preconditioner history. */ + void reset_orth_stats(); + /** @brief Publish diagnostics accumulated over accepted trial intervals only. */ + void set_orth_stats(const TDOrthStats& stats) + { + orth_stats_ = stats; + } + /** @brief Clear spinor padding without changing physical coefficients or the k-point cursor; no communication. */ + void zero_padding(psi::Psi* current); + /** @brief Orthogonalize initial orbitals with clean padding; return whether this pool changed any physical orbital. */ + bool orth_initial(psi::Psi* current, int iter); + /** @brief Check the converged initial state once; finite orthogonality errors are diagnostic only. */ + void check_initial(const psi::Psi& current, int iter); + /** @brief Occupation-weighted electron count for the local k-point pool. */ + double wave_electrons(const ModuleBase::matrix& occupations) const; + const TDOrthStats& orth_stats() const + { + return orth_stats_; + } + + /** @brief Evaluate band expectations after the caller restores the endpoint Hamiltonian. */ + void cal_band_energy(HSOperator& op, const psi::Psi& current, ModuleBase::matrix* energies); + + /** @brief Return the pool-reduced, column-major Psi-adjoint H Psi for one local k point. */ + std::vector> cal_eij(HSOperator& op, const psi::Psi& current, const int ik); +}; +} // namespace hsolver +#endif diff --git a/source/source_pw/module_rt/td_prop_pw.cpp b/source/source_pw/module_rt/td_prop_pw.cpp new file mode 100644 index 00000000000..2409c5816e7 --- /dev/null +++ b/source/source_pw/module_rt/td_prop_pw.cpp @@ -0,0 +1,132 @@ +#include "source_pw/module_rt/td_prop_pw.h" + +#include "source_pw/module_rt/prop_cn_pw.h" +#include "source_pw/module_rt/prop_etrs_pw.h" + +#include + +namespace pw +{ +template +std::unique_ptr> make_td_prop(const ModulePW::PW_Basis_K& basis, + const Input_para& input, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log) +{ + const hsolver::OrthMethod orth_method = hsolver::parse_orth_method(input.td_orthonormal); + std::unique_ptr> orb_ops( + new hsolver::TDOrbOps(npol, orth_method, input.td_out_stat, global_k, comm, log)); + std::unique_ptr> prop; + if (input.propagator == 0) + { + hsolver::CNControls cn_ctrl; + cn_ctrl.linear.solver = hsolver::parse_linear_method(input.lin_solver); + cn_ctrl.linear.tolerance = input.lin_thr; + cn_ctrl.linear.max_iterations = input.lin_maxiter; + cn_ctrl.linear.restart = input.lin_gmres_restart; + cn_ctrl.linear.reconstruct = input.lin_reconstruct; + cn_ctrl.preconditioner = hsolver::parse_pw_precond(input.lin_precond); + cn_ctrl.cn_init = input.td_cn_init; + cn_ctrl.kinetic_enabled = input.t_in_h; + prop.reset(new CNPropPW(basis, cn_ctrl, npol, global_k, comm, log)); + } + else + { + hsolver::ExpControls exp_ctrl; + if (input.td_exp_method == "taylor") + { + exp_ctrl.expansion = hsolver::ExpMethod::taylor; + } + exp_ctrl.taylor_order = input.td_exp_order; + exp_ctrl.rel_tol = input.td_exp_thr; + exp_ctrl.krylov_max = input.td_exp_krylov_dim; + prop.reset(new ETRSPropPW(exp_ctrl, npol, global_k, comm, log)); + } + + return std::unique_ptr>(new TDPropPW(basis, std::move(orb_ops), std::move(prop))); +} + +template +TDPropPW::TDPropPW(const ModulePW::PW_Basis_K& basis, + std::unique_ptr> orb_ops, + std::unique_ptr> prop) + : basis_(basis), orb_ops_(std::move(orb_ops)), prop_(std::move(prop)) +{ +} + +template +PropStage TDPropPW::stage(int scf_iter) const +{ + return scf_iter == 1 ? PropStage::predictor : PropStage::corrector; +} +template +void TDPropPW::begin_trial() +{ + prop_->begin_trial(); +} +template +void TDPropPW::finish_trial() +{ + prop_->discard_trial(); +} +template +void TDPropPW::discard_trial() +{ + prop_->discard_trial(); +} +template +void TDPropPW::invalidate_basis() +{ + prop_->invalidate_basis(); +} +template +void TDPropPW::evolve(hamilt::HamiltPW& hamilt, + elecstate::Potential& potential, + const TDHistoryPW& history, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) +{ + using Real = typename T::value_type; + TDHamiltPW td_hamilt(hamilt, basis_); + prop_->evolve(td_hamilt, history, potential, field, current, elec_step, scf_iter, log_detail); + orb_ops_->correct(current, elec_step, scf_iter, log_detail); + const Real* endpoint = potential.template get_veff_smooth_data(); + const ModuleBase::Vector3& vecpot_ha = field.A_right_ha(); + td_hamilt.bind(endpoint, vecpot_ha); +} +template class TDPropPW, base_device::DEVICE_CPU>; +template std::unique_ptr, base_device::DEVICE_CPU>> make_td_prop(const ModulePW::PW_Basis_K&, + const Input_para&, + int, + const std::vector&, + const hsolver::diag_comm_info&, + std::ostream&); +template class TDPropPW, base_device::DEVICE_CPU>; +template std::unique_ptr, base_device::DEVICE_CPU>> make_td_prop(const ModulePW::PW_Basis_K&, + const Input_para&, + int, + const std::vector&, + const hsolver::diag_comm_info&, + std::ostream&); +#if defined(__CUDA) || defined(__ROCM) +template class TDPropPW, base_device::DEVICE_GPU>; +template std::unique_ptr, base_device::DEVICE_GPU>> make_td_prop(const ModulePW::PW_Basis_K&, + const Input_para&, + int, + const std::vector&, + const hsolver::diag_comm_info&, + std::ostream&); +template class TDPropPW, base_device::DEVICE_GPU>; +template std::unique_ptr, base_device::DEVICE_GPU>> make_td_prop(const ModulePW::PW_Basis_K&, + const Input_para&, + int, + const std::vector&, + const hsolver::diag_comm_info&, + std::ostream&); +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/td_prop_pw.h b/source/source_pw/module_rt/td_prop_pw.h new file mode 100644 index 00000000000..cb056cc77d6 --- /dev/null +++ b/source/source_pw/module_rt/td_prop_pw.h @@ -0,0 +1,79 @@ +#ifndef PW_TD_PROP_PW_H +#define PW_TD_PROP_PW_H +#include "source_estate/module_pot/td_field_manager.h" +#include "source_pw/module_rt/td_orbital_ops.h" +#include "source_io/module_parameter/input_parameter.h" +#include "source_pw/module_rt/td_hamilt_pw.h" +#include "source_pw/module_rt/td_history_pw.h" + +namespace pw +{ +enum class PropStage +{ + predictor, + corrector +}; + +/** @brief Method-specific wavefunction map; density and acceptance stay above it. */ +template +class PWProp +{ + public: + virtual ~PWProp() = default; + virtual void begin_trial() = 0; + virtual void discard_trial() = 0; + virtual void invalidate_basis() = 0; + virtual void evolve(TDHamiltPW& hamilt, + const TDHistoryPW& history, + elecstate::Potential& potential, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail) = 0; +}; + +/** @brief Sole PW propagation entry point, independent of the selected method. */ +template +class TDPropPW +{ + private: + const ModulePW::PW_Basis_K& basis_; + std::unique_ptr> orb_ops_; + std::unique_ptr> prop_; + + public: + /** @brief Take ownership of the initialized orbital service and propagator. */ + TDPropPW(const ModulePW::PW_Basis_K& basis, + std::unique_ptr> orb_ops, + std::unique_ptr> prop); + PropStage stage(int scf_iter) const; + void begin_trial(); + void finish_trial(); + void discard_trial(); + void invalidate_basis(); + hsolver::TDOrbOps& orbitals() + { + return *orb_ops_; + } + /** @brief Restore the endpoint sample before returning to density construction. */ + void evolve(hamilt::HamiltPW& hamilt, + elecstate::Potential& potential, + const TDHistoryPW& history, + const elecstate::TDFieldManager& field, + psi::Psi* current, + int elec_step, + int scf_iter, + bool log_detail); +}; + +/** @brief Resolve input controls and construct only the selected propagation method. */ +template +std::unique_ptr> make_td_prop(const ModulePW::PW_Basis_K& basis, + const Input_para& input, + int npol, + const std::vector& global_k, + const hsolver::diag_comm_info& comm, + std::ostream& log); +} // namespace pw +#endif diff --git a/source/source_pw/module_pwdft/td_pw.cpp b/source/source_pw/module_rt/td_pw.cpp similarity index 76% rename from source/source_pw/module_pwdft/td_pw.cpp rename to source/source_pw/module_rt/td_pw.cpp index 1cf36b05880..796c9e04d49 100644 --- a/source/source_pw/module_pwdft/td_pw.cpp +++ b/source/source_pw/module_rt/td_pw.cpp @@ -1,4 +1,4 @@ -#include "source_pw/module_pwdft/td_pw.h" +#include "source_pw/module_rt/td_pw.h" #include "source_base/parallel_reduce.h" #include "source_base/timer.h" @@ -9,17 +9,15 @@ namespace pw { - -void check_td_input(const Input_para& input, const UnitCell& cell, const bool needs_ked, const bool cal_exx) +void check_td_input(const Input_para& input, const UnitCell& cell, int xc_type, bool cal_exx) { if (input.out_current != 0 && input.out_current != 1) { ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT requires out_current=0 or 1."); } - if (input.scf_nmax < 2) + if (input.scf_nmax < 1) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", - "PW RT-TDDFT requires scf_nmax >= 2: one predictor and at least one corrector iteration."); + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT requires scf_nmax >= 1."); } if (unitcell::if_atoms_can_move(cell.atoms, cell.ntype)) { @@ -38,23 +36,29 @@ void check_td_input(const Input_para& input, const UnitCell& cell, const bool ne { ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT does not support spin constraints; set sc_mag_switch=false."); } + if (xc_type == 3 || xc_type == 5) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT does not support meta-GGA."); + } if (cal_exx) { ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT does not support exact exchange (EXX); use a non-hybrid functional."); } - if ((input.nspin != 1 && input.nspin != 2) || input.bndpar != 1 || (input.td_stype != 0 && input.td_stype != 1)) + if ((input.nspin != 1 && input.nspin != 2 && input.nspin != 4) || input.bndpar != 1 || (input.td_stype != 0 && input.td_stype != 1)) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT requires nspin=1 or 2, bndpar=1 and td_stype=0 or 1."); + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT requires nspin=1, 2 or 4, bndpar=1 and td_stype=0 or 1."); } - if (input.mdp.md_restart || input.restart_load) + if (input.nspin == 4 && !input.noncolin) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT restart is not supported yet."); + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "nspin=4 PW RT-TDDFT requires noncolin=true."); } - if (input.td_stype == 1 && needs_ked) + if (input.out_elf[0] > 0) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", - "PW RT-TDDFT with a kinetic-energy-density functional requires td_stype=0; " - "the velocity-gauge coupling of the functional is not implemented."); + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT does not support ELF."); + } + if (input.mdp.md_restart || input.restart_load) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "PW RT-TDDFT restart is not supported yet."); } } diff --git a/source/source_pw/module_pwdft/td_pw.h b/source/source_pw/module_rt/td_pw.h similarity index 88% rename from source/source_pw/module_pwdft/td_pw.h rename to source/source_pw/module_rt/td_pw.h index 9bc6908b896..787f6ed800d 100644 --- a/source/source_pw/module_pwdft/td_pw.h +++ b/source/source_pw/module_rt/td_pw.h @@ -10,13 +10,14 @@ namespace pw { /** @brief Check PW propagation restrictions after resolving the XC functional and EXX configuration. */ -void check_td_input(const Input_para& input, const UnitCell& cell, const bool needs_ked, const bool cal_exx); +void check_td_input(const Input_para& input, const UnitCell& cell, int xc_type, bool cal_exx); /** @brief Return the global unshifted momentum bound after updating the distributed basis. */ double td_momentum_bound(const ModulePW::PW_Basis_K& basis, const double tpiba); /** @brief Extend the projector table to cover both endpoint and propagation fields in Hartree atomic units. */ -void ensure_td_vnl(const UnitCell& cell, const double unshifted_bound, +void ensure_td_vnl(const UnitCell& cell, + const double unshifted_bound, const ModuleBase::Vector3& A_right_ha, const ModuleBase::Vector3& A_prop_ha, pseudopot_cell_vnl* projectors); diff --git a/source/source_pw/module_rt/td_spin_pw.cpp b/source/source_pw/module_rt/td_spin_pw.cpp new file mode 100644 index 00000000000..7c64a621326 --- /dev/null +++ b/source/source_pw/module_rt/td_spin_pw.cpp @@ -0,0 +1,413 @@ +#include "source_pw/module_rt/td_spin_pw.h" + +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" +#include "source_pw/module_proj/onsite_proj.h" +#include "source_pw/module_rt/td_pw.h" + +#include +#include +#include +#include +#include + +namespace pw +{ +namespace +{ +double image_dist(const ModuleBase::Vector3& delta, const ModuleBase::Matrix3& lattice, const std::array& inverse_norm) +{ + ModuleBase::Vector3 nearest; + for (int a = 0; a < 3; ++a) + { + nearest[a] = delta[a] - std::round(delta[a]); + } + double best = (nearest * lattice).norm2(); + const double radius = std::sqrt(best); + int lower[3]; + int upper[3]; + for (int a = 0; a < 3; ++a) + { + // Every better image lies inside these bounds, even for highly skew cells. + const double extent = radius * inverse_norm[a] + 1e-12; + lower[a] = static_cast(std::ceil(-delta[a] - extent)); + upper[a] = static_cast(std::floor(-delta[a] + extent)); + } + for (int i = lower[0]; i <= upper[0]; ++i) + { + for (int j = lower[1]; j <= upper[1]; ++j) + { + for (int k = lower[2]; k <= upper[2]; ++k) + { + const ModuleBase::Vector3 image(delta.x + i, delta.y + j, delta.z + k); + const double distance_sq = (image * lattice).norm2(); + best = std::min(best, distance_sq); + } + } + } + return best; +} +} // namespace + +std::vector td_voronoi_pw(const UnitCell& cell, const ModulePW::PW_Basis& grid) +{ + const ModuleBase::Matrix3 inverse = cell.latvec.Inverse(); + const std::array inverse_norm{ + {std::sqrt(inverse.e11 * inverse.e11 + inverse.e21 * inverse.e21 + inverse.e31 * inverse.e31), + std::sqrt(inverse.e12 * inverse.e12 + inverse.e22 * inverse.e22 + inverse.e32 * inverse.e32), + std::sqrt(inverse.e13 * inverse.e13 + inverse.e23 * inverse.e23 + inverse.e33 * inverse.e33)}}; + std::vector> atoms; + for (int it = 0; it < cell.ntype; ++it) + { + for (int ia = 0; ia < cell.atoms[it].na; ++ia) + { + atoms.push_back(cell.atoms[it].taud[ia]); + } + } + std::vector labels(grid.nrxx, 0); + for (int ir = 0; ir < grid.nrxx; ++ir) + { + const int ix = ir / (grid.ny * grid.nplane); + const int iy = ir / grid.nplane % grid.ny; + const int iz = ir % grid.nplane + grid.startz_current; + const ModuleBase::Vector3 point(double(ix) / grid.nx, double(iy) / grid.ny, double(iz) / grid.nz); + double best = std::numeric_limits::infinity(); + for (int atom = 0; atom < cell.nat; ++atom) + { + const ModuleBase::Vector3 delta = point - atoms[atom]; + const double distance = image_dist(delta, cell.latvec, inverse_norm); + const double tolerance = 64 * std::numeric_limits::epsilon() * std::max(1.0, distance); + if (atom == 0 || distance < best - tolerance) + { + best = distance; + labels[ir] = atom; + } + } + } + return labels; +} + +template +void TDSpinPW::initialize(const UnitCell& cell, + const ModulePW::PW_Basis& grid, + const ModulePW::PW_Basis_K& basis, + const K_Vectors& kv, + Structure_Factor& sf, + pseudopot_cell_vnl& pp, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque) +{ + if (cell_ != nullptr || cell.get_npol() != 2) + { + ModuleBase::WARNING_QUIT("TDSpinPW", "Initialize once with a spinor basis."); + } + if (mag_partition != "none" && mag_partition != "voronoi" && mag_partition != "onsite") + { + ModuleBase::WARNING_QUIT("TDSpinPW", "Unknown magnetic partition."); + } + cell_ = &cell; + grid_ = &grid; + basis_ = &basis; + kv_ = &kv; + sf_ = &sf; + pp_ = &pp; + mag_partition_ = mag_partition; + orbital_dir_ = orbital_dir; + onsite_radius_ = onsite_radius; + calc_torque_ = calc_torque; +} + +template +void TDSpinPW::sync_positions() +{ + bool changed = pos_cache_.size() != static_cast(cell_->nat); + int atom = 0; + for (int it = 0; !changed && it < cell_->ntype; ++it) + { + for (int ia = 0; !changed && ia < cell_->atoms[it].na; ++ia, ++atom) + { + changed = !(pos_cache_[atom] == cell_->atoms[it].taud[ia]); + } + } + if (!changed) + { + return; + } + // Atomic phases and nearest-atom labels change even at fixed grid, k point and vector potential. + labels_.clear(); + if (onsite_projector_) + { + onsite_projector_->invalidate_proj(); + } + pos_cache_.clear(); + for (int it = 0; it < cell_->ntype; ++it) + { + for (int ia = 0; ia < cell_->atoms[it].na; ++ia) + { + pos_cache_.push_back(cell_->atoms[it].taud[ia]); + } + } +} + +template +void TDSpinPW::density(const elecstate::ElecState& state, TDSpinResultPW* result) +{ + const UnitCell& cell = *cell_; + const ModulePW::PW_Basis& grid = *grid_; + const bool voronoi = mag_partition_ == "voronoi"; + if (voronoi && labels_.size() != static_cast(grid.nrxx)) + { + labels_ = td_voronoi_pw(cell, grid); + } + const double volume = cell.omega / grid.nxyz; + const double* const* rho = state.charge->rho; + const ModuleBase::matrix& potential = state.pot->get_eff_v(); + double totals[8] = {}; + if (voronoi) + { + result->atom_mag.assign(3 * cell.nat, 0.0); + } + for (int ir = 0; ir < grid.nrxx; ++ir) + { + double norm = 0.0; + for (int a = 0; a < 3; ++a) + { + const double m = rho[a + 1][ir]; + totals[a] += m * volume; + norm += m * m; + if (voronoi) + { + result->atom_mag[3 * labels_[ir] + a] += m * volume; + } + if (calc_torque_) + { + // The effective spin field is in Ry; the angular-momentum torque here uses Hartree time. + const int b = (a + 1) % 3; + const int c = (a + 2) % 3; + totals[5 + a] += 0.5 * volume * (potential(b + 1, ir) * rho[c + 1][ir] - potential(c + 1, ir) * rho[b + 1][ir]); + } + } + totals[3] += std::sqrt(norm) * volume; + totals[4] += rho[0][ir] * volume; + } + // Density already contains all k pools. Reduce only the grid partition. + Parallel_Reduce::reduce_pool(totals, 8); + if (voronoi) + { + const int count = result->atom_mag.size(); + Parallel_Reduce::reduce_pool(result->atom_mag.data(), count); + } + for (int a = 0; a < 3; ++a) + { + result->mag[a] = totals[a]; + result->xc[a] = totals[5 + a]; + } + result->mag_abs = totals[3]; + result->electrons = totals[4]; +} + +template +void TDSpinPW::soc(const psi::Psi& psi, + const ModuleBase::matrix& weights, + const ModuleBase::Vector3& a, + TDSpinResultPW* result) +{ + const UnitCell& cell = *cell_; + const ModulePW::PW_Basis_K& basis = *basis_; + pseudopot_cell_vnl& pp = *pp_; + result->atom_soc.assign(3 * cell.nat, 0.0); + if (pp.nkb == 0) + { + return; + } + using CtDevice = typename ct::PsiToContainer::type; + const ct::DeviceType device = ct::DeviceTypeToEnum::value; + const int nbands = psi.get_nbands(); + // Projection kernels count spin-component columns, not physical bands. + const int ncols = 2 * nbands; + const int ld_psi = psi.get_nbasis(); + const std::int64_t size = std::max(1, static_cast(pp.nkb) * basis.npwk_max); + // Empty local PW partitions still need a correctly typed buffer before projector reductions. + if (beta_.NumElements() < size || beta_.data_type() != ct::DataTypeToEnum::value || beta_.device_type() != device) + { + beta_ = ct::Tensor(ct::DataTypeToEnum::value, device, {size}); + } + Complex* beta = beta_.template data(); + const size_t count = static_cast(pp.nkb) * ncols; + projections_.resize(count); + contracted_.resize(count); + Device* context = nullptr; + for (int ik = 0; ik < basis.nks; ++ik) + { + psi.fix_k(ik); + const int npw = basis.npwk[ik]; + if (npw > 0) + { + pp.getvnl(context, cell, ik, a, beta); + } + nonlocal_.project_contract(cell, pp, basis, 0, ncols, ld_psi, 2, npw, beta, psi.get_pointer()); + if (basis.poolrank != 0) + { + // B and DB already contain the full pool sum; count each k-point contribution only once. + continue; + } + base_device::memory::synchronize_memory_op()(projections_.data(), + nonlocal_.projections(), + count); + base_device::memory::synchronize_memory_op()(contracted_.data(), + nonlocal_.contracted(), + count); + int offset = 0; + int atom = 0; + const Complex imaginary(0, 1); + for (int it = 0; it < cell.ntype; ++it) + { + const int nh = cell.atoms[it].ncpp.nh; + for (int ia = 0; ia < cell.atoms[it].na; ++ia, ++atom) + { + for (int p = offset; p < offset + nh; ++p) + { + for (int band = 0; band < nbands; ++band) + { + const Complex up = std::conj(projections_[(2 * band) * pp.nkb + p]); + const Complex down = std::conj(projections_[(2 * band + 1) * pp.nkb + p]); + const Complex du = contracted_[p * ncols + 2 * band]; + const Complex dd = contracted_[p * ncols + 2 * band + 1]; + const double weight = 0.5 * weights(ik, band); + result->atom_soc[3 * atom] += weight * std::imag(up * dd + down * du); + result->atom_soc[3 * atom + 1] += weight * std::imag(-imaginary * up * dd + imaginary * down * du); + result->atom_soc[3 * atom + 2] += weight * std::imag(up * du - down * dd); + } + } + offset += nh; + } + } + } + const int values = result->atom_soc.size(); + Parallel_Reduce::reduce_all(result->atom_soc.data(), values); + for (int atom = 0; atom < cell.nat; ++atom) + { + for (int a = 0; a < 3; ++a) + { + result->soc[a] += result->atom_soc[3 * atom + a]; + } + } +} + +template +void TDSpinPW::onsite(const psi::Psi& psi, + const elecstate::ElecState& state, + const ModuleBase::Vector3& a, + TDSpinResultPW* result) +{ + const UnitCell& cell = *cell_; + const ModulePW::PW_Basis_K& basis = *basis_; + const K_Vectors& kv = *kv_; + Structure_Factor& sf = *sf_; + // Onsite owns its atomic result; the independently integrated total moment remains unchanged. + result->atom_mag.assign(3 * cell.nat, 0.0); + const double dq = pp_->table_dq(); + using OnsiteValue = std::complex; + const int nbands = psi.get_nbands(); + const int ld_psi = psi.get_nbasis(); + if (!onsite_psi_) + { + const int npw = basis.npwk[0]; + onsite_psi_.reset(new psi::Psi(1, nbands, ld_psi, npw, true)); + onsite_projector_.reset(new projectors::OnsiteProjector()); + q_bound_ = td_momentum_bound(basis, cell.tpiba); + const int nq = static_cast(std::ceil(q_bound_ / dq)) + 4; + onsite_projector_->init(orbital_dir_, &cell, *onsite_psi_, kv, basis, sf, onsite_radius_, nq, dq, state.wg, state.ekb); + } + projectors::OnsiteProjector* projector = onsite_projector_.get(); + if (onsite_psi_->get_nbands() != nbands || onsite_psi_->get_nbasis() != ld_psi) + { + ModuleBase::WARNING_QUIT("TDSpinPW", "The onsite wavefunction layout changed after initialization."); + } + const double bound = q_bound_ + a.norm(); + projector->ensure_range(bound, dq); + const int nkb = projector->get_tot_nproj(); + const int npwx = ld_psi / 2; + const size_t size = static_cast(nbands) * ld_psi; + for (int ik = 0; ik < basis.nks; ++ik) + { + psi.fix_k(ik); + OnsiteValue* converted = onsite_psi_->get_pointer(); + if (size > 0) + { + // Onsite projections use double precision, so float spinors require a value conversion, not a pointer cast. + base_device::memory::cast_memory_op()(converted, psi.get_pointer(), size); + } + const int columns = 2 * nbands; + projector->overlap_td(ik, columns, converted, npwx, a); + if (basis.poolrank != 0) + { + // Overlaps are replicated after the pool reduction; count each occupied orbital only once. + continue; + } + const OnsiteValue* b = projector->get_h_becp(); + int offset = 0; + for (int atom = 0; atom < cell.nat; ++atom) + { + const int nh = projector->get_nh(atom); + for (int p = offset; p < offset + nh; ++p) + { + for (int band = 0; band < nbands; ++band) + { + const OnsiteValue up = b[2 * band * nkb + p]; + const OnsiteValue down = b[(2 * band + 1) * nkb + p]; + const double weight = state.wg(ik, band); + const OnsiteValue cross = std::conj(up) * down; + result->atom_mag[3 * atom] += 2 * weight * cross.real(); + result->atom_mag[3 * atom + 1] += 2 * weight * cross.imag(); + result->atom_mag[3 * atom + 2] += weight * (std::norm(up) - std::norm(down)); + } + } + offset += nh; + } + } + const int count = result->atom_mag.size(); + Parallel_Reduce::reduce_all(result->atom_mag.data(), count); +} + +template +TDSpinResultPW TDSpinPW::calculate(const psi::Psi& psi, + const elecstate::ElecState& state, + const ModuleBase::Vector3& a) +{ + ModuleBase::timer::start("TDSpinPW", "calculate"); + if (cell_ == nullptr) + { + ModuleBase::WARNING_QUIT("TDSpinPW", "Initialize before sampling observables."); + } + if (psi.get_npol() != 2 || psi.get_nbasis() != 2 * basis_->npwk_max) + { + ModuleBase::WARNING_QUIT("TDSpinPW", "Magnetic observables require the initialized spinor layout."); + } + sync_positions(); + const int old_k = psi.get_current_k(); + TDSpinResultPW result; + density(state, &result); + if (mag_partition_ == "onsite") + { + onsite(psi, state, a, &result); + } + if (calc_torque_) + { + soc(psi, state.wg, a, &result); + } + // Observable evaluation must preserve the caller's k-point cursor. + psi.fix_k(old_k); + ModuleBase::timer::end("TDSpinPW", "calculate"); + return result; +} + +template class TDSpinPW; +template class TDSpinPW; +#if defined(__CUDA) || defined(__ROCM) +template class TDSpinPW; +template class TDSpinPW; +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/td_spin_pw.h b/source/source_pw/module_rt/td_spin_pw.h new file mode 100644 index 00000000000..84b6f286c6a --- /dev/null +++ b/source/source_pw/module_rt/td_spin_pw.h @@ -0,0 +1,80 @@ +#ifndef TD_SPIN_PW_H +#define TD_SPIN_PW_H + +#include "source_base/module_container/ATen/core/tensor.h" +#include "source_estate/elecstate.h" +#include "source_pw/module_proj/onsite_proj.h" +#include "source_pw/module_pwdft/nonlocal_workspace.h" +#include "source_pw/module_rt/td_obs_pw.h" + +#include +#include +#include +#include + +namespace pw +{ +/** @brief Periodic nearest-atom labels on the local charge grid, in global atom order. */ +std::vector td_voronoi_pw(const UnitCell& cell, const ModulePW::PW_Basis& grid); + +/** @brief Endpoint magnetism with reusable device workspaces and position-aware caches. */ +template +class TDSpinPW +{ + private: + using Complex = std::complex; + const UnitCell* cell_ = nullptr; + const ModulePW::PW_Basis* grid_ = nullptr; + const ModulePW::PW_Basis_K* basis_ = nullptr; + const K_Vectors* kv_ = nullptr; + Structure_Factor* sf_ = nullptr; + pseudopot_cell_vnl* pp_ = nullptr; + std::string mag_partition_; + std::string orbital_dir_; + double onsite_radius_ = 0.0; + bool calc_torque_ = false; + std::vector> pos_cache_; + std::vector labels_; + hamilt::NonlocalWorkspace nonlocal_; + ct::Tensor beta_; + std::vector projections_; + std::vector contracted_; + std::unique_ptr, Device>> onsite_psi_; + // Destroy the projector before the wavefunction it borrows. + std::unique_ptr> onsite_projector_; + double q_bound_ = 0.0; + + void sync_positions(); + void density(const elecstate::ElecState& state, TDSpinResultPW* result); + void soc(const psi::Psi& psi, + const ModuleBase::matrix& weights, + const ModuleBase::Vector3& a, + TDSpinResultPW* result); + void onsite(const psi::Psi& psi, + const elecstate::ElecState& state, + const ModuleBase::Vector3& a, + TDSpinResultPW* result); + + public: + /** @brief Bind once; dependencies outlive this object and retain their cell and layout. + * The caller must refresh structure factors and electronic data before sampling moved ions. + * @param mag_partition Atomic moment partition: none, voronoi, or onsite. + * @param orbital_dir Directory containing the onsite projector orbitals. + * @param onsite_radius Onsite projector cutoff in Bohr. + * @param calc_torque Whether to calculate XC and SOC spin torques. + */ + void initialize(const UnitCell& cell, + const ModulePW::PW_Basis& grid, + const ModulePW::PW_Basis_K& basis, + const K_Vectors& kv, + Structure_Factor& sf, + pseudopot_cell_vnl& pp, + const std::string& mag_partition, + const std::string& orbital_dir, + double onsite_radius, + bool calc_torque); + /** @brief Sample all ranks and restore the k cursor; coordinate changes invalidate geometric caches. */ + TDSpinResultPW calculate(const psi::Psi& psi, const elecstate::ElecState& state, const ModuleBase::Vector3& a); +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/td_vel_pw.cpp b/source/source_pw/module_rt/td_vel_pw.cpp new file mode 100644 index 00000000000..345d249c363 --- /dev/null +++ b/source/source_pw/module_rt/td_vel_pw.cpp @@ -0,0 +1,205 @@ +#include "source_pw/module_rt/td_vel_pw.h" + +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" +#include "source_hsolver/module_linalg/kernels/linear_op.h" + +#include +#include +#include + +namespace pw +{ +template +void TDVelPW::initialize(const UnitCell& cell, const ModulePW::PW_Basis_K& basis, const K_Vectors& kv, pseudopot_cell_vnl& pp) +{ + if (cell_ != nullptr) + { + ModuleBase::WARNING_QUIT("TDVelPW", "Initialize once before sampling."); + } + cell_ = &cell; + basis_ = &basis; + kv_ = &kv; + pp_ = &pp; +} + +template +TDVelResultPW TDVelPW::calculate(const psi::Psi& psi, + const elecstate::ElecState& state, + const ModuleBase::Vector3& a, + const CurrentRequest& request) +{ + ModuleBase::timer::start("TDVelPW", "calculate"); + if (cell_ == nullptr) + { + ModuleBase::WARNING_QUIT("TDVelPW", "Initialize before sampling observables."); + } + TDVelResultPW result; + if (!request.charge_total && !request.charge_per_k && !request.spin_current) + { + ModuleBase::timer::end("TDVelPW", "calculate"); + return result; + } + const int npol = psi.get_npol(); + const int npwx = basis_->npwk_max; + const int nbands = psi.get_nbands(); + const int ncols = nbands * npol; + const int old_k = psi.get_current_k(); + if (psi.get_nbasis() != npwx * npol || npol != cell_->get_npol() || (request.spin_current && npol != 2)) + { + ModuleBase::WARNING_QUIT("TDVelPW", "Incompatible wavefunction layout or spin-current request."); + } + + if (!vel_) + { + vel_.reset(new hamilt::Velocity(basis_, kv_->isk.data(), pp_, cell_, true, nullptr, 0, 0)); + } + + using CtDevice = typename ct::PsiToContainer::type; + using CopyToHost = base_device::memory::synchronize_memory_op; + using Zero = base_device::memory::set_memory_op; + const ct::DeviceType device = ct::DeviceTypeToEnum::value; + const std::int64_t comp_size = static_cast(ncols) * npwx; + const std::int64_t vel_size = 3 * comp_size; + const std::int64_t capacity = std::max(1, vel_size); + const std::int64_t dot_size = std::max(1, ncols); + // Default tensors contain one CPU float element; capacity alone does not establish a usable buffer. + if (vpsi_.NumElements() < capacity || vpsi_.data_type() != ct::DataTypeToEnum::value || vpsi_.device_type() != device) + { + vpsi_ = ct::Tensor(ct::DataTypeToEnum::value, device, {capacity}); + } + if (dots_.NumElements() < dot_size || dots_.data_type() != ct::DataTypeToEnum::value || dots_.device_type() != device) + { + dots_ = ct::Tensor(ct::DataTypeToEnum::value, device, {dot_size}); + } + Complex* vpsi = vpsi_.template data(); + Complex* dots = dots_.template data(); + diag_.resize(ncols); + if (request.spin_current) + { + cross_.resize(nbands); + } + if (request.charge_per_k) + { + const std::int64_t size = 3 * static_cast(kv_->get_nkstot()); + result.per_k.resize(size, 0.0); + } + + for (int ik = 0; ik < basis_->nks; ++ik) + { + psi.fix_k(ik); + const Complex* data = psi.get_pointer(); + const int npw = basis_->npwk[ik]; + if (vel_size > 0) + { + Zero()(vpsi, 0, vel_size); + } + vel_->init(ik, a); + vel_->act(&psi, ncols, data, vpsi, false); + if (npw == 0) + { + // Projection reductions above are collective; only local inner products can be skipped. + continue; + } + for (int id = 0; id < 3; ++id) + { + const Complex* component = vpsi + id * comp_size; + // Each spin component is one npwx-strided column; reuse its diagonal product for both currents. + hsolver::linear_op().dot(npwx, npw, ncols, data, component, dots); + CopyToHost()(diag_.data(), dots, ncols); + if (request.charge_total || request.charge_per_k) + { + for (int ib = 0; ib < nbands; ++ib) + { + double value = 0.0; + for (int spin = 0; spin < npol; ++spin) + { + value += std::real(diag_[ib * npol + spin]); + } + const double charge = -state.wg(ik, ib) * value; + if (request.charge_total) + { + result.total[id] += charge; + } + if (request.charge_per_k) + { + const std::int64_t index = 3 * static_cast(kv_->ik2iktot[ik]) + id; + result.per_k[index] += charge; + } + } + } + if (request.spin_current) + { + const int ld_psi = 2 * npwx; + // Sigma_z uses the diagonal products already needed by charge current; S = sigma/2. + for (int spin = 0; spin < 2; ++spin) + { + const double sign = spin == 0 ? 1.0 : -1.0; + for (int ib = 0; ib < nbands; ++ib) + { + const double weight = 0.5 * state.wg(ik, ib); + result.spin[3 * id + 2] += weight * sign * std::real(diag_[2 * ib + spin]); + } + } + // Sigma_x adds the cross products, while sigma_y takes their imaginary parts with opposite signs. + for (int left = 0; left < 2; ++left) + { + const int right = 1 - left; + const Complex* bra = data + left * npwx; + const Complex* ket = component + right * npwx; + hsolver::linear_op().dot(ld_psi, npw, nbands, bra, ket, dots); + CopyToHost()(cross_.data(), dots, nbands); + const double sign = left == 0 ? 1.0 : -1.0; + for (int ib = 0; ib < nbands; ++ib) + { + const double weight = 0.5 * state.wg(ik, ib); + result.spin[3 * id] += weight * std::real(cross_[ib]); + result.spin[3 * id + 1] += weight * sign * std::imag(cross_[ib]); + } + } + } + } + } + // Sampling must not leave a different k-point selected for the propagation driver. + psi.fix_k(old_k); + if (request.charge_total) + { + Parallel_Reduce::reduce_all(result.total.data(), 3); + } + const std::int64_t max_chunk = std::numeric_limits::max(); + const std::int64_t k_size = result.per_k.size(); + for (std::int64_t offset = 0; offset < k_size;) + { + const std::int64_t remaining = k_size - offset; + const int count = static_cast(std::min(max_chunk, remaining)); + double* chunk = result.per_k.data() + offset; + Parallel_Reduce::reduce_all(chunk, count); + offset += count; + } + if (request.spin_current) + { + Parallel_Reduce::reduce_all(result.spin.data(), 9); + } + for (double& value: result.total) + { + value /= cell_->omega; + } + for (double& value: result.per_k) + { + value /= cell_->omega; + } + for (double& value: result.spin) + { + value /= cell_->omega; + } + ModuleBase::timer::end("TDVelPW", "calculate"); + return result; +} + +template class TDVelPW; +template class TDVelPW; +#if defined(__CUDA) || defined(__ROCM) +template class TDVelPW; +template class TDVelPW; +#endif +} // namespace pw diff --git a/source/source_pw/module_rt/td_vel_pw.h b/source/source_pw/module_rt/td_vel_pw.h new file mode 100644 index 00000000000..7ca602f0540 --- /dev/null +++ b/source/source_pw/module_rt/td_vel_pw.h @@ -0,0 +1,44 @@ +#ifndef TD_VEL_PW_H +#define TD_VEL_PW_H + +#include "source_estate/elecstate.h" +#include "source_pw/module_pwdft/op_pw_vel.h" +#include "source_pw/module_rt/td_obs_pw.h" + +#include +#include +#include + +namespace pw +{ +/** @brief Charge and spin currents sharing one velocity action per k point. */ +template +class TDVelPW +{ + private: + using Complex = std::complex; + const UnitCell* cell_ = nullptr; + const ModulePW::PW_Basis_K* basis_ = nullptr; + const K_Vectors* kv_ = nullptr; + pseudopot_cell_vnl* pp_ = nullptr; + std::unique_ptr> vel_; + ct::Tensor vpsi_; + ct::Tensor dots_; + std::vector diag_; + std::vector cross_; + + public: + /** @brief Bind once; dependencies must outlive this object and retain their layout. + * Ionic positions may change after the caller updates the structure factors. + */ + void initialize(const UnitCell& cell, const ModulePW::PW_Basis_K& basis, const K_Vectors& kv, pseudopot_cell_vnl& pp); + /** @brief Sample an endpoint on all ranks, restoring the wavefunction's k-point cursor. + * Spin current requires npol=2; requests must agree across ranks. + */ + TDVelResultPW calculate(const psi::Psi& psi, + const elecstate::ElecState& state, + const ModuleBase::Vector3& a, + const CurrentRequest& request); +}; +} // namespace pw +#endif diff --git a/source/source_pw/module_rt/unittests/CMakeLists.txt b/source/source_pw/module_rt/unittests/CMakeLists.txt new file mode 100644 index 00000000000..7bc58db6f3a --- /dev/null +++ b/source/source_pw/module_rt/unittests/CMakeLists.txt @@ -0,0 +1,65 @@ +abacus_disable_feature_definitions(__MLALGO) +abacus_disable_feature_definitions(__CUDA) +abacus_disable_feature_definitions(__ROCM) +abacus_disable_feature_definitions(__EXX) + +set(LINALG_DIR ${PROJECT_SOURCE_DIR}/source/source_hsolver/module_linalg) +AddTest( + TARGET MODULE_PW_cn_solver + LIBS parameter base device container psi planewave + SOURCES test_cn_solver_pw.cpp ../cn_solver_pw.cpp ../td_orbital_ops.cpp + ${LINALG_DIR}/hsolver_linear.cpp + ${LINALG_DIR}/linear_bicgstab.cpp + ${LINALG_DIR}/linear_cgs.cpp + ${LINALG_DIR}/linear_gmres.cpp + ${LINALG_DIR}/linear_algebra.cpp + ${LINALG_DIR}/cn_subspace.cpp + ${LINALG_DIR}/linear_low_rank.cpp + ${LINALG_DIR}/linear_workspace.cpp + ${LINALG_DIR}/orb_buffer.cpp + ${LINALG_DIR}/orthonormal.cpp + ${LINALG_DIR}/orthonormal_small.cpp +) + +if(ENABLE_MPI) + AddTest( + TARGET MODULE_PW_td_observables + LIBS parameter base device container psi planewave nao_smoothgen symmetry + SOURCES + td_test_utils.cpp test_td_spin_pw.cpp test_td_vel_pw.cpp + ../td_spin_pw.cpp ../td_vel_pw.cpp ../td_pw.cpp + ../../module_pwdft/op_pw_vel.cpp ../../module_pwdft/projector_gradient.cpp ../../module_pwdft/velocity_workspace.cpp ../../module_pwdft/nonlocal_workspace.cpp + ../../module_pwdft/vnl_pw.cpp ../../module_pwdft/vnl_pw_init_vnl.cpp ../../module_pwdft/vnl_pw_getvnl.cpp ../../module_pwdft/vnl_pw_deeq.cpp + ../../module_pwdft/vnl_pw_grad.cpp ../../module_pwdft/vnl_pw_table.cpp ../../module_pwdft/vnl_pw_qrad.cpp + ../../module_pwdft/stru_fac.cpp ../../module_pwdft/stru_fac_k.cpp ../../module_pwdft/soc.cpp ../../module_pwdft/nonlocal_maths.cpp + ../../module_proj/onsite_proj.cpp ../../module_proj/onsite_proj_init.cpp + ../../module_proj/onsite_proj_overlap.cpp ../../module_proj/onsite_proj_tools.cpp + ../../module_proj/onsite_proj_tools_becp.cpp ../../module_proj/radial_proj.cpp + ../../module_proj/onsite_proj_print.cpp + ../../../source_basis/module_ao/orb_gaunt_table.cpp + ../../../source_cell/klist.cpp ../../../source_cell/reciprocal_grid.cpp + ../../../source_cell/klist_io.cpp + ../../../source_cell/unitcell.cpp ../../../source_cell/unitcell_index.cpp + ../../../source_cell/atom_spec.cpp ../../../source_cell/atom_pseudo.cpp ../../../source_cell/pseudo.cpp + ../../../source_cell/magnetism.cpp ../../../source_cell/sep.cpp ../../../source_cell/sep_cell.cpp + ../../../source_cell/read_pp.cpp ../../../source_cell/read_pp_complete.cpp + ../../../source_cell/read_pp_upf100.cpp ../../../source_cell/read_pp_upf201.cpp + ../../../source_cell/read_pp_vwr.cpp ../../../source_cell/read_pp_blps.cpp + ../../../source_estate/elecstate.cpp ../../../source_estate/module_charge/charge.cpp + ../../../source_estate/module_pot/potential_new.cpp + ../../../source_hamilt/module_xc/xc_functional.cpp + ) + target_compile_definitions(MODULE_PW_td_observables PRIVATE TD_TEST_PP_DIR="${PROJECT_SOURCE_DIR}/tests/PP_ORB") + # Keep real PW initialization and observable implementations without linking the SCF driver. + if(MSVC) + target_compile_options(MODULE_PW_td_observables PRIVATE /Gy /Gw) + target_link_options(MODULE_PW_td_observables PRIVATE /OPT:REF) + else() + target_compile_options(MODULE_PW_td_observables PRIVATE -ffunction-sections -fdata-sections) + if(APPLE) + target_link_options(MODULE_PW_td_observables PRIVATE -Wl,-dead_strip) + else() + target_link_options(MODULE_PW_td_observables PRIVATE -Wl,--gc-sections) + endif() + endif() +endif() diff --git a/source/source_pw/module_rt/unittests/td_test_utils.cpp b/source/source_pw/module_rt/unittests/td_test_utils.cpp new file mode 100644 index 00000000000..ac473caf9fb --- /dev/null +++ b/source/source_pw/module_rt/unittests/td_test_utils.cpp @@ -0,0 +1,243 @@ +#include "source_base/parallel_global.h" +#include "source_cell/read_pp.h" +#include "source_pw/module_rt/unittests/td_test_utils.h" + +#include +#include + +static_assert(noexcept(std::swap(std::declval(), std::declval())), + "Test input installation and restoration must not throw."); +static_assert(noexcept(std::swap(std::declval(), std::declval())), + "Test system installation and restoration must not throw."); + +TestParameters::TestParameters(Parameter& target) : target_(target) +{ + input_.nspin = 4; + input_.noncolin = true; + input_.lspinorb = true; + input_.device = "cpu"; + input_.basis_type = "pw"; + input_.precision = "double"; + system_.nqx = 600; + system_.nqxq = 600; + system_.has_double_data = true; + system_.has_float_data = false; + // Prepare the complete configuration before installing it; retain the original state in these members. + std::swap(target_.input, input_); + std::swap(target_.sys, system_); +} + +TestParameters::~TestParameters() noexcept +{ + std::swap(target_.input, input_); + std::swap(target_.sys, system_); +} + +namespace td_test +{ +Observables::Observables() : parameters_(PARAM) +{ +} + +void Observables::SetUp() +{ + cell_.ntype = 1; + cell_.nat = 2; + cell_.atoms = new Atom[1]; + cell_.set_atom_flag = true; + cell_.atoms[0].na = 2; + cell_.atoms[0].label = "Fe"; + cell_.atoms[0].taud = {{0.11, 0.21, 0.31}, {0.59, 0.43, 0.77}}; + cell_.lat0 = 6.0; + cell_.latvec = ModuleBase::Matrix3(1, 0, 0, 0.4, 0.8, 0, 0.1, 0.2, 1); + cell_.G = cell_.latvec.Inverse().Transpose(); + cell_.omega = std::pow(cell_.lat0, 3) * cell_.latvec.Det(); + cell_.tpiba = ModuleBase::TWO_PI / cell_.lat0; + cell_.tpiba2 = cell_.tpiba * cell_.tpiba; + for (const ModuleBase::Vector3& position: cell_.atoms[0].taud) + { + cell_.atoms[0].tau.push_back(position * cell_.latvec); + } + cell_.set_iat2itia(); + cell_.set_iat2iwt(2); + + Pseudopot_upf reader; + std::string type = "upf201"; + const std::string filename = std::string(TD_TEST_PP_DIR) + "/Fe.upf"; + ASSERT_EQ(reader.init_pseudo_reader(filename, type, cell_.atoms[0].ncpp), 0); + Atom_pseudo& atom_pp = cell_.atoms[0].ncpp; + atom_pp.nh = 0; + for (const int l: atom_pp.lll) + { + atom_pp.nh += 2 * l + 1; + } + +#ifdef __MPI + basis_.initmpi(1, 0, POOL_WORLD); +#endif + basis_.initgrids(cell_.lat0, cell_.latvec, 12.0); + const ModuleBase::Vector3 k(0.17, 0.11, 0.07); + basis_.initparameters(false, 3.0, 1, &k); + basis_.setuptransform(); + basis_.collect_local_pw(); + kv_.set_nkstot(1); + kv_.set_nks(1); + kv_.isk = {0}; + kv_.ik2iktot = {0}; + sf_.set(&basis_, 0); + Parallel_Grid grid; + sf_.setup(&cell_, grid, &basis_, false); + pp_.init(cell_, &sf_, &basis_, true); + pp_.init_vnl(cell_, &basis_); + charge_.set_rhopw(&basis_); + charge_.allocate(4, false, false, 0); + state_.charge = &charge_; + state_.pot = new elecstate::Potential; + state_.pot->get_eff_v().create(4, basis_.nrxx); + pp_.cal_effective_D(state_.pot->get_eff_v(), &basis_, cell_); + state_.wg.create(1, 2); + state_.wg(0, 0) = 0.8; + state_.wg(0, 1) = 0.3; + const int n = 2 * basis_.npwk_max; + const std::vector sizes{basis_.npwk[0]}; + psi_.reset(new psi::Psi(1, 2, n, sizes, true)); + for (int band = 0; band < 2; ++band) + { + double norm = 0; + for (int i = 0; i < n; ++i) + { + const Complex value(std::sin(0.37 * (i + 1) * (band + 1)), std::cos(0.23 * (i + 2) * (band + 2))); + (*psi_)(band, i) = value; + norm += std::norm(value); + } + for (int i = 0; i < n; ++i) + { + (*psi_)(band, i) /= std::sqrt(norm); + } + } +} + +void Observables::TearDown() +{ + pp_.release_memory(); +} + +Vector Observables::projectors(const ModuleBase::Vector3& a) +{ + Vector beta(pp_.nkb * basis_.npwk_max); + pp_.getvnl(nullptr, cell_, 0, a, beta.data()); + return beta; +} + +Vector Observables::nonlocal(const Vector& beta, const Vector& x, int atom) const +{ + // Explicit beta D beta-adjoint action in Hartree units, independent of the production contraction kernels. + const int npw = basis_.npwk[0]; + const int nh = cell_.atoms[0].ncpp.nh; + Vector b(2 * nh, 0.0); + for (int s = 0; s < 2; ++s) + { + for (int p = 0; p < nh; ++p) + { + for (int g = 0; g < npw; ++g) + { + b[s * nh + p] += std::conj(beta[(atom * nh + p) * npw + g]) * x[s * npw + g]; + } + } + } + Vector y(x.size(), 0.0); + for (int s = 0; s < 2; ++s) + { + for (int t = 0; t < 2; ++t) + { + for (int p = 0; p < nh; ++p) + { + for (int q = 0; q < nh; ++q) + { + const Complex db = 0.5 * pp_.deeq_nc(2 * s + t, atom, p, q) * b[t * nh + q]; + for (int g = 0; g < npw; ++g) + { + y[s * npw + g] += beta[(atom * nh + p) * npw + g] * db; + } + } + } + } + } + return y; +} + +Vector Observables::hamiltonian(const ModuleBase::Vector3& a, const Vector& x) +{ + const Vector beta = projectors(a); + Vector y(x.size(), 0.0); + for (int atom = 0; atom < cell_.nat; ++atom) + { + const Vector term = nonlocal(beta, x, atom); + for (size_t i = 0; i < x.size(); ++i) + { + y[i] += term[i]; + } + } + const int npw = basis_.npwk[0]; + for (int g = 0; g < npw; ++g) + { + const ModuleBase::Vector3 q = basis_.getgpluskcar(0, g) * cell_.tpiba + a; + for (int s = 0; s < 2; ++s) + { + y[s * npw + g] += 0.5 * q.norm2() * x[s * npw + g]; + } + } + return y; +} + +Vector pauli(const Vector& x, int axis) +{ + const Complex matrices[3][4] = {{0.0, 1.0, 1.0, 0.0}, {0.0, Complex(0, -1), Complex(0, 1), 0.0}, {1.0, 0.0, 0.0, -1.0}}; + const int npw = x.size() / 2; + Vector y(x.size(), 0.0); + for (int s = 0; s < 2; ++s) + { + for (int t = 0; t < 2; ++t) + { + for (int g = 0; g < npw; ++g) + { + y[s * npw + g] += matrices[axis][2 * s + t] * x[t * npw + g]; + } + } + } + return y; +} + +Complex inner(const Vector& x, const Vector& y) +{ + Complex value(0); + for (size_t i = 0; i < x.size(); ++i) + { + value += std::conj(x[i]) * y[i]; + } + return value; +} +} // namespace td_test + +int main(int argc, char** argv) +{ + int nproc = 1; + int nthread = 1; + int rank = 0; + Parallel_Global::read_pal_param(argc, argv, nproc, nthread, rank); +#ifdef __MPI + POOL_WORLD = MPI_COMM_SELF; +#endif + testing::InitGoogleTest(&argc, argv); + const int result = RUN_ALL_TESTS(); +#ifdef __MPI + POOL_WORLD = MPI_COMM_NULL; + KP_WORLD = MPI_COMM_NULL; + INT_BGROUP = MPI_COMM_NULL; + BP_WORLD = MPI_COMM_NULL; + GRID_WORLD = MPI_COMM_NULL; + DIAG_WORLD = MPI_COMM_NULL; + Parallel_Global::finalize_mpi(); +#endif + return result; +} diff --git a/source/source_pw/module_rt/unittests/td_test_utils.h b/source/source_pw/module_rt/unittests/td_test_utils.h new file mode 100644 index 00000000000..59f8817fe89 --- /dev/null +++ b/source/source_pw/module_rt/unittests/td_test_utils.h @@ -0,0 +1,59 @@ +#ifndef TD_TEST_UTILS_H +#define TD_TEST_UTILS_H + +#include "source_io/module_parameter/parameter.h" +#include "source_pw/module_rt/td_spin_pw.h" +#include "source_pw/module_rt/td_vel_pw.h" + +#include + +/** @brief Install isolated spinor test settings and restore the supplied parameter object's state. */ +class TestParameters +{ + private: + Parameter& target_; + Input_para input_; + System_para system_; + + public: + explicit TestParameters(Parameter& target); + ~TestParameters() noexcept; + TestParameters(const TestParameters&) = delete; + TestParameters& operator=(const TestParameters&) = delete; + TestParameters(TestParameters&&) = delete; + TestParameters& operator=(TestParameters&&) = delete; +}; + +namespace td_test +{ +using Complex = std::complex; +using Device = base_device::DEVICE_CPU; +using Vector = std::vector; + +/** @brief Small real PW basis and relativistic projectors, without an SCF calculation. */ +class Observables : public testing::Test +{ + protected: + TestParameters parameters_; + UnitCell cell_; + ModulePW::PW_Basis_K basis_; + K_Vectors kv_; + Structure_Factor sf_; + pseudopot_cell_vnl pp_; + Charge charge_; + elecstate::ElecState state_; + std::unique_ptr> psi_; + + Observables(); + void SetUp() override; + void TearDown() override; + Vector projectors(const ModuleBase::Vector3& a); + Vector nonlocal(const Vector& beta, const Vector& x, int atom) const; + Vector hamiltonian(const ModuleBase::Vector3& a, const Vector& x); +}; + +/** @brief Apply a Pauli matrix to a packed two-component vector. */ +Vector pauli(const Vector& x, int axis); +Complex inner(const Vector& x, const Vector& y); +} // namespace td_test +#endif diff --git a/source/source_hsolver/test/test_hsolver_pw_tddft.cpp b/source/source_pw/module_rt/unittests/test_cn_solver_pw.cpp similarity index 70% rename from source/source_hsolver/test/test_hsolver_pw_tddft.cpp rename to source/source_pw/module_rt/unittests/test_cn_solver_pw.cpp index 8500e142329..9f08e3d0aba 100644 --- a/source/source_hsolver/test/test_hsolver_pw_tddft.cpp +++ b/source/source_pw/module_rt/unittests/test_cn_solver_pw.cpp @@ -1,6 +1,7 @@ #include "source_base/parallel_global.h" -#include "source_hsolver/hsolver_pw_tddft.h" -#include "source_hsolver/test/linear_test_utils.h" +#include "source_pw/module_rt/cn_solver_pw.h" +#include "source_pw/module_rt/td_orbital_ops.h" +#include "source_hsolver/module_linalg/unittests/linear_test_utils.h" #include #include @@ -20,6 +21,7 @@ class DenseHamiltonian final : public hsolver::HSOperator public: std::vector> matrices; std::vector dimensions; + bool spinor = false; explicit DenseHamiltonian(const std::vector& sizes) : dimensions(sizes) { @@ -38,12 +40,14 @@ class DenseHamiltonian final : public hsolver::HSOperator const std::vector& h = matrices.at(current_k_); for (int band = 0; band < nvec; ++band) { + std::fill_n(y + band * ld, ld, T(0)); for (int i = 0; i < n; ++i) { - y[band * ld + i] = T(0); + const int row = spinor ? (i / (n / 2)) * (ld / 2) + i % (n / 2) : i; for (int j = 0; j < n; ++j) { - y[band * ld + i] += h[j * n + i] * x[band * ld + j]; + const int col = spinor ? (j / (n / 2)) * (ld / 2) + j % (n / 2) : j; + y[band * ld + row] += h[j * n + i] * x[band * ld + col]; } } } @@ -147,6 +151,107 @@ class PWTDDFTTest : public testing::Test using Precisions = testing::Types; TYPED_TEST_SUITE(PWTDDFTTest, Precisions); +TYPED_TEST(PWTDDFTTest, SpinorCNMatchesDenseSolve) +{ + using T = std::complex; + using Wide = linear_test::Complex; + const bool single = std::is_same::value; + const double tolerance = single ? 1e-4 : 1e-10; + const std::vector sizes{5, 3}; + const int npwx = 5; + const int bands = 3; + const double dt = 0.27; + ModulePW::PW_Basis_K basis; + initialize_basis(sizes, &basis); + const std::vector dimensions{2 * sizes[0], 2 * sizes[1]}; + DenseHamiltonian op(dimensions); + op.spinor = true; + hsolver::CNControls cn_ctrl; + const int npol = 2; + const std::vector global_k{0, 1}; + cn_ctrl.linear.solver = hsolver::LinearMethod::bicgstab; + cn_ctrl.linear.tolerance = single ? 2e-6 : 1e-13; + cn_ctrl.linear.max_iterations = 100; + cn_ctrl.kinetic_enabled = true; +#ifdef __MPI + const hsolver::diag_comm_info comm(MPI_COMM_SELF, 0, 1); +#else + const hsolver::diag_comm_info comm(0, 1); +#endif + std::ostringstream log; + hsolver::TDOrbOps orbitals(npol, hsolver::OrthMethod::cholesky, false, global_k, comm, log); + hsolver::CNSolverPW solver(basis, cn_ctrl, npol, global_k, comm, log); + const int ld = 2 * npwx; + psi::Psi previous(2, bands, ld, sizes, true); + std::vector> packed(2); + const T padding(std::numeric_limits::quiet_NaN()); + for (int ik = 0; ik < 2; ++ik) + { + previous.fix_k(ik); + const int n = dimensions[ik]; + packed[ik].resize(n * bands); + std::fill_n(previous.get_pointer(), ld * bands, padding); + for (int band = 0; band < bands; ++band) + { + for (int i = 0; i < n; ++i) + { + const double phase = 2 * std::acos(-1.0) * i * band / n; + const T value = T(std::polar(1.0 / std::sqrt(n), phase)); + const int row = (i / sizes[ik]) * npwx + i % sizes[ik]; + previous(band, row) = value; + packed[ik][band * n + i] = value; + } + } + } + psi::Psi current(previous); + const ModuleBase::Vector3 shift(0.13, -0.07, 0.02); + solver.solve(op, previous, ¤t, dt, shift, 1, 1, false); + orbitals.correct(¤t, 1, 1, false); + for (int ik = 0; ik < 2; ++ik) + { + current.fix_k(ik); + const int n = dimensions[ik]; + const std::vector reference = dense_cn(op.matrices[ik], packed[ik], n, bands, dt); + const std::vector> eij = orbitals.cal_eij(op, current, ik); + for (int band = 0; band < bands; ++band) + { + for (int spin = 0; spin < 2; ++spin) + { + for (int g = 0; g < npwx; ++g) + { + const int row = spin * npwx + g; + if (g < sizes[ik]) + { + const Wide expected = reference[band * n + spin * sizes[ik] + g]; + EXPECT_NEAR(std::abs(Wide(current(band, row)) - expected), 0.0, tolerance); + } + else + { + EXPECT_EQ(current(band, row), T(0)); + } + } + } + for (int other = 0; other < bands; ++other) + { + Wide overlap(0); + Wide expectation(0); + for (int i = 0; i < n; ++i) + { + const int row = (i / sizes[ik]) * npwx + i % sizes[ik]; + overlap += std::conj(Wide(current(other, row))) * Wide(current(band, row)); + for (int j = 0; j < n; ++j) + { + expectation += std::conj(reference[other * n + i]) * Wide(op.matrices[ik][j * n + i]) * reference[band * n + j]; + } + } + const Wide identity = band == other ? Wide(1) : Wide(0); + EXPECT_NEAR(std::abs(overlap - identity), 0.0, tolerance); + EXPECT_NEAR(std::abs(eij[band * bands + other] - expectation), 0.0, tolerance); + } + } + } +} + TYPED_TEST(PWTDDFTTest, ComplexEijExcludesPadding) { using T = std::complex; @@ -156,15 +261,16 @@ TYPED_TEST(PWTDDFTTest, ComplexEijExcludesPadding) ModulePW::PW_Basis_K basis; initialize_basis(sizes, &basis); DenseHamiltonian op(sizes); - hsolver::PWLinearOptions options; - options.global_k_indices = {0}; + hsolver::CNControls cn_ctrl; + const std::vector global_k{0}; #ifdef __MPI const hsolver::diag_comm_info comm(MPI_COMM_SELF, 0, 1); #else const hsolver::diag_comm_info comm(0, 1); #endif std::ostringstream log; - hsolver::HSolverPWTDDFT solver(basis, options, comm, log); + hsolver::TDOrbOps orbitals(1, hsolver::OrthMethod::cholesky, false, global_k, comm, log); + hsolver::CNSolverPW solver(basis, cn_ctrl, 1, global_k, comm, log); psi::Psi current(1, bands, ld, sizes, true); const T phases[]{T(1), T(0, 1), T(-1)}; const T padding(std::numeric_limits::quiet_NaN()); @@ -176,7 +282,7 @@ TYPED_TEST(PWTDDFTTest, ComplexEijExcludesPadding) } current(band, band) = phases[band]; } - const std::vector> eij = solver.cal_eij(op, current, 0); + const std::vector> eij = orbitals.cal_eij(op, current, 0); ASSERT_EQ(eij.size(), bands * bands); // These orbitals select H's leading block, with an independent phase on each column. for (int j = 0; j < bands; ++j) @@ -223,18 +329,19 @@ TYPED_TEST(PWTDDFTTest, DenseCNCorrectorsAndConservation) initialize_basis(sizes, &basis); DenseHamiltonian op(sizes); std::ostringstream log; - hsolver::PWLinearOptions options; - options.global_k_indices = {0, 1}; + hsolver::CNControls cn_ctrl; + const std::vector global_k{0, 1}; const std::string solver_name = cn_variant ? method.substr(0, method.size() - 3) : method; - options.linear.method = hsolver::parse_linear_method(solver_name); - options.linear.tolerance = single_precision ? 2e-6 : 1e-13; - options.linear.max_iterations = 100; - options.preconditioner = hsolver::parse_pw_precond(precond); - options.kinetic_enabled = true; - options.linear.restart = 2; - options.linear.reconstruct = method == "gmres" && recycle; - options.cn_init = method == "gmres" || cn_variant; - hsolver::HSolverPWTDDFT solver(basis, options, comm, log); + cn_ctrl.linear.solver = hsolver::parse_linear_method(solver_name); + cn_ctrl.linear.tolerance = single_precision ? 2e-6 : 1e-13; + cn_ctrl.linear.max_iterations = 100; + cn_ctrl.preconditioner = hsolver::parse_pw_precond(precond); + cn_ctrl.kinetic_enabled = true; + cn_ctrl.linear.restart = 2; + cn_ctrl.linear.reconstruct = method == "gmres" && recycle; + cn_ctrl.cn_init = method == "gmres" || cn_variant; + hsolver::TDOrbOps orbitals(1, hsolver::OrthMethod::cholesky, false, global_k, comm, log); + hsolver::CNSolverPW solver(basis, cn_ctrl, 1, global_k, comm, log); psi::Psi previous(2, bands, ld, sizes, true); for (int ik = 0; ik < 2; ++ik) { @@ -256,6 +363,7 @@ TYPED_TEST(PWTDDFTTest, DenseCNCorrectorsAndConservation) log.str(""); log.clear(); solver.solve(op, previous, ¤t, step_dt, shift, step, 1, true); + orbitals.correct(¤t, step, 1, true); check_dense_step(op, previous, current, step_dt); if (recycle || precond == "kinetic_subspace") { @@ -307,6 +415,7 @@ TYPED_TEST(PWTDDFTTest, DenseCNCorrectorsAndConservation) log.str(""); log.clear(); solver.solve(op, previous, ¤t, step_dt, shift, step, 2, true); + orbitals.correct(¤t, step, 2, true); check_dense_step(op, previous, current, step_dt); EXPECT_EQ(log.str().find("cn_initial=1"), std::string::npos); } @@ -321,7 +430,7 @@ TYPED_TEST(PWTDDFTTest, DenseCNCorrectorsAndConservation) } } ModuleBase::matrix energies(2, bands); - solver.cal_band_energy(op, current, &energies); + orbitals.cal_band_energy(op, current, &energies); for (int ik = 0; ik < 2; ++ik) { current.fix_k(ik); @@ -371,15 +480,15 @@ TYPED_TEST(PWTDDFTTest, UnequalOccupationsAndDiagnosticsPreservePropagation) for (const bool out_stat: {false, true}) { std::ostringstream log; - hsolver::PWLinearOptions options; - options.global_k_indices = {0}; - options.linear.method = hsolver::LinearMethod::gmres; - options.linear.tolerance = single ? 2e-6 : 1e-13; - options.linear.max_iterations = 100; - options.linear.restart = n; - options.preconditioner = hsolver::PWPreconditioner::none; - options.out_stat = out_stat; - hsolver::HSolverPWTDDFT solver(basis, options, comm, log); + hsolver::CNControls cn_ctrl; + const std::vector global_k{0}; + cn_ctrl.linear.solver = hsolver::LinearMethod::gmres; + cn_ctrl.linear.tolerance = single ? 2e-6 : 1e-13; + cn_ctrl.linear.max_iterations = 100; + cn_ctrl.linear.restart = n; + cn_ctrl.preconditioner = hsolver::PWPreconditioner::none; + hsolver::TDOrbOps orbitals(1, hsolver::OrthMethod::cholesky, out_stat, global_k, comm, log); + hsolver::CNSolverPW solver(basis, cn_ctrl, 1, global_k, comm, log); psi::Psi previous(1, bands, ld, sizes, true); std::fill_n(previous.get_pointer(), ld * bands, T(0)); std::vector reference(n * bands, Wide(0)); @@ -391,14 +500,15 @@ TYPED_TEST(PWTDDFTTest, UnequalOccupationsAndDiagnosticsPreservePropagation) psi::Psi initial(previous); initial(0, 0) = T(1.01); const psi::Psi original(initial); - solver.check_initial(initial, 1); + orbitals.check_initial(initial, 1); EXPECT_EQ(std::memcmp(initial.get_pointer(), original.get_pointer(), ld * bands * sizeof(T)), 0); // The finite initial defect is diagnostic; propagate the orthonormal reference state. psi::Psi current(previous); for (int step = 1; step <= 8; ++step) { - solver.reset_orth_stats(); + orbitals.reset_orth_stats(); solver.solve(op, previous, ¤t, dt, shift, step, 1, false); + orbitals.correct(¤t, step, 1, false); reference = dense_cn(h, reference, n, bands, dt); for (int band = 0; band < bands; ++band) { @@ -424,7 +534,7 @@ TYPED_TEST(PWTDDFTTest, UnequalOccupationsAndDiagnosticsPreservePropagation) } } const double expected_electrons = out_stat ? 1.4 : 0.0; - EXPECT_NEAR(solver.wave_electrons(occupations), expected_electrons, tolerance); + EXPECT_NEAR(orbitals.wave_electrons(occupations), expected_electrons, tolerance); const T* data = current.get_pointer(); if (!out_stat) { diff --git a/source/source_pw/module_rt/unittests/test_td_spin_pw.cpp b/source/source_pw/module_rt/unittests/test_td_spin_pw.cpp new file mode 100644 index 00000000000..6675715dc39 --- /dev/null +++ b/source/source_pw/module_rt/unittests/test_td_spin_pw.cpp @@ -0,0 +1,113 @@ +#include "source_pw/module_rt/unittests/td_test_utils.h" + +#include +#include + +namespace td_test +{ +TEST_F(Observables, SOCTorqueMatchesCommutator) +{ + const ModuleBase::Vector3 a(0.13, -0.07, 0.09); + const std::string mag_partition = "none"; + pw::TDSpinPW observer; + observer.initialize(cell_, basis_, basis_, kv_, sf_, pp_, mag_partition, "", 0.0, true); + const pw::TDSpinResultPW actual = observer.calculate(*psi_, state_, a); + const Vector beta = projectors(a); + const int n = psi_->get_nbasis(); + double signal = 0; + for (int axis = 0; axis < 3; ++axis) + { + double total = 0; + for (int atom = 0; atom < cell_.nat; ++atom) + { + double expected = 0; + for (int band = 0; band < psi_->get_nbands(); ++band) + { + const Complex* data = psi_->get_pointer() + band * n; + const Vector x(data, data + n); + const Vector sx = pauli(x, axis); + const Vector hx = nonlocal(beta, x, atom); + const Vector hsx = nonlocal(beta, sx, atom); + const Vector shx = pauli(hx, axis); + const Complex commutator = inner(x, hsx) - inner(x, shx); + expected += state_.wg(0, band) * std::real(Complex(0, 0.5) * commutator); + } + EXPECT_NEAR(actual.atom_soc[3 * atom + axis], expected, 1e-10); + total += expected; + signal += std::abs(expected); + } + EXPECT_NEAR(actual.soc[axis], total, 1e-10); + } + EXPECT_GT(signal, 1e-8); +} + +TEST_F(Observables, DensityMomentsAndPeriodicVoronoi) +{ + const std::vector labels = pw::td_voronoi_pw(cell_, basis_); + std::vector atom_integrals(cell_.nat, 0.0); + const double dv = cell_.omega / basis_.nxyz; + for (int ir = 0; ir < basis_.nrxx; ++ir) + { + const int ix = ir / (basis_.ny * basis_.nplane); + const int iy = ir / basis_.nplane % basis_.ny; + const int iz = ir % basis_.nplane + basis_.startz_current; + const ModuleBase::Vector3 point(double(ix) / basis_.nx, double(iy) / basis_.ny, double(iz) / basis_.nz); + double best = std::numeric_limits::infinity(); + int nearest = -1; + // Independent exhaustive periodic-image reference for this moderately skew cell. + for (int atom = 0; atom < cell_.nat; ++atom) + { + for (int i = -3; i <= 3; ++i) + { + for (int j = -3; j <= 3; ++j) + { + for (int k = -3; k <= 3; ++k) + { + const ModuleBase::Vector3 image(i, j, k); + const ModuleBase::Vector3 delta = (point - cell_.atoms[0].taud[atom] + image) * cell_.latvec; + const double distance = delta.norm2(); + if (distance < best - 1e-12) + { + best = distance; + nearest = atom; + } + } + } + } + } + ASSERT_EQ(labels[ir], nearest); + const double f = 1.0 + 0.01 * ir; + atom_integrals[nearest] += f * dv; + charge_.rho[0][ir] = 2 * f; + charge_.rho[1][ir] = 0.2 * f; + charge_.rho[2][ir] = -0.3 * f; + charge_.rho[3][ir] = 0.5 * f; + // Potential storage is in Ry; the reference spin field is (0.4, 0.1, -0.2) Ha. + state_.pot->get_eff_v()(1, ir) = 0.8; + state_.pot->get_eff_v()(2, ir) = 0.2; + state_.pot->get_eff_v()(3, ir) = -0.4; + } + const std::string mag_partition = "voronoi"; + pw::TDSpinPW observer; + observer.initialize(cell_, basis_, basis_, kv_, sf_, pp_, mag_partition, "", 0.0, true); + const ModuleBase::Vector3 zero(0, 0, 0); + const pw::TDSpinResultPW actual = observer.calculate(*psi_, state_, zero); + const double integral = cell_.omega * (1.0 + 0.005 * (basis_.nxyz - 1)); + EXPECT_NEAR(actual.electrons, 2 * integral, 1e-10); + EXPECT_NEAR(actual.mag_abs, std::sqrt(0.38) * integral, 1e-10); + const double m[3] = {0.2, -0.3, 0.5}; + const double torque[3] = {-0.01, -0.24, -0.14}; + for (int axis = 0; axis < 3; ++axis) + { + EXPECT_NEAR(actual.mag[axis], m[axis] * integral, 1e-10); + EXPECT_NEAR(actual.xc[axis], torque[axis] * integral, 1e-10); + double sum = 0; + for (int atom = 0; atom < cell_.nat; ++atom) + { + EXPECT_NEAR(actual.atom_mag[3 * atom + axis], m[axis] * atom_integrals[atom], 1e-10); + sum += actual.atom_mag[3 * atom + axis]; + } + EXPECT_NEAR(sum, actual.mag[axis], 1e-10); + } +} +} // namespace td_test diff --git a/source/source_pw/module_rt/unittests/test_td_vel_pw.cpp b/source/source_pw/module_rt/unittests/test_td_vel_pw.cpp new file mode 100644 index 00000000000..d8c685e179f --- /dev/null +++ b/source/source_pw/module_rt/unittests/test_td_vel_pw.cpp @@ -0,0 +1,73 @@ +#include "source_pw/module_rt/unittests/td_test_utils.h" + +#include + +namespace td_test +{ +TEST_F(Observables, CurrentsMatchPauliAndHamiltonianDerivative) +{ + const ModuleBase::Vector3 a(0.13, -0.07, 0.09); + pw::TDVelPW observer; + observer.initialize(cell_, basis_, kv_, pp_); + pw::CurrentRequest request; + request.charge_total = true; + request.charge_per_k = true; + request.spin_current = true; + const pw::TDVelResultPW actual = observer.calculate(*psi_, state_, a, request); + hamilt::Velocity velocity(&basis_, kv_.isk.data(), &pp_, &cell_, true, nullptr, 0, 0); + velocity.init(0, a); + const int n = psi_->get_nbasis(); + std::array charge{}; + std::array spin{}; + const double epsilon = 1e-4; + for (int band = 0; band < psi_->get_nbands(); ++band) + { + const Complex* data = psi_->get_pointer() + band * n; + const Vector x(data, data + n); + Vector vx(3 * n); + velocity.act(psi_.get(), 2, x.data(), vx.data(), false); + for (int direction = 0; direction < 3; ++direction) + { + const Vector component(vx.begin() + direction * n, vx.begin() + (direction + 1) * n); + ModuleBase::Vector3 plus = a; + ModuleBase::Vector3 minus = a; + plus[direction] += epsilon; + minus[direction] -= epsilon; + const Vector hp = hamiltonian(plus, x); + const Vector hm = hamiltonian(minus, x); + double error = 0; + double norm = 0; + for (int i = 0; i < n; ++i) + { + const Complex derivative = (hp[i] - hm[i]) / (2 * epsilon); + error += std::norm(component[i] - derivative); + norm += std::norm(derivative); + } + EXPECT_LE(std::sqrt(error), 1e-10 + 1e-6 * std::sqrt(norm)); + charge[direction] -= state_.wg(0, band) * inner(x, component).real() / cell_.omega; + for (int axis = 0; axis < 3; ++axis) + { + const Vector sx = pauli(x, axis); + Vector vsx(3 * n); + velocity.act(psi_.get(), 2, sx.data(), vsx.data(), false); + const Vector v_sigma(vsx.begin() + direction * n, vsx.begin() + (direction + 1) * n); + const Vector sigma_v = pauli(component, axis); + const Complex anticommutator = inner(x, v_sigma) + inner(x, sigma_v); + spin[3 * direction + axis] += 0.25 * state_.wg(0, band) * anticommutator.real() / cell_.omega; + } + } + } + double signal = 0; + for (int i = 0; i < 3; ++i) + { + EXPECT_NEAR(actual.total[i], charge[i], 1e-10); + EXPECT_NEAR(actual.per_k[i], charge[i], 1e-10); + } + for (int i = 0; i < 9; ++i) + { + EXPECT_NEAR(actual.spin[i], spin[i], 1e-10); + signal += std::abs(spin[i]); + } + EXPECT_GT(signal, 1e-8); +} +} // namespace td_test diff --git a/source/source_pw/module_stodft/test/CMakeLists.txt b/source/source_pw/module_stodft/test/CMakeLists.txt index 07d8e07f60d..8abb1f159a0 100644 --- a/source/source_pw/module_stodft/test/CMakeLists.txt +++ b/source/source_pw/module_stodft/test/CMakeLists.txt @@ -1,6 +1,6 @@ abacus_disable_feature_definitions(__MPI) # These tests exercise CPU code only and link no GPU kernels, so build them -# without the device instantiations (as source_hsolver/test does). +# without the device instantiations (as source_hsolver/unittests does). abacus_disable_feature_definitions(__CUDA) abacus_disable_feature_definitions(__ROCM) diff --git a/source/source_pw/module_stodft/test/test_sto_hsolver_pw.cpp b/source/source_pw/module_stodft/test/test_sto_hsolver_pw.cpp index 22292183184..0a361000f7d 100644 --- a/source/source_pw/module_stodft/test/test_sto_hsolver_pw.cpp +++ b/source/source_pw/module_stodft/test/test_sto_hsolver_pw.cpp @@ -2,8 +2,8 @@ #include #include -#include "source_hsolver/test/hsolver_pw_sup.h" -#include "source_hsolver/test/hsolver_supplementary_mock.h" +#include "source_hsolver/unittests/hsolver_pw_sup.h" +#include "source_hsolver/unittests/hsolver_supplementary_mock.h" #include "source_base/parallel_comm.h" #include "source_estate/elecstate_pw.h" #include "source_hsolver/hsolver_pw.h" diff --git a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/INPUT b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/INPUT index 5a387517cad..6d8ae4f25eb 100644 --- a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/INPUT +++ b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/INPUT @@ -10,7 +10,8 @@ pseudo_dir ../../PP_ORB #Parameters (2.Iteration) ecutwfc 20 -scf_thr 1e-9 +scf_thr 1e-13 +pw_diag_thr 1e-12 scf_nmax 100 #Parameters (3.Basis) diff --git a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/pchgi4s1.cube.ref b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/pchgi4s1.cube.ref index 49c2d24afab..982b1c0a79a 100644 --- a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/pchgi4s1.cube.ref +++ b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/pchgi4s1.cube.ref @@ -6,975 +6,975 @@ Ionic_Step 1 Cubefile created from ABACUS. Inner loop is z, followed by y and x 18 0.247222 0.247222 0.000000 14 4.000000 0.000000 0.000000 0.000000 14 4.000000 2.581000 2.403000 2.225000 - 4.19011399368e-07 2.16803846536e-03 9.82791492926e-03 1.98308309354e-02 2.65725792908e-02 2.84310762946e-02 - 2.69944146948e-02 2.34236764017e-02 1.81730323932e-02 1.22120626491e-02 6.88841887249e-03 3.24502986743e-03 - 1.80070909648e-03 2.11659392567e-03 2.83284209532e-03 2.90741618148e-03 2.22657082227e-03 9.82176485309e-04 - 2.68014873221e-03 1.25909541325e-02 2.67753232651e-02 3.73920695598e-02 4.08067082948e-02 3.92484681158e-02 - 3.51353079861e-02 2.87927446984e-02 2.06258697996e-02 1.24491015397e-02 6.22328579623e-03 2.87757157410e-03 - 2.20335331684e-03 2.94964712071e-03 3.50859567428e-03 2.95054978010e-03 1.32926317902e-03 3.67495229894e-05 - 1.10789055788e-02 2.74713201135e-02 4.24682178545e-02 4.95468916190e-02 4.97416642851e-02 4.65036037121e-02 - 4.05502205105e-02 3.13099517866e-02 2.03325477443e-02 1.08911638785e-02 5.09646927372e-03 2.94477872128e-03 - 3.14867895602e-03 3.94775681549e-03 3.82996660100e-03 2.19765970380e-03 1.82253761747e-04 1.61579821535e-03 - 2.13966890593e-02 3.83519119286e-02 4.98310483892e-02 5.39480993008e-02 5.35367005583e-02 4.99032174792e-02 - 4.17562283176e-02 2.93983274780e-02 1.68232010579e-02 8.18901200731e-03 4.38681742403e-03 3.78801123540e-03 - 4.30460441940e-03 4.31193381354e-03 2.94381690938e-03 6.91022573166e-04 4.37030170446e-04 6.83460048949e-03 - 2.80687583514e-02 4.16054275606e-02 4.97900514387e-02 5.32213736187e-02 5.31039109921e-02 4.80821269045e-02 - 3.69226754614e-02 2.27992987863e-02 1.15780629520e-02 6.10944479216e-03 4.88016836446e-03 5.07012073149e-03 - 4.81600271190e-03 3.42909873455e-03 1.24142306562e-03 4.05013183150e-05 3.17841758106e-03 1.32220784722e-02 - 2.95047322583e-02 3.94534559074e-02 4.58159289369e-02 4.88435940966e-02 4.75144975441e-02 3.98368768216e-02 - 2.70322463312e-02 1.47921351332e-02 7.93269221088e-03 6.16087909551e-03 6.27932737801e-03 5.84974584191e-03 - 4.19949229248e-03 1.85626973622e-03 1.51380075900e-04 1.15550258159e-03 6.89886924054e-03 1.73807070542e-02 - 2.73305562495e-02 3.45440279380e-02 3.92246267647e-02 4.06218001378e-02 3.70732767248e-02 2.81852199368e-02 - 1.75667729895e-02 1.03569347052e-02 7.96336880031e-03 7.87341879261e-03 7.39238013442e-03 5.56980359132e-03 - 2.90508497645e-03 6.48524239098e-04 2.89474899524e-04 3.10153678749e-03 9.48688276578e-03 1.83311581766e-02 - 2.31493639904e-02 2.79809058286e-02 3.06640570712e-02 3.03319316350e-02 2.62277165245e-02 1.95984163522e-02 - 1.38659338805e-02 1.11829899273e-02 1.04348215151e-02 9.49888007189e-03 7.42517482246e-03 4.47849981821e-03 - 1.65946667344e-03 2.28667008709e-04 1.12259014553e-03 4.59229934307e-03 1.01921204841e-02 1.68486551223e-02 - 1.80794183092e-02 2.09941567811e-02 2.24268459883e-02 2.21022796989e-02 2.01248501404e-02 1.76421827517e-02 - 1.58841218471e-02 1.45873821882e-02 1.26871017844e-02 9.82729646775e-03 6.38895710438e-03 3.08323113112e-03 - 8.32328125658e-04 3.98613776514e-04 1.94197847915e-03 5.11194784961e-03 9.37240901140e-03 1.39909201451e-02 - 1.33847167363e-02 1.54268415134e-02 1.71058885560e-02 1.85089397834e-02 1.95898662127e-02 2.01213897689e-02 - 1.94245388731e-02 1.69128380923e-02 1.29717963349e-02 8.60448525534e-03 4.66423949130e-03 1.79693362078e-03 - 4.88896696612e-04 8.04516293324e-04 2.38024877340e-03 4.81524982455e-03 7.77937944545e-03 1.07983769677e-02 - 1.01238820788e-02 1.24623780903e-02 1.54276149340e-02 1.88076087599e-02 2.16837740444e-02 2.26234706290e-02 - 2.06383052110e-02 1.62272324676e-02 1.09714445120e-02 6.26202843765e-03 2.83101201380e-03 9.58279963442e-04 - 5.43775024378e-04 1.16997965415e-03 2.43656490983e-03 4.14815069037e-03 6.12438450081e-03 8.12162853655e-03 - 8.79710982005e-03 1.22228049129e-02 1.65683981090e-02 2.08374281405e-02 2.32708734645e-02 2.23785095629e-02 - 1.83050590811e-02 1.27619107674e-02 7.57680326530e-03 3.75214716498e-03 1.54078112407e-03 7.21531878939e-04 - 8.16515388624e-04 1.40690280559e-03 2.30934078215e-03 3.45294989732e-03 4.78590363722e-03 6.43659954150e-03 - 9.42174177592e-03 1.40297002299e-02 1.89956228301e-02 2.24652763861e-02 2.25243356294e-02 1.89229263434e-02 - 1.34179491872e-02 8.15530538518e-03 4.31262900389e-03 2.08747253842e-03 1.14569788284e-03 9.70586768099e-04 - 1.16528813484e-03 1.56340223386e-03 2.11173208071e-03 2.83554077007e-03 3.98981023355e-03 6.05459610346e-03 - 1.10238512126e-02 1.60727711104e-02 2.03822468842e-02 2.15762170118e-02 1.86201593346e-02 1.31871418678e-02 - 7.95085798210e-03 4.37597392972e-03 2.51285007652e-03 1.78585846198e-03 1.57274562826e-03 1.51881092385e-03 - 1.54527015168e-03 1.64061896544e-03 1.84605726408e-03 2.46347104099e-03 4.00312353280e-03 6.83629875475e-03 - 1.15623176026e-02 1.58175087216e-02 1.82062563277e-02 1.66620141929e-02 1.19651793488e-02 7.11969250642e-03 - 4.12716992874e-03 2.98855123013e-03 2.82610203978e-03 2.82242590552e-03 2.61277118391e-03 2.25762513719e-03 - 1.88464596054e-03 1.57849674548e-03 1.64828575546e-03 2.57401320382e-03 4.55643294303e-03 7.56883344761e-03 - 9.60375722133e-03 1.18903284388e-02 1.17264914772e-02 8.72360341925e-03 5.36141133611e-03 3.84068780130e-03 - 4.05204709537e-03 4.83665730860e-03 5.25917963414e-03 4.94222971196e-03 4.07345819016e-03 3.02587727437e-03 - 2.03656824521e-03 1.44274169603e-03 1.73319920912e-03 2.94488281802e-03 4.68873853017e-03 6.88784247043e-03 - 5.75323598357e-03 5.58191135531e-03 3.95146747575e-03 2.83745388251e-03 4.03126095241e-03 6.62226102446e-03 - 8.82941247313e-03 9.78262777907e-03 9.31553519921e-03 7.71458069891e-03 5.60361454784e-03 3.53179382756e-03 - 1.95441597866e-03 1.42855304294e-03 2.03712895903e-03 3.05774157489e-03 3.95864454987e-03 4.87779293380e-03 - 1.87886591085e-03 6.84495483026e-04 1.44923585418e-03 5.93364628402e-03 1.18928981385e-02 1.60178523332e-02 - 1.74088227564e-02 1.65773833950e-02 1.40226105348e-02 1.04173008518e-02 6.67365952333e-03 3.57426757138e-03 - 1.79676178063e-03 1.63972172819e-03 2.37416801179e-03 2.90858022104e-03 2.96137794973e-03 2.70515259251e-03 - 4.35427191104e-03 1.45213811355e-02 2.87925004070e-02 3.90023455715e-02 4.16426771655e-02 3.92600864231e-02 - 3.44630846746e-02 2.76828613383e-02 1.93986709620e-02 1.14086041742e-02 5.58746884194e-03 2.77602240859e-03 - 2.67102979506e-03 3.91885988188e-03 4.83632683418e-03 4.47493732542e-03 2.91471097592e-03 1.61564330874e-03 - 1.40680755483e-02 3.22138464156e-02 4.80303168495e-02 5.43448195275e-02 5.29712660350e-02 4.83232059127e-02 - 4.13932989596e-02 3.14584965587e-02 1.99797900804e-02 1.03247801696e-02 4.68103000884e-03 2.96374333645e-03 - 3.68364932782e-03 4.87944174276e-03 4.94484793550e-03 3.33331355863e-03 1.36946830216e-03 3.28009582510e-03 - 2.81344718244e-02 4.77198544938e-02 5.93626936572e-02 6.16812872151e-02 5.93097982381e-02 5.43875423738e-02 - 4.51784007809e-02 3.14288341019e-02 1.74043901315e-02 7.91526939170e-03 4.04273140632e-03 3.87122901729e-03 - 4.92559230203e-03 5.30886640163e-03 4.06237635487e-03 1.83445556190e-03 2.09191463478e-03 1.03650307728e-02 - 3.80686801686e-02 5.35677113531e-02 6.10891801206e-02 6.29531498339e-02 6.18556564735e-02 5.60432468825e-02 - 4.30046141707e-02 2.59230384809e-02 1.21601950602e-02 5.59342860785e-03 4.46172435916e-03 5.24889570810e-03 - 5.57705574566e-03 4.50013957114e-03 2.36564915015e-03 1.41578041214e-03 5.99444209766e-03 1.93318064966e-02 - 4.03665184113e-02 5.14679523737e-02 5.75972551370e-02 6.05136459446e-02 5.91687258713e-02 4.98950351768e-02 - 3.31893909057e-02 1.66328658903e-02 7.29148095552e-03 5.10400790346e-03 5.82843730884e-03 6.15325860184e-03 - 5.00023518742e-03 2.81910469652e-03 1.21466861355e-03 2.97623320059e-03 1.09893192692e-02 2.50839278720e-02 - 3.74102116851e-02 4.57291776648e-02 5.11690781179e-02 5.32032980712e-02 4.87182667438e-02 3.60012459978e-02 - 2.01367099418e-02 9.29487242756e-03 5.95997793483e-03 6.52127233095e-03 7.02887222003e-03 5.93241037844e-03 - 3.59213704631e-03 1.43846230572e-03 1.42951326332e-03 5.47709131931e-03 1.43151180616e-02 2.61620545189e-02 - 3.19432302750e-02 3.79385625401e-02 4.14221324251e-02 4.06442105563e-02 3.35194898773e-02 2.19222369247e-02 - 1.21174736401e-02 8.08065103489e-03 7.98354798317e-03 8.29076898702e-03 7.25718792148e-03 4.87322885044e-03 - 2.23202008285e-03 9.70773003965e-04 2.48467822788e-03 7.36238933641e-03 1.50917819948e-02 2.39687211939e-02 - 2.51552506579e-02 2.87171575021e-02 2.99549165888e-02 2.77447669020e-02 2.21321468176e-02 1.60197854736e-02 - 1.25668283319e-02 1.15624179043e-02 1.08383364308e-02 9.19554801608e-03 6.57459902550e-03 3.56812230273e-03 - 1.37243362055e-03 1.19116826319e-03 3.47882083534e-03 7.94127128756e-03 1.38222161749e-02 1.99553108317e-02 - 1.83162004188e-02 2.03279921468e-02 2.11747412336e-02 2.07720017138e-02 1.96642198416e-02 1.87181111260e-02 - 1.76959935429e-02 1.56511225678e-02 1.25126495620e-02 8.87819403625e-03 5.27127761291e-03 2.36614483934e-03 - 1.02219798596e-03 1.63496604922e-03 3.90918820086e-03 7.33461557054e-03 1.13623053503e-02 1.52456256992e-02 - 1.32148749890e-02 1.53748308521e-02 1.79200965320e-02 2.08081615681e-02 2.33327337190e-02 2.40600453051e-02 - 2.18727346519e-02 1.73405536353e-02 1.21046304257e-02 7.35513021605e-03 3.67126132907e-03 1.50417668134e-03 - 1.04416714573e-03 1.95902507438e-03 3.74596770848e-03 6.08806045886e-03 8.67110519432e-03 1.10875879041e-02 - 1.09674040701e-02 1.45665971161e-02 1.93467053070e-02 2.43351650216e-02 2.74199650698e-02 2.66274426100e-02 - 2.20344865922e-02 1.57090157382e-02 9.74043270162e-03 5.16735930717e-03 2.32205205689e-03 1.15788015706e-03 - 1.24858060094e-03 2.05295353247e-03 3.27666181765e-03 4.81335879285e-03 6.54128067936e-03 8.46779662007e-03 - 1.16346713118e-02 1.69688691818e-02 2.30101149909e-02 2.76591058216e-02 2.84764490615e-02 2.47813202711e-02 - 1.83774534849e-02 1.18132637219e-02 6.64826390976e-03 3.33405612396e-03 1.70820565702e-03 1.27329597192e-03 - 1.47804030999e-03 2.00789065057e-03 2.78978085096e-03 3.85875897209e-03 5.39596522605e-03 7.82238408794e-03 - 1.44134465359e-02 2.08163031436e-02 2.64273337892e-02 2.85498445662e-02 2.58293333207e-02 1.97253736253e-02 - 1.30674408547e-02 7.79122614873e-03 4.40775620113e-03 2.62167384868e-03 1.86977949017e-03 1.64862248455e-03 - 1.68997393417e-03 1.91896052440e-03 2.39915777853e-03 3.41940781103e-03 5.49237698777e-03 9.10518673971e-03 - 1.73463949503e-02 2.34688630958e-02 2.70092127645e-02 2.56919438250e-02 2.02369229413e-02 1.37242664018e-02 - 8.62242156925e-03 5.53785576550e-03 3.95460300111e-03 3.13046532005e-03 2.57643653217e-03 2.15399812007e-03 - 1.87286955047e-03 1.80071138741e-03 2.23981689190e-03 3.73123599490e-03 6.71065036058e-03 1.13299886512e-02 - 1.78244417476e-02 2.21183721275e-02 2.27480771171e-02 1.90850794546e-02 1.36962617639e-02 9.42352771056e-03 - 7.09172155218e-03 6.06755379703e-03 5.43233756001e-03 4.62808245034e-03 3.64160321673e-03 2.69641050741e-03 - 1.96178614997e-03 1.73465641932e-03 2.53368356200e-03 4.65451909584e-03 8.01793000935e-03 1.25396411164e-02 - 1.44555236795e-02 1.59225376896e-02 1.45807356380e-02 1.19168597768e-02 1.01593706078e-02 9.72629563399e-03 - 9.80020597352e-03 9.56496845755e-03 8.54828331798e-03 6.81070319834e-03 4.84094655417e-03 3.09087713238e-03 - 1.93956884059e-03 1.90641417397e-03 3.21754818118e-03 5.43740276395e-03 8.14062382749e-03 1.13067477936e-02 - 8.44189080345e-03 8.06969374890e-03 8.42740785775e-03 1.09193011558e-02 1.42523750483e-02 1.63695603636e-02 - 1.66695588856e-02 1.53325649859e-02 1.26188126786e-02 9.14701721299e-03 5.76937267351e-03 3.16811136765e-03 - 1.93513965223e-03 2.37498303694e-03 3.90210489667e-03 5.52498066567e-03 6.87713371745e-03 7.98758367612e-03 - 3.40819300690e-03 5.58371507101e-03 1.25351953287e-02 2.11807758734e-02 2.66200337970e-02 2.76495044554e-02 - 2.57332843455e-02 2.18812286514e-02 1.65959985749e-02 1.08955933289e-02 6.04683484282e-03 2.97538860274e-03 - 2.12663410351e-03 3.05087037720e-03 4.40690146936e-03 5.11198259281e-03 4.95916437418e-03 4.10318088994e-03 - 1.54321021681e-02 3.18034255948e-02 4.61691463859e-02 5.17631831747e-02 4.99620320523e-02 4.47541109680e-02 - 3.73303309429e-02 2.74745387414e-02 1.67399279875e-02 8.06896425023e-03 3.29574237219e-03 2.31875663393e-03 - 3.74756609229e-03 5.66159482721e-03 6.45040091689e-03 5.54489119064e-03 4.07816030803e-03 5.81594384521e-03 - 3.04669290365e-02 4.97757867368e-02 6.07620065379e-02 6.19784612664e-02 5.82669442185e-02 5.21276171307e-02 - 4.22316265572e-02 2.85104906289e-02 1.49836042614e-02 6.10220880315e-03 2.84168328004e-03 3.33809523364e-03 - 5.11184538180e-03 6.19570414944e-03 5.57613301484e-03 3.86521585173e-03 4.44427548209e-03 1.27914679694e-02 - 4.38634072727e-02 5.95996663878e-02 6.59130298816e-02 6.59745257749e-02 6.33559236801e-02 5.65183418239e-02 - 4.27108261571e-02 2.49401690903e-02 1.07167391539e-02 4.12903599823e-03 3.41552478678e-03 4.89382153174e-03 - 5.98854142821e-03 5.60213835854e-03 4.02403993118e-03 3.60669253647e-03 9.02711521516e-03 2.37507560048e-02 - 4.86763161894e-02 5.95799497133e-02 6.44052430120e-02 6.62368367922e-02 6.43496668573e-02 5.42027479422e-02 - 3.55758773152e-02 1.67368521135e-02 5.99709165574e-03 3.63067303056e-03 4.91344230084e-03 6.03073764971e-03 - 5.63303425787e-03 4.06163593879e-03 3.00667656233e-03 5.65064012755e-03 1.53867374416e-02 3.18140122845e-02 - 4.60583283660e-02 5.42603345154e-02 5.94810125186e-02 6.17676422332e-02 5.69526604627e-02 4.18708371195e-02 - 2.21626187567e-02 8.26259051133e-03 3.87759575111e-03 4.82831683066e-03 6.20466429163e-03 5.95518396796e-03 - 4.28817843029e-03 2.67197625802e-03 3.34084742169e-03 8.68898195453e-03 1.96572511763e-02 3.37172937844e-02 - 3.98549235196e-02 4.63246561895e-02 5.04180189093e-02 4.96433522699e-02 4.03048881144e-02 2.43330266734e-02 - 1.04988850520e-02 4.77248146358e-03 4.98966865904e-03 6.39079579300e-03 6.46926818086e-03 4.94564430196e-03 - 2.89938997647e-03 2.16374875695e-03 4.49790812743e-03 1.08157026669e-02 2.04692900458e-02 3.10128324699e-02 - 3.18437733222e-02 3.58582044909e-02 3.69166756526e-02 3.27166632453e-02 2.30096120207e-02 1.27308809021e-02 - 7.35340977409e-03 6.72868336256e-03 7.41870610666e-03 7.31378424217e-03 5.94190331948e-03 3.74093643792e-03 - 2.03256901092e-03 2.35982904961e-03 5.50130727645e-03 1.12660634127e-02 1.86251966888e-02 2.59281080286e-02 - 2.29793534624e-02 2.45476223837e-02 2.37559811508e-02 2.01886965909e-02 1.55093433587e-02 1.25105798669e-02 - 1.15608691759e-02 1.08815514229e-02 9.51894223106e-03 7.51978449275e-03 5.04238605339e-03 2.70561660930e-03 - 1.68217575574e-03 2.75317958740e-03 5.79547757390e-03 1.02262640418e-02 1.52207071774e-02 1.97319409438e-02 - 1.53901055917e-02 1.64017624176e-02 1.70572727437e-02 1.77640060838e-02 1.87626405378e-02 1.91362609143e-02 - 1.75521818052e-02 1.42428206687e-02 1.04776175683e-02 6.94120602455e-03 3.89954929389e-03 1.94315547371e-03 - 1.66066906654e-03 2.95895152800e-03 5.31854593408e-03 8.27563141022e-03 1.12914533748e-02 1.37462413953e-02 - 1.12893637388e-02 1.39318580703e-02 1.78674350028e-02 2.24899573974e-02 2.56773840630e-02 2.51197294206e-02 - 2.08420315115e-02 1.50789154736e-02 9.75865260855e-03 5.56841386916e-03 2.76550228623e-03 1.56111831311e-03 - 1.76436678289e-03 2.83558592997e-03 4.37987608132e-03 6.17401742895e-03 7.93266253190e-03 9.51767870380e-03 - 1.12647427393e-02 1.63348021420e-02 2.26882783736e-02 2.81617349199e-02 2.97711329937e-02 2.63845042000e-02 - 1.99007062010e-02 1.31319944198e-02 7.68616805197e-03 4.01207400497e-03 2.08614105362e-03 1.55280908302e-03 - 1.82956536125e-03 2.49466391412e-03 3.41417230618e-03 4.54853450246e-03 5.94542807817e-03 7.96521797259e-03 - 1.44564543627e-02 2.12492543121e-02 2.77418050708e-02 3.09974921872e-02 2.91214097508e-02 2.31639047044e-02 - 1.59949828390e-02 9.86053327856e-03 5.58671644161e-03 3.12726868208e-03 2.03889556984e-03 1.74318726373e-03 - 1.81970690130e-03 2.12196079847e-03 2.69122179385e-03 3.74043654006e-03 5.70824766177e-03 9.15540262516e-03 - 1.91061519349e-02 2.60817777184e-02 3.05276401908e-02 3.00462601221e-02 2.49543232787e-02 1.79860031606e-02 - 1.17593228565e-02 7.35651870074e-03 4.69051352541e-03 3.22869572426e-03 2.43677958939e-03 1.99140574422e-03 - 1.77296177308e-03 1.81362754806e-03 2.38107769714e-03 4.00394686319e-03 7.23107926606e-03 1.23516145302e-02 - 2.25928828460e-02 2.80606490158e-02 2.93428590280e-02 2.57236663000e-02 1.95092955194e-02 1.36309787803e-02 - 9.47836617572e-03 6.94808014366e-03 5.35553653276e-03 4.12869838113e-03 3.08036995702e-03 2.24514840951e-03 - 1.69343862589e-03 1.67412005315e-03 2.72391784666e-03 5.34927653305e-03 9.73163907216e-03 1.57476879870e-02 - 2.22729139052e-02 2.50771432233e-02 2.38697233370e-02 1.98511226887e-02 1.55652247098e-02 1.24388603781e-02 - 1.04611457132e-02 8.98263688247e-03 7.39749436153e-03 5.58657467040e-03 3.83216724368e-03 2.41150776553e-03 - 1.60213905767e-03 1.90746636900e-03 3.75299345135e-03 7.07054396715e-03 1.15867505140e-02 1.70146963488e-02 - 1.74080067458e-02 1.79920029047e-02 1.73156632679e-02 1.67894861677e-02 1.65980742064e-02 1.61482537405e-02 - 1.50760578237e-02 1.31637293326e-02 1.04028401006e-02 7.27032129350e-03 4.42658378510e-03 2.37503360300e-03 - 1.63101370537e-03 2.59972711461e-03 5.00570553973e-03 8.11171010217e-03 1.15055573447e-02 1.49192382603e-02 - 1.07295065242e-02 1.24622488610e-02 1.68355728561e-02 2.19581482703e-02 2.48091582259e-02 2.46743489520e-02 - 2.23850463233e-02 1.85221480216e-02 1.36001703668e-02 8.59581440458e-03 4.53894324485e-03 2.17115024884e-03 - 1.94039352315e-03 3.57361891125e-03 5.95072606387e-03 8.04376284738e-03 9.52550165322e-03 1.03137782644e-02 - 8.23680192316e-03 1.64175860251e-02 2.78493399603e-02 3.59553375412e-02 3.78057018731e-02 3.52573101594e-02 - 3.03568920797e-02 2.36894665416e-02 1.60118803824e-02 8.96630180472e-03 4.07328378221e-03 2.03414550290e-03 - 2.62761235607e-03 4.63820443504e-03 6.45719445876e-03 7.11578539261e-03 6.56881951706e-03 5.91338893028e-03 - 2.72725283108e-02 4.34656913175e-02 5.31726260270e-02 5.44368514841e-02 5.06556347067e-02 4.40444992605e-02 - 3.42819940973e-02 2.20414785214e-02 1.06823563524e-02 3.52403735823e-03 1.23859814559e-03 2.34129125187e-03 - 4.73110664187e-03 6.57956358597e-03 6.82918477738e-03 5.84575952471e-03 6.34741934086e-03 1.29322760956e-02 - 4.15959311461e-02 5.60715783762e-02 6.17253549409e-02 6.09144969449e-02 5.69059770552e-02 4.89852005704e-02 - 3.55570539025e-02 1.95762326291e-02 7.28186024629e-03 1.90968851167e-03 1.87165177347e-03 3.93774935799e-03 - 5.73753493842e-03 6.14734054926e-03 5.29823912551e-03 5.22897953670e-03 1.01504573883e-02 2.33527940404e-02 - 4.98147617969e-02 5.99249066283e-02 6.34615868927e-02 6.36034212465e-02 6.01259829331e-02 4.92780300458e-02 - 3.11477846657e-02 1.33628852563e-02 3.48388623838e-03 1.68957670786e-03 3.50794483522e-03 5.27599118986e-03 - 5.63448959218e-03 4.82149706164e-03 4.38234925372e-03 7.37590415364e-03 1.71601114148e-02 3.33866853327e-02 - 4.97127591711e-02 5.70107399930e-02 6.10120265982e-02 6.22221362673e-02 5.65967206900e-02 4.08199012092e-02 - 2.04256338480e-02 6.04076820933e-03 1.63189492368e-03 2.98726116077e-03 4.98001136019e-03 5.43076492643e-03 - 4.49573453709e-03 3.58731844851e-03 4.93046173351e-03 1.10141939118e-02 2.28170299098e-02 3.74891886451e-02 - 4.43949992779e-02 5.04013618387e-02 5.41780494662e-02 5.30612648939e-02 4.25954155058e-02 2.45348192256e-02 - 8.65782502689e-03 1.97155195986e-03 2.34339558938e-03 4.43364355831e-03 5.29892924276e-03 4.53639418516e-03 - 3.21308141552e-03 3.19059922687e-03 6.34113460909e-03 1.36975672251e-02 2.44549856172e-02 3.56506136373e-02 - 3.63499398266e-02 4.03431702656e-02 4.11331729791e-02 3.55392230932e-02 2.29787670428e-02 9.72950917765e-03 - 2.88163922922e-03 2.40704585976e-03 4.05708788888e-03 5.08990355905e-03 4.76366690020e-03 3.43015877773e-03 - 2.43751717232e-03 3.46895279010e-03 7.46780238434e-03 1.42668498565e-02 2.25711944005e-02 3.03659744443e-02 - 2.64715885411e-02 2.74286356928e-02 2.48779459362e-02 1.80447922194e-02 9.82753689629e-03 5.00224654920e-03 - 4.39004645855e-03 5.21522768062e-03 5.62614867615e-03 5.25500053327e-03 4.05477463097e-03 2.58369006207e-03 - 2.17827894788e-03 3.87633690512e-03 7.68203956894e-03 1.29368719026e-02 1.85688875677e-02 2.33344456787e-02 - 1.66506627031e-02 1.58556341186e-02 1.34964270869e-02 1.07204956843e-02 9.43315190154e-03 9.64379032241e-03 - 9.52391567131e-03 8.41072323790e-03 6.88877731282e-03 5.18191748770e-03 3.33361122862e-03 2.02880354812e-03 - 2.19878056990e-03 3.99795172442e-03 6.92376808667e-03 1.03824659074e-02 1.36248791174e-02 1.58521916475e-02 - 1.00205625778e-02 1.04261504507e-02 1.18083467407e-02 1.44879776901e-02 1.70343665959e-02 1.70936170826e-02 - 1.43813042462e-02 1.07173885138e-02 7.40971822591e-03 4.64973599644e-03 2.59754910911e-03 1.75473684993e-03 - 2.26160878485e-03 3.66789553239e-03 5.51453464309e-03 7.44346683528e-03 8.96722902951e-03 9.75425100177e-03 - 8.40075684441e-03 1.18562201699e-02 1.71095003277e-02 2.23323975575e-02 2.43375407807e-02 2.17386871101e-02 - 1.64332500350e-02 1.10429101578e-02 6.74203374869e-03 3.72466681283e-03 2.08265489818e-03 1.72803799958e-03 - 2.18765513076e-03 3.00792215214e-03 3.99108040193e-03 4.96029802621e-03 5.76526883778e-03 6.65860101917e-03 - 1.11803444071e-02 1.72499457492e-02 2.38020781372e-02 2.77892585265e-02 2.68351130776e-02 2.16753656500e-02 - 1.51453680304e-02 9.46113261220e-03 5.40664307615e-03 3.01554354605e-03 1.99066432181e-03 1.79379757182e-03 - 1.95493322080e-03 2.29483719729e-03 2.79052825795e-03 3.49232774892e-03 4.69671761202e-03 7.03018153910e-03 - 1.64244738627e-02 2.32641111819e-02 2.82463009122e-02 2.88203971245e-02 2.47678898091e-02 1.83673693362e-02 - 1.21800408895e-02 7.51241757910e-03 4.55872389724e-03 2.96683186268e-03 2.19814242238e-03 1.82368377636e-03 - 1.66384317084e-03 1.71887016927e-03 2.15023176857e-03 3.35699407984e-03 5.90461892039e-03 1.02635905431e-02 - 2.17354881465e-02 2.73622898395e-02 2.91911823063e-02 2.63877166458e-02 2.06927858838e-02 1.46909138046e-02 - 9.95540868142e-03 6.78693654417e-03 4.79673730853e-03 3.47290328641e-03 2.50853297057e-03 1.81056620781e-03 - 1.38381877226e-03 1.39745351646e-03 2.30610919356e-03 4.68468243116e-03 8.89637995593e-03 1.48729809430e-02 - 2.45050122367e-02 2.76825987223e-02 2.66633782309e-02 2.24262049255e-02 1.73118011544e-02 1.30222813559e-02 - 9.99147152644e-03 7.83236591295e-03 6.00682510501e-03 4.30997888061e-03 2.84694443485e-03 1.74033412927e-03 - 1.15704139824e-03 1.53197340006e-03 3.40901710779e-03 7.03087155880e-03 1.22700863590e-02 1.85849686680e-02 - 2.28684455548e-02 2.37904662452e-02 2.21969727476e-02 1.95504443497e-02 1.69585873969e-02 1.47427832056e-02 - 1.27228414544e-02 1.05001678768e-02 7.92465980296e-03 5.31229751963e-03 3.08598579711e-03 1.54799043506e-03 - 1.11503594596e-03 2.28223737991e-03 5.12688002950e-03 9.25040750085e-03 1.41807172676e-02 1.92033314842e-02 - 1.75383774512e-02 1.85250273848e-02 1.99543817901e-02 2.13223681023e-02 2.15213669402e-02 2.02860220266e-02 - 1.78229501979e-02 1.42872197352e-02 1.01195054574e-02 6.11581492589e-03 2.98303077930e-03 1.26215044829e-03 - 1.43222617422e-03 3.49742477138e-03 6.72683903892e-03 1.02531196249e-02 1.35461004107e-02 1.60956312207e-02 - 1.29980886089e-02 1.81845027841e-02 2.52011069281e-02 3.00568326619e-02 3.08634015427e-02 2.85002507001e-02 - 2.40884771671e-02 1.82243948060e-02 1.18243195568e-02 6.20290744923e-03 2.42836496237e-03 1.09115162879e-03 - 2.18269760447e-03 4.82797689825e-03 7.66594335973e-03 9.72184529740e-03 1.07063090944e-02 1.11488465986e-02 - 1.55788939798e-02 2.76248703336e-02 3.85493523160e-02 4.31208400183e-02 4.17356091647e-02 3.69697644156e-02 - 2.99550945280e-02 2.11714804500e-02 1.22111562467e-02 5.26958275422e-03 1.65163021831e-03 1.35392641862e-03 - 3.34471783399e-03 5.98064329874e-03 7.74126404572e-03 7.95506011759e-03 7.32912155618e-03 8.65067208271e-03 - 3.39303965803e-02 4.55816250415e-02 5.05962202033e-02 4.98069964889e-02 4.53496583288e-02 3.73706319050e-02 - 2.57909537204e-02 1.32907811338e-02 4.13420902338e-03 3.47348505113e-04 7.43199590612e-04 2.95562317847e-03 - 5.11628128932e-03 6.19557282856e-03 6.11521489610e-03 6.34294992372e-03 1.00841253416e-02 1.99687299687e-02 - 4.35312709064e-02 5.24232301260e-02 5.51915460030e-02 5.39357096419e-02 4.88731950122e-02 3.81416914633e-02 - 2.27658895936e-02 8.68847555605e-03 1.25148769125e-03 2.98021842000e-04 2.28055026792e-03 4.27116878277e-03 - 5.12708483860e-03 4.97684975030e-03 5.02217179994e-03 7.74524154299e-03 1.59390850129e-02 2.95018924206e-02 - 4.66887257408e-02 5.29271531910e-02 5.53421849804e-02 5.44875015671e-02 4.76176550432e-02 3.28583490182e-02 - 1.52325813049e-02 3.32234206110e-03 5.24671208178e-05 1.68406262919e-03 3.80304993773e-03 4.56000567974e-03 - 4.14193661139e-03 3.80390226037e-03 5.47118359605e-03 1.12998233387e-02 2.21613313934e-02 3.55679759833e-02 - 4.39118929260e-02 4.88119068638e-02 5.11379654838e-02 4.87232058328e-02 3.79701890683e-02 2.08468916944e-02 - 6.22387876143e-03 2.71059858679e-04 9.00464962140e-04 3.11234108665e-03 4.16501578079e-03 3.75882916076e-03 - 2.95488750417e-03 3.48889212517e-03 7.05389889421e-03 1.45511612224e-02 2.51436424897e-02 3.58975480259e-02 - 3.72969452704e-02 4.06085770675e-02 4.06256114853e-02 3.42636407549e-02 2.11402288417e-02 7.65406088136e-03 - 7.70379491364e-04 3.42114736156e-04 2.14536506823e-03 3.45121806346e-03 3.51397567463e-03 2.68699468929e-03 - 2.28420433171e-03 3.92526427808e-03 8.48305991169e-03 1.57115692161e-02 2.41951756821e-02 3.18115060701e-02 - 2.78854038396e-02 2.82283042484e-02 2.45069027872e-02 1.59317286316e-02 6.15448331255e-03 7.28165467927e-04 - 3.38280970089e-04 1.70570909547e-03 2.78937846446e-03 3.17796918496e-03 2.74023966285e-03 1.95890143791e-03 - 2.18347856848e-03 4.49839876180e-03 8.89097066256e-03 1.46065684392e-02 2.04364558466e-02 2.50898488472e-02 - 1.71143970126e-02 1.47479188648e-02 9.79600473039e-03 4.18352525793e-03 1.29498529695e-03 1.68391301904e-03 - 2.82099825227e-03 3.29624052976e-03 3.34467819035e-03 3.01114958834e-03 2.20594292017e-03 1.62002250016e-03 - 2.36207495549e-03 4.70290254360e-03 8.10484549520e-03 1.18712922787e-02 1.51472966539e-02 1.70742589250e-02 - 8.23332812457e-03 5.99829376151e-03 4.12893306963e-03 4.22527159069e-03 5.95644001900e-03 6.97014566771e-03 - 6.34004321653e-03 5.13372965996e-03 4.02794440694e-03 2.88596992248e-03 1.81685900499e-03 1.55443743929e-03 - 2.51598180824e-03 4.31163014536e-03 6.42037926069e-03 8.39408536993e-03 9.61762156021e-03 9.58396691388e-03 - 4.35527903993e-03 5.12911440456e-03 7.90994658286e-03 1.17236776924e-02 1.37220047271e-02 1.24468395001e-02 - 9.43440841281e-03 6.55682263102e-03 4.28832886876e-03 2.54926187480e-03 1.58569916566e-03 1.64689060176e-03 - 2.41748407045e-03 3.42809459077e-03 4.43473260839e-03 5.15148524842e-03 5.23931400239e-03 4.75501093454e-03 - 5.89457404223e-03 1.00870549612e-02 1.54777797051e-02 1.92604279440e-02 1.89738866541e-02 1.52421106252e-02 - 1.05906695838e-02 6.67522362675e-03 3.87496426229e-03 2.21058307815e-03 1.61824279574e-03 1.71375700185e-03 - 2.03762603879e-03 2.40683723393e-03 2.74438630538e-03 2.92771197628e-03 3.06668010059e-03 3.75510304058e-03 - 1.08683728387e-02 1.66723009882e-02 2.14924957215e-02 2.27247283438e-02 1.98114745287e-02 1.46908301858e-02 - 9.64680306160e-03 5.82096772535e-03 3.43028808342e-03 2.25265475669e-03 1.80434888703e-03 1.62623971836e-03 - 1.54449483062e-03 1.55880786311e-03 1.70250982642e-03 2.17602904126e-03 3.48230563067e-03 6.26053478602e-03 - 1.66944320298e-02 2.18012290061e-02 2.39719828391e-02 2.21939389913e-02 1.76519379943e-02 1.24931929624e-02 - 8.22384259650e-03 5.33235032306e-03 3.62886297253e-03 2.63276989018e-03 1.94450507208e-03 1.42656415326e-03 - 1.09298261544e-03 1.03571069425e-03 1.53747287966e-03 3.09392697674e-03 6.17617553484e-03 1.09125115369e-02 - 2.10945589337e-02 2.40363165452e-02 2.33788098449e-02 1.98148838999e-02 1.52031904517e-02 1.10841116930e-02 - 8.06166609721e-03 5.99042264133e-03 4.43348761153e-03 3.10845290356e-03 2.00280220867e-03 1.18337541394e-03 - 7.49018692298e-04 1.00123685740e-03 2.43916027870e-03 5.45815737834e-03 1.00847852423e-02 1.57705220284e-02 - 2.23343205452e-02 2.30949295577e-02 2.11646697399e-02 1.79068027108e-02 1.46191853755e-02 1.19104999840e-02 - 9.72667031285e-03 7.68487735293e-03 5.58411754207e-03 3.59693483579e-03 1.97571280953e-03 8.87192952145e-04 - 6.23140078957e-04 1.65011568080e-03 4.26527039409e-03 8.37226337300e-03 1.35148545263e-02 1.87043248773e-02 - 2.00121517841e-02 2.01919716870e-02 1.95611959913e-02 1.85286820404e-02 1.71226372377e-02 1.53310959802e-02 - 1.30215101225e-02 1.01061071622e-02 6.90140172729e-03 3.96955184934e-03 1.73785667589e-03 5.66472807982e-04 - 8.97491308583e-04 2.93631572146e-03 6.36178607768e-03 1.05617620161e-02 1.48362957927e-02 1.82603674531e-02 - 1.63250724283e-02 1.87752638656e-02 2.16954377207e-02 2.34052280934e-02 2.30869363929e-02 2.09600950825e-02 - 1.73737146221e-02 1.27704964379e-02 7.97163641604e-03 3.88822807317e-03 1.19938568383e-03 3.99318341872e-04 - 1.65626179475e-03 4.48400646899e-03 7.92450468345e-03 1.10980620206e-02 1.34422126209e-02 1.48944639791e-02 - 1.59370472447e-02 2.30974676194e-02 2.95996309165e-02 3.23843246845e-02 3.13043255442e-02 2.74943010791e-02 - 2.17342070894e-02 1.48252320983e-02 8.12780450420e-03 3.07272238402e-03 5.30198166447e-04 6.46227754013e-04 - 2.81411593198e-03 5.82898965033e-03 8.42100449126e-03 9.84707831750e-03 1.03512968041e-02 1.16232871057e-02 - 2.24875796029e-02 3.37722330188e-02 4.10268831080e-02 4.23356472933e-02 3.92799061712e-02 3.33213403143e-02 - 2.49305178956e-02 1.52891088083e-02 6.82917348025e-03 1.64360464113e-03 1.86562149136e-04 1.52168307387e-03 - 4.13565877440e-03 6.52864573310e-03 7.67444230152e-03 7.63112583774e-03 8.24519885098e-03 1.27525336135e-02 - 3.37296901728e-02 4.06678061829e-02 4.28369292367e-02 4.10897596693e-02 3.58712154374e-02 2.69657019121e-02 - 1.58371968408e-02 6.27201589113e-03 1.30767631352e-03 6.95975956318e-04 2.13885613626e-03 3.69307192980e-03 - 4.56833500015e-03 4.80839352292e-03 5.20491420049e-03 7.48330853076e-03 1.35571431549e-02 2.33759228978e-02 - 3.86599027285e-02 4.37561278107e-02 4.49477457631e-02 4.26333440173e-02 3.57345867038e-02 2.40581173911e-02 - 1.14226011294e-02 3.24213630394e-03 1.06234225115e-03 2.18940881846e-03 3.57585634420e-03 3.98391127876e-03 - 3.65019810926e-03 3.57632367794e-03 5.20479642137e-03 1.00826286952e-02 1.87930896440e-02 2.95291211013e-02 - 3.87309237740e-02 4.24255216603e-02 4.31291779387e-02 3.96526145437e-02 3.02519481436e-02 1.70449905394e-02 - 6.33854098633e-03 2.06540331681e-03 2.39107539830e-03 3.64068514342e-03 3.92065749553e-03 3.18904048766e-03 - 2.43886885700e-03 3.12396283502e-03 6.52798075281e-03 1.32245754755e-02 2.24545728784e-02 3.18169522228e-02 - 3.45757945183e-02 3.69211742293e-02 3.61049296851e-02 3.01658921977e-02 1.94007291239e-02 8.91182148958e-03 - 3.59185314089e-03 2.86138101893e-03 3.49913462474e-03 3.68656233607e-03 3.05369464711e-03 2.00629253113e-03 - 1.72235072441e-03 3.55594500418e-03 8.10235760504e-03 1.49820314895e-02 2.28723997347e-02 2.98321435078e-02 - 2.70255749641e-02 2.70546046573e-02 2.34643753982e-02 1.59848051822e-02 8.03732612993e-03 3.89265998914e-03 - 3.27978109135e-03 3.36141859901e-03 3.12023556081e-03 2.68005979080e-03 1.92342072039e-03 1.19389530186e-03 - 1.68195995658e-03 4.29603050935e-03 8.87354363587e-03 1.45849811373e-02 2.02345595657e-02 2.45923218560e-02 - 1.71300832549e-02 1.44980037829e-02 9.38840434433e-03 4.09525147994e-03 1.93305776643e-03 2.63433662580e-03 - 3.17610165134e-03 2.71090277149e-03 2.20073262284e-03 1.80385051394e-03 1.19776986788e-03 9.14890040248e-04 - 2.01944369523e-03 4.72490225998e-03 8.39962868843e-03 1.22777725638e-02 1.55072922459e-02 1.72926040992e-02 - 7.49135183427e-03 4.08833764664e-03 9.13396696572e-04 2.84522835348e-04 2.05968688821e-03 3.36636779629e-03 - 3.02213995911e-03 2.28022180928e-03 1.85836510124e-03 1.41057221990e-03 8.65753815670e-04 1.00349084531e-03 - 2.34869062908e-03 4.48470434402e-03 6.80504644624e-03 8.81848850797e-03 9.90872460039e-03 9.53644996601e-03 - 1.60032437534e-03 3.22096493942e-04 1.13596401095e-03 3.81100538224e-03 5.72519343130e-03 5.30982317412e-03 - 3.85736183191e-03 2.74531531556e-03 1.96544520357e-03 1.20663129458e-03 7.98965222105e-04 1.25432260198e-03 - 2.36071403557e-03 3.58847529408e-03 4.64343073578e-03 5.20667676379e-03 4.86275280446e-03 3.50580533070e-03 - 1.16578853167e-03 3.22223291139e-03 6.90229600545e-03 9.86363553509e-03 9.88470481167e-03 7.63121415038e-03 - 5.14829015320e-03 3.29277953377e-03 1.93615183336e-03 1.08362901817e-03 9.71102996585e-04 1.42326707670e-03 - 1.97259010475e-03 2.40172067388e-03 2.60947122969e-03 2.38391531369e-03 1.68600081032e-03 9.74002263626e-04 - 4.95548499978e-03 9.13882867487e-03 1.30278255496e-02 1.42193418223e-02 1.22075516780e-02 8.74289753029e-03 - 5.55491777347e-03 3.22605222260e-03 1.80129648987e-03 1.23804449324e-03 1.23460583288e-03 1.34341324587e-03 - 1.37873849744e-03 1.34692200137e-03 1.20418392729e-03 9.92677734961e-04 1.10525376936e-03 2.22168079217e-03 - 1.02990003090e-02 1.44096355935e-02 1.64538401652e-02 1.53621512813e-02 1.20254108134e-02 8.20994902081e-03 - 5.09888866787e-03 3.07972776989e-03 2.06060758237e-03 1.63568431411e-03 1.36048846122e-03 1.07300273265e-03 - 8.21756192681e-04 6.58777676519e-04 7.08268495958e-04 1.33040660393e-03 3.01678791895e-03 6.08571361405e-03 - 1.48992024043e-02 1.73233989999e-02 1.69915920968e-02 1.43171616050e-02 1.07136192511e-02 7.43969635489e-03 - 5.08665780364e-03 3.64698936616e-03 2.74358908247e-03 1.99845364289e-03 1.30858469570e-03 7.51417369189e-04 - 4.17374914722e-04 4.79418583581e-04 1.29745568715e-03 3.26974669188e-03 6.54511055441e-03 1.07769038769e-02 - 1.74056895799e-02 1.78577646408e-02 1.60737958453e-02 1.31845390644e-02 1.02997573528e-02 7.99333514459e-03 - 6.29416497433e-03 4.89350064979e-03 3.52905978523e-03 2.22715872363e-03 1.15214285024e-03 4.32413285559e-04 - 2.57525140913e-04 9.73195479131e-04 2.90914320695e-03 6.13634231690e-03 1.03188015515e-02 1.45418309823e-02 - 1.74136565717e-02 1.69573394037e-02 1.54527698527e-02 1.36487019592e-02 1.19151741791e-02 1.02844038936e-02 - 8.52861538976e-03 6.47226159515e-03 4.28875247290e-03 2.33747407903e-03 8.83084312047e-04 1.61266782607e-04 - 5.04544062804e-04 2.15732075959e-03 5.06045296295e-03 8.86363372377e-03 1.28824073710e-02 1.60470549784e-02 - 1.58267021467e-02 1.63753245199e-02 1.67623754613e-02 1.66311997508e-02 1.57469800207e-02 1.40185432650e-02 - 1.14044109594e-02 8.17204856921e-03 4.91818400531e-03 2.21522143435e-03 4.81943140265e-04 9.50464728678e-05 - 1.25183920078e-03 3.73257867634e-03 7.00127426879e-03 1.04088018049e-02 1.32421659032e-02 1.49871106130e-02 - 1.51529661785e-02 1.84806444609e-02 2.13181909661e-02 2.23597524510e-02 2.13672840792e-02 1.85918784080e-02 - 1.44287370976e-02 9.60308326237e-03 5.08103449100e-03 1.71979689730e-03 1.02394643703e-04 4.33408752474e-04 - 2.38578163893e-03 5.20566487137e-03 8.03804052422e-03 1.02086368679e-02 1.15609850291e-02 1.28325486770e-02 - 1.82580537099e-02 2.46926241846e-02 2.89364529077e-02 2.97465177652e-02 2.75358124478e-02 2.29946994668e-02 - 1.68009350202e-02 1.00958341387e-02 4.40719731787e-03 9.45132716516e-04 6.68610205368e-05 1.28088878030e-03 - 3.62558565396e-03 6.06631957400e-03 7.78257459243e-03 8.61168656751e-03 9.58066314439e-03 1.25604326212e-02 - 2.55453599910e-02 3.33962381411e-02 3.71052173863e-02 3.65492947127e-02 3.27156458330e-02 2.61444864172e-02 - 1.75775028346e-02 9.00482842134e-03 2.88622565948e-03 3.53897241711e-04 7.26271071079e-04 2.53519431044e-03 - 4.52800505753e-03 5.91071083909e-03 6.47187027698e-03 7.09870172763e-03 9.87012837469e-03 1.64328746734e-02 - 2.87933177142e-02 3.26075839679e-02 3.32340036005e-02 3.09568818669e-02 2.58532765825e-02 1.85190289839e-02 - 1.11262612872e-02 6.26479305834e-03 4.55093152535e-03 4.50337335753e-03 4.51237045033e-03 4.02793349234e-03 - 3.35322452334e-03 3.20110215581e-03 4.52152243125e-03 8.23893713824e-03 1.45408609885e-02 2.21661350822e-02 - 3.07563342999e-02 3.35128462045e-02 3.35107523701e-02 3.05758406508e-02 2.45142679719e-02 1.68745361886e-02 - 1.08027052714e-02 7.93915867323e-03 7.07770824306e-03 6.33783824197e-03 4.97144281157e-03 3.27054087858e-03 - 2.09376831952e-03 2.50499050005e-03 5.30100483593e-03 1.06588801916e-02 1.78714368175e-02 2.52247894116e-02 - 2.92188550696e-02 3.09755490461e-02 3.03114954964e-02 2.67321062823e-02 2.09282889798e-02 1.55775540652e-02 - 1.25367889297e-02 1.08253313234e-02 8.89730394555e-03 6.50526609359e-03 4.01015177384e-03 1.93040897794e-03 - 1.18890078968e-03 2.70269969505e-03 6.67154869956e-03 1.25587248207e-02 1.92536139318e-02 2.52093073117e-02 - 2.44413294646e-02 2.49340151339e-02 2.33404764250e-02 2.00937468483e-02 1.72582310912e-02 1.61223456794e-02 - 1.49068723101e-02 1.19178789750e-02 8.12563275597e-03 4.88456931476e-03 2.39387305363e-03 8.31664321628e-04 - 1.00731359667e-03 3.42565229697e-03 7.68291216181e-03 1.29203960429e-02 1.80878864900e-02 2.21142587363e-02 - 1.71449642935e-02 1.61923882394e-02 1.43928749447e-02 1.36663563486e-02 1.52139743460e-02 1.64398800100e-02 - 1.41657317531e-02 9.53287299437e-03 5.49269112877e-03 2.85792244908e-03 1.09293573055e-03 3.56808342615e-04 - 1.35505816684e-03 4.04863868863e-03 7.68738021042e-03 1.14879193761e-02 1.46848546466e-02 1.66476787717e-02 - 9.02582452524e-03 7.53977690448e-03 7.33884023741e-03 9.98928830235e-03 1.34961476195e-02 1.36059034280e-02 - 9.91225414898e-03 5.75021868034e-03 3.06624796636e-03 1.44662322195e-03 3.97327936001e-04 4.04358105930e-04 - 1.81282809597e-03 4.08760696610e-03 6.53621892597e-03 8.65549979924e-03 9.93842290190e-03 1.00448369490e-02 - 2.77352531491e-03 2.50014903777e-03 4.78431178628e-03 8.80482302566e-03 1.08363581925e-02 9.01202431421e-03 - 5.63278982253e-03 3.13675920302e-03 1.69344851219e-03 6.73423261722e-04 1.88840141540e-04 7.12457822913e-04 - 1.99230176389e-03 3.40532697307e-03 4.59296083000e-03 5.26260361416e-03 5.09655699295e-03 4.08352610426e-03 - 5.04014507355e-04 2.36958286961e-03 6.02273553487e-03 8.88133123141e-03 8.53337522081e-03 5.95566477331e-03 - 3.53363308396e-03 2.02432820576e-03 9.94283781574e-04 3.14017620910e-04 3.33223729513e-04 9.77900482741e-04 - 1.72521142177e-03 2.27761150611e-03 2.51802894441e-03 2.25823134307e-03 1.46787274143e-03 5.73710932775e-04 - 2.14784776072e-03 5.42852310833e-03 8.62068246284e-03 9.41387160044e-03 7.54323065925e-03 4.89280068529e-03 - 2.84866940516e-03 1.47808147808e-03 6.08430634744e-04 3.53758915799e-04 6.23498278249e-04 9.79935089522e-04 - 1.16489907279e-03 1.15849679383e-03 9.06412736699e-04 4.13654006868e-04 1.54829745589e-05 3.60032306854e-04 - 5.79208270834e-03 8.94033550436e-03 1.05015150129e-02 9.51854694394e-03 6.93816618884e-03 4.30967028143e-03 - 2.35618509013e-03 1.16015948217e-03 6.82394364394e-04 6.97027876008e-04 7.90845572211e-04 7.45829608206e-04 - 5.94242597398e-04 3.73770050447e-04 1.42862937039e-04 1.79710725993e-04 9.41331839663e-04 2.81457583834e-03 - 9.33307330067e-03 1.11309308744e-02 1.08368854716e-02 8.74317460461e-03 6.04702459913e-03 3.73785767064e-03 - 2.21420691166e-03 1.47197557983e-03 1.21278751439e-03 1.03309393143e-03 7.54160151858e-04 4.41633711866e-04 - 1.89000256924e-04 1.02000108192e-04 4.34201168612e-04 1.52743836257e-03 3.56749903953e-03 6.40073357079e-03 - 1.15606184893e-02 1.17009407374e-02 1.01599975116e-02 7.83977390043e-03 5.63854636290e-03 4.01769466596e-03 - 3.02690100116e-03 2.40862826941e-03 1.83516544638e-03 1.19808902190e-03 6.00498335273e-04 1.71574682898e-04 - 5.04478039690e-05 4.76241460831e-04 1.71922640229e-03 3.87624321883e-03 6.72855869815e-03 9.63077409346e-03 - 1.22370225844e-02 1.13984727669e-02 9.75910090928e-03 8.07008964708e-03 6.68739366290e-03 5.61801210572e-03 - 4.64409420980e-03 3.54674458796e-03 2.34248178615e-03 1.22804233104e-03 3.91206635043e-04 8.79025581719e-06 - 3.13194674414e-04 1.49830297385e-03 3.58105037444e-03 6.36051631787e-03 9.31239161969e-03 1.15389654699e-02 - 1.19170944319e-02 1.14025053907e-02 1.07545653382e-02 1.00924400047e-02 9.31325477945e-03 8.20839756581e-03 - 6.61884269317e-03 4.67325307258e-03 2.73571700225e-03 1.14764675956e-03 1.81055021820e-04 1.03528237408e-04 - 1.05329424178e-03 2.91507515053e-03 5.42267085168e-03 8.17905927150e-03 1.05296015334e-02 1.18041904408e-02 - 1.18780927868e-02 1.29042023189e-02 1.37276417106e-02 1.38885978900e-02 1.31299530793e-02 1.13419777359e-02 - 8.69546541900e-03 5.70387136993e-03 2.96792026575e-03 9.85720856542e-04 1.48042612111e-04 6.08896208183e-04 - 2.14099158585e-03 4.31069763199e-03 6.67902494157e-03 8.76620182360e-03 1.01823472010e-02 1.10393137670e-02 - 1.36915127174e-02 1.67101686772e-02 1.86920088963e-02 1.90002773762e-02 1.75488857931e-02 1.45547597272e-02 - 1.05691653148e-02 6.41945352250e-03 2.97690619321e-03 9.30465421511e-04 5.44866095709e-04 1.52913681570e-03 - 3.28451920664e-03 5.23994934297e-03 6.91555700634e-03 8.07065722542e-03 9.09194477371e-03 1.08604978885e-02 - 1.80779527092e-02 2.25124993304e-02 2.47282045568e-02 2.43618112814e-02 2.16909343884e-02 1.72229588873e-02 - 1.17776579808e-02 6.57760558775e-03 2.88480106537e-03 1.31572795042e-03 1.53206286863e-03 2.69755291322e-03 - 4.10601710377e-03 5.30389297022e-03 6.09724654645e-03 6.92763659341e-03 8.93531278140e-03 1.29105044866e-02 - 2.39158403900e-02 2.85401272681e-02 3.00743096125e-02 2.86464672889e-02 2.46895594620e-02 1.87131221485e-02 - 1.19151068052e-02 6.24495630174e-03 3.15674062506e-03 2.50005166860e-03 3.04013608643e-03 3.72988368134e-03 - 4.18196265379e-03 4.43026071664e-03 4.93286587353e-03 6.74495423499e-03 1.09318643802e-02 1.72885625802e-02 - 2.21774032521e-02 2.43605545788e-02 2.46333447022e-02 2.33987706719e-02 2.10922945682e-02 1.83594859041e-02 - 1.59909257039e-02 1.41416341491e-02 1.21599125174e-02 9.55453633409e-03 6.56597333855e-03 3.82954126500e-03 - 2.05017882267e-03 1.90630321725e-03 3.82067000135e-03 7.68910989012e-03 1.28242992993e-02 1.80750661953e-02 - 2.27285864571e-02 2.45105681312e-02 2.50518716786e-02 2.48158469085e-02 2.42784181560e-02 2.37770576999e-02 - 2.27689185970e-02 2.01024573484e-02 1.56310202331e-02 1.04935612564e-02 5.86388379420e-03 2.47048766135e-03 - 9.58016776488e-04 1.78351498114e-03 4.80401843189e-03 9.36697209080e-03 1.45739030672e-02 1.93381711138e-02 - 2.09264372193e-02 2.26541320377e-02 2.42231749510e-02 2.63848897160e-02 2.93861904362e-02 3.15698209479e-02 - 2.99420364230e-02 2.38345097134e-02 1.59473580042e-02 9.04538146681e-03 4.03733612704e-03 1.08339902850e-03 - 5.08457260777e-04 2.30655446675e-03 5.82686165293e-03 1.02269694221e-02 1.46776547614e-02 1.83698500366e-02 - 1.72420137629e-02 1.93702114800e-02 2.29378046511e-02 2.88659132789e-02 3.54561989137e-02 3.76218114563e-02 - 3.21528721010e-02 2.21236646139e-02 1.27517150635e-02 6.18414156484e-03 2.10785527872e-03 2.50342581323e-04 - 6.88616707871e-04 2.97385467405e-03 6.24137385549e-03 9.75669318970e-03 1.29200963382e-02 1.53519138335e-02 - 1.26671004880e-02 1.57755137735e-02 2.20108125390e-02 3.09881339310e-02 3.76537120706e-02 3.59949224984e-02 - 2.67018138576e-02 1.60384831070e-02 8.23332474468e-03 3.43870953773e-03 7.65793657283e-04 5.57124080500e-05 - 1.13981270285e-03 3.26948763221e-03 5.69629891885e-03 7.95454199301e-03 9.73617356779e-03 1.10893376658e-02 - 8.58549126530e-03 1.30701203954e-02 2.10307728137e-02 2.94777764005e-02 3.21604450651e-02 2.66205094792e-02 - 1.73110423216e-02 9.46782506222e-03 4.47444400395e-03 1.51151974057e-03 1.17411239800e-04 2.64801032497e-04 - 1.44300178111e-03 2.92467814397e-03 4.30045035244e-03 5.35617098551e-03 6.04401663542e-03 6.77367423854e-03 - 6.21237734688e-03 1.15908568005e-02 1.87549873310e-02 2.34015342066e-02 2.18504091251e-02 1.57025350665e-02 - 9.30291821225e-03 4.81764464644e-03 2.01254369162e-03 4.11083030832e-04 1.45497292943e-05 5.40524660231e-04 - 1.35128358668e-03 2.06430025815e-03 2.55321883367e-03 2.75891712171e-03 2.89273302323e-03 3.65762508872e-03 - 5.81075284356e-03 1.07732725002e-02 1.51726043311e-02 1.58979340214e-02 1.26384344151e-02 8.10417098520e-03 - 4.49180892472e-03 2.09192081936e-03 6.02108831196e-04 1.71521513626e-05 1.93380151392e-04 6.16604906359e-04 - 9.32561996333e-04 1.07415321021e-03 1.02541120826e-03 9.00473125393e-04 1.15952248629e-03 2.55090346844e-03 - 6.61076397347e-03 1.00164143384e-02 1.15205427708e-02 1.00843805528e-02 6.96378574838e-03 4.01353562893e-03 - 1.92971698699e-03 6.34729993749e-04 7.49724935279e-05 1.15865350942e-04 3.47717473062e-04 4.67223771992e-04 - 4.44105484508e-04 3.10805513911e-04 1.57577183455e-04 3.01933088122e-04 1.22476181951e-03 3.32905569483e-03 - 7.56379915179e-03 9.06153569382e-03 8.56222444584e-03 6.40415728250e-03 3.88750633530e-03 1.92956385433e-03 - 7.34366965705e-04 2.36982835325e-04 2.29203409171e-04 3.46700264980e-04 3.48695732272e-04 2.40711827381e-04 - 9.47293947307e-05 8.66347045297e-06 2.25148261856e-04 1.06732298321e-03 2.70910806770e-03 5.05914355237e-03 - 8.01287778692e-03 7.88030454920e-03 6.35145441267e-03 4.25650221311e-03 2.44649516454e-03 1.28985780716e-03 - 7.77583817417e-04 6.72014755952e-04 6.36554882331e-04 4.85877140187e-04 2.59321517386e-04 6.29687565033e-05 - 1.46953059708e-05 3.18085841471e-04 1.20449168861e-03 2.73167615253e-03 4.71526427874e-03 6.72145163847e-03 - 7.82944475985e-03 6.75408122608e-03 5.11618962587e-03 3.62161353573e-03 2.60437730776e-03 2.05250944817e-03 - 1.75126407242e-03 1.43805132932e-03 1.00547815546e-03 5.34049934977e-04 1.59883633669e-04 2.95474852402e-05 - 3.29995499377e-04 1.21819910886e-03 2.68784334319e-03 4.54908039443e-03 6.42618374403e-03 7.71352767880e-03 - 7.35455191875e-03 6.31048512851e-03 5.34191131072e-03 4.68336569765e-03 4.24004404942e-03 3.77854123091e-03 - 3.10462118566e-03 2.22238526570e-03 1.30570772041e-03 5.49006894650e-04 1.42890759392e-04 2.90113148849e-04 - 1.08781574672e-03 2.43697830818e-03 4.14278044905e-03 5.94470307681e-03 7.37206198956e-03 7.87680637841e-03 - 7.31557096543e-03 7.19131690445e-03 7.22450507120e-03 7.20523735690e-03 6.84423151359e-03 5.93803701236e-03 - 4.55110377163e-03 2.99234517340e-03 1.59542435123e-03 6.45631389985e-04 4.05808657637e-04 9.67330037404e-04 - 2.12994130721e-03 3.60559787015e-03 5.18681778808e-03 6.58694232187e-03 7.40727171752e-03 7.52823707701e-03 - 8.52349545552e-03 9.68676206385e-03 1.05495359125e-02 1.07188207332e-02 9.94455879694e-03 8.25672215235e-03 - 6.03655679151e-03 3.80430061667e-03 2.02896592596e-03 1.09849706091e-03 1.16722283967e-03 1.99263434843e-03 - 3.16285211789e-03 4.41127230810e-03 5.54690073963e-03 6.36153552080e-03 6.88873298522e-03 7.51827676044e-03 - 1.13551308461e-02 1.35922321789e-02 1.48192674381e-02 1.46810842567e-02 1.31476975109e-02 1.05704029268e-02 - 7.56973014130e-03 4.82772839628e-03 2.95262399821e-03 2.24437105086e-03 2.47582642867e-03 3.13673325326e-03 - 3.88390669981e-03 4.56589560680e-03 5.09082044666e-03 5.63647998305e-03 6.75284531736e-03 8.79292117447e-03 - 1.53771439886e-02 1.81296966851e-02 1.91853088057e-02 1.84090477976e-02 1.60913326652e-02 1.28063549345e-02 - 9.31005759761e-03 6.45379303479e-03 4.81513960694e-03 4.26103352338e-03 4.16642660012e-03 4.09279212514e-03 - 3.98398378759e-03 3.91828371035e-03 4.15481206136e-03 5.30110890794e-03 7.87399016176e-03 1.15860845561e-02 - 1.94313613775e-02 2.20813814455e-02 2.26558326800e-02 2.13558824788e-02 1.86515134072e-02 1.51577133084e-02 - 1.17651236806e-02 9.33851970450e-03 7.97246154126e-03 6.98286298557e-03 5.79448712543e-03 4.43835072788e-03 - 3.28241465272e-03 2.78751419075e-03 3.54172784103e-03 6.05036009918e-03 1.02127245127e-02 1.51150618777e-02 - 1.64009966583e-02 1.84881135923e-02 2.03427709498e-02 2.26136291427e-02 2.53424047301e-02 2.76571456446e-02 - 2.80245396944e-02 2.52650520412e-02 1.97520925187e-02 1.32278660001e-02 7.39768017578e-03 3.18795953139e-03 - 1.02814678262e-03 1.06145178646e-03 2.99784679711e-03 6.19154672476e-03 9.93147588622e-03 1.35251897294e-02 - 1.71049550301e-02 2.01593612248e-02 2.43624877869e-02 3.02384607775e-02 3.67593649243e-02 4.09156194995e-02 - 3.94611310038e-02 3.21153548069e-02 2.20314252186e-02 1.27125423933e-02 5.81856268370e-03 1.69599482257e-03 - 3.18545617272e-04 1.29977739268e-03 3.86676260322e-03 7.25509587205e-03 1.08680088174e-02 1.41990368959e-02 - 1.70191649768e-02 2.20878442797e-02 3.00553693139e-02 4.07233867326e-02 5.05653109407e-02 5.35677645024e-02 - 4.66822131444e-02 3.34560667308e-02 2.00790272117e-02 1.00022512405e-02 3.64126540132e-03 5.56112289193e-04 - 2.39484104635e-04 1.86210590347e-03 4.50615161645e-03 7.55175599216e-03 1.06183110032e-02 1.35990100423e-02 - 1.67776568383e-02 2.46818253485e-02 3.68977143071e-02 5.11649187124e-02 6.04486230271e-02 5.79009783691e-02 - 4.45736714745e-02 2.82112318495e-02 1.50455403831e-02 6.49512297228e-03 1.76054690679e-03 4.73208163193e-05 - 5.55784650687e-04 2.29401067159e-03 4.51120600606e-03 6.85282019358e-03 9.26386998526e-03 1.21863846457e-02 - 1.67707265144e-02 2.73179227825e-02 4.19038298834e-02 5.52586906450e-02 5.89853554670e-02 4.99656192144e-02 - 3.41511708415e-02 1.95219419054e-02 9.42725033292e-03 3.46102579696e-03 5.98301984536e-04 4.95388862792e-05 - 8.85588491142e-04 2.26926208993e-03 3.79076950032e-03 5.38430533718e-03 7.36257825939e-03 1.06472646170e-02 - 1.68258726787e-02 2.82129376633e-02 4.10905019063e-02 4.88084390889e-02 4.59402337178e-02 3.45207858598e-02 - 2.14243739034e-02 1.13174105129e-02 4.90816790405e-03 1.41789403405e-03 1.29068443036e-04 2.44892739824e-04 - 9.41645711475e-04 1.77149991945e-03 2.63853908858e-03 3.71124297296e-03 5.61200127565e-03 9.50530183775e-03 - 1.62968932634e-02 2.57879837058e-02 3.36118314483e-02 3.49436602731e-02 2.89355949576e-02 1.96169126303e-02 - 1.12659720694e-02 5.43965874288e-03 1.96330252857e-03 3.79696381120e-04 8.60400195450e-05 3.42160203240e-04 - 7.01348905192e-04 1.06655713071e-03 1.51615102611e-03 2.41383739305e-03 4.54662560334e-03 8.93329336116e-03 - 1.46349417947e-02 2.04292107913e-02 2.30267149637e-02 2.07440905242e-02 1.52025966070e-02 9.35382589093e-03 - 4.84443121555e-03 1.93883491929e-03 4.73926174186e-04 7.29843667197e-05 1.40283492900e-04 2.62433480124e-04 - 3.55706055002e-04 4.74020741261e-04 8.24262057889e-04 1.90729878206e-03 4.37699797082e-03 8.69716083587e-03 - 1.19898112537e-02 1.41995212284e-02 1.35864946507e-02 1.05049879454e-02 6.69269992971e-03 3.52409301152e-03 - 1.41602701614e-03 3.33448930601e-04 3.27121015760e-05 7.47562251899e-05 1.23612053629e-04 1.16279720576e-04 - 1.09457801388e-04 2.41992303020e-04 8.39296661471e-04 2.30783214177e-03 4.85853045235e-03 8.34573041423e-03 - 9.07727305895e-03 8.91808178686e-03 7.08091706064e-03 4.51084926669e-03 2.26670942059e-03 8.10351563715e-04 - 1.33322932960e-04 4.16893716535e-06 7.64979043271e-05 1.06018393266e-04 6.75234875560e-05 3.16376627409e-05 - 1.14187902864e-04 5.45908726171e-04 1.58696239122e-03 3.28872668246e-03 5.44724776462e-03 7.63489890467e-03 - 6.52810808770e-03 5.25314319513e-03 3.39284322659e-03 1.72557565555e-03 6.76886801725e-04 2.50373332193e-04 - 2.12579376217e-04 2.65075528176e-04 2.33307967804e-04 1.31268880800e-04 5.21267574630e-05 1.15418624576e-04 - 5.01998431404e-04 1.37887411328e-03 2.71769853804e-03 4.28227030677e-03 5.74417022052e-03 6.65771977098e-03 - 4.65726743689e-03 3.27858478268e-03 2.06155964155e-03 1.33248099840e-03 1.05338743062e-03 9.92564942954e-04 - 9.08410256855e-04 7.00479371817e-04 4.27620040329e-04 2.07104618488e-04 1.78699158780e-04 5.11219739098e-04 - 1.30230084896e-03 2.45600861300e-03 3.74228526901e-03 4.91219385774e-03 5.64895773329e-03 5.58985089210e-03 - 3.73767487494e-03 3.00657273011e-03 2.66992142504e-03 2.61635228110e-03 2.57294277692e-03 2.31595147437e-03 - 1.81989111905e-03 1.23031756636e-03 7.20907131037e-04 4.61855214325e-04 6.38701671867e-04 1.31829212827e-03 - 2.32734173422e-03 3.40523137282e-03 4.37974523429e-03 5.06534727187e-03 5.18207588236e-03 4.62928181051e-03 - 4.09135544474e-03 4.32062934442e-03 4.69293722426e-03 4.88796222990e-03 4.63226099256e-03 3.89390325399e-03 - 2.90678254008e-03 1.96761029344e-03 1.31957600920e-03 1.17862846165e-03 1.61971429391e-03 2.42610765367e-03 - 3.27165718561e-03 3.99507185836e-03 4.52520528133e-03 4.71855859452e-03 4.52242794866e-03 4.19344523040e-03 - 5.80658667709e-03 6.86642431161e-03 7.59873902168e-03 7.67706373717e-03 6.98317811484e-03 5.74550344255e-03 - 4.38133023648e-03 3.26241698654e-03 2.66410532114e-03 2.68363825734e-03 3.10264353975e-03 3.56087670055e-03 - 3.88692461760e-03 4.07553219629e-03 4.10528650099e-03 4.04140915754e-03 4.18193584617e-03 4.79786508616e-03 - 8.55542956795e-03 1.01354792395e-02 1.09177642115e-02 1.07026890655e-02 9.64409355627e-03 8.18053717555e-03 - 6.77031621651e-03 5.75661683248e-03 5.26996523088e-03 5.09678670852e-03 4.86769399345e-03 4.45456319040e-03 - 3.97161795052e-03 3.52227946852e-03 3.26123484872e-03 3.56212656661e-03 4.72872470960e-03 6.57576203829e-03 - 1.17119304031e-02 1.35120032725e-02 1.42008841680e-02 1.38798210558e-02 1.29666890014e-02 1.18887217290e-02 - 1.09295506835e-02 1.01793421219e-02 9.40309135278e-03 8.21355985727e-03 6.56740286827e-03 4.82944872473e-03 - 3.37389976450e-03 2.47777816626e-03 2.51977925262e-03 3.82395334269e-03 6.22888791813e-03 9.09748714217e-03 - 1.45371408591e-02 1.63834189167e-02 1.72320869854e-02 1.75532768049e-02 1.77737930438e-02 1.79635184259e-02 - 1.78608346375e-02 1.69416130303e-02 1.47230776015e-02 1.13488359054e-02 7.62568201205e-03 4.40191670406e-03 - 2.22274471029e-03 1.48020767121e-03 2.41626758138e-03 4.85419414581e-03 8.18635486639e-03 1.16510006931e-02 - 1.32213940089e-02 1.70182419833e-02 2.23914301815e-02 2.94003785990e-02 3.65878050096e-02 4.10760667517e-02 - 4.01221907803e-02 3.34221850373e-02 2.36058451046e-02 1.40486330140e-02 6.75272414829e-03 2.25036553521e-03 - 3.76803857475e-04 6.13988686064e-04 2.23766605879e-03 4.62075580376e-03 7.35987645146e-03 1.02051201906e-02 - 1.58900565333e-02 2.26119273482e-02 3.23853888912e-02 4.41983599915e-02 5.42599988386e-02 5.73374722104e-02 - 5.09058096754e-02 3.78111933225e-02 2.36187154895e-02 1.22363941402e-02 4.80022444411e-03 1.00281121273e-03 - 5.90013492073e-05 9.76190386392e-04 2.89735951926e-03 5.35360866701e-03 8.16828516169e-03 1.14568826233e-02 - 1.94530493601e-02 3.02125817831e-02 4.50419025935e-02 6.07124563723e-02 7.02979576370e-02 6.77174068816e-02 - 5.38116006984e-02 3.56355347787e-02 1.98417112130e-02 8.97773723858e-03 2.80146016904e-03 2.73546582563e-04 - 1.82574632568e-04 1.40309833632e-03 3.25579428565e-03 5.54435759555e-03 8.44833202038e-03 1.26576630409e-02 - 2.38388952519e-02 3.85478487852e-02 5.67279696139e-02 7.21216288143e-02 7.62094526352e-02 6.58666258502e-02 - 4.69053688502e-02 2.80502652656e-02 1.41073047009e-02 5.58059642806e-03 1.34860222156e-03 6.68186493022e-05 - 4.47952779487e-04 1.58372127560e-03 3.13033839493e-03 5.22115565060e-03 8.49137201837e-03 1.41685957477e-02 - 2.79077815755e-02 4.44089874489e-02 6.15080198982e-02 7.12863733443e-02 6.75840614305e-02 5.24402945875e-02 - 3.39278858491e-02 1.86229603388e-02 8.51564472592e-03 2.93495763556e-03 5.81013065098e-04 1.37092828581e-04 - 5.76903553934e-04 1.41240343986e-03 2.64121677666e-03 4.72001563739e-03 8.66913681619e-03 1.59485784302e-02 - 2.97511614714e-02 4.42882064181e-02 5.56979555661e-02 5.77349083108e-02 4.90216559814e-02 3.45467970946e-02 - 2.06115439873e-02 1.04357576526e-02 4.30762800320e-03 1.32671444999e-03 3.03866361214e-04 2.03968601862e-04 - 4.81786530467e-04 1.03931489696e-03 2.12047747397e-03 4.42980941605e-03 9.12578722178e-03 1.74163857559e-02 - 2.78751901228e-02 3.73735336542e-02 4.17655034191e-02 3.84999251424e-02 2.94793657415e-02 1.90639262307e-02 - 1.04889097724e-02 4.82370284402e-03 1.80476081540e-03 5.78615348624e-04 2.09219603297e-04 1.49731214031e-04 - 2.81207157319e-04 7.22430811474e-04 1.88393680488e-03 4.56311685120e-03 9.66947747517e-03 1.76825888151e-02 - 2.25276554018e-02 2.65621933470e-02 2.60887692330e-02 2.13584659406e-02 1.47561740853e-02 8.66616411855e-03 - 4.27411113731e-03 1.75523525842e-03 6.60899016734e-04 2.78330576988e-04 1.12375727665e-04 4.58803997345e-05 - 1.57271799099e-04 6.82768517804e-04 2.11743626523e-03 5.06165374583e-03 9.83374688929e-03 1.61177476506e-02 - 1.56743505858e-02 1.59649621794e-02 1.35812918299e-02 9.69264082153e-03 5.83704157273e-03 2.93411919359e-03 - 1.22174499051e-03 4.78163462578e-04 2.33454947931e-04 1.13054002666e-04 2.03741803066e-05 1.92855145430e-05 - 2.67020996242e-04 1.07333317598e-03 2.80090354370e-03 5.58533446174e-03 9.19921456583e-03 1.29745044009e-02 - 9.46122277767e-03 8.05678234340e-03 5.65079779207e-03 3.23029280734e-03 1.46375073826e-03 5.04324326495e-04 - 1.60199473019e-04 9.58300005159e-05 6.21254773570e-05 1.22663620737e-05 1.34779252301e-05 1.86793076393e-04 - 7.40739025963e-04 1.88931574766e-03 3.63825919236e-03 5.74325663492e-03 7.81805482284e-03 9.28976592598e-03 - 4.97803509205e-03 3.30121284009e-03 1.67151685080e-03 5.70359398750e-04 8.16764716980e-05 3.95365422467e-06 - 5.49510255476e-05 6.18538731566e-05 2.46123958592e-05 3.03929886963e-05 1.96102067791e-04 6.78110166943e-04 - 1.59378625043e-03 2.86694881652e-03 4.24027990875e-03 5.43151254497e-03 6.14572278217e-03 6.04233856174e-03 - 2.38524903345e-03 1.23705489246e-03 5.47554678634e-04 3.25593796984e-04 3.59590432176e-04 4.06806700875e-04 - 3.52614415912e-04 2.39648860324e-04 1.77910832431e-04 2.95835243210e-04 7.36911881328e-04 1.56017108080e-03 - 2.61968187582e-03 3.64721446005e-03 4.42882198781e-03 4.79631095927e-03 4.55826971386e-03 3.65796885746e-03 - 1.52939409807e-03 1.20104803061e-03 1.23338887527e-03 1.38326037713e-03 1.40716464207e-03 1.22506316954e-03 - 9.42851464247e-04 7.24534692494e-04 7.17187801006e-04 1.05856177101e-03 1.78252137919e-03 2.69592234521e-03 - 3.50406337967e-03 4.03570565502e-03 4.21847523599e-03 3.95382857393e-03 3.22351294069e-03 2.28063520125e-03 - 2.14110591590e-03 2.52131822385e-03 2.92853224332e-03 3.08871676724e-03 2.88300539743e-03 2.44705116101e-03 - 2.03828560488e-03 1.86361414815e-03 2.04857478867e-03 2.59026329631e-03 3.27223208373e-03 3.79725245411e-03 - 4.02967197570e-03 3.97378711910e-03 3.61934611686e-03 3.00630221760e-03 2.37738407982e-03 2.04983281896e-03 - 3.80475910203e-03 4.64999081044e-03 5.19480379672e-03 5.25731236209e-03 4.92004434942e-03 4.48781535996e-03 - 4.24816413919e-03 4.32986579164e-03 4.65975799784e-03 4.96222062778e-03 4.95939479192e-03 4.61873718109e-03 - 4.07215047268e-03 3.40247583235e-03 2.70740823684e-03 2.26007565015e-03 2.33973754961e-03 2.93772682074e-03 - 6.06394639092e-03 7.22278406035e-03 7.88920456494e-03 8.09392204754e-03 8.11722934794e-03 8.24746842885e-03 - 8.56926221030e-03 8.89411479459e-03 8.80676070638e-03 7.98506007710e-03 6.56266134380e-03 4.97467821036e-03 - 3.52954053589e-03 2.38998582190e-03 1.82485387210e-03 2.10727067742e-03 3.16490393741e-03 4.61307879159e-03 - 8.52704527839e-03 1.00225462701e-02 1.11610792301e-02 1.22584655982e-02 1.35700672989e-02 1.49927956645e-02 - 1.60329089754e-02 1.59532973731e-02 1.42379665242e-02 1.11711472199e-02 7.70161258886e-03 4.66896603331e-03 - 2.46441034612e-03 1.31725291359e-03 1.41461145372e-03 2.64060827205e-03 4.54192729369e-03 6.62654964459e-03 - 1.09117064472e-02 1.31049895816e-02 1.56327640918e-02 1.89092835394e-02 2.26943266973e-02 2.59187316025e-02 - 2.70340123408e-02 2.49064388892e-02 1.98510225106e-02 1.35698592730e-02 7.85407000515e-03 3.65338371620e-03 - 1.25327477480e-03 6.65339441725e-04 1.62339948248e-03 3.60023742203e-03 6.05913405011e-03 8.58544693456e-03 - 1.34249052373e-02 2.04066452953e-02 2.99579293320e-02 4.06452255063e-02 4.91884277872e-02 5.16907583520e-02 - 4.63497495595e-02 3.52195244454e-02 2.26403961256e-02 1.21285814543e-02 5.06081356682e-03 1.30157713027e-03 - 6.53579493009e-05 4.22417877912e-04 1.66748810478e-03 3.46462271140e-03 5.76439782021e-03 8.84011270980e-03 - 1.95466019191e-02 3.10308800184e-02 4.55752359759e-02 5.97164283340e-02 6.77259669972e-02 6.51217051175e-02 - 5.26830512132e-02 3.59563308402e-02 2.06967977993e-02 9.74640972631e-03 3.34717037357e-03 5.36412189963e-04 - 2.59507143393e-05 7.44396912754e-04 2.14410557722e-03 4.15953649471e-03 7.12322610462e-03 1.18560070406e-02 - 2.74971321709e-02 4.36424744879e-02 6.19153833017e-02 7.61746674807e-02 7.93057265949e-02 6.90731998092e-02 - 5.04847298310e-02 3.12491246371e-02 1.63088408215e-02 6.83716623174e-03 1.97195473618e-03 2.23812474768e-04 - 1.87886604123e-04 9.91530567140e-04 2.40091102413e-03 4.72347740873e-03 8.80511355753e-03 1.59622255447e-02 - 3.57076790949e-02 5.46224271699e-02 7.27081966294e-02 8.21730074516e-02 7.76340806828e-02 6.12869770138e-02 - 4.08940992105e-02 2.32947993660e-02 1.11930270825e-02 4.28846826789e-03 1.14274049118e-03 1.95516823555e-04 - 3.16490567160e-04 1.02973731561e-03 2.46735056303e-03 5.35217890654e-03 1.09652584438e-02 2.07858104504e-02 - 4.13552522538e-02 5.91103457353e-02 7.21246488361e-02 7.39055786196e-02 6.33021399882e-02 4.57162447003e-02 - 2.82324355183e-02 1.49972334429e-02 6.76813365559e-03 2.51920415263e-03 7.43891137863e-04 2.12332519311e-04 - 2.97086669001e-04 9.30476922862e-04 2.56968432783e-03 6.25636472015e-03 1.34003649840e-02 2.51458565577e-02 - 4.16779201083e-02 5.43042011532e-02 5.98485638344e-02 5.54306144181e-02 4.33477599890e-02 2.89709099456e-02 - 1.67288154909e-02 8.40205985519e-03 3.72401236890e-03 1.49632959357e-03 5.24438472414e-04 1.42866519868e-04 - 1.95249391147e-04 9.01621246191e-04 2.94151192271e-03 7.43472280825e-03 1.54787223534e-02 2.73836683912e-02 - 3.59632650536e-02 4.20437081583e-02 4.16174014740e-02 3.49677606488e-02 2.51737937203e-02 1.56814727159e-02 - 8.54813773288e-03 4.21285002268e-03 2.00413955050e-03 9.21650959552e-04 3.19683791542e-04 3.18355406160e-05 - 1.74496437675e-04 1.13531434192e-03 3.65185396596e-03 8.57001690347e-03 1.62972821021e-02 2.61854445373e-02 - 2.63724187217e-02 2.74181652970e-02 2.43244382417e-02 1.85714119267e-02 1.23235268773e-02 7.18784462283e-03 - 3.82075274993e-03 2.01380795154e-03 1.09739914582e-03 5.26666563255e-04 1.37199822365e-04 1.26714115944e-05 - 3.95035491891e-04 1.72630185323e-03 4.53696362026e-03 9.11756964952e-03 1.51952161361e-02 2.16285115313e-02 - 1.63783028503e-02 1.49482543147e-02 1.17355772776e-02 8.02669030761e-03 4.86236548158e-03 2.71584277148e-03 - 1.53470415008e-03 9.33177709162e-04 5.42232705834e-04 2.34293063274e-04 7.04923637522e-05 2.23081057313e-04 - 9.71993815002e-04 2.61037670588e-03 5.24325548216e-03 8.68371516646e-03 1.23907765104e-02 1.53542695408e-02 - 8.47980014812e-03 6.52583867077e-03 4.30420785985e-03 2.49213679889e-03 1.35177967058e-03 7.86845235025e-04 - 5.25156826429e-04 3.39906929593e-04 1.74485153194e-04 9.55264907844e-05 2.35160633722e-04 7.82236845581e-04 - 1.88986020922e-03 3.52272886866e-03 5.46100883437e-03 7.40099825924e-03 8.90195364436e-03 9.37719488129e-03 - 3.45220326582e-03 1.97981554405e-03 8.94434425687e-04 3.33738364174e-04 1.62281512458e-04 1.38378591888e-04 - 9.77708289499e-05 3.36938066275e-05 3.81615761942e-05 2.38464453630e-04 7.74319488952e-04 1.70992470584e-03 - 2.91979745498e-03 4.14615088870e-03 5.16016388778e-03 5.76252633112e-03 5.71074336482e-03 4.86718311961e-03 - 9.93587710006e-04 2.99922183142e-04 3.31264313523e-05 3.80936897831e-05 1.02109151681e-04 9.98019873553e-05 - 5.56029560418e-05 8.32379539999e-05 3.16939827237e-04 8.77186013807e-04 1.77683887914e-03 2.82833513984e-03 - 3.74576563982e-03 4.33550699037e-03 4.49945950593e-03 4.14349351879e-03 3.25787040510e-03 2.07572302922e-03 - 4.34832383669e-04 3.84491629202e-04 5.19584735381e-04 6.33474910094e-04 6.18995564195e-04 5.36645085970e-04 - 5.42428055392e-04 7.82773577198e-04 1.34929527619e-03 2.20909730137e-03 3.13922953811e-03 3.84804170006e-03 - 4.17767985556e-03 4.09783194751e-03 3.58936794550e-03 2.69923099447e-03 1.67167780347e-03 8.51504011596e-04 - 1.08641684151e-03 1.42683981991e-03 1.70514068980e-03 1.79329605041e-03 1.75071839789e-03 1.78488842017e-03 - 2.08426304549e-03 2.70452449909e-03 3.52070320607e-03 4.24644149033e-03 4.61334364521e-03 4.55673965194e-03 - 4.14886587662e-03 3.44030901867e-03 2.51147102868e-03 1.60755646531e-03 1.02905100923e-03 8.89378324656e-04 - 2.43864810738e-03 3.04830519919e-03 3.48184792280e-03 3.76701926279e-03 4.10890698246e-03 4.71746125607e-03 - 5.61336108469e-03 6.53756098602e-03 7.04029408733e-03 6.81655708962e-03 5.97172517358e-03 4.83207985450e-03 - 3.61031899248e-03 2.42406852996e-03 1.50078271332e-03 1.10263181952e-03 1.26171948099e-03 1.78192054734e-03 - 4.23105247157e-03 5.22456947806e-03 6.20010239050e-03 7.36343922619e-03 8.87160210549e-03 1.06205069074e-02 - 1.21414745064e-02 1.26970264424e-02 1.17707225200e-02 9.59871628156e-03 6.97452926902e-03 4.55306877234e-03 - 2.61163852850e-03 1.32875867147e-03 8.83962000550e-04 1.23754594793e-03 2.09759547478e-03 3.15904753952e-03 - 6.42199648766e-03 8.27744177326e-03 1.07040205048e-02 1.38858589003e-02 1.75075053831e-02 2.06795438332e-02 - 2.21257713447e-02 2.08383316668e-02 1.69882274214e-02 1.19598381589e-02 7.26186162558e-03 3.68597678746e-03 - 1.44609752976e-03 5.47116089490e-04 8.02755339048e-04 1.82852664014e-03 3.23976430828e-03 4.79536609480e-03 - 9.27106079514e-03 1.29886383468e-02 1.82518157571e-02 2.47615861047e-02 3.11225991425e-02 3.50900678662e-02 - 3.45958721066e-02 2.93125764560e-02 2.11856341172e-02 1.29891084374e-02 6.56254983575e-03 2.46081441545e-03 - 5.21858889193e-04 2.75922994422e-04 1.14042973776e-03 2.63751064518e-03 4.49294636045e-03 6.62854147545e-03 - 1.68223705906e-02 2.75391161378e-02 4.04664469346e-02 5.22490269685e-02 5.82895727993e-02 5.55126102684e-02 - 4.49336638971e-02 3.09524560683e-02 1.80831290832e-02 8.72280771196e-03 3.19202493212e-03 6.67104649838e-04 - 7.84015665147e-06 3.39527383053e-04 1.25929918177e-03 2.75362729653e-03 5.20945295891e-03 9.52752404976e-03 - 2.69810656597e-02 4.27665339963e-02 5.95277704486e-02 7.14837213670e-02 7.30014266330e-02 6.30564813233e-02 - 4.62561734279e-02 2.89925220155e-02 1.54291926604e-02 6.72379977706e-03 2.17731257107e-03 3.93394101570e-04 - 9.18407485959e-05 5.53905277765e-04 1.64775214622e-03 3.75630231557e-03 7.82589683071e-03 1.52117709522e-02 - 3.86824828654e-02 5.80683619484e-02 7.52715044047e-02 8.29669107313e-02 7.71266938230e-02 6.06755801668e-02 - 4.08522729448e-02 2.37295412303e-02 1.17978581448e-02 4.86606853609e-03 1.56247995272e-03 3.57117502066e-04 - 1.88885152993e-04 6.69436447972e-04 2.04488480582e-03 5.19948450447e-03 1.15528833895e-02 2.25474444163e-02 - 4.85444887016e-02 6.77400500683e-02 8.05783072227e-02 8.09259055471e-02 6.86643390348e-02 4.97810075339e-02 - 3.13027495816e-02 1.72279731998e-02 8.29776236043e-03 3.48177051070e-03 1.24875342233e-03 3.56858086321e-04 - 1.81717740395e-04 7.26420296905e-04 2.64152952345e-03 7.21228981320e-03 1.59861809039e-02 2.99935534351e-02 - 5.25404647831e-02 6.70517640030e-02 7.25379077391e-02 6.64429787539e-02 5.19826704209e-02 3.52784264198e-02 - 2.11135332418e-02 1.13336111097e-02 5.58136824644e-03 2.55700887283e-03 1.01898790415e-03 2.59439958900e-04 - 1.08792887701e-04 9.13347707041e-04 3.61967457606e-03 9.60826559459e-03 2.00841719699e-02 3.51427293494e-02 - 4.85399829267e-02 5.60845502976e-02 5.51393187772e-02 4.64524874502e-02 3.39859991615e-02 2.19606350507e-02 - 1.28294275368e-02 7.03943355638e-03 3.76063246920e-03 1.88873575919e-03 7.34728440902e-04 9.73846887630e-05 - 1.34281094385e-04 1.41838858942e-03 4.95175697391e-03 1.18017845731e-02 2.24174111750e-02 3.57501385902e-02 - 3.81223982864e-02 3.97804969262e-02 3.57510714426e-02 2.80347262483e-02 1.94858893938e-02 1.22827853617e-02 - 7.32901978750e-03 4.35679445209e-03 2.55682830322e-03 1.31064070581e-03 4.31551734292e-04 2.56563732818e-05 - 4.38238458960e-04 2.28807511564e-03 6.30607632056e-03 1.29418280250e-02 2.18325235633e-02 3.12325940825e-02 - 2.54515496099e-02 2.40031958169e-02 1.98539378190e-02 1.46741211520e-02 9.91866165572e-03 6.38486939639e-03 - 4.13102050964e-03 2.70794505832e-03 1.65646205016e-03 8.08651172104e-04 2.47208641832e-04 2.23777080753e-04 - 1.12566156413e-03 3.35842647053e-03 7.16171249339e-03 1.24228898116e-02 1.83600819789e-02 2.33224203641e-02 - 1.43505835785e-02 1.21655378553e-02 9.28174403569e-03 6.58364939901e-03 4.53273718567e-03 3.17477388707e-03 - 2.27246331162e-03 1.56050773839e-03 9.37686185136e-04 4.66962120561e-04 3.37654361148e-04 8.22556227759e-04 - 2.13396520583e-03 4.29448862138e-03 7.16744394103e-03 1.04271627487e-02 1.33394728873e-02 1.48581120938e-02 - 6.60504888935e-03 4.91279036721e-03 3.44802052119e-03 2.44840678066e-03 1.85011000837e-03 1.44608105781e-03 - 1.07369338329e-03 7.12281616706e-04 4.46181037912e-04 4.25174478886e-04 8.40446479276e-04 1.79717271315e-03 - 3.18920229493e-03 4.79306474738e-03 6.40904123878e-03 7.76341225887e-03 8.40105227185e-03 7.96441210427e-03 - 2.22883566628e-03 1.34583499470e-03 8.66220677705e-04 6.85780279779e-04 6.01096045306e-04 4.70432507529e-04 - 3.03519775642e-04 2.15723940430e-04 3.57605754412e-04 8.70232696926e-04 1.77966700951e-03 2.90318643566e-03 - 3.96242612482e-03 4.77366419882e-03 5.22782698395e-03 5.17448747028e-03 4.51205321594e-03 3.39990872944e-03 - 3.74787329927e-04 1.12560612514e-04 8.26840521250e-05 1.12218019913e-04 8.41490923278e-05 1.88527796747e-05 - 4.57193075236e-05 3.20529466411e-04 9.55785582890e-04 1.92069475173e-03 2.97905725755e-03 3.82560001861e-03 - 4.28724270582e-03 4.31703442315e-03 3.88356012573e-03 3.01964285925e-03 1.94579712158e-03 9.91649644230e-04 - 4.43028947088e-05 9.59475070751e-05 1.73207833253e-04 1.82217135168e-04 1.66870464868e-04 2.84273367330e-04 - 6.95630358326e-04 1.46925788489e-03 2.50103451278e-03 3.50417523226e-03 4.17489473940e-03 4.38434757984e-03 - 4.14896901156e-03 3.50172124417e-03 2.52761528428e-03 1.47013429489e-03 6.35274335813e-04 1.75725189340e-04 - 5.21635072254e-04 7.23251602732e-04 8.61474573948e-04 9.89414053440e-04 1.29380442867e-03 1.95535476122e-03 - 2.99201620448e-03 4.17423829159e-03 5.09509486217e-03 5.43902899985e-03 5.19067435608e-03 4.51784287104e-03 - 3.55622937733e-03 2.42761422630e-03 1.36587768440e-03 6.35412885075e-04 3.26800527820e-04 3.41449395897e-04 - 1.49742061870e-03 1.94081928890e-03 2.46810536038e-03 3.27751170622e-03 4.53276900856e-03 6.17689774707e-03 - 7.81259627274e-03 8.79518875184e-03 8.66410978042e-03 7.53080197746e-03 5.89386687290e-03 4.17024825305e-03 - 2.58214438068e-03 1.33593063791e-03 6.26296566782e-04 4.62823181379e-04 6.70710864371e-04 1.05779818173e-03 - 3.00052294093e-03 4.16485974963e-03 5.91629345683e-03 8.39181068997e-03 1.13596023519e-02 1.41418898981e-02 - 1.57137086800e-02 1.52449172960e-02 1.28219370189e-02 9.41703460986e-03 6.07133384411e-03 3.35376590879e-03 - 1.48426729616e-03 5.29655961198e-04 3.74459748073e-04 7.46095350710e-04 1.38131306616e-03 2.13340893873e-03 - 5.44193583881e-03 8.35214454422e-03 1.26345000288e-02 1.79135714846e-02 2.30461406848e-02 2.63358080405e-02 - 2.62428867281e-02 2.25199161773e-02 1.65870390463e-02 1.04710865069e-02 5.54800186564e-03 2.28547144475e-03 - 6.03914676341e-04 1.54363063000e-04 4.99344365405e-04 1.28601337470e-03 2.32021207291e-03 3.60560067107e-03 - 9.71171399200e-03 1.58322306943e-02 2.40429015853e-02 3.28582876465e-02 3.96063474598e-02 4.14464159653e-02 - 3.72110776864e-02 2.85131568525e-02 1.86036110146e-02 1.01948943014e-02 4.44961435874e-03 1.30933295616e-03 - 1.24733233788e-04 1.46044426337e-04 8.42772091710e-04 1.96599662315e-03 3.51222138209e-03 5.83863333877e-03 - 2.23596822056e-02 3.62779501174e-02 5.07678830582e-02 6.05102169967e-02 6.08168396665e-02 5.15231032915e-02 - 3.71316762893e-02 2.29871986264e-02 1.21931835700e-02 5.41755816198e-03 1.92230743377e-03 4.88273826972e-04 - 1.07037242284e-04 2.76758882879e-04 9.27960840299e-04 2.41603071691e-03 5.66754844261e-03 1.19970281279e-02 - 3.60541936865e-02 5.45818006755e-02 7.03937740958e-02 7.63409725318e-02 6.93588681395e-02 5.32973725587e-02 - 3.52452477204e-02 2.03296420198e-02 1.02437584412e-02 4.48791607506e-03 1.70665007508e-03 5.53793058473e-04 - 1.92182142535e-04 3.72217880810e-04 1.38300164881e-03 4.12383281638e-03 1.00222940521e-02 2.05124223854e-02 - 4.98375285240e-02 6.95727207694e-02 8.18111835636e-02 8.04417282807e-02 6.65588990634e-02 4.72404074504e-02 - 2.94401539966e-02 1.64075478410e-02 8.29762134496e-03 3.88381400738e-03 1.68972879941e-03 6.18053758672e-04 - 1.71989370972e-04 4.52195524933e-04 2.20888624426e-03 6.80733799528e-03 1.58474641502e-02 3.04396494296e-02 - 5.85092808404e-02 7.43660562419e-02 7.92837135586e-02 7.10731469206e-02 5.44575626366e-02 3.66023349398e-02 - 2.21980206638e-02 1.24932492265e-02 6.71644754619e-03 3.48464477064e-03 1.63364498292e-03 5.28554097612e-04 - 6.45944748800e-05 7.18609369114e-04 3.61038999008e-03 1.02470980021e-02 2.19521707452e-02 3.89121318704e-02 - 5.79034649594e-02 6.65413929758e-02 6.45721618883e-02 5.35829690083e-02 3.89245467176e-02 2.55201308468e-02 - 1.56570157014e-02 9.33856292271e-03 5.49972399419e-03 3.05253165863e-03 1.37632833762e-03 2.97565773257e-04 - 5.07854319394e-05 1.39386361630e-03 5.52858909329e-03 1.36714094010e-02 2.63928795582e-02 4.25070694792e-02 - 4.83284816677e-02 5.03515169198e-02 4.50884152177e-02 3.54198733620e-02 2.51038652348e-02 1.66584918350e-02 - 1.08169286065e-02 7.04129290489e-03 4.44013633087e-03 2.45869192052e-03 9.65311363004e-04 1.09115121479e-04 - 3.58737061986e-04 2.52466043792e-03 7.50930141159e-03 1.58888538808e-02 2.72748177396e-02 3.94334982513e-02 - 3.43235175753e-02 3.27833369272e-02 2.76483324594e-02 2.11459929088e-02 1.51727417387e-02 1.06590804664e-02 - 7.55057568985e-03 5.27736497450e-03 3.38590262507e-03 1.77833224161e-03 6.04599528422e-04 2.09165507836e-04 - 1.11618199660e-03 3.86696953210e-03 8.81764446680e-03 1.58980964587e-02 2.40853977847e-02 3.10865548478e-02 - 2.09397115436e-02 1.86143107042e-02 1.51702118125e-02 1.17299015770e-02 8.92789905071e-03 6.85327649244e-03 - 5.22185211296e-03 3.74591068661e-03 2.35952583645e-03 1.19269913358e-03 5.34907005351e-04 7.79038034750e-04 - 2.22655613423e-03 4.96345008705e-03 8.91588091344e-03 1.36955787198e-02 1.82203152283e-02 2.09426942020e-02 - 1.09462498459e-02 9.22769737394e-03 7.54888028094e-03 6.21352826950e-03 5.19604848349e-03 4.29537326234e-03 - 3.35559914344e-03 2.38074965359e-03 1.49112936574e-03 9.09677928695e-04 9.43717411168e-04 1.78505092404e-03 - 3.35135465856e-03 5.44542207836e-03 7.88608730259e-03 1.02757906691e-02 1.18677593830e-02 1.20535357153e-02 - 4.78732134765e-03 3.96077708602e-03 3.45906192297e-03 3.16973859369e-03 2.86472892354e-03 2.40310315141e-03 - 1.82972149630e-03 1.29637443397e-03 9.93039649899e-04 1.13489321527e-03 1.82712500484e-03 2.91347284000e-03 - 4.11578762214e-03 5.26670354236e-03 6.23958571585e-03 6.76910913452e-03 6.59520342813e-03 5.79740311407e-03 - 1.65213642090e-03 1.44438437225e-03 1.44388608464e-03 1.44478968694e-03 1.29188212916e-03 1.00868759838e-03 - 7.62472806555e-04 7.52983679542e-04 1.13920828151e-03 1.93357088829e-03 2.91712181060e-03 3.78133392418e-03 - 4.35546100692e-03 4.59227434779e-03 4.42923198591e-03 3.83897550801e-03 2.98733734961e-03 2.18173787043e-03 - 3.74661205825e-04 4.03079999778e-04 4.57030229489e-04 4.14975313164e-04 2.91054748816e-04 2.44733873332e-04 - 4.77231234091e-04 1.11383525908e-03 2.09129857678e-03 3.12394879443e-03 3.88071516706e-03 4.20602331340e-03 - 4.09965283672e-03 3.58133343864e-03 2.72354690134e-03 1.75782425092e-03 9.76408345378e-04 5.25845002751e-04 - 3.56874437487e-05 7.19277000073e-05 4.57532286351e-05 1.68550814748e-07 1.13896637113e-04 5.87690717860e-04 - 1.49765383807e-03 2.68714205183e-03 3.78834657710e-03 4.44933521683e-03 4.55546374240e-03 4.17934711646e-03 - 3.41632972795e-03 2.39339586472e-03 1.35728824517e-03 5.77358013399e-04 1.56237387323e-04 2.02915955860e-05 - 1.92937267310e-04 2.48237166345e-04 3.48564054699e-04 7.09619123319e-04 1.54564558124e-03 2.88003501498e-03 - 4.41995701110e-03 5.63319647552e-03 6.09314327857e-03 5.76527788812e-03 4.89001191540e-03 3.70839746252e-03 - 2.42238012524e-03 1.28235139548e-03 5.07654040157e-04 1.35289645360e-04 4.91341791994e-05 1.07023281288e-04 - 8.13557923482e-04 1.25186191081e-03 2.13985303663e-03 3.69008215256e-03 5.84222224353e-03 8.12361920964e-03 - 9.71939525989e-03 9.95684445387e-03 8.83310865634e-03 6.91213771127e-03 4.79067958837e-03 2.85627432727e-03 - 1.37627047710e-03 4.97098270022e-04 1.56302415360e-04 1.58300288903e-04 3.26201957625e-04 5.51373233986e-04 - 2.28579640056e-03 4.00487026954e-03 6.81315616062e-03 1.05203119367e-02 1.43529883638e-02 1.70381050874e-02 - 1.73905756503e-02 1.52252192163e-02 1.15150112248e-02 7.55196641006e-03 4.20773437381e-03 1.86776382018e-03 - 5.75436350388e-04 1.08966484858e-04 1.45305914815e-04 4.34953209368e-04 8.43104394508e-04 1.37695239919e-03 - 5.56281086000e-03 9.96982280830e-03 1.60480209583e-02 2.26602568864e-02 2.77739991801e-02 2.92413991106e-02 - 2.62743620233e-02 2.01726812995e-02 1.32676368255e-02 7.38720887492e-03 3.32226942709e-03 1.06367114081e-03 - 1.49772760321e-04 2.97086761622e-05 3.28306772379e-04 8.63074056152e-04 1.63350246510e-03 2.97285841919e-03 - 1.19622517989e-02 2.06104458920e-02 3.10120275062e-02 4.03111933824e-02 4.47884631805e-02 4.22220390008e-02 - 3.37893702529e-02 2.30823552802e-02 1.34435003557e-02 6.52412848193e-03 2.47611619138e-03 6.12578551069e-04 - 3.98559245158e-05 1.29394157049e-04 6.05630829977e-04 1.45383344810e-03 3.03088036597e-03 6.20212821257e-03 - 2.76401094892e-02 4.30681330534e-02 5.64478192711e-02 6.11169834053e-02 5.43891182395e-02 4.03602933427e-02 - 2.56715119664e-02 1.43794255632e-02 7.25430118293e-03 3.42244617426e-03 1.59953447293e-03 7.40357010084e-04 - 3.09198141182e-04 1.93071481832e-04 6.60754347813e-04 2.50189204551e-03 6.92135004970e-03 1.51110950845e-02 - 4.31965558513e-02 6.17451810117e-02 7.30977428612e-02 7.08614604392e-02 5.67725412235e-02 3.87159228181e-02 - 2.33808256140e-02 1.30061725959e-02 6.95402803860e-03 3.74218999195e-03 2.02214635667e-03 9.69203260838e-04 - 2.99060483828e-04 1.95153378061e-04 1.38987485245e-03 5.11119879254e-03 1.27602888411e-02 2.55265818344e-02 - 5.64623724185e-02 7.29700903983e-02 7.75288202501e-02 6.78701044280e-02 5.01919392011e-02 3.27272264362e-02 - 1.97808366115e-02 1.16424321382e-02 6.93716727985e-03 4.17102729253e-03 2.33083511614e-03 9.73448017772e-04 - 1.33611273177e-04 3.81860172444e-04 2.84238198888e-03 8.89859930535e-03 1.98876619675e-02 3.64608379179e-02 - 6.09994836774e-02 7.06705314077e-02 6.78205461249e-02 5.48748654411e-02 3.89021264583e-02 2.54659427732e-02 - 1.62756960621e-02 1.05716228012e-02 6.94681559292e-03 4.34048768310e-03 2.27671531970e-03 7.09474196153e-04 - 5.61049520879e-07 1.03599551071e-03 5.04055883158e-03 1.32051777423e-02 2.63503094725e-02 4.37387150336e-02 - 5.44155422230e-02 5.68261120599e-02 5.03586614169e-02 3.90661119545e-02 2.78206823294e-02 1.92436654347e-02 - 1.35199545301e-02 9.64303264568e-03 6.62020510431e-03 4.02092199093e-03 1.85111342598e-03 3.69849735195e-04 - 1.92861309927e-04 2.27272781409e-03 7.55565985027e-03 1.66811354331e-02 2.94769543146e-02 4.36880774363e-02 - 4.07500136379e-02 3.91771713814e-02 3.32218931473e-02 2.58615466554e-02 1.94321528718e-02 1.47398548890e-02 - 1.13575169799e-02 8.50503833396e-03 5.79194674218e-03 3.29423600951e-03 1.29928897370e-03 2.77272616894e-04 - 9.10121506323e-04 3.85605005156e-03 9.50458179654e-03 1.78029317662e-02 2.76732674411e-02 3.64266813929e-02 - 2.63736443323e-02 2.41346888386e-02 2.04730551194e-02 1.67830033220e-02 1.37991975188e-02 1.14674954686e-02 - 9.30475776847e-03 6.99236301891e-03 4.60571265693e-03 2.45156995619e-03 9.70856782416e-04 7.05057040057e-04 - 2.07705803151e-03 5.22009935026e-03 1.00400833329e-02 1.60488723077e-02 2.19245764328e-02 2.57657926733e-02 - 1.51856437590e-02 1.38083001778e-02 1.23140204205e-02 1.10428954743e-02 9.94124145352e-03 8.70264196403e-03 - 7.11372469289e-03 5.24433721703e-03 3.35456904160e-03 1.83424029693e-03 1.16696444907e-03 1.67220354014e-03 - 3.30205113631e-03 5.83964509232e-03 9.04613960742e-03 1.23743375877e-02 1.48644424670e-02 1.57701956770e-02 - 7.96792883125e-03 7.60772485233e-03 7.45450526335e-03 7.33642498936e-03 6.94903782257e-03 6.11024106815e-03 - 4.90183592778e-03 3.55713168612e-03 2.37997659214e-03 1.75341739168e-03 1.94007861521e-03 2.83251093721e-03 - 4.12323399777e-03 5.61537890126e-03 7.12638869007e-03 8.27147036948e-03 8.68898076015e-03 8.44766630467e-03 - 3.93367700109e-03 4.17525113167e-03 4.52511660476e-03 4.67896419199e-03 4.41272725195e-03 3.76732253331e-03 - 2.97674471444e-03 2.31285812292e-03 2.04060352822e-03 2.30671146511e-03 2.96683073255e-03 3.70562688665e-03 - 4.33351507669e-03 4.78856185666e-03 4.96066057109e-03 4.75998880610e-03 4.33096800885e-03 3.98555849523e-03 - 1.89159856023e-03 2.25818006029e-03 2.56406366512e-03 2.59356274009e-03 2.32076174609e-03 1.94517526671e-03 - 1.74208166040e-03 1.91841506264e-03 2.49228091812e-03 3.22588608156e-03 3.79549083323e-03 4.04938665330e-03 - 3.99133562829e-03 3.61914902177e-03 2.97002361508e-03 2.26351707366e-03 1.79281967121e-03 1.68718433778e-03 - 8.48143691959e-04 1.05264525989e-03 1.11572947773e-03 1.01210791191e-03 9.06217536072e-04 1.05534150087e-03 - 1.63302034214e-03 2.56925088612e-03 3.52181589824e-03 4.11279919248e-03 4.20925662985e-03 3.88558938117e-03 - 3.22491750428e-03 2.32731798536e-03 1.43249245995e-03 8.21205106593e-04 5.89401103552e-04 6.44737419368e-04 - 2.67331827956e-04 2.54830697388e-04 1.86049035408e-04 2.50112959133e-04 6.96769902287e-04 1.65219111420e-03 - 2.95393460347e-03 4.15222421828e-03 4.80032604653e-03 4.76917899382e-03 4.20388801949e-03 3.28758904170e-03 - 2.19862700262e-03 1.19027027233e-03 5.01303627585e-04 1.84791921216e-04 1.29450838606e-04 1.96491685906e-04 - 2.56111302080e-05 2.46207040985e-05 2.91449315781e-04 1.09765344245e-03 2.53340966613e-03 4.32333000886e-03 - 5.83738926327e-03 6.48600588885e-03 6.15477269717e-03 5.13688495945e-03 3.77820784513e-03 2.36543824583e-03 - 1.18660262489e-03 4.37620243580e-04 9.55488585500e-05 4.95852881280e-06 2.45285392405e-05 5.10079184455e-05 - 3.92063973253e-04 1.06423577578e-03 2.50145798935e-03 4.75084613533e-03 7.41250988460e-03 9.57814513504e-03 - 1.03077206911e-02 9.39201218663e-03 7.41210628704e-03 5.10511228916e-03 2.98526080823e-03 1.39079538476e-03 - 4.65436476056e-04 8.44425665062e-05 4.14771796630e-06 4.81202645712e-05 1.17932417736e-04 1.84926507608e-04 - 2.15906282220e-03 4.60857456624e-03 8.27631178162e-03 1.25928663675e-02 1.62320402669e-02 1.75770618793e-02 - 1.59847823655e-02 1.23586288352e-02 8.21224401846e-03 4.62902830939e-03 2.10265303276e-03 6.94815597433e-04 - 1.23603288127e-04 2.02919587919e-07 6.94077789502e-05 2.11021168517e-04 4.12261618032e-04 9.00167329398e-04 - 6.56646648073e-03 1.21777965637e-02 1.91923951954e-02 2.57366197631e-02 2.90353756183e-02 2.73319156082e-02 - 2.15798305976e-02 1.44807144888e-02 8.28511588861e-03 3.95389967643e-03 1.50167973443e-03 4.19111365898e-04 - 7.46384348596e-05 5.93552064264e-05 2.03455666363e-04 4.89345274239e-04 1.19244138907e-03 2.98264105858e-03 - 1.48788665653e-02 2.50995166593e-02 3.60440174723e-02 4.34814097729e-02 4.34829355344e-02 3.60689305078e-02 - 2.52027643226e-02 1.51038363271e-02 7.81039639907e-03 3.47688193865e-03 1.35667446862e-03 4.88481460871e-04 - 1.85567625430e-04 1.55807749073e-04 3.64934080403e-04 1.09692449602e-03 3.12670034990e-03 7.48106790627e-03 - 2.90123542488e-02 4.30854359789e-02 5.21171725963e-02 5.01992991048e-02 3.88090068492e-02 2.51119122322e-02 - 1.45614576406e-02 8.22448918631e-03 4.94034170484e-03 3.28383127731e-03 2.24418877678e-03 1.36351580642e-03 - 5.69632036424e-04 8.15775547275e-05 5.44724577350e-04 2.87394298868e-03 7.89371068059e-03 1.64685849815e-02 - 4.35915676032e-02 5.81929538603e-02 6.22624912756e-02 5.33036643534e-02 3.78170173870e-02 2.38418042366e-02 - 1.45986507860e-02 9.39269759591e-03 6.52628563561e-03 4.64640003478e-03 3.04956641594e-03 1.56744505391e-03 - 3.78621722441e-04 8.09930940244e-05 1.64212614761e-03 5.99662767919e-03 1.40883437216e-02 2.69320847868e-02 - 5.31499581860e-02 6.28506028140e-02 5.99281755002e-02 4.72017603978e-02 3.26635948933e-02 2.16515773473e-02 - 1.48612645146e-02 1.08514963075e-02 8.09098999291e-03 5.68195528489e-03 3.38835598790e-03 1.36460222689e-03 - 1.02983631757e-04 5.12751761960e-04 3.58838515182e-03 1.01482481368e-02 2.11073196544e-02 3.66180332357e-02 - 5.19671021018e-02 5.47434337505e-02 4.80609353654e-02 3.69232299855e-02 2.67771554787e-02 1.97454482551e-02 - 1.52782268559e-02 1.20261037556e-02 9.00515208638e-03 5.96224904326e-03 3.11832493176e-03 9.08984167996e-04 - 8.13278599879e-05 1.59293340636e-03 6.17777625550e-03 1.43426727716e-02 2.63276512482e-02 4.05485970475e-02 - 4.14586506595e-02 4.02010064404e-02 3.44181056502e-02 2.76263616809e-02 2.21456275990e-02 1.83265007788e-02 - 1.53466046909e-02 1.22934397552e-02 8.88347303314e-03 5.43276421273e-03 2.45341630245e-03 5.78360990334e-04 - 6.13184374875e-04 3.21756973565e-03 8.63760284411e-03 1.68035699261e-02 2.69093982571e-02 3.63864898911e-02 - 2.83650519882e-02 2.68059498618e-02 2.39067275588e-02 2.10610588979e-02 1.88221864268e-02 1.68637905522e-02 - 1.44925268983e-02 1.13792295403e-02 7.81866044890e-03 4.41582804109e-03 1.83254982300e-03 7.60593230066e-04 - 1.72481940935e-03 4.83313247057e-03 9.84656600181e-03 1.61895038690e-02 2.25725704133e-02 2.70725725053e-02 - 1.78244681820e-02 1.75114610654e-02 1.70418226691e-02 1.66068383397e-02 1.60088603914e-02 1.47606675233e-02 - 1.25398295880e-02 9.51858282482e-03 6.24312046036e-03 3.40731284544e-03 1.71007293887e-03 1.59359967148e-03 - 3.03389891803e-03 5.72024505479e-03 9.25073643926e-03 1.29633875898e-02 1.59204249779e-02 1.74911396503e-02 - 1.09524304328e-02 1.17447539955e-02 1.25842481980e-02 1.31573472545e-02 1.30268158675e-02 1.18939940159e-02 - 9.83840499714e-03 7.25296748096e-03 4.71848206626e-03 2.91128044913e-03 2.28509737436e-03 2.76429678142e-03 - 3.96517625310e-03 5.58626931020e-03 7.34652651096e-03 8.82511892184e-03 9.75503086150e-03 1.03361843522e-02 - 6.88053954745e-03 8.15713501646e-03 9.34434061500e-03 9.98922830786e-03 9.76078305527e-03 8.67477348077e-03 - 7.02519849773e-03 5.23364007868e-03 3.81650115997e-03 3.17474906484e-03 3.25857463110e-03 3.68947626794e-03 - 4.19968611647e-03 4.69164198058e-03 5.03642744758e-03 5.17301994730e-03 5.33740816265e-03 5.87579508880e-03 - 4.49231674321e-03 5.69142020189e-03 6.62513026829e-03 6.94157082510e-03 6.56607929875e-03 5.73023614703e-03 - 4.78230787324e-03 4.07054620776e-03 3.81623096406e-03 3.91541893524e-03 4.04089795782e-03 4.00171006166e-03 - 3.79948529161e-03 3.43451202207e-03 2.94614330072e-03 2.59517713326e-03 2.71794578554e-03 3.40594594923e-03 - 2.93397502718e-03 3.73364629077e-03 4.20242649487e-03 4.21566992998e-03 3.92707357324e-03 3.64935248959e-03 - 3.65481936157e-03 3.99897667713e-03 4.42211645836e-03 4.55528485445e-03 4.27844876202e-03 3.71480067764e-03 - 2.96797414553e-03 2.11567266260e-03 1.39779760992e-03 1.12975875644e-03 1.40560285577e-03 2.07707194984e-03 - 1.73170809550e-03 2.05715922820e-03 2.15803776641e-03 2.16091251531e-03 2.33243438438e-03 2.89439143328e-03 - 3.81148156163e-03 4.69330849464e-03 5.05464171347e-03 4.74593904176e-03 3.97624316304e-03 2.98358625571e-03 - 1.92383590167e-03 1.01431050263e-03 5.08053277087e-04 4.76677740219e-04 7.84129121082e-04 1.25427977251e-03 - 7.35581514658e-04 7.47425355428e-04 8.52913102584e-04 1.31494394028e-03 2.30143436701e-03 3.69480850434e-03 - 5.00129714556e-03 5.62892290753e-03 5.36561990229e-03 4.45007476432e-03 3.23137408512e-03 1.98092402452e-03 - 9.51052693666e-04 3.37216896367e-04 1.45604632839e-04 2.29829284693e-04 4.33682521713e-04 6.34414287969e-04 - 1.04358621413e-04 2.84776829527e-04 9.93901459284e-04 2.38433574802e-03 4.27813215920e-03 6.03570962727e-03 - 6.87232414527e-03 6.50474577691e-03 5.28010685420e-03 3.70953114324e-03 2.17926605285e-03 9.90564943205e-04 - 3.10240582644e-04 6.46307822580e-05 5.59328892707e-05 1.30820876239e-04 1.87255302805e-04 1.56402340255e-04 - 4.16142103095e-04 1.51107820276e-03 3.45941194098e-03 6.08643350096e-03 8.60818299942e-03 9.83332266595e-03 - 9.17732424410e-03 7.18134315041e-03 4.79873801756e-03 2.67941311281e-03 1.15900895320e-03 3.43307675170e-04 - 6.26402931921e-05 3.22143839648e-05 6.82158631734e-05 8.01745924232e-05 2.60820321760e-05 2.84591624616e-05 - 2.53862780464e-03 5.38410712294e-03 9.25222353105e-03 1.32590729111e-02 1.55905975022e-02 1.48456296754e-02 - 1.15566131951e-02 7.51317116454e-03 4.09061255113e-03 1.79471992174e-03 6.04626330248e-04 1.82569652746e-04 - 1.02490111094e-04 1.07913120155e-04 1.00161656600e-04 5.59651498646e-05 1.57155026203e-04 8.49958989845e-04 - 7.39406660839e-03 1.31137073903e-02 1.97012935826e-02 2.45770982629e-02 2.47934451136e-02 2.01310891697e-02 - 1.34178186832e-02 7.53812299421e-03 3.62529101666e-03 1.55188196124e-03 7.06239819790e-04 4.24006850794e-04 - 3.00061733315e-04 1.96391553844e-04 9.84383305921e-05 2.20434922265e-04 1.12888702052e-03 3.41280880332e-03 - 1.60625726864e-02 2.60069437038e-02 3.52219667292e-02 3.86264409743e-02 3.38075903369e-02 2.39830002491e-02 - 1.43550780536e-02 7.63624386523e-03 3.87601942609e-03 2.11590076780e-03 1.34310820822e-03 8.92844044468e-04 - 5.15116811367e-04 1.90586876220e-04 1.44646857072e-04 1.00980200330e-03 3.57243468264e-03 8.43677130733e-03 - 2.39508360172e-02 3.33179086561e-02 3.59026408329e-02 2.96688184433e-02 1.98496156402e-02 1.23091079586e-02 - 8.40373884976e-03 6.75007296082e-03 5.87714611052e-03 4.93579177062e-03 3.67767221362e-03 2.21323335507e-03 - 8.03886802060e-04 1.59688086493e-05 6.06944169509e-04 2.91202362076e-03 7.12071343127e-03 1.40702684932e-02 - 3.42297525408e-02 4.14704016073e-02 3.91302045285e-02 2.99428833329e-02 2.08106286095e-02 1.51521560791e-02 - 1.22898113724e-02 1.06004682611e-02 8.95918065889e-03 6.90365681803e-03 4.52862465326e-03 2.18512333726e-03 - 4.39696692930e-04 1.34524028627e-04 1.86205782760e-03 5.74637582557e-03 1.23448830375e-02 2.24592506314e-02 - 3.79932521341e-02 4.04142680650e-02 3.53583222758e-02 2.78050399447e-02 2.20352949610e-02 1.86094329006e-02 - 1.63598575325e-02 1.41549184454e-02 1.13639602907e-02 8.01850937900e-03 4.59635493060e-03 1.71684968901e-03 - 1.95990005296e-04 8.34954022986e-04 3.87862099457e-03 9.37746086208e-03 1.78109645931e-02 2.86611844087e-02 - 3.31072543243e-02 3.26796818784e-02 2.92666547812e-02 2.58410663057e-02 2.34274053172e-02 2.15548374545e-02 - 1.94231474417e-02 1.63860942127e-02 1.23717866015e-02 7.96564400467e-03 3.96910250413e-03 1.18637308542e-03 - 4.44289862006e-04 2.19684862974e-03 6.29378128787e-03 1.25165781064e-02 2.05240163354e-02 2.85003147779e-02 - 2.44047081823e-02 2.46867525713e-02 2.46043715407e-02 2.45225943782e-02 2.41546095218e-02 2.30290175264e-02 - 2.06073353111e-02 1.66824380571e-02 1.17909313222e-02 6.94152701535e-03 3.10441433613e-03 1.07839824904e-03 - 1.36135231235e-03 3.86414776957e-03 8.04877920388e-03 1.32776779283e-02 1.85988582260e-02 2.25928064613e-02 - 1.72782570712e-02 1.93888175797e-02 2.15202682837e-02 2.30677956930e-02 2.35495115269e-02 2.24939115300e-02 - 1.95756532893e-02 1.50871773825e-02 1.00098815536e-02 5.53775121470e-03 2.61403629456e-03 1.69838490699e-03 - 2.68031085254e-03 5.03379100858e-03 8.09677502274e-03 1.11751041664e-02 1.36678889191e-02 1.55098493316e-02 - 1.29365646907e-02 1.60452594748e-02 1.89147807041e-02 2.08556228886e-02 2.13231482410e-02 1.99212260710e-02 - 1.66812423658e-02 1.22708521473e-02 7.83923703175e-03 4.53194491312e-03 2.92971192036e-03 2.85349677722e-03 - 3.74452968412e-03 5.10538393018e-03 6.52960975568e-03 7.71163170757e-03 8.78748128227e-03 1.03908877661e-02 - 1.02472238724e-02 1.34077121594e-02 1.60994805951e-02 1.76675965137e-02 1.76525388070e-02 1.59528003439e-02 - 1.29104581785e-02 9.32343947960e-03 6.26246632220e-03 4.47607601508e-03 3.88388494076e-03 3.88623997927e-03 - 4.04651219101e-03 4.22173456484e-03 4.35017833705e-03 4.57908590604e-03 5.43056222839e-03 7.36862051056e-03 - 8.21643685028e-03 1.08644910264e-02 1.28800003728e-02 1.37515809716e-02 1.33091570952e-02 1.17424290467e-02 - 9.51450821414e-03 7.34057458164e-03 5.87721329412e-03 5.17874552278e-03 4.75837201662e-03 4.23670673209e-03 - 3.59430061478e-03 2.92874034445e-03 2.41396100837e-03 2.46367650196e-03 3.50965380025e-03 5.56665853890e-03 - 6.39405023433e-03 8.26550399301e-03 9.47106843978e-03 9.78159940719e-03 9.31796856334e-03 8.40206512394e-03 - 7.43948771776e-03 6.77230486315e-03 6.36623521199e-03 5.83738803420e-03 4.95539620238e-03 3.84050200655e-03 - 2.68662848754e-03 1.66244498882e-03 1.08820850115e-03 1.34304376138e-03 2.50815847581e-03 4.32234965583e-03 - 4.64637600320e-03 5.72534118535e-03 6.30585891024e-03 6.45821510584e-03 6.44900075157e-03 6.55010199653e-03 - 6.85646803510e-03 7.10331638128e-03 6.81331499867e-03 5.81638716541e-03 4.40471133511e-03 2.93903593546e-03 - 1.62742094931e-03 6.95494057943e-04 4.24203293261e-04 8.98356118621e-04 1.93663495023e-03 3.27774128027e-03 - 2.98389599101e-03 3.46067136834e-03 3.82328524636e-03 4.30788348791e-03 5.11036583646e-03 6.20391667427e-03 - 7.17191190619e-03 7.37902322590e-03 6.54965055098e-03 5.01964078614e-03 3.32399627578e-03 1.81377768604e-03 - 7.06776643009e-04 1.75407119774e-04 2.39159141047e-04 7.40747037080e-04 1.48352014678e-03 2.29149435218e-03 - 1.53326329779e-03 1.84611178052e-03 2.53573688064e-03 3.74952009005e-03 5.37262544690e-03 6.89055920482e-03 - 7.55348973841e-03 6.97719301771e-03 5.46628364257e-03 3.63894820994e-03 1.98048598761e-03 7.78131469797e-04 - 1.56061571629e-04 4.40573150365e-05 2.57024555992e-04 6.28415055451e-04 1.02442021667e-03 1.32645519489e-03 - 7.19813689388e-04 1.46265110500e-03 2.89590350875e-03 4.90589815021e-03 6.90737528971e-03 7.94220745368e-03 - 7.45391080871e-03 5.80532258342e-03 3.78988541959e-03 2.00273588795e-03 7.56477547911e-04 1.41295064953e-04 - 9.20360964380e-06 1.17970505609e-04 3.06434685159e-04 4.71444270863e-04 5.22989834028e-04 5.12469371217e-04 - 1.11571709309e-03 2.67445718870e-03 4.99023009616e-03 7.59579812895e-03 9.25218298360e-03 8.86855088572e-03 - 6.74689786138e-03 4.14501390825e-03 2.01251119724e-03 6.74730003656e-04 1.01718949984e-04 3.27253766017e-05 - 1.46202680935e-04 2.64471162673e-04 3.12527134590e-04 2.31885065816e-04 1.18137705356e-04 3.08493981963e-04 - 2.97197779700e-03 5.64769794227e-03 9.08150490610e-03 1.19334613975e-02 1.21910231282e-02 9.50656061405e-03 - 5.71453576212e-03 2.66012746041e-03 9.20966048989e-04 2.74039481938e-04 2.44578480132e-04 3.76906186311e-04 - 4.45312532357e-04 3.97085905430e-04 2.08497623903e-04 1.84130931501e-05 2.42173009179e-04 1.20627720687e-03 - 6.69841459323e-03 1.13594376345e-02 1.62063605507e-02 1.81959759304e-02 1.54580082974e-02 9.96813483910e-03 - 5.09618510508e-03 2.29551769392e-03 1.21877797044e-03 1.04597497914e-03 1.09172076281e-03 1.01923421931e-03 - 7.80557363105e-04 3.95957072480e-04 3.44336114103e-05 1.92943162888e-04 1.30269410651e-03 3.41397682897e-03 - 1.35633433417e-02 2.11508899494e-02 2.64099318745e-02 2.51549815935e-02 1.82368258605e-02 1.06801051560e-02 - 5.84080653674e-03 3.70593972471e-03 3.02932349044e-03 2.76562671631e-03 2.36906555392e-03 1.73920955080e-03 - 9.51571112560e-04 2.09367732544e-04 6.10113007469e-05 1.10327785658e-03 3.48536632547e-03 7.43784711676e-03 - 1.39384055066e-02 1.69130809053e-02 1.49768262245e-02 1.07162085657e-02 8.47524628685e-03 8.81424880177e-03 - 9.83200966971e-03 1.02004768521e-02 9.48846853546e-03 7.76018865894e-03 5.42965637115e-03 2.98228896111e-03 - 9.85626819877e-04 1.81564419576e-04 8.06483967713e-04 2.33563150533e-03 4.72806745741e-03 8.75710216940e-03 - 1.81313352910e-02 1.90535678913e-02 1.68008352563e-02 1.52937691172e-02 1.59077001326e-02 1.69532670637e-02 - 1.70441296216e-02 1.58195663322e-02 1.32631624615e-02 9.73614657233e-03 5.94292843215e-03 2.63261900644e-03 - 6.21057744656e-04 4.84939149231e-04 1.91723155990e-03 4.35710056202e-03 8.11624452984e-03 1.34136493350e-02 - 1.78054431025e-02 1.85057380207e-02 1.96112334424e-02 2.20485586489e-02 2.41487225921e-02 2.45664625786e-02 - 2.32117162274e-02 2.01607168923e-02 1.56140228198e-02 1.03747059300e-02 5.52596142275e-03 2.02231687171e-03 - 6.12475949304e-04 1.38895622543e-03 3.64995224412e-03 6.85506474298e-03 1.09746792620e-02 1.52316871518e-02 - 1.50010063676e-02 1.85122443350e-02 2.35902988677e-02 2.80270992949e-02 3.00534502568e-02 2.96091440242e-02 - 2.69665619010e-02 2.21760530771e-02 1.59025831802e-02 9.56892171015e-03 4.53403043356e-03 1.66209485433e-03 - 1.24989420601e-03 2.81363247545e-03 5.39397963084e-03 8.26075965853e-03 1.09232906914e-02 1.29851461054e-02 - 1.35825447839e-02 1.99515000622e-02 2.65507066788e-02 3.09546199292e-02 3.25137670985e-02 3.14228534022e-02 - 2.76121071109e-02 2.13726605709e-02 1.41369603820e-02 7.81302054093e-03 3.66393588999e-03 2.01670740212e-03 - 2.46124332602e-03 4.09576877339e-03 5.93657492686e-03 7.31508412361e-03 8.21512918899e-03 9.73075458150e-03 - 1.39008127830e-02 2.09444630949e-02 2.70084335057e-02 3.07102631838e-02 3.17529074967e-02 2.99021020091e-02 - 2.50325056605e-02 1.80954731628e-02 1.11686644104e-02 6.14442647940e-03 3.63419588831e-03 3.10159315368e-03 - 3.62070802667e-03 4.38044011656e-03 4.82756600145e-03 4.90984086228e-03 5.52366637080e-03 8.28085808113e-03 - 1.41211685580e-02 2.02789926843e-02 2.51622457086e-02 2.79421825320e-02 2.81592444643e-02 2.54629472341e-02 - 2.01637480630e-02 1.38205575268e-02 8.58071049791e-03 5.62797196872e-03 4.56104036613e-03 4.27488442995e-03 - 4.01459911625e-03 3.55005953147e-03 2.97106209303e-03 2.85446870253e-03 4.33209462254e-03 8.25384887982e-03 - 1.32734467761e-02 1.80808002968e-02 2.16314423956e-02 2.32703177434e-02 2.26149695104e-02 1.96342803915e-02 - 1.50873019846e-02 1.06219057492e-02 7.70249268894e-03 6.39594457672e-03 5.69060748720e-03 4.76370970264e-03 - 3.51385279851e-03 2.23954002189e-03 1.43160908410e-03 1.83412279079e-03 4.11093568475e-03 8.21603713725e-03 - 1.14607874302e-02 1.48707135677e-02 1.71020628898e-02 1.77782186536e-02 1.68480128824e-02 1.45945287662e-02 - 1.18442289076e-02 9.67121502084e-03 8.41712529382e-03 7.45085315784e-03 6.10645962717e-03 4.33809607694e-03 - 2.50402855750e-03 1.06690863226e-03 5.84076149330e-04 1.54994013157e-03 4.02706590451e-03 7.57337363525e-03 - 9.12510315949e-03 1.12872106357e-02 1.25428472762e-02 1.28837848630e-02 1.25048034853e-02 1.17268503863e-02 - 1.09648043739e-02 1.03173731005e-02 9.34875669411e-03 7.68477435237e-03 5.50589242358e-03 3.27632509098e-03 - 1.41151822715e-03 3.11829109935e-04 3.40883991374e-04 1.56991219896e-03 3.73324101074e-03 6.41979090410e-03 - 6.71382020937e-03 7.97355671897e-03 8.83862927767e-03 9.52578714267e-03 1.02147338283e-02 1.09255459704e-02 - 1.13539018491e-02 1.08927575813e-02 9.21994515829e-03 6.73257263264e-03 4.14892951115e-03 1.98530753087e-03 - 5.42266206394e-04 2.47857012942e-05 4.44571463289e-04 1.59520752503e-03 3.21736529420e-03 5.03864199461e-03 - 4.53732598549e-03 5.41957479602e-03 6.52850840047e-03 8.00481155987e-03 9.71609063562e-03 1.11381570359e-02 - 1.14518992216e-02 1.01721684695e-02 7.68111397700e-03 4.87610881577e-03 2.48254152734e-03 8.52018605664e-04 - 8.45631208541e-05 8.29938777821e-05 6.26403074796e-04 1.51313209809e-03 2.57765979484e-03 3.62714047948e-03 - 2.94520634373e-03 4.09338298450e-03 5.89573440241e-03 8.15226108265e-03 1.02247946201e-02 1.11435101174e-02 - 1.02770671445e-02 7.95264131795e-03 5.13602613828e-03 2.67653174468e-03 1.00234932431e-03 1.84491430162e-04 - 3.66157122970e-05 2.88839395807e-04 7.56878029564e-04 1.31883373997e-03 1.84389279588e-03 2.30807269794e-03 - 2.39824741510e-03 4.16584552081e-03 6.61190315682e-03 9.13927622464e-03 1.05842797149e-02 9.99760193050e-03 - 7.66347140832e-03 4.78449501097e-03 2.37342275280e-03 8.39967189467e-04 1.67570752917e-04 8.15303061164e-05 - 2.58803585143e-04 5.24795196685e-04 7.96994160661e-04 9.76818732050e-04 1.08538377336e-03 1.42974660874e-03 - 2.80781679507e-03 4.97830702546e-03 7.67062719958e-03 9.78416602786e-03 9.75647516917e-03 7.38185688386e-03 - 4.19302194334e-03 1.71154271980e-03 4.04147054021e-04 4.88495638362e-05 1.99146847909e-04 4.50944524514e-04 - 6.35858089276e-04 7.28548232608e-04 6.76448726859e-04 5.34600813077e-04 6.49261213656e-04 1.37398724788e-03 - 3.52671506668e-03 5.92786080458e-03 8.58513083907e-03 9.57435669709e-03 7.58590396872e-03 4.02223837362e-03 - 1.24174496914e-03 1.00796405896e-04 1.40568384544e-04 6.31375434247e-04 1.03321525214e-03 1.16270805649e-03 - 1.07090826887e-03 7.81989697491e-04 3.90441365971e-04 2.93465343801e-04 8.26942583201e-04 1.90677988513e-03 - 4.87439991338e-03 7.89309894236e-03 1.00900578877e-02 9.01607195016e-03 5.21119126193e-03 1.85096705993e-03 - 6.70927364981e-04 1.07341963778e-03 1.91482779281e-03 2.45367508114e-03 2.45381782758e-03 2.04237560937e-03 - 1.37133761898e-03 5.94679022480e-04 1.64409766634e-04 5.09759455394e-04 1.44497183893e-03 2.76189451435e-03 - 8.35559979822e-03 1.20668035362e-02 1.25987240137e-02 9.01439584896e-03 4.83208300271e-03 3.17927959967e-03 - 3.70630913973e-03 4.76815681163e-03 5.33146912294e-03 5.06070414830e-03 4.10031499095e-03 2.76481406042e-03 - 1.33274541803e-03 2.99950289289e-04 2.65348498302e-04 1.15343849298e-03 2.53516313914e-03 4.75021433623e-03 - 4.12397557795e-03 3.37306591358e-03 3.34612968679e-03 6.67953696907e-03 1.19915380077e-02 1.59841646523e-02 - 1.74370866885e-02 1.67084009573e-02 1.42435457575e-02 1.06369418208e-02 6.74152538065e-03 3.35997102288e-03 - 1.25520261482e-03 8.22957691189e-04 1.40872505554e-03 2.03455504358e-03 2.65995208516e-03 3.60808678392e-03 - 4.51341003998e-03 6.17521617271e-03 1.17380566051e-02 1.95804437039e-02 2.52951898234e-02 2.71164673697e-02 - 2.59932470751e-02 2.27547821164e-02 1.77839698932e-02 1.19931057453e-02 6.66111019039e-03 2.83721705350e-03 - 1.15341137147e-03 1.36312192805e-03 2.31218660196e-03 3.13270130874e-03 3.81590544431e-03 4.31343164657e-03 - 5.96136922938e-03 1.32433520951e-02 2.39790903711e-02 3.26544025864e-02 3.61599806995e-02 3.55472300150e-02 - 3.22991639732e-02 2.66686876892e-02 1.92221534547e-02 1.16651661380e-02 5.74266208704e-03 2.37329101721e-03 - 1.57440837006e-03 2.41380736764e-03 3.52977501931e-03 4.06697779506e-03 3.89310626968e-03 3.72879477030e-03 - 1.02995833061e-02 2.20958212906e-02 3.37181732405e-02 4.03927334532e-02 4.19730310103e-02 4.01548907478e-02 - 3.52915016139e-02 2.73407478975e-02 1.79425317822e-02 9.79610990743e-03 4.60197719259e-03 2.49589336313e-03 - 2.60965239040e-03 3.57679400175e-03 4.10195659122e-03 3.54484918279e-03 2.53169089516e-03 3.67225817822e-03 - 1.59169455472e-02 2.81158466530e-02 3.75995501888e-02 4.23813244559e-02 4.32850082327e-02 4.06894129995e-02 - 3.40232195118e-02 2.41743539178e-02 1.43126700487e-02 7.41461219227e-03 4.15550805311e-03 3.43957203403e-03 - 3.77633260745e-03 3.94407030191e-03 3.22495511760e-03 1.85928722383e-03 1.75188998713e-03 6.02759951645e-03 - 1.95738822295e-02 2.95860441574e-02 3.67214688645e-02 4.04059250969e-02 4.06571132960e-02 3.66932527478e-02 - 2.83971821246e-02 1.83079573022e-02 1.02752975452e-02 6.13545378616e-03 4.91208684921e-03 4.69843940918e-03 - 4.23774885534e-03 3.11283836546e-03 1.56897626232e-03 7.79923233263e-04 2.88284008707e-03 9.50676201531e-03 - 2.01652191020e-02 2.76754112986e-02 3.29303796193e-02 3.53849089502e-02 3.43197438251e-02 2.90642992734e-02 - 2.08057260172e-02 1.29501742587e-02 8.31023301244e-03 6.74654458652e-03 6.27689702235e-03 5.35998988279e-03 - 3.68124950210e-03 1.72362467756e-03 4.11347201589e-04 1.05918738043e-03 4.86157225236e-03 1.17982272463e-02 - 1.84099461306e-02 2.37340838124e-02 2.71926423527e-02 2.81830190033e-02 2.61251404689e-02 2.11739822956e-02 - 1.52439931390e-02 1.09546917129e-02 9.09875363729e-03 8.31968018661e-03 7.09474940558e-03 5.00264940099e-03 - 2.54317547902e-03 6.06347123805e-04 1.64820542047e-04 1.98171482661e-03 6.19861369802e-03 1.21156664909e-02 - 1.53057262817e-02 1.87613724520e-02 2.07286352395e-02 2.09441968860e-02 1.93375852231e-02 1.65046539604e-02 - 1.38292818119e-02 1.21849402810e-02 1.09993563491e-02 9.27624928325e-03 6.75643356407e-03 3.88276439333e-03 - 1.39287810966e-03 7.31695767239e-05 4.91344361186e-04 2.73144168182e-03 6.42258075281e-03 1.09050331785e-02 - 1.17936367956e-02 1.39276752046e-02 1.52501324516e-02 1.58726309986e-02 1.59235148425e-02 1.56592997382e-02 - 1.52033438467e-02 1.41157328296e-02 1.19045086068e-02 8.77105933821e-03 5.40206052116e-03 2.47658660799e-03 - 5.60596314887e-04 4.64717379967e-05 9.59408527748e-04 3.00255269971e-03 5.80667610248e-03 8.93186885467e-03 - 8.66584207354e-03 1.02479061277e-02 1.18557558842e-02 1.36318128407e-02 1.54067448707e-02 1.66367221549e-02 - 1.64682180031e-02 1.43744573315e-02 1.08213752944e-02 6.90364960043e-03 3.53811083354e-03 1.22837953040e-03 - 1.79398445160e-04 3.03298910439e-04 1.29462763478e-03 2.87324851828e-03 4.82755522548e-03 6.85815325051e-03 - 6.42329675045e-03 8.25915723541e-03 1.07469949192e-02 1.36438259923e-02 1.61551855970e-02 1.70971381024e-02 - 1.56567285259e-02 1.22072777523e-02 8.03794435117e-03 4.35820050534e-03 1.79567954334e-03 4.80958263221e-04 - 2.07898433499e-04 6.19616680946e-04 1.44766452172e-03 2.55439199828e-03 3.79504440101e-03 5.04587051309e-03 - 5.46498949013e-03 8.10528689165e-03 1.14824747929e-02 1.47431342845e-02 1.64959559252e-02 1.56494085413e-02 - 1.24538277926e-02 8.31353031432e-03 4.61521393370e-03 2.05795077841e-03 7.28468481686e-04 3.37549018237e-04 - 4.82628438772e-04 9.00742775670e-04 1.48029518643e-03 2.12645515250e-03 2.81335393588e-03 3.78315022072e-03 - 5.75266409372e-03 9.04522399376e-03 1.26695620141e-02 1.51598449236e-02 1.49272072843e-02 1.18922243965e-02 - 7.70632117570e-03 4.11274719582e-03 1.84124055659e-03 8.06521798028e-04 5.69924307367e-04 6.73262835086e-04 - 8.80986547273e-04 1.13449258958e-03 1.37186166091e-03 1.60231303032e-03 2.13035208890e-03 3.42348896618e-03 - 6.15518199318e-03 9.34637458048e-03 1.23037380072e-02 1.30681688724e-02 1.06180656804e-02 6.48040459731e-03 - 3.01881423005e-03 1.22472344337e-03 7.80678973959e-04 9.77905653392e-04 1.23704540159e-03 1.34339704162e-03 - 1.33983295734e-03 1.24237309768e-03 1.09000818966e-03 1.21146959777e-03 2.03096227877e-03 3.67951082823e-03 - 5.46846231784e-03 7.88029276816e-03 9.36208795300e-03 8.04633980387e-03 4.54487899204e-03 1.56323375524e-03 - 5.67796965171e-04 1.04237842558e-03 1.93408719805e-03 2.50896070558e-03 2.54866786681e-03 2.22670403781e-03 - 1.71624715527e-03 1.12400203346e-03 8.09605011282e-04 1.19092885424e-03 2.18076924248e-03 3.54976231800e-03 - 4.15390743218e-03 5.43175893770e-03 4.91454140245e-03 2.32451301762e-03 2.35995447599e-04 5.06071227928e-04 - 2.32391388974e-03 4.15347850844e-03 5.13301695500e-03 5.06681008689e-03 4.24237018780e-03 3.06647689165e-03 - 1.80518442576e-03 8.66236607940e-04 7.62515514786e-04 1.35343622743e-03 2.05139835939e-03 2.85406210910e-03 - 3.67827506346e-03 3.59686031474e-03 1.74117679172e-03 5.27235887042e-04 2.24935659755e-03 5.71187826889e-03 - 8.59913745216e-03 9.91643146930e-03 9.61991020892e-03 8.05673816738e-03 5.83276513538e-03 3.49967986123e-03 - 1.57739892397e-03 7.06596545695e-04 9.57113561673e-04 1.52668348675e-03 1.97047918722e-03 2.68350892101e-03 + 4.19796127760e-07 2.16785886153e-03 9.82780714783e-03 1.98314099013e-02 2.65738526290e-02 2.84325358303e-02 + 2.69957310273e-02 2.34248028415e-02 1.81739754247e-02 1.22128123871e-02 6.88896490865e-03 3.24534074330e-03 + 1.80078795971e-03 2.11652009522e-03 2.83266308314e-03 2.90713887507e-03 2.22630047545e-03 9.82082916676e-04 + 2.67982867041e-03 1.25901943401e-02 2.67750092712e-02 3.73927831636e-02 4.08080253988e-02 3.92498238923e-02 + 3.51365518936e-02 2.87939138564e-02 2.06269471162e-02 1.24500091124e-02 6.22391147441e-03 2.87783704519e-03 + 2.20330924837e-03 2.94938180961e-03 3.50814054906e-03 2.95005079423e-03 1.32902267629e-03 3.67522844661e-05 + 1.10779622580e-02 2.74702510133e-02 4.24680096881e-02 4.95475424977e-02 4.97426124804e-02 4.65046117739e-02 + 4.05513452152e-02 3.13111891211e-02 2.03337577650e-02 1.08921397609e-02 5.09701497710e-03 2.94485925341e-03 + 3.14841971649e-03 3.94725898613e-03 3.82935697181e-03 2.19726061877e-03 1.82221854139e-04 1.61558790082e-03 + 2.13956092811e-02 3.83511402787e-02 4.98309121334e-02 5.39482825366e-02 5.35370172151e-02 4.99037888042e-02 + 4.17571346814e-02 2.93994565428e-02 1.68243176274e-02 8.18980384097e-03 4.38707510375e-03 3.78780569163e-03 + 4.30413396660e-03 4.31135316918e-03 2.94335397572e-03 6.90902218897e-04 4.36986424085e-04 6.83400732546e-03 + 2.80680315686e-02 4.16048736052e-02 4.97895562440e-02 5.32208545985e-02 5.31035530431e-02 4.80821280515e-02 + 3.69230770847e-02 2.28000212867e-02 1.15788209991e-02 6.10982644518e-03 4.88003290692e-03 5.06967069873e-03 + 4.81547654111e-03 3.42866256692e-03 1.24123396700e-03 4.05081219813e-05 3.17822651912e-03 1.32214634989e-02 + 2.95041338109e-02 3.94526429695e-02 4.58148579582e-02 4.88424258357e-02 4.75134531252e-02 3.98361394093e-02 + 2.70320199568e-02 1.47924102680e-02 7.93301411007e-03 6.16080820688e-03 6.27889917975e-03 5.84923853484e-03 + 4.19908838532e-03 1.85605429835e-03 1.51359207333e-04 1.15549807388e-03 6.89864838333e-03 1.73802565206e-02 + 2.73297052092e-02 3.45427945780e-02 3.92231006193e-02 4.06201235708e-02 3.70716335978e-02 2.81839910459e-02 + 1.75663101184e-02 1.03570023777e-02 7.96334774926e-03 7.87306500531e-03 7.39189652111e-03 5.56940797037e-03 + 2.90485266079e-03 6.48460231856e-04 2.89502183498e-04 3.10149056433e-03 9.48663452308e-03 1.83306478382e-02 + 2.31482333643e-02 2.79794228179e-02 3.06623017610e-02 3.03300195074e-02 2.62260034691e-02 1.95974260262e-02 + 1.38657373864e-02 1.11830271091e-02 1.04346242129e-02 9.49848582844e-03 7.42479704869e-03 4.47824607974e-03 + 1.65935818009e-03 2.28672460710e-04 1.12260208912e-03 4.59217649355e-03 1.01917439193e-02 1.68479251078e-02 + 1.80782080284e-02 2.09926732676e-02 2.24251843165e-02 2.21006955137e-02 2.01238064974e-02 1.76419150884e-02 + 1.58842648602e-02 1.45874061568e-02 1.26868754876e-02 9.82697955765e-03 6.38869115249e-03 3.08307792588e-03 + 8.32295654334e-04 3.98641250371e-04 1.94195223847e-03 5.11174570108e-03 9.37191444362e-03 1.39900582175e-02 + 1.33836413196e-02 1.54256399243e-02 1.71047535609e-02 1.85081939452e-02 1.95897392795e-02 2.01216863756e-02 + 1.94247995602e-02 1.69128253914e-02 1.29715856260e-02 8.60423155661e-03 4.66405167461e-03 1.79686053286e-03 + 4.88914607083e-04 8.04547464768e-04 2.38020029383e-03 4.81501549014e-03 7.77885822831e-03 1.07975434693e-02 + 1.01231377849e-02 1.24617236710e-02 1.54272665135e-02 1.88077260422e-02 2.16842447509e-02 2.26239394500e-02 + 2.06385039479e-02 1.62271555551e-02 1.09712330062e-02 6.26182927635e-03 2.83091273930e-03 9.58282315606e-04 + 5.43823611322e-04 1.17001234028e-03 2.43650874038e-03 4.14791259013e-03 6.12390906619e-03 8.12095891990e-03 + 8.79682913234e-03 1.22227960873e-02 1.65687695519e-02 2.08380898572e-02 2.32715294103e-02 2.23788913960e-02 + 1.83051154931e-02 1.27617648585e-02 7.57662355619e-03 3.75205006241e-03 1.54078524747e-03 7.21589802285e-04 + 8.16578574622e-04 1.40692706056e-03 2.30926285873e-03 3.45271877037e-03 4.78554192689e-03 6.43620785694e-03 + 9.42195251705e-03 1.40302743797e-02 1.89964839595e-02 2.24661316842e-02 2.25248845553e-02 1.89230923001e-02 + 1.34178672299e-02 8.15516862432e-03 4.31256819522e-03 2.08751172021e-03 1.14579004604e-03 9.70682636577e-04 + 1.16535345992e-03 1.56339792950e-03 2.11162809404e-03 2.83535880259e-03 3.98963285632e-03 6.05454283613e-03 + 1.10244983349e-02 1.60737445898e-02 2.03832655583e-02 2.15769133238e-02 1.86204017109e-02 1.31870947483e-02 + 7.95076569104e-03 4.37597978466e-03 2.51296888421e-03 1.78603614604e-03 1.57292321845e-03 1.51894429288e-03 + 1.54532537290e-03 1.64058417149e-03 1.84596425049e-03 2.46339325073e-03 4.00316350998e-03 6.83658622338e-03 + 1.15631757191e-02 1.58184902126e-02 1.82069915417e-02 1.66622865708e-02 1.19651379753e-02 7.11964018100e-03 + 4.12727404283e-03 2.98880475201e-03 2.82643354967e-03 2.82276541307e-03 2.61305079548e-03 2.25779070908e-03 + 1.88468924841e-03 1.57846272936e-03 1.64824693288e-03 2.57405776955e-03 4.55667402435e-03 7.56937549219e-03 + 9.60443077479e-03 1.18908936756e-02 1.17267254384e-02 8.72357230284e-03 5.36141986902e-03 3.84094115633e-03 + 4.05251270285e-03 4.83721968695e-03 5.25975709415e-03 4.94274316779e-03 4.07382100273e-03 3.02606044560e-03 + 2.03662100195e-03 1.44273960529e-03 1.73321864983e-03 2.94502052581e-03 4.68907312345e-03 6.88838909093e-03 + 5.75349170951e-03 5.58204220056e-03 3.95146781196e-03 2.83753475819e-03 4.03167966136e-03 6.62301116298e-03 + 8.83029477799e-03 9.78349951991e-03 9.31632485462e-03 7.71520345991e-03 5.60401453581e-03 3.53200296581e-03 + 1.95450275615e-03 1.42857702490e-03 2.03717346991e-03 3.05788077139e-03 3.95887818269e-03 4.87807589635e-03 + 1.87887990258e-03 6.84507106271e-04 1.44927260915e-03 5.93402466510e-03 1.18938157127e-02 1.60190730759e-02 + 1.74100309389e-02 1.65784527374e-02 1.40234988043e-02 1.04179651042e-02 6.67410463304e-03 3.57453279373e-03 + 1.79687227131e-03 1.63973311459e-03 2.37416380702e-03 2.90857819730e-03 2.96135375334e-03 2.70512563790e-03 + 4.35383130227e-03 1.45209223920e-02 2.87930084915e-02 3.90040473581e-02 4.16448196395e-02 3.92620289550e-02 + 3.44647270049e-02 2.76842694383e-02 1.93998119748e-02 1.14094157193e-02 5.58793886283e-03 2.77619583168e-03 + 2.67102040148e-03 3.91877995202e-03 4.83622075736e-03 4.47486368768e-03 2.91473549344e-03 1.61559059411e-03 + 1.40667154477e-02 3.22128724245e-02 4.80307891736e-02 5.43463850344e-02 5.29730444556e-02 4.83248616727e-02 + 4.13948947016e-02 3.14600195431e-02 1.99810812371e-02 1.03256838159e-02 4.68148007453e-03 2.96382099220e-03 + 3.68352883653e-03 4.87923879505e-03 4.94465370150e-03 3.33326843532e-03 1.36944433838e-03 3.27948125335e-03 + 2.81326530908e-02 4.77189615841e-02 5.93630551323e-02 6.16822402125e-02 5.93109036114e-02 5.43888357267e-02 + 4.51799124036e-02 3.14303713061e-02 1.74056784802e-02 7.91607677465e-03 4.04299523577e-03 3.87112200829e-03 + 4.92533756717e-03 5.30860102620e-03 4.06224362076e-03 1.83445574864e-03 2.09150749120e-03 1.03636222460e-02 + 3.80672664373e-02 5.35670512666e-02 6.10890383582e-02 6.29532218041e-02 6.18560109302e-02 5.60439977424e-02 + 4.30056679741e-02 2.59241939283e-02 1.21611608289e-02 5.59389598498e-03 4.46167740101e-03 5.24860109399e-03 + 5.57674832371e-03 4.49994572781e-03 2.36561611243e-03 1.41562828128e-03 5.99359315713e-03 1.93302436934e-02 + 4.03655289097e-02 5.14670778218e-02 5.75963633541e-02 6.05128442636e-02 5.91681756735e-02 4.98947886929e-02 + 3.31895420192e-02 1.66333970526e-02 7.29196239691e-03 5.10403838009e-03 5.82811663121e-03 6.15289966606e-03 + 5.00000172962e-03 2.81902463608e-03 1.21462917733e-03 2.97589876457e-03 1.09884556178e-02 2.50828062318e-02 + 3.74091389542e-02 4.57278200014e-02 5.11675200016e-02 5.32016515393e-02 4.87166082914e-02 3.59999205076e-02 + 2.01362021216e-02 9.29501018844e-03 5.96004213196e-03 6.52097383875e-03 7.02846506513e-03 5.93213145512e-03 + 3.59201722495e-03 1.43843527799e-03 1.42942098696e-03 5.47673439800e-03 1.43144637356e-02 2.61612013068e-02 + 3.19418711649e-02 3.79368405884e-02 4.14200926047e-02 4.06418572968e-02 3.35171661403e-02 2.19207293047e-02 + 1.21170794692e-02 8.08068076447e-03 7.98333950060e-03 8.29036576173e-03 7.25686243648e-03 4.87306488376e-03 + 2.23196928445e-03 9.70750108626e-04 2.48455413534e-03 7.36204972601e-03 1.50911704047e-02 2.39677667061e-02 + 2.51537590812e-02 2.87153120446e-02 2.99527033184e-02 2.77423992966e-02 2.21303356410e-02 1.60190950025e-02 + 1.25668501331e-02 1.15623625925e-02 1.08380150531e-02 9.19520281017e-03 6.57438183252e-03 3.56802908152e-03 + 1.37241365306e-03 1.19113790416e-03 3.47866750012e-03 7.94089328373e-03 1.38215151041e-02 1.99542093007e-02 + 1.83147987285e-02 2.03263245631e-02 2.11729502760e-02 2.07705593171e-02 1.96636426182e-02 1.87182443770e-02 + 1.76961460188e-02 1.56509558133e-02 1.25123315120e-02 8.87792908998e-03 5.27112627784e-03 2.36609670799e-03 + 1.02220119308e-03 1.63492877010e-03 3.90901426436e-03 7.33420861367e-03 1.13615703467e-02 1.52445339832e-02 + 1.32137799981e-02 1.53737135485e-02 1.79192435307e-02 2.08079121483e-02 2.33330467357e-02 2.40604129080e-02 + 2.18727704626e-02 1.73403206326e-02 1.21043473992e-02 7.35492414370e-03 3.67117157700e-03 1.50418016985e-03 + 1.04418942079e-03 1.95898713387e-03 3.74579696061e-03 6.08766783807e-03 8.67042838130e-03 1.10866559431e-02 + 1.09668057772e-02 1.45662351422e-02 1.93467750779e-02 2.43356424290e-02 2.74204969219e-02 2.66276732862e-02 + 2.20343846249e-02 1.57087651957e-02 9.74020517583e-03 5.16724396714e-03 2.32205226787e-03 1.15793041181e-03 + 1.24860959997e-03 2.05291258413e-03 3.27649104497e-03 4.81299621942e-03 6.54073133844e-03 8.46715259344e-03 + 1.16346301730e-02 1.69691746147e-02 2.30107325501e-02 2.76597592078e-02 2.84768247265e-02 2.47813437511e-02 + 1.83772726268e-02 1.18130658472e-02 6.64816913431e-03 3.33408469704e-03 1.70829441835e-03 1.27337078653e-03 + 1.47806193617e-03 2.00782752477e-03 2.78959631766e-03 3.85845689628e-03 5.39562115242e-03 7.82211970976e-03 + 1.44138943329e-02 2.08170382992e-02 2.64281005481e-02 2.85503235828e-02 2.58294313772e-02 1.97252490353e-02 + 1.30673059454e-02 7.79120998524e-03 4.40787372268e-03 2.62185393686e-03 1.86993759426e-03 1.64871305148e-03 + 1.68997744220e-03 1.91886643199e-03 2.39898674099e-03 3.41922938820e-03 5.49229322446e-03 9.10531721717e-03 + 1.73471552665e-02 2.34696937981e-02 2.70097603083e-02 2.56920671228e-02 2.02368146587e-02 1.37242025972e-02 + 8.62253920865e-03 5.53813972181e-03 3.95496043851e-03 3.13079626654e-03 2.57667307829e-03 2.15410807459e-03 + 1.87285435078e-03 1.80061388509e-03 2.23971464173e-03 3.73122022347e-03 6.71082540599e-03 1.13304556679e-02 + 1.78251806268e-02 2.21189088407e-02 2.27482070487e-02 1.90849841904e-02 1.36962955822e-02 9.42385513897e-03 + 7.09227358595e-03 6.06819194257e-03 5.43295181469e-03 4.62858543916e-03 3.64192495006e-03 2.69653475880e-03 + 1.96177010255e-03 1.73459693037e-03 2.53367324945e-03 4.65465016609e-03 8.01829233619e-03 1.25402618894e-02 + 1.44559313384e-02 1.59226705828e-02 1.45807026945e-02 1.19170401367e-02 1.01599990447e-02 9.72725556709e-03 + 9.80125398817e-03 9.56596059744e-03 8.54914699951e-03 6.81134979442e-03 4.84131525620e-03 3.09100954028e-03 + 1.93957690916e-03 1.90640298700e-03 3.21760722638e-03 5.43761167251e-03 8.14100873656e-03 1.13072413154e-02 + 8.44200148259e-03 8.06972223289e-03 8.42765956568e-03 1.09201450628e-02 1.42537838938e-02 1.63711461252e-02 + 1.66710192097e-02 1.53338215280e-02 1.26198270664e-02 9.14771603162e-03 5.76975131630e-03 3.16826390185e-03 + 1.93517601513e-03 2.37499687649e-03 3.90218248324e-03 5.52515571820e-03 6.87737198130e-03 7.98780553715e-03 + 3.40818871948e-03 5.58372318324e-03 1.25357221637e-02 2.11822074231e-02 2.66220309743e-02 2.76514608933e-02 + 2.57349390652e-02 2.18825899749e-02 1.65970584216e-02 1.08963137491e-02 6.04724686960e-03 2.97557002762e-03 + 2.12667268050e-03 3.05086808028e-03 4.40692202639e-03 5.11202700384e-03 4.95922822270e-03 4.10324880800e-03 + 1.54313029090e-02 3.18035357534e-02 4.61708008469e-02 5.17656923900e-02 4.99644577426e-02 4.47561637690e-02 + 3.73321010461e-02 2.74760189009e-02 1.67409936576e-02 8.06957034862e-03 3.29597070970e-03 2.31876896217e-03 + 3.74753245294e-03 5.66160796688e-03 6.45048872089e-03 5.54503348284e-03 4.07813240533e-03 5.81538891719e-03 + 3.04654718198e-02 4.97757409810e-02 6.07634044985e-02 6.19803661426e-02 5.82687977520e-02 5.21294251502e-02 + 4.22334024126e-02 2.85120282236e-02 1.49846845777e-02 6.10276388029e-03 2.84181732017e-03 3.33803306610e-03 + 5.11177640398e-03 6.19570526940e-03 5.57622306981e-03 3.86522055678e-03 4.44365044715e-03 1.27899450316e-02 + 4.38620139354e-02 5.95995519805e-02 6.59137248386e-02 6.59754903601e-02 6.33571102407e-02 5.65197930412e-02 + 4.27123436023e-02 2.49414654239e-02 1.07176018051e-02 4.12937729889e-03 3.41548936590e-03 4.89368365875e-03 + 5.98846625870e-03 5.60215986872e-03 4.02406232733e-03 3.60628736439e-03 9.02574663225e-03 2.37487500098e-02 + 4.86752574239e-02 5.95794426847e-02 6.44049906469e-02 6.62368344223e-02 6.43499977945e-02 5.42033089620e-02 + 3.55765508495e-02 1.67375535148e-02 5.99755583837e-03 3.63071840184e-03 4.91325519438e-03 6.03058535793e-03 + 5.63299575781e-03 4.06164511155e-03 3.00649242134e-03 5.64983194708e-03 1.53851930747e-02 3.18123685991e-02 + 4.60572175278e-02 5.42591946691e-02 5.94798861968e-02 6.17666052228e-02 5.69516563468e-02 4.18700018251e-02 + 2.21623447341e-02 8.26279572360e-03 3.87770573329e-03 4.82813010872e-03 6.20443388480e-03 5.95508452906e-03 + 4.28816537072e-03 2.67190604351e-03 3.34048359444e-03 8.68812870953e-03 1.96560557655e-02 3.37161023230e-02 + 3.98534975973e-02 4.63229917361e-02 5.04161452709e-02 4.96411634014e-02 4.03025784082e-02 2.43314082773e-02 + 1.04984146399e-02 4.77252594145e-03 4.98953599319e-03 6.39051657847e-03 6.46909230542e-03 4.94559643017e-03 + 2.89935806548e-03 2.16360458513e-03 4.49751344480e-03 1.08150070581e-02 2.04683620587e-02 3.10116837757e-02 + 3.18421447321e-02 3.58562416652e-02 3.69142552665e-02 3.27138723634e-02 2.30072642003e-02 1.27298239532e-02 + 7.35331193337e-03 6.72862307682e-03 7.41842649398e-03 7.31352814177e-03 5.94179048825e-03 3.74089812992e-03 + 2.03251103908e-03 2.35966322750e-03 5.50094399110e-03 1.12654498952e-02 1.86242812016e-02 2.59268288933e-02 + 2.29777437567e-02 2.45456479389e-02 2.37536724313e-02 2.01866025783e-02 1.55082690657e-02 1.25104888022e-02 + 1.15609174398e-02 1.08813134936e-02 9.51862138171e-03 7.51958114746e-03 5.04229832488e-03 2.70557673263e-03 + 1.68211826603e-03 2.75302094477e-03 5.79513495369e-03 1.02256630632e-02 1.52197719296e-02 1.97306528484e-02 + 1.53887399235e-02 1.64002435941e-02 1.70559192948e-02 1.77633516626e-02 1.87627510423e-02 1.91364889831e-02 + 1.75520467647e-02 1.42424708855e-02 1.04773228593e-02 6.94103899581e-03 3.89948076359e-03 1.94313819426e-03 + 1.66062986541e-03 2.95880901360e-03 5.31823203677e-03 8.27506986091e-03 1.12905904676e-02 1.37451018281e-02 + 1.12884911481e-02 1.39311741239e-02 1.78672331578e-02 2.24902880278e-02 2.56777979714e-02 2.51197643465e-02 + 2.08417310608e-02 1.50785676849e-02 9.75841079446e-03 5.56829917992e-03 2.76548833701e-03 1.56113813198e-03 + 1.76434103359e-03 2.83546110791e-03 4.37959709262e-03 6.17352076787e-03 7.93194509807e-03 9.51682232306e-03 + 1.12644867926e-02 1.63349016998e-02 2.26887444805e-02 2.81622638226e-02 2.97713382358e-02 2.63843305360e-02 + 1.99003842789e-02 1.31317274524e-02 7.68603425021e-03 4.01206991502e-03 2.08620124292e-03 1.55284890677e-03 + 1.82953783473e-03 2.49454085879e-03 3.41391112116e-03 4.54812131318e-03 5.94493148237e-03 7.96476521460e-03 + 1.44567254685e-02 2.12498012603e-02 2.77423959177e-02 3.09978085118e-02 2.91213582334e-02 2.31636609270e-02 + 1.59947614545e-02 9.86044763503e-03 5.58677600729e-03 3.12740248678e-03 2.03900855544e-03 1.74322880035e-03 + 1.81966548036e-03 2.12182311077e-03 2.69098780820e-03 3.74016315439e-03 5.70804216044e-03 9.15538519941e-03 + 1.91067499768e-02 2.60824190172e-02 3.05280192303e-02 3.00462675286e-02 2.49541381954e-02 1.79858693030e-02 + 1.17593651071e-02 7.35673099330e-03 4.69080377479e-03 3.22895170949e-03 2.43693672639e-03 1.99145268307e-03 + 1.77290536949e-03 1.81349103926e-03 2.38092245025e-03 4.00386551919e-03 7.23117195491e-03 1.23519649923e-02 + 2.25935386479e-02 2.80610678778e-02 2.93428872383e-02 2.57235088240e-02 1.95092737965e-02 1.36312345383e-02 + 9.47884448232e-03 6.94864444303e-03 5.35605462201e-03 4.12908469965e-03 3.08059036838e-03 2.24520792586e-03 + 1.69338053144e-03 1.67402419594e-03 2.72387743950e-03 5.34938255282e-03 9.73197422258e-03 1.57482662916e-02 + 2.22733360617e-02 2.50772100061e-02 2.38696177933e-02 1.98512609062e-02 1.55658072841e-02 1.24397599681e-02 + 1.04621312250e-02 8.98354824242e-03 7.39824492456e-03 5.58710246513e-03 3.83244310376e-03 2.41157316343e-03 + 1.60209779006e-03 1.90743041982e-03 3.75305587276e-03 7.07078700762e-03 1.15872098355e-02 1.70152717119e-02 + 1.74081333866e-02 1.79919939971e-02 1.73159684780e-02 1.67904453380e-02 1.65995488173e-02 1.61498443086e-02 + 1.50774940382e-02 1.31649357363e-02 1.04037780826e-02 7.27092953346e-03 4.42686521645e-03 2.37509533345e-03 + 1.63099520693e-03 2.59973870085e-03 5.00583457705e-03 8.11200476869e-03 1.15059727233e-02 1.49196028102e-02 + 1.07295460873e-02 1.24625153675e-02 1.68366065611e-02 2.19600543477e-02 2.48114276638e-02 2.46764318358e-02 + 2.23867610797e-02 1.85235187840e-02 1.36011760276e-02 8.59641394379e-03 4.53920003265e-03 2.17120820882e-03 + 1.94038812124e-03 3.57365634649e-03 5.95087349751e-03 8.04401475090e-03 9.52577262967e-03 1.03139381155e-02 + 8.23667869751e-03 1.64179531532e-02 2.78508768694e-02 3.59578413577e-02 3.78083291128e-02 3.52595279024e-02 + 3.03586733937e-02 2.36908828102e-02 1.60128922291e-02 8.96688701937e-03 4.07353069584e-03 2.03419465779e-03 + 2.62760335674e-03 4.63824175825e-03 6.45731280519e-03 7.11596403491e-03 6.56898066031e-03 5.91338512685e-03 + 2.72722481830e-02 4.34668231220e-02 5.31748914086e-02 5.44393345828e-02 5.06578372332e-02 4.40464058654e-02 + 3.42836001592e-02 2.20426386902e-02 1.06829910987e-02 3.52424984961e-03 1.23859762156e-03 2.34128502623e-03 + 4.73121032347e-03 6.57978207810e-03 6.82944348182e-03 5.84584539982e-03 6.34700822132e-03 1.29314631167e-02 + 4.15954701008e-02 5.60724757660e-02 6.17269847305e-02 6.09162469885e-02 5.69077293831e-02 4.89869342500e-02 + 3.55585458380e-02 1.95772416982e-02 7.28234485511e-03 1.90979093676e-03 1.87161560762e-03 3.93778134856e-03 + 5.73768877506e-03 6.14755206676e-03 5.29833131530e-03 5.22857067502e-03 1.01492706067e-02 2.33513874823e-02 + 4.98142962192e-02 5.99252386088e-02 6.34622789743e-02 6.36043574114e-02 6.01271586924e-02 4.92792252056e-02 + 3.11487264070e-02 1.33634738831e-02 3.48411694273e-03 1.68955877540e-03 3.50791382954e-03 5.27608797853e-03 + 5.63466402025e-03 4.82159472775e-03 4.38208350601e-03 7.37491474340e-03 1.71584965893e-02 3.33852838467e-02 + 4.97120711380e-02 5.70103054536e-02 6.10118086351e-02 6.22221613844e-02 5.65968175336e-02 4.08199278518e-02 + 2.04257211322e-02 6.04092938697e-03 1.63192829008e-03 2.98719130185e-03 4.98003637287e-03 5.43090779252e-03 + 4.49584573428e-03 3.58719844302e-03 4.92985892584e-03 1.10129984344e-02 2.28155955961e-02 3.74880633094e-02 + 4.43938919905e-02 5.04002608576e-02 5.41769807096e-02 5.30600633612e-02 4.25940433522e-02 2.45337800396e-02 + 8.65750512201e-03 1.97157068729e-03 2.34333270278e-03 4.43357771168e-03 5.29899981766e-03 4.53650690795e-03 + 3.21306117910e-03 3.19029724111e-03 6.34043559892e-03 1.36965305547e-02 2.44538533480e-02 3.56495164596e-02 + 3.63485162566e-02 4.03415925415e-02 4.11312748584e-02 3.55369420499e-02 2.29767385509e-02 9.72854112582e-03 + 2.88152116968e-03 2.40701356864e-03 4.05694581568e-03 5.08984531448e-03 4.76372236675e-03 3.43018435406e-03 + 2.43739033129e-03 3.46859587370e-03 7.46717148987e-03 1.42659845790e-02 2.25701423617e-02 3.03647237937e-02 + 2.64700621827e-02 2.74267962895e-02 2.48757110021e-02 1.80426385088e-02 9.82633019429e-03 5.00204115280e-03 + 4.39004462314e-03 5.21503402550e-03 5.62594816085e-03 5.25493420669e-03 4.05477566763e-03 2.58364543135e-03 + 2.17812225384e-03 3.87600597086e-03 7.68148601254e-03 1.29360769606e-02 1.85678296685e-02 2.33331372196e-02 + 1.66492506513e-02 1.58540036377e-02 1.34948599578e-02 1.07196093803e-02 9.43308364403e-03 9.64386822793e-03 + 9.52368447303e-03 8.41038292152e-03 6.88856330758e-03 5.18183265197e-03 3.33357122257e-03 2.02874622976e-03 + 2.19864700292e-03 3.99766887640e-03 6.92328458737e-03 1.03817420486e-02 1.36238973995e-02 1.58509882718e-02 + 1.00195546197e-02 1.04252787797e-02 1.18079590319e-02 1.44881622369e-02 1.70345982062e-02 1.70934194436e-02 + 1.43808496722e-02 1.07170198638e-02 7.40951822277e-03 4.64964731127e-03 2.59751788538e-03 1.75470950419e-03 + 2.26151057315e-03 3.66766768647e-03 5.51413327139e-03 7.44284927163e-03 8.96640481890e-03 9.75329220406e-03 + 8.40036643925e-03 1.18561901378e-02 1.71098604395e-02 2.23327762518e-02 2.43374867946e-02 2.17382435529e-02 + 1.64327790920e-02 1.10426033413e-02 6.74188479040e-03 3.72463084556e-03 2.08267715007e-03 1.72804115210e-03 + 2.18758117978e-03 3.00773890768e-03 3.99074743440e-03 4.95979936833e-03 5.76467203230e-03 6.65803179471e-03 + 1.11805028747e-02 1.72503765026e-02 2.38025326536e-02 2.77893726296e-02 2.68348135407e-02 2.16749201932e-02 + 1.51450264833e-02 9.46096477031e-03 5.40662569422e-03 3.01561429668e-03 1.99073557330e-03 1.79380872597e-03 + 1.95486623357e-03 2.29467342306e-03 2.79025245899e-03 3.49198635306e-03 4.69642463898e-03 7.03006325686e-03 + 1.64249327908e-02 2.32645954925e-02 2.82465223372e-02 2.88202439794e-02 2.47675467596e-02 1.83670889950e-02 + 1.21799423261e-02 7.51249480973e-03 4.55889987468e-03 2.96700154550e-03 2.19823758046e-03 1.82369446215e-03 + 1.66377346772e-03 1.71872243816e-03 2.15004567824e-03 3.35686157381e-03 5.90464236518e-03 1.02638398838e-02 + 2.17359931543e-02 2.73625680289e-02 2.91911060418e-02 2.63874563497e-02 2.06926199474e-02 1.46909844089e-02 + 9.95569384365e-03 6.78732451097e-03 4.79709681227e-03 3.47315147059e-03 2.50865697138e-03 1.81058323441e-03 + 1.38375122545e-03 1.39734891429e-03 2.30604979735e-03 4.68475755238e-03 8.89665429016e-03 1.48734476137e-02 + 2.45053355538e-02 2.76825724990e-02 2.66631767890e-02 2.24261840306e-02 1.73121434822e-02 1.30229153101e-02 + 9.99221431288e-03 7.83304956635e-03 6.00735104534e-03 4.31031844186e-03 2.84710825338e-03 1.74035647969e-03 + 1.15698756606e-03 1.53193315382e-03 3.40907963127e-03 7.03110870573e-03 1.22705163068e-02 1.85854747536e-02 + 2.28685011784e-02 2.37903481158e-02 2.21971196951e-02 1.95511449403e-02 1.69597300764e-02 1.47440564848e-02 + 1.27240007478e-02 1.05011061224e-02 7.92534368083e-03 5.31271481006e-03 3.08615976887e-03 1.54800257695e-03 + 1.11500084524e-03 2.28225905954e-03 5.12704084111e-03 9.25075037228e-03 1.41811772857e-02 1.92036916371e-02 + 1.75383665162e-02 1.85252769240e-02 1.99553605358e-02 2.13240626046e-02 2.15233253190e-02 2.02878131896e-02 + 1.78244090696e-02 1.42883388826e-02 1.01202756501e-02 6.11622965752e-03 2.98316296082e-03 1.26214128753e-03 + 1.43221140143e-03 3.49750449437e-03 6.72707535429e-03 1.02534942708e-02 1.35464682967e-02 1.60957937931e-02 + 1.29982235185e-02 1.81853247318e-02 2.52029640500e-02 3.00593478391e-02 3.08658784798e-02 2.85022993310e-02 + 2.40900705767e-02 1.82255746081e-02 1.18250673616e-02 6.20325057178e-03 2.42843959467e-03 1.09112861897e-03 + 2.18271203134e-03 4.82811446253e-03 7.66622174675e-03 9.72218718415e-03 1.07065547423e-02 1.11489047543e-02 + 1.55789644742e-02 2.76260025845e-02 3.85516952838e-02 4.31236511903e-02 4.17381382555e-02 3.69717996217e-02 + 2.99567002214e-02 2.11726529864e-02 1.22118470478e-02 5.26985830826e-03 1.65166521544e-03 1.35390489821e-03 + 3.34477322687e-03 5.98082930978e-03 7.74155229830e-03 7.95533873629e-03 7.32919863820e-03 8.65049702618e-03 + 3.39308828874e-02 4.55831356657e-02 5.05982033757e-02 4.98089618820e-02 4.53514482296e-02 3.73721534582e-02 + 2.57920286291e-02 1.32913156694e-02 4.13433206313e-03 3.47319301413e-04 7.43249854746e-04 2.95585244150e-03 + 5.11664328434e-03 6.19594059399e-03 6.11540705414e-03 6.34274657797e-03 1.00835288204e-02 1.99682986084e-02 + 4.35315939015e-02 5.24242725980e-02 5.51928867192e-02 5.39371788296e-02 4.88746918718e-02 3.81429492974e-02 + 2.27666510924e-02 8.68874736399e-03 1.25149221931e-03 2.98033730779e-04 2.28075147607e-03 4.27154408455e-03 + 5.12747780191e-03 4.97707215225e-03 5.02199741600e-03 7.74450043482e-03 1.59380382530e-02 2.95012822598e-02 + 4.66887080052e-02 5.29275213092e-02 5.53428429951e-02 5.44884039789e-02 4.76185455919e-02 3.28589191765e-02 + 1.52327971034e-02 3.32235665029e-03 5.24554846758e-05 1.68421673535e-03 3.80343130798e-03 4.56045409091e-03 + 4.14222301006e-03 3.80383288393e-03 5.47058566204e-03 1.12987283863e-02 2.21601978653e-02 3.55673538143e-02 + 4.39114109595e-02 4.88116531839e-02 5.11379492779e-02 4.87232326401e-02 3.79700170060e-02 2.08466236859e-02 + 6.22374094533e-03 2.71032104961e-04 9.00542801343e-04 3.11263645378e-03 4.16546720478e-03 3.75918937455e-03 + 2.95494708242e-03 3.48853175294e-03 7.05307790632e-03 1.45500612543e-02 2.51426296199e-02 3.58968223531e-02 + 3.72960895207e-02 4.06078202690e-02 4.06248070653e-02 3.42626144979e-02 2.11392469484e-02 7.65358250294e-03 + 7.70313960778e-04 3.42126726994e-04 2.14547093757e-03 3.45151484506e-03 3.51432154193e-03 2.68715452771e-03 + 2.28405374141e-03 3.92476500583e-03 8.48224403883e-03 1.57105943632e-02 2.41942033352e-02 3.18105783515e-02 + 2.78843436888e-02 2.82271344014e-02 2.45054908338e-02 1.59303528455e-02 6.15373979888e-03 7.28057460423e-04 + 3.38262588986e-04 1.70561976472e-03 2.78940928358e-03 3.17815183803e-03 2.74040374478e-03 1.95888743112e-03 + 2.18323300539e-03 4.49789945965e-03 8.89023782351e-03 1.46056791298e-02 2.04354684102e-02 2.50888068473e-02 + 1.71132925710e-02 1.47466620909e-02 9.79479014948e-03 4.18285195863e-03 1.29491998898e-03 1.68388083124e-03 + 2.82073651887e-03 3.29600524345e-03 3.34462832131e-03 3.01120875240e-03 2.20596717065e-03 1.61993293523e-03 + 2.36183304422e-03 4.70246449772e-03 8.10421179778e-03 1.18704946684e-02 1.51463699005e-02 1.70732484847e-02 + 8.23244112018e-03 5.99751484917e-03 4.12857025945e-03 4.22535810983e-03 5.95644065976e-03 6.96973039511e-03 + 6.33953314438e-03 5.13343337952e-03 4.02784526343e-03 2.88594540726e-03 1.81682563508e-03 1.55435435851e-03 + 2.51578979079e-03 4.31128370783e-03 6.41987234694e-03 8.39342307287e-03 9.61683530059e-03 9.58311024050e-03 + 4.35488425190e-03 5.12904440304e-03 7.91019113971e-03 1.17237924350e-02 1.37215823066e-02 1.24461211498e-02 + 9.43385303103e-03 6.55653902306e-03 4.28820928916e-03 2.54921637775e-03 1.58568426930e-03 1.64684837980e-03 + 2.41735268419e-03 3.42784594274e-03 4.43434860920e-03 5.15096734378e-03 5.23872615740e-03 4.75445668359e-03 + 5.89467509619e-03 1.00873820384e-02 1.54780245312e-02 1.92601906663e-02 1.89732054806e-02 1.52414150967e-02 + 1.05902246652e-02 6.67500715871e-03 3.87489087194e-03 2.21059646406e-03 1.61827835312e-03 1.71374771634e-03 + 2.03754005425e-03 2.40665582289e-03 2.74409569560e-03 2.92735476407e-03 3.06636613107e-03 3.75495115169e-03 + 1.08687236212e-02 1.66726223282e-02 2.14924777428e-02 2.27242745402e-02 1.98108516261e-02 1.46903474480e-02 + 9.64655393206e-03 5.82090932574e-03 3.43035159173e-03 2.25275676594e-03 1.80441517384e-03 1.62624244123e-03 + 1.54442861462e-03 1.55866540302e-03 1.70231784873e-03 2.17587560707e-03 3.48229206078e-03 6.26071835246e-03 + 1.66947854513e-02 2.18013463468e-02 2.39717358059e-02 2.21934803426e-02 1.76515483444e-02 1.24930277226e-02 + 8.22389757118e-03 5.33254237790e-03 3.62908157624e-03 2.63292889590e-03 1.94458134793e-03 1.42656874454e-03 + 1.09292404824e-03 1.03561419682e-03 1.53740819967e-03 3.09397888364e-03 6.17639093760e-03 1.09128657716e-02 + 2.10947497620e-02 2.40361871701e-02 2.33784814709e-02 1.98146423034e-02 1.52032213707e-02 1.10844091399e-02 + 8.06210872946e-03 5.99086128303e-03 4.43381701837e-03 3.10864893187e-03 2.00288867622e-03 1.18337847560e-03 + 7.48971997560e-04 1.00120444120e-03 2.43922061564e-03 5.45836331560e-03 1.00851297161e-02 1.57708942963e-02 + 2.23342829325e-02 2.30947008364e-02 2.11645871444e-02 1.79071095272e-02 1.46198547321e-02 1.19113368611e-02 + 9.72746641966e-03 7.68550024826e-03 5.58453232504e-03 3.59716593187e-03 1.97579928150e-03 8.87185224742e-04 + 6.23112115182e-04 1.65015148282e-03 4.26543600930e-03 8.37257756526e-03 1.35152385255e-02 1.87045818073e-02 + 2.00120351505e-02 2.01920280654e-02 1.95617825137e-02 1.85298003007e-02 1.71239996142e-02 1.53323916781e-02 + 1.30225596761e-02 1.01068610351e-02 6.90187396912e-03 3.96977989631e-03 1.73790747675e-03 5.66446524933e-04 + 8.97493732185e-04 2.93642968917e-03 6.36205338790e-03 1.05621413436e-02 1.48366229936e-02 1.82604499807e-02 + 1.63251811780e-02 1.87759563846e-02 2.16968837196e-02 2.34071241800e-02 2.30888204086e-02 2.09616736112e-02 + 1.73749056741e-02 1.27713063183e-02 7.97208766645e-03 3.88838607316e-03 1.19937806761e-03 3.99290094162e-04 + 1.65632380316e-03 4.48421973173e-03 7.92485914101e-03 1.10984410235e-02 1.34424293583e-02 1.48944716002e-02 + 1.59374842807e-02 2.30987773374e-02 2.96017331751e-02 3.23866727820e-02 3.13064247316e-02 2.74959653809e-02 + 2.17354248714e-02 1.48260038723e-02 8.12815961338e-03 3.07278615546e-03 5.30156398664e-04 6.46239654878e-04 + 2.81427180213e-03 5.82930224637e-03 8.42139808536e-03 9.84739595901e-03 1.03514048510e-02 1.16233144209e-02 + 2.24881357227e-02 3.37738380002e-02 4.10291813363e-02 4.23379875376e-02 3.92819221059e-02 3.33229566351e-02 + 2.49316943509e-02 1.52897901130e-02 6.82941628110e-03 1.64360296672e-03 1.86536759214e-04 1.52178244328e-03 + 4.13592420937e-03 6.52902239704e-03 7.67480256126e-03 7.63129143663e-03 8.24507916408e-03 1.27524209614e-02 + 3.37303660845e-02 4.06689624249e-02 4.28382906763e-02 4.10911580734e-02 3.58724769638e-02 2.69665913859e-02 + 1.58375932365e-02 6.27205740708e-03 1.30766341481e-03 6.96164446409e-04 2.13931416362e-03 3.69367704551e-03 + 4.56889090739e-03 4.80872524351e-03 5.20488875936e-03 7.48292963979e-03 1.35567163488e-02 2.33759348885e-02 + 3.86602952038e-02 4.37568680892e-02 4.49487361321e-02 4.26344668348e-02 3.57355569647e-02 2.40586550021e-02 + 1.14227149340e-02 3.24210856840e-03 1.06250188660e-03 2.18992050930e-03 3.57661401132e-03 3.98464241674e-03 + 3.65066587786e-03 3.57638747633e-03 5.20439767590e-03 1.00819147147e-02 1.87924799589e-02 2.95289990335e-02 + 3.87309473488e-02 4.24258542513e-02 4.31297933708e-02 3.96532893831e-02 3.02523641993e-02 1.70450733258e-02 + 6.33849472118e-03 2.06550362073e-03 2.39154279307e-03 3.64151687998e-03 3.92156995864e-03 3.18969659598e-03 + 2.43908895103e-03 3.12369919012e-03 6.52728936195e-03 1.32237122943e-02 2.24539010523e-02 3.18166462157e-02 + 3.45755183610e-02 3.69211591678e-02 3.61050475979e-02 3.01659040951e-02 1.94006005208e-02 8.91172443644e-03 + 3.59189063488e-03 2.86166119385e-03 3.49978193477e-03 3.68744967045e-03 3.05447164185e-03 2.00668321031e-03 + 1.72228471635e-03 3.55545628560e-03 8.10156427257e-03 1.49811711951e-02 2.28716826444e-02 2.98316330698e-02 + 2.70251097164e-02 2.70542358337e-02 2.34639628284e-02 1.59844002237e-02 8.03714442319e-03 3.89265925535e-03 + 3.27982126572e-03 3.36164637343e-03 3.12077019187e-03 2.68071175302e-03 1.92388245811e-03 1.19400230125e-03 + 1.68171160755e-03 4.29547048480e-03 8.87277628638e-03 1.45841681488e-02 2.02338127453e-02 2.45916971488e-02 + 1.71295020739e-02 1.44974068939e-02 9.38787764618e-03 4.09502584793e-03 1.93303651824e-03 2.63416654306e-03 + 3.17586004028e-03 2.71091742623e-03 2.20102631237e-03 1.80419742580e-03 1.19794858178e-03 9.14826170273e-04 + 2.01913986446e-03 4.72437281140e-03 8.39895157214e-03 1.22770522739e-02 1.55065977141e-02 1.72919749310e-02 + 7.49080881899e-03 4.08789756474e-03 9.13232556247e-04 2.84518245615e-04 2.05937433404e-03 3.36570944570e-03 + 3.02162736704e-03 2.28008982241e-03 1.85846824240e-03 1.41069509823e-03 8.65770891562e-04 1.00337413251e-03 + 2.34841497574e-03 4.48427268608e-03 6.80451633612e-03 8.81791494383e-03 9.90814450566e-03 9.53588608868e-03 + 1.60005516474e-03 3.22055282442e-04 1.13603496812e-03 3.81070701971e-03 5.72430773218e-03 5.30885038533e-03 + 3.85679265526e-03 2.74512870861e-03 1.96542592229e-03 1.20663017904e-03 7.98933790285e-04 1.25422730520e-03 + 2.36051563831e-03 3.58817909818e-03 4.64305946318e-03 5.20624969208e-03 4.86231128703e-03 3.50540895079e-03 + 1.16585358860e-03 3.22239364312e-03 6.90216902161e-03 9.86286780471e-03 9.88356013607e-03 7.63029053419e-03 + 5.14780304137e-03 3.29258086122e-03 1.93607715716e-03 1.08360937452e-03 9.71098702990e-04 1.42322247591e-03 + 1.97247715226e-03 2.40153648663e-03 2.60921544521e-03 2.38362150228e-03 1.68575011966e-03 9.73881682342e-04 + 4.95570194232e-03 9.13888839388e-03 1.30273955958e-02 1.42184159031e-02 1.22065612981e-02 8.74221381443e-03 + 5.55456421805e-03 3.22590677378e-03 1.80127419540e-03 1.23808677516e-03 1.23464534048e-03 1.34340771384e-03 + 1.37867686808e-03 1.34679880494e-03 1.20401958873e-03 9.92545176017e-04 1.10523586617e-03 2.22181155793e-03 + 1.02991704657e-02 1.44094989406e-02 1.64532767151e-02 1.53613633034e-02 1.20247388394e-02 8.20955473031e-03 + 5.09874270286e-03 3.07974949562e-03 2.06071218869e-03 1.63578839360e-03 1.36054596262e-03 1.07300763493e-03 + 8.21710947915e-04 6.58699033636e-04 7.08214101472e-04 1.33044815243e-03 3.01695152919e-03 6.08595376850e-03 + 1.48992289223e-02 1.73231001785e-02 1.69910543010e-02 1.43166480355e-02 1.07133343326e-02 7.43967344950e-03 + 5.08682086338e-03 3.64722376822e-03 2.74379105506e-03 1.99857714444e-03 1.30863653152e-03 7.51414939716e-04 + 4.17339558943e-04 4.79398661355e-04 1.29751485575e-03 3.26991489274e-03 6.54535731191e-03 1.07771266625e-02 + 1.74055472478e-02 1.78574104839e-02 1.60734722935e-02 1.31844664786e-02 1.02999823829e-02 7.99375955143e-03 + 6.29463379925e-03 4.89388125299e-03 3.52929970374e-03 2.22727750806e-03 1.15217808422e-03 4.32399294697e-04 + 2.57510614302e-04 9.73243170388e-04 2.90929508323e-03 6.13658900693e-03 1.03190630155e-02 1.45419554774e-02 + 1.74134452921e-02 1.69571851210e-02 1.54529365559e-02 1.36492459141e-02 1.19159575500e-02 1.02852186120e-02 + 8.52928713443e-03 6.47271271205e-03 4.28899935059e-03 2.33757184197e-03 8.83090682262e-04 1.61246503801e-04 + 5.04570021629e-04 2.15745002282e-03 5.06069865237e-03 8.86393793239e-03 1.28826276515e-02 1.60470442306e-02 + 1.58266712943e-02 1.63756665309e-02 1.67632054261e-02 1.66323621730e-02 1.57482078299e-02 1.40196066690e-02 + 1.14051860006e-02 8.17251954210e-03 4.91840237924e-03 2.21526821751e-03 4.81916297652e-04 9.50474321937e-05 + 1.25194606782e-03 3.73282304017e-03 7.00161888220e-03 1.04091217005e-02 1.32422997628e-02 1.49870386351e-02 + 1.51533131558e-02 1.84815654956e-02 2.13195987279e-02 2.23613431339e-02 2.13687577410e-02 1.85930482646e-02 + 1.44295301217e-02 9.60351050570e-03 5.08117378354e-03 1.71977900946e-03 1.02367516823e-04 4.33487416405e-04 + 2.38601764660e-03 5.20603565117e-03 8.03844132991e-03 1.02089083307e-02 1.15610449936e-02 1.28325672094e-02 + 1.82587240965e-02 2.46939353738e-02 2.89381581395e-02 2.97482575652e-02 2.75373289068e-02 2.29958543110e-02 + 1.68016640060e-02 1.00961563359e-02 4.40723913099e-03 9.45088328829e-04 6.69040853761e-05 1.28110704268e-03 + 3.62596824367e-03 6.06677282564e-03 7.78294960411e-03 8.61185245009e-03 9.58066075320e-03 1.25605727330e-02 + 2.55461385455e-02 3.33976264247e-02 3.71068795027e-02 3.65509264665e-02 3.27170653578e-02 2.61455487013e-02 + 1.75781055385e-02 9.00501505462e-03 2.88620076135e-03 3.53907444542e-04 7.26472508474e-04 2.53559827936e-03 + 4.52850927544e-03 5.91116334916e-03 6.47211644949e-03 7.09866363130e-03 9.86996240478e-03 1.64330009926e-02 + 2.87937546547e-02 3.26082580779e-02 3.32348371955e-02 3.09577264520e-02 2.58539030773e-02 1.85193059066e-02 + 1.11263059393e-02 6.26490292410e-03 4.55137004579e-03 4.50418095073e-03 4.51334852122e-03 4.02880995416e-03 + 3.35380602632e-03 3.20129385330e-03 4.52133776956e-03 8.23856898021e-03 1.45406277021e-02 2.21662438327e-02 + 3.07565377171e-02 3.35133046416e-02 3.35114052509e-02 3.05764705683e-02 2.45146356444e-02 1.68746347518e-02 + 1.08028025958e-02 7.93960351472e-03 7.07866456020e-03 6.33912583747e-03 4.97267402393e-03 3.27140703389e-03 + 2.09415171796e-03 2.50489630857e-03 5.30055211307e-03 1.06583375627e-02 1.78710839377e-02 2.52247273419e-02 + 2.92188717562e-02 3.09758301299e-02 3.03119103356e-02 2.67324205785e-02 2.09284085051e-02 1.55776308475e-02 + 1.25371208677e-02 1.08261944086e-02 8.89868007116e-03 6.50676564406e-03 4.01132373924e-03 1.93103667719e-03 + 1.18899216027e-03 2.70235115983e-03 6.67093885126e-03 1.25581054799e-02 1.92531637205e-02 2.52090750816e-02 + 2.44412380101e-02 2.49340970741e-02 2.33405846774e-02 2.00937992929e-02 1.72582701927e-02 1.61224665978e-02 + 1.49073045652e-02 1.19188485754e-02 8.12698013879e-03 4.88583272697e-03 2.39469075941e-03 8.31956680508e-04 + 1.00716373757e-03 3.42517352397e-03 7.68226949962e-03 1.29197736646e-02 1.80873920150e-02 2.21139454594e-02 + 1.71447894888e-02 1.61922775693e-02 1.43928059315e-02 1.36663321615e-02 1.52138728227e-02 1.64397060008e-02 + 1.41658651127e-02 9.53354409192e-03 5.49363233311e-03 2.85871508179e-03 1.09334977422e-03 3.56844406542e-04 + 1.35478793092e-03 4.04814397514e-03 7.68679429503e-03 1.14873703541e-02 1.46844116271e-02 1.66473756751e-02 + 9.02561259350e-03 7.53963471583e-03 7.33876837864e-03 9.98904777686e-03 1.34954731478e-02 1.36051270833e-02 + 9.91198043096e-03 5.75051322792e-03 3.06675046297e-03 1.44700485940e-03 3.97464784749e-04 4.04266744282e-04 + 1.81253797573e-03 4.08718326208e-03 6.53576731254e-03 8.65509332305e-03 9.93808702708e-03 1.00445711212e-02 + 2.77339544790e-03 2.50008926185e-03 4.78407893613e-03 8.80398075335e-03 1.08349893343e-02 9.01088446511e-03 + 5.63234353441e-03 3.13681377747e-03 1.69364497878e-03 6.73546708496e-04 1.88841719030e-04 7.12336445626e-04 + 1.99206802661e-03 3.40503825591e-03 4.59267338284e-03 5.26233619714e-03 5.09631622942e-03 4.08332572445e-03 + 5.04008819064e-04 2.36946523781e-03 6.02207645825e-03 8.87992998712e-03 8.53177876066e-03 5.95459367556e-03 + 3.53320350817e-03 2.02424836664e-03 9.94296330020e-04 3.14021555844e-04 3.33193974560e-04 9.77814004437e-04 + 1.72507621331e-03 2.27745422092e-03 2.51785823237e-03 2.25805716040e-03 1.46772911419e-03 5.73637201847e-04 + 2.14785317499e-03 5.42818164611e-03 8.61968678385e-03 9.41239204093e-03 7.54188900158e-03 4.89198767693e-03 + 2.84830259776e-03 1.47793891364e-03 6.08384075050e-04 3.53757920201e-04 6.23496814010e-04 9.79904931661e-04 + 1.16484064383e-03 1.15841058185e-03 9.06307741555e-04 4.13571540612e-04 1.54687886896e-05 3.60084369379e-04 + 5.79198514687e-03 8.93980887316e-03 1.05004944969e-02 9.51735448533e-03 6.93722356059e-03 4.30911542633e-03 + 2.35592139656e-03 1.16007202508e-03 6.82408654843e-04 6.97075378309e-04 7.90875887867e-04 7.45828949222e-04 + 5.94211106153e-04 3.73717961329e-04 1.42829753565e-04 1.79742669398e-04 9.41427617586e-04 2.81466185279e-03 + 9.33285526360e-03 1.11303438032e-02 1.08360341113e-02 8.74235576362e-03 6.04646411377e-03 3.73758586507e-03 + 2.21415125373e-03 1.47204481358e-03 1.21289068791e-03 1.03316903152e-03 7.54192083429e-04 4.41629945476e-04 + 1.88976709203e-04 1.01993536089e-04 4.34255934307e-04 1.52755807835e-03 3.56762951719e-03 6.40076883760e-03 + 1.15603067952e-02 1.17003922826e-02 1.01594109423e-02 7.83936822988e-03 5.63840805931e-03 4.01777926046e-03 + 3.02710184183e-03 2.40883205838e-03 1.83530292005e-03 1.19815270712e-03 6.00510371959e-04 1.71561466892e-04 + 5.04465908242e-05 4.76296363279e-04 1.71935199783e-03 3.87640275886e-03 6.72867264593e-03 9.63072703780e-03 + 1.22366932586e-02 1.13981120344e-02 9.75891775141e-03 8.07017991586e-03 6.68771215268e-03 5.61843098956e-03 + 4.64447286191e-03 3.54699712223e-03 2.34260406914e-03 1.22807567701e-03 3.91196832529e-04 8.78376635615e-06 + 3.13240416492e-04 1.49842913576e-03 3.58124038452e-03 6.36070507257e-03 9.31247235432e-03 1.15388363679e-02 + 1.19169146861e-02 1.14025226048e-02 1.07548883058e-02 1.00930193908e-02 9.31394535816e-03 8.20902985918e-03 + 6.61929417576e-03 4.67349658690e-03 2.73580154836e-03 1.14764509804e-03 1.81038868576e-04 1.03563810318e-04 + 1.05342603612e-03 2.91530415150e-03 5.42294384115e-03 8.17927041325e-03 1.05296360366e-02 1.18040369418e-02 + 1.18782215965e-02 1.29046672382e-02 1.37284137262e-02 1.38895325686e-02 1.31308659421e-02 1.13427026756e-02 + 8.69591746390e-03 5.70407004499e-03 2.96795288208e-03 9.85696214277e-04 1.48063203650e-04 6.09033159640e-04 + 2.14126186376e-03 4.31105507767e-03 6.67936448121e-03 8.76639538747e-03 1.01823476975e-02 1.10392564905e-02 + 1.36919522426e-02 1.67109705640e-02 1.86930549009e-02 1.90013888745e-02 1.75498748901e-02 1.45554762332e-02 + 1.05695551699e-02 6.41957522015e-03 2.97689237455e-03 9.30466693471e-04 5.44997511112e-04 1.52943895242e-03 + 3.28495032763e-03 5.24040232287e-03 6.91589404869e-03 8.07079012023e-03 9.09194844199e-03 1.08606109265e-02 + 1.80785606705e-02 2.25134394193e-02 2.47293206267e-02 2.43629275882e-02 2.16918731164e-02 1.72235804655e-02 + 1.17779343789e-02 6.57764510704e-03 2.88479296031e-03 1.31584832436e-03 1.53239392587e-03 2.69805837661e-03 + 4.10657822928e-03 5.30436127846e-03 6.09749953170e-03 6.92766829744e-03 8.93530437563e-03 1.29107289583e-02 + 2.39164393014e-02 2.85410031861e-02 3.00753219871e-02 2.86474692169e-02 2.46903684522e-02 1.87135920049e-02 + 1.19152503262e-02 6.24496162837e-03 3.15685511355e-03 2.50043069581e-03 3.04076043105e-03 3.73060002129e-03 + 4.18258830140e-03 4.43064873947e-03 4.93294557314e-03 6.74481171524e-03 1.09317651765e-02 1.72887774544e-02 + 2.21776244618e-02 2.43609109238e-02 2.46337602542e-02 2.33991009544e-02 2.10924591106e-02 1.83595925548e-02 + 1.59912340968e-02 1.41423855358e-02 1.21611248138e-02 9.55594996473e-03 6.56724608813e-03 3.83045776542e-03 + 2.05066383643e-03 1.90636487418e-03 3.82043510118e-03 7.68882304515e-03 1.28241631178e-02 1.80751252626e-02 + 2.27286825084e-02 2.45108219701e-02 2.50521675401e-02 2.48160452949e-02 2.42785363201e-02 2.37773247032e-02 + 2.27696591477e-02 2.01038424569e-02 1.56328341747e-02 1.04953196709e-02 5.86520329421e-03 2.47124942251e-03 + 9.58258575780e-04 1.78334205368e-03 4.80362941474e-03 9.36659991752e-03 1.45736724225e-02 1.93380979084e-02 + 2.09264645666e-02 2.26542847867e-02 2.42233248819e-02 2.63849792145e-02 2.93863270622e-02 3.15702751276e-02 + 2.99431368439e-02 2.38362906119e-02 1.59493659002e-02 9.04704556937e-03 4.03838119565e-03 1.08385182479e-03 + 5.08445936483e-04 2.30622988925e-03 5.82641576957e-03 1.02265640474e-02 1.46773588148e-02 1.83696998997e-02 + 1.72419950112e-02 1.93702432288e-02 2.29378150848e-02 2.88658755133e-02 3.54561681124e-02 3.76220958928e-02 + 3.21538652508e-02 2.21252692497e-02 1.27533539746e-02 6.18533000488e-03 2.10847527005e-03 2.50502212841e-04 + 6.88447505703e-04 2.97348703525e-03 6.24095295697e-03 9.75632014891e-03 1.29198200282e-02 1.53517699083e-02 + 1.26670328687e-02 1.57754418364e-02 2.20106417184e-02 3.09876847452e-02 3.76530404015e-02 3.59946020820e-02 + 2.67023074499e-02 1.60395288461e-02 8.23434550915e-03 3.43936902949e-03 7.66067413270e-04 5.56938704008e-05 + 1.13958727870e-03 3.26915931020e-03 5.69597367846e-03 7.95427601201e-03 9.73598570607e-03 1.10892262924e-02 + 8.58538753515e-03 1.30699141960e-02 2.10301801893e-02 2.94765489118e-02 3.21589816875e-02 2.66196583261e-02 + 1.73110855616e-02 9.46833854972e-03 4.47494785377e-03 1.51180884620e-03 1.17485925516e-04 2.64705463392e-04 + 1.44279692741e-03 2.92445233759e-03 4.30026186525e-03 5.35602702452e-03 6.04390499855e-03 6.77357888867e-03 + 6.21221520193e-03 1.15903704276e-02 1.87537936854e-02 2.33996673894e-02 2.18486414294e-02 1.57015853750e-02 + 9.30274525008e-03 4.81780918910e-03 2.01272281032e-03 4.11169406150e-04 1.45346689477e-05 5.40426364765e-04 + 1.35115583196e-03 2.06419124290e-03 2.55313328611e-03 2.75883988559e-03 2.89265674941e-03 3.65753963311e-03 + 5.81045661274e-03 1.07724476030e-02 1.51710461085e-02 1.58960220929e-02 1.26369157174e-02 8.10338605038e-03 + 4.49155509459e-03 2.09188673536e-03 6.02123788714e-04 1.71568981581e-05 1.93351194944e-04 6.16552865997e-04 + 9.32512609288e-04 1.07410956233e-03 1.02536386217e-03 9.00425711005e-04 1.15947681115e-03 2.55081428046e-03 + 6.61030809056e-03 1.00154162940e-02 1.15190503659e-02 1.00828526575e-02 6.96268514815e-03 4.01294066812e-03 + 1.92945341409e-03 6.34634372007e-04 7.49557216745e-05 1.15869866528e-04 3.47714247767e-04 4.67213032125e-04 + 4.44087829979e-04 3.10779410209e-04 1.57556583378e-04 3.01930479826e-04 1.22474433139e-03 3.32891895261e-03 + 7.56324657636e-03 9.06057351075e-03 8.56102924730e-03 6.40308044751e-03 3.88677181116e-03 1.92916408716e-03 + 7.34199558083e-04 2.36952784588e-04 2.29230350353e-04 3.46728443666e-04 3.48707456941e-04 2.40707878875e-04 + 9.47165954482e-05 8.66298811160e-06 2.25180573030e-04 1.06736406963e-03 2.70908004643e-03 5.05892800482e-03 + 8.01230588668e-03 7.87948841508e-03 6.35060151281e-03 4.25583941135e-03 2.44611231705e-03 1.28971641581e-03 + 7.77595749084e-04 6.72086093891e-04 6.36616665550e-04 4.85905924848e-04 2.59323735059e-04 6.29607107760e-05 + 1.47034460966e-05 3.18136086776e-04 1.20457158637e-03 2.73172307310e-03 4.71519336008e-03 6.72116812715e-03 + 7.82893033400e-03 6.75349806175e-03 5.11572410353e-03 3.62137728197e-03 2.60436330214e-03 2.05263492169e-03 + 1.75142502111e-03 1.43817040454e-03 1.00553289598e-03 5.34058175670e-04 1.59875148700e-04 2.95559536663e-05 + 3.30051661440e-04 1.21830377075e-03 2.68795166297e-03 4.54912117281e-03 6.42607938150e-03 7.71321376852e-03 + 7.35420874306e-03 6.31024080664e-03 5.34187252089e-03 4.68353276850e-03 4.24033652910e-03 3.77884526013e-03 + 3.10484318539e-03 2.22249483929e-03 1.30573275364e-03 5.48997161845e-04 1.42896046784e-04 2.90174446126e-04 + 1.08794709870e-03 2.43715196755e-03 4.14293478108e-03 5.94475977002e-03 7.37195209888e-03 7.87652673742e-03 + 7.31549810689e-03 7.19144011495e-03 7.22483291669e-03 7.20569907445e-03 6.84471147320e-03 5.93841684105e-03 + 4.55132099545e-03 2.99241829740e-03 1.59542159592e-03 6.45630444064e-04 4.05874389562e-04 9.67495275322e-04 + 2.13019149061e-03 3.60587479630e-03 5.18703656012e-03 6.58701990586e-03 7.40718596642e-03 7.52807874547e-03 + 8.52368668609e-03 9.68716461499e-03 1.05500997018e-02 1.07194457591e-02 9.94511355027e-03 8.25709689095e-03 + 6.03672737436e-03 3.80433127456e-03 2.02896183849e-03 1.09855993551e-03 1.16741735815e-03 1.99296264927e-03 + 3.16325404964e-03 4.41165035708e-03 5.54715377358e-03 6.36161325302e-03 6.88869890722e-03 7.51828850511e-03 + 1.13554899876e-02 1.35927824520e-02 1.48199325319e-02 1.46817476041e-02 1.31482219440e-02 1.05707033754e-02 + 7.56982998411e-03 4.82773842601e-03 2.95268230371e-03 2.24458532773e-03 2.47622612599e-03 3.13725758818e-03 + 3.88444092763e-03 4.56631812745e-03 5.09104781897e-03 5.63652917221e-03 6.75285721161e-03 8.79306676243e-03 + 1.53775558008e-02 1.81302665477e-02 1.91859496338e-02 1.84096380909e-02 1.60917454567e-02 1.28065448968e-02 + 9.31010448321e-03 6.45385772542e-03 4.81538026625e-03 4.26152025060e-03 4.16709969847e-03 4.09350771714e-03 + 3.98459337950e-03 3.91867568976e-03 4.15494850833e-03 5.30108207247e-03 7.87399641135e-03 1.15862806476e-02 + 1.94317156340e-02 2.20818635155e-02 2.26563665530e-02 2.13563447701e-02 1.86517906370e-02 1.51578150734e-02 + 1.17652072335e-02 9.33880158386e-03 7.97307934125e-03 6.98376929778e-03 5.79548164631e-03 4.43922172003e-03 + 3.28302239419e-03 2.78778815645e-03 3.54169835385e-03 6.05020451612e-03 1.02126726307e-02 1.51152257904e-02 + 1.64011126976e-02 1.84882583545e-02 2.03428832374e-02 2.26137034442e-02 2.53425652713e-02 2.76576163841e-02 + 2.80255298082e-02 2.52665766026e-02 1.97538675690e-02 1.32294873705e-02 7.39889996530e-03 3.18872546785e-03 + 1.02848052968e-03 1.06142924201e-03 2.99764851647e-03 6.19137543603e-03 9.93142094392e-03 1.35252362371e-02 + 1.71050024080e-02 2.01594390193e-02 2.43625406350e-02 3.02385457126e-02 3.67596850055e-02 4.09164602305e-02 + 3.94626842492e-02 3.21174469506e-02 2.20335329058e-02 1.27142008113e-02 5.81962773375e-03 1.69652924485e-03 + 3.18653543688e-04 1.29960599452e-03 3.86650604815e-03 7.25489032868e-03 1.08678875869e-02 1.41990018236e-02 + 1.70191620545e-02 2.20878382169e-02 3.00553383112e-02 4.07234206578e-02 5.05656363706e-02 5.35687292562e-02 + 4.66839742672e-02 3.34582388543e-02 2.00809582147e-02 1.00035691470e-02 3.64197696414e-03 5.56365203173e-04 + 2.39421205997e-04 1.86187931120e-03 4.50589860792e-03 7.55154181906e-03 1.06181590645e-02 1.35989425952e-02 + 1.67775857601e-02 2.46816890662e-02 3.68974709324e-02 5.11645950606e-02 6.04485110246e-02 5.79015845790e-02 + 4.45750971878e-02 2.82129287167e-02 1.50468991468e-02 6.49593626011e-03 1.76090853325e-03 4.73748069485e-05 + 5.55650299710e-04 2.29380230151e-03 4.51100114057e-03 6.85264854480e-03 9.26375018931e-03 1.21863148785e-02 + 1.67705384183e-02 2.73175373130e-02 4.19030851866e-02 5.52576183515e-02 5.89845081297e-02 4.99656353245e-02 + 3.41519872257e-02 1.95229541217e-02 9.42800466126e-03 3.46143238835e-03 5.98440331818e-04 4.94959529374e-05 + 8.85453276204e-04 2.26911630302e-03 3.79064869130e-03 5.38421120062e-03 7.36250015616e-03 1.06471651215e-02 + 1.68254863059e-02 2.82121300600e-02 4.10890728250e-02 4.88066641815e-02 4.59389074609e-02 3.45204013574e-02 + 2.14246683432e-02 1.13178691216e-02 4.90850753014e-03 1.41806335288e-03 1.29091146516e-04 2.44821321205e-04 + 9.41555096729e-04 1.77143405044e-03 2.63849306168e-03 3.71119219109e-03 5.61191209839e-03 9.50511823248e-03 + 1.62962435323e-02 2.57867413674e-02 3.36099747130e-02 3.49417224063e-02 2.89342803710e-02 1.96164012522e-02 + 1.12659486442e-02 5.43978619015e-03 1.96341818536e-03 3.79743652405e-04 8.60158144335e-05 3.42110503010e-04 + 7.01315795678e-04 1.06653935518e-03 1.51612354038e-03 2.41377294165e-03 4.54648190837e-03 8.93298483644e-03 + 1.46340746120e-02 2.04277817674e-02 2.30249188099e-02 2.07424619893e-02 1.52015414307e-02 9.35332781263e-03 + 4.84426432924e-03 1.93881467460e-03 4.73944523050e-04 7.29839629344e-05 1.40264506543e-04 2.62419780431e-04 + 3.55698994344e-04 4.74004706047e-04 8.24223779860e-04 1.90721275560e-03 4.37679699978e-03 8.69672053639e-03 + 1.19888677225e-02 1.41981896782e-02 1.35850444133e-02 1.05037883082e-02 6.69192602571e-03 3.52368848278e-03 + 1.41586251461e-03 3.33410664964e-04 3.27135341192e-05 7.47571568536e-05 1.23611292251e-04 1.16277593103e-04 + 1.09449296550e-04 2.41979193857e-04 8.39271441488e-04 2.30774159185e-03 4.85827635143e-03 8.34518992215e-03 + 9.07637997488e-03 8.91698588464e-03 7.07985938792e-03 4.51004547556e-03 2.26622083452e-03 8.10121075017e-04 + 1.33255785214e-04 4.17326189674e-06 7.65133595202e-05 1.06026091426e-04 6.75232411454e-05 3.16338226120e-05 + 1.14193222718e-04 5.45930062566e-04 1.58696200371e-03 3.28861930232e-03 5.44694057069e-03 7.63431340427e-03 + 6.52735301689e-03 5.25234272134e-03 3.39217942468e-03 1.72515158252e-03 6.76693455170e-04 2.50336877489e-04 + 2.12612255941e-04 2.65112899907e-04 2.33325162181e-04 1.31269215162e-04 5.21241211142e-05 1.15433599571e-04 + 5.02046458613e-04 1.37893319496e-03 2.71769953409e-03 4.28213342832e-03 5.74383454955e-03 6.65715445896e-03 + 4.65673770439e-03 3.27813225457e-03 2.06128496186e-03 1.33239567942e-03 1.05343366471e-03 9.92660663244e-04 + 9.08489315276e-04 7.00515720982e-04 4.27623561860e-04 2.07101572964e-04 1.78719995947e-04 5.11286829904e-04 + 1.30240452873e-03 2.45609727013e-03 3.74229032013e-03 4.91205807069e-03 5.64864823143e-03 5.58938422244e-03 + 3.73742709611e-03 3.00646009917e-03 2.66996352066e-03 2.61650545853e-03 2.57313079189e-03 2.31610160014e-03 + 1.81996827436e-03 1.23033402480e-03 7.20903924415e-04 4.61879943880e-04 6.38790321418e-04 1.31844741350e-03 + 2.32752380816e-03 3.40537683661e-03 4.37979344092e-03 5.06525722551e-03 5.18184967595e-03 4.62898825173e-03 + 4.09135850798e-03 4.32076679744e-03 4.69318213761e-03 4.88824805958e-03 4.63250589433e-03 3.89405052582e-03 + 2.90683262810e-03 1.96761318524e-03 1.31960102192e-03 1.17873621932e-03 1.61992903495e-03 2.42639950185e-03 + 3.27195671709e-03 3.99530399321e-03 4.52531429218e-03 4.71853046295e-03 4.52231340661e-03 4.19334489536e-03 + 5.80675403488e-03 6.86670755332e-03 7.59908542689e-03 7.67739028889e-03 6.98340574559e-03 5.74560674939e-03 + 4.38135307871e-03 3.26244387803e-03 2.66422462166e-03 2.68390631721e-03 3.10304948708e-03 3.56134205702e-03 + 3.88734840413e-03 4.07583486757e-03 4.10543194038e-03 4.04142491616e-03 4.18191385713e-03 4.79790996887e-03 + 8.55568262478e-03 1.01358195545e-02 1.09181163176e-02 1.07029669383e-02 9.64424641931e-03 8.18058876849e-03 + 6.77035356312e-03 5.75674994359e-03 5.27028413708e-03 5.09730887158e-03 4.86833767247e-03 4.45519573573e-03 + 3.97212824727e-03 3.52260495612e-03 3.26136956105e-03 3.56214081969e-03 4.72874420659e-03 6.57588716129e-03 + 1.17121965212e-02 1.35123136059e-02 1.42011612578e-02 1.38800009001e-02 1.29667670362e-02 1.18887752002e-02 + 1.09297081847e-02 1.01797300917e-02 9.40376250795e-03 8.21443236381e-03 6.56830029907e-03 4.83021365631e-03 + 3.37444398046e-03 2.47806463352e-03 2.51983828485e-03 3.82391308071e-03 6.22890694124e-03 9.09764148136e-03 + 1.45373471963e-02 1.63836445055e-02 1.72322694842e-02 1.75533783012e-02 1.77738614626e-02 1.79636961148e-02 + 1.78612988525e-02 1.69424757530e-02 1.47242721945e-02 1.13501204126e-02 7.62680673205e-03 4.40275040294e-03 + 2.22324210518e-03 1.48036960338e-03 2.41619379046e-03 4.85407916409e-03 8.18635015851e-03 1.16511277189e-02 + 1.32214190630e-02 1.70182371454e-02 2.23914346298e-02 2.94005341373e-02 3.65883134017e-02 4.10771061480e-02 + 4.01237907162e-02 3.34240994180e-02 2.36076522012e-02 1.40500332982e-02 6.75365834626e-03 2.25088494174e-03 + 3.76975540731e-04 6.13933628779e-04 2.23755063116e-03 4.62068987662e-03 7.35987361584e-03 1.02051495518e-02 + 1.58900192853e-02 2.26118578774e-02 3.23853665475e-02 4.41985743405e-02 5.42606917622e-02 5.73388367325e-02 + 5.09077709744e-02 3.78133073842e-02 2.36204801963e-02 1.22375985232e-02 4.80091803726e-03 1.00310586764e-03 + 5.90161514082e-05 9.76074566842e-04 2.89723662549e-03 5.35352266955e-03 8.16823506164e-03 1.14568566797e-02 + 1.94529153898e-02 3.02123813564e-02 4.50417270437e-02 6.07124954502e-02 7.02985119513e-02 6.77187149759e-02 + 5.38134679499e-02 3.56373795480e-02 1.98430799910e-02 8.97855478432e-03 2.80185055807e-03 2.73646131008e-04 + 1.82511456518e-04 1.40298487435e-03 3.25568500020e-03 5.54426372674e-03 8.44825874064e-03 1.26575872343e-02 + 2.38385853595e-02 3.85473717324e-02 5.67273677570e-02 7.21211274410e-02 7.62095092245e-02 6.58675039683e-02 + 4.69067314436e-02 2.80515191463e-02 1.41081429396e-02 5.58103947065e-03 1.34876862907e-03 6.68171422544e-05 + 4.47881107532e-04 1.58363970481e-03 3.13026027142e-03 5.22108077150e-03 8.49128311407e-03 1.41684304690e-02 + 2.79071785579e-02 4.44080417781e-02 6.15067717055e-02 7.12852197898e-02 6.75835874317e-02 5.24406381653e-02 + 3.39286153411e-02 1.86236154182e-02 8.51606269948e-03 2.93516121467e-03 5.81061062209e-04 1.37058960411e-04 + 5.76855370265e-04 1.41236350319e-03 2.64117424075e-03 4.71994442247e-03 8.66897657164e-03 1.59482397285e-02 + 2.97501907954e-02 4.42867611798e-02 5.56962132111e-02 5.77334216963e-02 4.90209039697e-02 3.45467227113e-02 + 2.06117704701e-02 1.04360100492e-02 4.30780636347e-03 1.32679053985e-03 3.03860804524e-04 2.03940394979e-04 + 4.81770679169e-04 1.03930098797e-03 2.12043260760e-03 4.42967840460e-03 9.12548254654e-03 1.74158054835e-02 + 2.78739321918e-02 3.73718412510e-02 4.17637009214e-02 3.84985092848e-02 2.94785728069e-02 1.90636229222e-02 + 1.04888661314e-02 4.82376281187e-03 1.80482157670e-03 5.78627424839e-04 2.09205377711e-04 1.49724976222e-04 + 2.81205260633e-04 7.22405338384e-04 1.88384671010e-03 4.56289081761e-03 9.66901580784e-03 1.76817819576e-02 + 2.25263155750e-02 2.65605864927e-02 2.60872336677e-02 2.13573141732e-02 1.47554791997e-02 8.66582672258e-03 + 4.27400333312e-03 1.75523476412e-03 6.60909699853e-04 2.78327360241e-04 1.12375150392e-04 4.58824074622e-05 + 1.57259240401e-04 6.82720759625e-04 2.11730881828e-03 5.06135836310e-03 9.83317762172e-03 1.61168112631e-02 + 1.56731157781e-02 1.59636332536e-02 1.35801298523e-02 9.69180807087e-03 5.83654794422e-03 2.93389216434e-03 + 1.22168131524e-03 4.78160140368e-04 2.33457307527e-04 1.13056900591e-04 2.03772103850e-05 1.92815120762e-05 + 2.67006752224e-04 1.07329143891e-03 2.80076766154e-03 5.58500163354e-03 9.19859563930e-03 1.29735543466e-02 + 9.46020891377e-03 8.05580519181e-03 5.65002898561e-03 3.22979937882e-03 1.46350232193e-03 5.04240902167e-04 + 1.60191027688e-04 9.58365167024e-05 6.21297433108e-05 1.22679167967e-05 1.34779380540e-05 1.86799142778e-04 + 7.40751669769e-04 1.88929227335e-03 3.63811143838e-03 5.74289898791e-03 7.81743942747e-03 9.28890115566e-03 + 4.97731915059e-03 3.30061405321e-03 1.67112059926e-03 5.70163115932e-04 8.16197162412e-05 3.96098189336e-06 + 5.49678012011e-05 6.18608218424e-05 2.46119654347e-05 3.03948039932e-05 1.96121257923e-04 6.78155849917e-04 + 1.59383231465e-03 2.86692715110e-03 4.24011738011e-03 5.43116391673e-03 6.14517968726e-03 6.04164917805e-03 + 2.38485472598e-03 1.23679420062e-03 5.47442865571e-04 3.25590526276e-04 3.59633271458e-04 4.06845410151e-04 + 3.52629900781e-04 2.39648399836e-04 1.77914475257e-04 2.95867929730e-04 7.36990216848e-04 1.56027870375e-03 + 2.61976364172e-03 3.64720743875e-03 4.42868549234e-03 4.79603189706e-03 4.55786993721e-03 3.65752002099e-03 + 1.52926161999e-03 1.20102150072e-03 1.23344748689e-03 1.38335314600e-03 1.40724023470e-03 1.22509785477e-03 + 9.42855596591e-04 7.24540094545e-04 7.17233913205e-04 1.05867932841e-03 1.78270642628e-03 2.69612498316e-03 + 3.50421561693e-03 4.03575878019e-03 4.21841145755e-03 3.95366015476e-03 3.22328624576e-03 2.28042275532e-03 + 2.14113749290e-03 2.52142549073e-03 2.92867409920e-03 3.08883670935e-03 2.88306865164e-03 2.44706610707e-03 + 2.03829385095e-03 1.86367042242e-03 2.04872962448e-03 2.59053538526e-03 3.27258092822e-03 3.79759296344e-03 + 4.02992640816e-03 3.97391933537e-03 3.61936140552e-03 3.00623748582e-03 2.37729788247e-03 2.04978644409e-03 + 3.80488225673e-03 4.65015890666e-03 5.19495556690e-03 5.25740014441e-03 4.92007039828e-03 4.48782799524e-03 + 4.24823029243e-03 4.33005297422e-03 4.66011247850e-03 4.96272421857e-03 4.95994948306e-03 4.61922238201e-03 + 4.07249322730e-03 3.40266526949e-03 2.70747335897e-03 2.26006944424e-03 2.33972826540e-03 2.93777399273e-03 + 6.06410758101e-03 7.22294358234e-03 7.88930346614e-03 8.09395269674e-03 8.11724365326e-03 8.24754664505e-03 + 8.56948649589e-03 8.89455437834e-03 8.80742605829e-03 7.98585308339e-03 6.56341729047e-03 4.97527293695e-03 + 3.52993535325e-03 2.39019521685e-03 1.82491975538e-03 2.10726915800e-03 3.16492692833e-03 4.61317888434e-03 + 8.52718757253e-03 1.00226472966e-02 1.11611142851e-02 1.22584771096e-02 1.35701494201e-02 1.49930568984e-02 + 1.60334458750e-02 1.59541502050e-02 1.42390447767e-02 1.11722405526e-02 7.70252852926e-03 4.66962599119e-03 + 2.46481354505e-03 1.31742443877e-03 1.41462207266e-03 2.64058162437e-03 4.54196519442e-03 6.62666715427e-03 + 1.09117918518e-02 1.31050307938e-02 1.56327714911e-02 1.89093432867e-02 2.26945812508e-02 2.59193289069e-02 + 2.70350435225e-02 2.49078403710e-02 1.98525378093e-02 1.35711923171e-02 7.85506925631e-03 3.65403616848e-03 + 1.25360483289e-03 6.65404139599e-04 1.62333209862e-03 3.60018787953e-03 6.05916724865e-03 8.58553549874e-03 + 1.34248171854e-02 2.04065556638e-02 2.99579895854e-02 4.06456343356e-02 4.91893404948e-02 5.16922031093e-02 + 4.63515394048e-02 3.52212919248e-02 2.26418218727e-02 1.21295618760e-02 5.06139638499e-03 1.30184372110e-03 + 6.54077156887e-05 4.22372083279e-04 1.66743900192e-03 3.46459893693e-03 5.76438338536e-03 8.84007338033e-03 + 1.95464004871e-02 3.10306774569e-02 4.55752230602e-02 5.97168227024e-02 6.77269338345e-02 6.51232330029e-02 + 5.26848394944e-02 3.59579444108e-02 2.06979749470e-02 9.74713525917e-03 3.34753470849e-03 5.36523624947e-04 + 2.59298523394e-05 7.44342318882e-04 2.14405699154e-03 4.15949293899e-03 7.12316750585e-03 1.18558891665e-02 + 2.74967269466e-02 4.36420232584e-02 6.19150718789e-02 7.61747408934e-02 7.93064139979e-02 6.90744644757e-02 + 5.04861773255e-02 3.12503260206e-02 1.63096301498e-02 6.83759035477e-03 1.97211915404e-03 2.23829747855e-04 + 1.87852994275e-04 9.91489749719e-04 2.40086461174e-03 4.72341369718e-03 8.80498973279e-03 1.59619685939e-02 + 3.57069378134e-02 5.46215318997e-02 7.27073454591e-02 8.21725528929e-02 7.76343126598e-02 6.12877704276e-02 + 4.08950133065e-02 2.32955036574e-02 1.11934504018e-02 4.28866464406e-03 1.14279128815e-03 1.95507334097e-04 + 3.16471819237e-04 1.02971303674e-03 2.46730513050e-03 5.35207217745e-03 1.09649994805e-02 2.07853112891e-02 + 4.13540774225e-02 5.91089280522e-02 7.21232821266e-02 7.39047065310e-02 6.33019672420e-02 4.57165366255e-02 + 2.82328301965e-02 1.49975433682e-02 6.76831924421e-03 2.51927620062e-03 7.43897458891e-04 2.12327540652e-04 + 2.97084662728e-04 9.30458510693e-04 2.56960785683e-03 6.25614051117e-03 1.33998714818e-02 2.51450203520e-02 + 4.16763830930e-02 5.43024572829e-02 5.98469959084e-02 5.54295929438e-02 4.33473198176e-02 2.89708220480e-02 + 1.67288742656e-02 8.40215729808e-03 3.72407819847e-03 1.49634406461e-03 5.24437011147e-04 1.42873692211e-04 + 1.95249976383e-04 9.01576210579e-04 2.94134670541e-03 7.43431553293e-03 1.54779610635e-02 2.73825069665e-02 + 3.59616014341e-02 4.20419738355e-02 4.16159507566e-02 3.49667929620e-02 2.51732573408e-02 1.56812321019e-02 + 8.54808242344e-03 4.21287020546e-03 2.00415228670e-03 9.21650367714e-04 3.19691846459e-04 3.18442711627e-05 + 1.74475752795e-04 1.13521512331e-03 3.65158157725e-03 8.56944870389e-03 1.62963344943e-02 2.61841003415e-02 + 2.63708741167e-02 2.74166884138e-02 2.43232755542e-02 1.85706364175e-02 1.23230843643e-02 7.18765354396e-03 + 3.82071041505e-03 2.01380850232e-03 1.09739912579e-03 5.26673434555e-04 1.37210281033e-04 1.26655301409e-05 + 3.94989163510e-04 1.72616075420e-03 4.53662363939e-03 9.11692433674e-03 1.51942116571e-02 2.16271673838e-02 + 1.63770431635e-02 1.49471560716e-02 1.17347785492e-02 8.02619821395e-03 4.86212204656e-03 2.71576292665e-03 + 1.53469236072e-03 9.33177102700e-04 5.42236927936e-04 2.34301156594e-04 7.04931452675e-05 2.23066694400e-04 + 9.71942768010e-04 2.61021849603e-03 5.24288835727e-03 8.68306433372e-03 1.23898230409e-02 1.53530753636e-02 + 8.47891610692e-03 6.52515153077e-03 4.30376961185e-03 2.49191374164e-03 1.35170074227e-03 7.86831919390e-04 + 5.25156358570e-04 3.39907337321e-04 1.74488306603e-04 9.55296694379e-05 2.35164834530e-04 7.82237489532e-04 + 1.88981405186e-03 3.52255559546e-03 5.46063883479e-03 7.40040074721e-03 8.90114418843e-03 9.37626500506e-03 + 3.45169668488e-03 1.97947808654e-03 8.94263024123e-04 3.33682714425e-04 1.62278433362e-04 1.38382313866e-04 + 9.77688590934e-05 3.36924091294e-05 3.81678443316e-05 2.38486915864e-04 7.74360919219e-04 1.70995550218e-03 + 2.91975412865e-03 4.14597761613e-03 5.15983837723e-03 5.76205179511e-03 5.71015719071e-03 4.86657810835e-03 + 9.93367325712e-04 2.99812132466e-04 3.31032606638e-05 3.81102001502e-05 1.02123667796e-04 9.98015726909e-05 + 5.55994677548e-05 8.32502579855e-05 3.16986939871e-04 8.77278618219e-04 1.77695538262e-03 2.82841679709e-03 + 3.74575618204e-03 4.33538686558e-03 4.49923671156e-03 4.14318919008e-03 3.25752852484e-03 2.07541182860e-03 + 4.34780372224e-04 3.84503037790e-04 5.19626904962e-04 6.33506637119e-04 6.19000773618e-04 5.36641503703e-04 + 5.42448009711e-04 7.82849093950e-04 1.34944966609e-03 2.20932237388e-03 3.13946866204e-03 3.84821963159e-03 + 4.17775363332e-03 4.09780379534e-03 3.58926353856e-03 2.69908293383e-03 1.67152477990e-03 8.51387333216e-04 + 1.08645167963e-03 1.42690283172e-03 1.70518891162e-03 1.79330688645e-03 1.75071402873e-03 1.78491551982e-03 + 2.08436638467e-03 2.70474073398e-03 3.52104541563e-03 4.24686577035e-03 4.61375194893e-03 4.55704089392e-03 + 4.14902904326e-03 3.44035899689e-03 2.51145180029e-03 1.60750582890e-03 1.02900237496e-03 8.89364125708e-04 + 2.43871613194e-03 3.04836094495e-03 3.48185988198e-03 3.76700996505e-03 4.10893804463e-03 4.71759146107e-03 + 5.61363648661e-03 6.53801535281e-03 7.04090939788e-03 6.81722659707e-03 5.97230263790e-03 4.83247590230e-03 + 3.61053622951e-03 2.42416068271e-03 1.50080259898e-03 1.10262025814e-03 1.26171749419e-03 1.78195773951e-03 + 4.23110746574e-03 5.22458194847e-03 6.20008495029e-03 7.36346360248e-03 8.87174982624e-03 1.06208392403e-02 + 1.21420392357e-02 1.26978314869e-02 1.17716702997e-02 9.59961674929e-03 6.97522228228e-03 4.55351208645e-03 + 2.61187901541e-03 1.32886053102e-03 8.83980611600e-04 1.23753991515e-03 2.09761565530e-03 3.15910378215e-03 + 6.42201300043e-03 8.27741900663e-03 1.07040190235e-02 1.38859847792e-02 1.75078593286e-02 2.06802000486e-02 + 2.21267580103e-02 2.08395648827e-02 1.69894878413e-02 1.19608923775e-02 7.26260416559e-03 3.68643042940e-03 + 1.44632640874e-03 5.47185416275e-04 8.02744715677e-04 1.82851664667e-03 3.23979252973e-03 4.79541143701e-03 + 9.27103425332e-03 1.29885944609e-02 1.82518550148e-02 2.47618576445e-02 3.11232387611e-02 3.50911472916e-02 + 3.45973341484e-02 2.93141866755e-02 2.11870815960e-02 1.29902000102e-02 6.56326663720e-03 2.46121599225e-03 + 5.22015189670e-04 2.75927164133e-04 1.14039021038e-03 2.63749714918e-03 4.49296367921e-03 6.62855310192e-03 + 1.68221764596e-02 2.75390241118e-02 4.04666704279e-02 5.22497308971e-02 5.82907788216e-02 5.55141492198e-02 + 4.49352270228e-02 3.09537617171e-02 1.80840542292e-02 8.72336838805e-03 3.19229787488e-03 6.67190030790e-04 + 7.83802368547e-06 3.39503688133e-04 1.25927604608e-03 2.75359631848e-03 5.20938150280e-03 9.52737603732e-03 + 2.69806716640e-02 4.27662419131e-02 5.95278042899e-02 7.14842462854e-02 7.30024566107e-02 6.30578103184e-02 + 4.62574680116e-02 2.89935352643e-02 1.54298540736e-02 6.72415064923e-03 2.17744292802e-03 3.93411965319e-04 + 9.18267394395e-05 5.53887343941e-04 1.64772442561e-03 3.75623634389e-03 7.82573244582e-03 1.52114611050e-02 + 3.86817428132e-02 5.80676571044e-02 7.52710747474e-02 8.29669846451e-02 7.71273168759e-02 6.06765090709e-02 + 4.08531626887e-02 2.37301904380e-02 1.17982354600e-02 4.86622929480e-03 1.56251776272e-03 3.57118322689e-04 + 1.88883424506e-04 6.69424900259e-04 2.04483771083e-03 5.19933864493e-03 1.15525394617e-02 2.25468585240e-02 + 4.85432625318e-02 6.77387936050e-02 8.05773400491e-02 8.09255235203e-02 6.86645396924e-02 4.97814892006e-02 + 3.13032123918e-02 1.72282890684e-02 8.29792172624e-03 3.48181991974e-03 1.24876351772e-03 3.56870911456e-04 + 1.81728206183e-04 7.26400616963e-04 2.64142045293e-03 7.21197271181e-03 1.59855357604e-02 2.99925647742e-02 + 5.25387903798e-02 6.70500986128e-02 7.25366358738e-02 6.64423333091e-02 5.19825343637e-02 3.52785201899e-02 + 2.11136696314e-02 1.13337135639e-02 5.58141229051e-03 2.55701857995e-03 1.01900311873e-03 2.59464709288e-04 + 1.08799104418e-04 9.13282288699e-04 3.61942604041e-03 9.60767969539e-03 2.00831575666e-02 3.51413174204e-02 + 4.85381160892e-02 5.60828149943e-02 5.51380487649e-02 4.64517653115e-02 3.39856653402e-02 2.19605150822e-02 + 1.28294156042e-02 7.03944848926e-03 3.76063505693e-03 1.88874334695e-03 7.34754196730e-04 9.74061313919e-05 + 1.34254177692e-04 1.41822846263e-03 4.95131770464e-03 1.18009312521e-02 2.24161123141e-02 3.57484661782e-02 + 3.81206397226e-02 3.97789809252e-02 3.57500042913e-02 2.80340852800e-02 1.94855524326e-02 1.22826510874e-02 + 7.32899061692e-03 4.35678754944e-03 2.55682718546e-03 1.31065943412e-03 4.31576805774e-04 2.56534902457e-05 + 4.38155249967e-04 2.28780672639e-03 6.30548399319e-03 1.29408296000e-02 2.18311325716e-02 3.12309087766e-02 + 2.54501112940e-02 2.40020573628e-02 1.98531838859e-02 1.46736889129e-02 9.91845938557e-03 6.38480573271e-03 + 4.13100496926e-03 2.70793781930e-03 1.65647107904e-03 8.08672105937e-04 2.47215854393e-04 2.23741792948e-04 + 1.12552592912e-03 3.35808210408e-03 7.16105729264e-03 1.24218904847e-02 1.83587742652e-02 2.33209276398e-02 + 1.43495764870e-02 1.21648230860e-02 9.28132148647e-03 6.58344387895e-03 4.53266463496e-03 3.17475450028e-03 + 2.27245161829e-03 1.56050525861e-03 9.37697113489e-04 4.66970848604e-04 3.37644377713e-04 8.22500472309e-04 + 2.13379227526e-03 4.29410693549e-03 7.16680408588e-03 1.04262681199e-02 1.33383763482e-02 1.48569553272e-02 + 6.60446800316e-03 4.91243059304e-03 3.44784370745e-03 2.44834433500e-03 1.85009455033e-03 1.44606886476e-03 + 1.07368083715e-03 7.12280097930e-04 4.46188636244e-04 4.25183582022e-04 8.40443538058e-04 1.79710952109e-03 + 3.18900429836e-03 4.79268815127e-03 6.40848968275e-03 7.76271081912e-03 8.40026200227e-03 7.96365929153e-03 + 2.22856691495e-03 1.34569673414e-03 8.66175143925e-04 6.85775550530e-04 6.01090419239e-04 4.70417164479e-04 + 3.03510901791e-04 2.15735156768e-04 3.57641426424e-04 8.70286781961e-04 1.77970146135e-03 2.90313354827e-03 + 3.96224314329e-03 4.77336252596e-03 5.22743716742e-03 5.17403598081e-03 4.51158952231e-03 3.39951265779e-03 + 3.74694622193e-04 1.12535123639e-04 8.26931701037e-05 1.12223443513e-04 8.41380057421e-05 1.88454027053e-05 + 4.57441361991e-05 3.20604819650e-04 9.55914451883e-04 1.92084745499e-03 2.97916591395e-03 3.82560543107e-03 + 4.28714277241e-03 4.31686635641e-03 3.88335443830e-03 3.01941750858e-03 1.94558147739e-03 9.91483447602e-04 + 4.42964637545e-05 9.59678471026e-05 1.73221855004e-04 1.82210530620e-04 1.66868648776e-04 2.84319152761e-04 + 6.95755029875e-04 1.46947419227e-03 2.50132565125e-03 3.50447796384e-03 4.17512478322e-03 4.38446041939e-03 + 4.14898145458e-03 3.50167566829e-03 2.52754130777e-03 1.47004749016e-03 6.35194148216e-04 1.75676078030e-04 + 5.21657268098e-04 7.23266016193e-04 8.61466967034e-04 9.89415109390e-04 1.29387103134e-03 1.95552993099e-03 + 2.99232054943e-03 4.17467113765e-03 5.09560902032e-03 5.43952220653e-03 5.19104462656e-03 4.51805384299e-03 + 3.55631440324e-03 2.42762979030e-03 1.36586209378e-03 6.35385413134e-04 3.26780006375e-04 3.41452518997e-04 + 1.49742782168e-03 1.94080513341e-03 2.46810159643e-03 3.27758849410e-03 4.53298536084e-03 6.17728291709e-03 + 7.81316294243e-03 8.79591266064e-03 8.66488758273e-03 7.53147907223e-03 5.89433413399e-03 4.17050006406e-03 + 2.58224917480e-03 1.33596234634e-03 6.26297335640e-04 4.62815337871e-04 6.70712246943e-04 1.05781216974e-03 + 3.00050179971e-03 4.16484019366e-03 5.91635085905e-03 8.39203111418e-03 1.13600415169e-02 1.41425753413e-02 + 1.57146312567e-02 1.52459807688e-02 1.28229528012e-02 9.41782220764e-03 6.07182706379e-03 3.35401673152e-03 + 1.48437111273e-03 5.29686260603e-04 3.74458534366e-04 7.46089375176e-04 1.38131462718e-03 2.13340757877e-03 + 5.44189303916e-03 8.35214030988e-03 1.26346441757e-02 1.79139755978e-02 2.30468765183e-02 2.63368827304e-02 + 2.62442031546e-02 2.25212613557e-02 1.65881755268e-02 1.04718832284e-02 5.54847051531e-03 2.28570169675e-03 + 6.04000568971e-04 1.54375288803e-04 4.99331558559e-04 1.28600231196e-03 2.32020342700e-03 3.60557596462e-03 + 9.71162682964e-03 1.58322140630e-02 2.40431179047e-02 3.28588901511e-02 3.96074019427e-02 4.14478461592e-02 + 3.72126558504e-02 2.85145944271e-02 1.86047096205e-02 1.01956121189e-02 4.45001319444e-03 1.30950642600e-03 + 1.24774780309e-04 1.46031282136e-04 8.42750620757e-04 1.96597959110e-03 3.51219389669e-03 5.83857042160e-03 + 2.23594738546e-02 3.62779734079e-02 5.07683353254e-02 6.05111713430e-02 6.08181459381e-02 5.15244485525e-02 + 3.71327929925e-02 2.29879850681e-02 1.21936555003e-02 5.41778169125e-03 1.92237854802e-03 4.88284317956e-04 + 1.07035238816e-04 2.76753722399e-04 9.27942989217e-04 2.41596773596e-03 5.66739414067e-03 1.19967886887e-02 + 3.60536506595e-02 5.45814265095e-02 7.03937936079e-02 7.63414975218e-02 6.93597604478e-02 5.32983268813e-02 + 3.52460246638e-02 2.03301584548e-02 1.02440297615e-02 4.48801255702e-03 1.70666828511e-03 5.53800293951e-04 + 1.92193169154e-04 3.72218936873e-04 1.38295705356e-03 4.12367200218e-03 1.00219507826e-02 2.05119152736e-02 + 4.98364107820e-02 6.95716968250e-02 8.18105836900e-02 8.04417284504e-02 6.65593386489e-02 4.72409596581e-02 + 2.94405950813e-02 1.64078086149e-02 8.29772480571e-03 3.88383558644e-03 1.68974301411e-03 6.18083307153e-04 + 1.72016135285e-04 4.52182255406e-04 2.20875589911e-03 6.80697484643e-03 1.58467903430e-02 3.04386888555e-02 + 5.85075533588e-02 7.43644835987e-02 7.92827016571e-02 7.10728104092e-02 5.44576557810e-02 3.66025477218e-02 + 2.21981877316e-02 1.24933277019e-02 6.71646374861e-03 3.48465748288e-03 1.63368518916e-03 5.28604789756e-04 + 6.46165909733e-05 7.18531099617e-04 3.61007710507e-03 1.02464053944e-02 2.19510383236e-02 3.89106112875e-02 + 5.79014409674e-02 6.65396853545e-02 6.45710938983e-02 5.35825042856e-02 3.89244205228e-02 2.55201272949e-02 + 1.56570322109e-02 9.33856362438e-03 5.49972602133e-03 3.05256628444e-03 1.37638881480e-03 2.97614442691e-04 + 5.07623780114e-05 1.39364804345e-03 5.52800851282e-03 1.36703448925e-02 2.63913325048e-02 4.25051516087e-02 + 4.83265798268e-02 5.03500402380e-02 4.50875179631e-02 3.54194293631e-02 2.51036771353e-02 1.66584281865e-02 + 1.08169074740e-02 7.04128147043e-03 4.44015218877e-03 2.45874348334e-03 9.65368821172e-04 1.09130271137e-04 + 3.58623429044e-04 2.52426390190e-03 7.50847141081e-03 1.58875479000e-02 2.72731027854e-02 3.94315362200e-02 + 3.43220002239e-02 3.27822570379e-02 2.76477066038e-02 2.11456839912e-02 1.51726158777e-02 1.06590383981e-02 + 7.55055256119e-03 5.27735741188e-03 3.38593104403e-03 1.77838178830e-03 6.04629853624e-04 2.09122070981e-04 + 1.11595845469e-03 3.86642183125e-03 8.81669194540e-03 1.58967655644e-02 2.40837841428e-02 3.10848426132e-02 + 2.09386738414e-02 1.86136516892e-02 1.51698682289e-02 1.17297529814e-02 8.92784530565e-03 6.85324487410e-03 + 5.22182239703e-03 3.74590704540e-03 2.35955335176e-03 1.19272761065e-03 5.34898858357e-04 7.78931074355e-04 + 2.22623926386e-03 4.96282765400e-03 8.91494534540e-03 1.36943882658e-02 1.82189720392e-02 2.09413874366e-02 + 1.09456620102e-02 9.22737565408e-03 7.54873916749e-03 6.21347680218e-03 5.19601741202e-03 4.29533131224e-03 + 3.35556413366e-03 2.38074474520e-03 1.49114441241e-03 9.09686505992e-04 9.43681663596e-04 1.78489156363e-03 + 3.35097980673e-03 5.44480629194e-03 7.88527483175e-03 1.02748465993e-02 1.18667832858e-02 1.20526872491e-02 + 4.78705229787e-03 3.96065518533e-03 3.45902260578e-03 3.16972129560e-03 2.86469397273e-03 2.40305382667e-03 + 1.82968909931e-03 1.29637465977e-03 9.93063911622e-04 1.13491646156e-03 1.82708601993e-03 2.91328492323e-03 + 4.11541388550e-03 5.26618582317e-03 6.23898685617e-03 6.76847979827e-03 6.59461669218e-03 5.79695336752e-03 + 1.65204039960e-03 1.44435889860e-03 1.44388740181e-03 1.44477539881e-03 1.29184122103e-03 1.00865012591e-03 + 7.62475315086e-04 7.53039550106e-04 1.13930437585e-03 1.93365606976e-03 2.91711026294e-03 3.78117100804e-03 + 4.35517642123e-03 4.59193923617e-03 4.42889033567e-03 3.83864639279e-03 2.98705568899e-03 2.18154474203e-03 + 3.74647149042e-04 4.03092021298e-04 4.57032236329e-04 4.14951217546e-04 2.91032908959e-04 2.44764122441e-04 + 4.77344253129e-04 1.11402798165e-03 2.09152820661e-03 3.12413157387e-03 3.88077407408e-03 4.20595485328e-03 + 4.09951956095e-03 3.58119208000e-03 2.72341007109e-03 1.75769160159e-03 9.76298765812e-04 5.25781774323e-04 + 3.56988799359e-05 7.19321438699e-05 4.57392321665e-05 1.67544373334e-07 1.13968125233e-04 5.87877141789e-04 + 1.49795893306e-03 2.68753074954e-03 3.78874159238e-03 4.44964076523e-03 4.55562884334e-03 4.17939681866e-03 + 3.41632356393e-03 2.39337045097e-03 1.35725009427e-03 5.77314042839e-04 1.56205913022e-04 2.02855200658e-05 + 1.92934527061e-04 2.48224571369e-04 3.48578196820e-04 7.09727500467e-04 1.54590119435e-03 2.88044986324e-03 + 4.42050565122e-03 5.63381215391e-03 6.09371836438e-03 5.76571151460e-03 4.89026980524e-03 3.70851598842e-03 + 2.42241992643e-03 1.28235581332e-03 5.07644356891e-04 1.35279024729e-04 4.91317660182e-05 1.07027358353e-04 + 8.13540981583e-04 1.25187750238e-03 2.13997419456e-03 3.69037826581e-03 5.84272507921e-03 8.12431941773e-03 + 9.72023616843e-03 9.95770888011e-03 8.83385056223e-03 6.91265720244e-03 4.79096777280e-03 2.85639432413e-03 + 1.37630406045e-03 4.97102192012e-04 1.56300252119e-04 1.58297581819e-04 3.26197326082e-04 5.51361031029e-04 + 2.28579257697e-03 4.00495584135e-03 6.81342458095e-03 1.05208395210e-02 1.43538036912e-02 1.70391633429e-02 + 1.73917401081e-02 1.52262964361e-02 1.15158411879e-02 7.55249045745e-03 4.20799545527e-03 1.86785993650e-03 + 5.75460424775e-04 1.08969310777e-04 1.45301696181e-04 4.34942427888e-04 8.43085573674e-04 1.37692802111e-03 + 5.56281011020e-03 9.96996297391e-03 1.60484383982e-02 2.26610552738e-02 2.77751785018e-02 2.92428101330e-02 + 2.62757520521e-02 2.01738246237e-02 1.32684299313e-02 7.38766745207e-03 3.32248059027e-03 1.06374333455e-03 + 1.49788604544e-04 2.97057139122e-05 3.28294487043e-04 8.63054094313e-04 1.63347267590e-03 2.97282175203e-03 + 1.19621939720e-02 2.06105901434e-02 3.10125588349e-02 4.03122115451e-02 4.47898808898e-02 4.22235832154e-02 + 3.37907380699e-02 2.30833773639e-02 1.34441575244e-02 6.52448220454e-03 2.47626285519e-03 6.12619057170e-04 + 3.98584129979e-05 1.29385117851e-04 6.05615452229e-04 1.45380533560e-03 3.03081929272e-03 6.20203132130e-03 + 2.76399541934e-02 4.30682398622e-02 5.64483708586e-02 6.11179799037e-02 5.43902614433e-02 4.03612349559e-02 + 2.56721240349e-02 1.43797557410e-02 7.25443704239e-03 3.42248104460e-03 1.59954789012e-03 7.40379415119e-04 + 3.09223914621e-04 1.93086024367e-04 6.60723855918e-04 2.50176720863e-03 6.92112694610e-03 1.51108460239e-02 + 4.31957387133e-02 6.17445174060e-02 7.30975777050e-02 7.08618585022e-02 5.67731834434e-02 3.87164696435e-02 + 2.33811602913e-02 1.30063220575e-02 6.95406514366e-03 3.74219962957e-03 2.02217851510e-03 9.69256079202e-04 + 2.99110584413e-04 1.95157834626e-04 1.38975455739e-03 5.11088113161e-03 1.27597601309e-02 2.55258668004e-02 + 5.64606784653e-02 7.29686478208e-02 7.75280973123e-02 6.78700778011e-02 5.01922065994e-02 3.27274692661e-02 + 1.97809606242e-02 1.16424606641e-02 6.93716875206e-03 4.17106298787e-03 2.33091267904e-03 9.73537427798e-04 + 1.33666146838e-04 3.81791315826e-04 2.84206333585e-03 8.89793567975e-03 1.98866037273e-02 3.64593746789e-02 + 6.09972695746e-02 7.06688437313e-02 6.78197110032e-02 5.48746650290e-02 3.89021635600e-02 2.54659930472e-02 + 1.62757039593e-02 1.05716130594e-02 6.94684262767e-03 4.34057379906e-03 2.27683224380e-03 7.09574680197e-04 + 5.65800526198e-07 1.03575988756e-03 5.03992470913e-03 1.32040475870e-02 2.63486416703e-02 4.37365843277e-02 + 5.44134639286e-02 5.68247078530e-02 5.03579904306e-02 3.90658861666e-02 2.78206243646e-02 1.92436431009e-02 + 1.35199319436e-02 9.64303554335e-03 6.62026972814e-03 4.02103726066e-03 1.85123406704e-03 3.69913395971e-04 + 1.92745133664e-04 2.27225033253e-03 7.55468301924e-03 1.66796196502e-02 2.94749448901e-02 4.36857942023e-02 + 4.07484644887e-02 3.91762281505e-02 3.32214580945e-02 2.58613870385e-02 1.94320982340e-02 1.47398183049e-02 + 1.13574844524e-02 8.50504973561e-03 5.79202228167e-03 3.29434303932e-03 1.29937438706e-03 2.77251447553e-04 + 9.09837989766e-04 3.85534273907e-03 9.50339503068e-03 1.78013157822e-02 2.76713540210e-02 3.64247527421e-02 + 2.63726711423e-02 2.41341652758e-02 2.04728376934e-02 1.67829251960e-02 1.37991476673e-02 1.14674279537e-02 + 9.30470041635e-03 6.99236563336e-03 4.60577324574e-03 2.45164267465e-03 9.70880828350e-04 7.04924479658e-04 + 2.07661772729e-03 5.21926480418e-03 1.00388908019e-02 1.60474265144e-02 2.19230374295e-02 2.57644144204e-02 + 1.51851368243e-02 1.38080726899e-02 1.23139360729e-02 1.10428424365e-02 9.94115810235e-03 8.70253215584e-03 + 7.11364530862e-03 5.24432491401e-03 3.35460249735e-03 1.83427141462e-03 1.16692131575e-03 1.67196566912e-03 + 3.30151190024e-03 5.83880626364e-03 9.04509213113e-03 1.23731963131e-02 1.48633567796e-02 1.57693490755e-02 + 7.96772049772e-03 7.60764916938e-03 7.45446686871e-03 7.33635890143e-03 6.94892149818e-03 6.11011031050e-03 + 4.90174981042e-03 3.55711051411e-03 2.37999622819e-03 1.75342740340e-03 1.93998590513e-03 2.83220342327e-03 + 4.12267685771e-03 5.61464357983e-03 7.12558053051e-03 8.27068594905e-03 8.68832827510e-03 8.44723722070e-03 + 3.93361474245e-03 4.17523589746e-03 4.52508974131e-03 4.67888488060e-03 4.41259923854e-03 3.76720091362e-03 + 2.97668515533e-03 2.31287349905e-03 2.04066450965e-03 2.30674325143e-03 2.96672243833e-03 3.70531276820e-03 + 4.33303908699e-03 4.78802713955e-03 4.96014765932e-03 4.75954888981e-03 4.33065054515e-03 3.98538587735e-03 + 1.89159777326e-03 2.25818430515e-03 2.56402875287e-03 2.59347253226e-03 2.32065672831e-03 1.94512636223e-03 + 1.74213192297e-03 1.91855493982e-03 2.49244786184e-03 3.22597331652e-03 3.79540981343e-03 4.04914707082e-03 + 3.99103003411e-03 3.61886057282e-03 2.96977917950e-03 2.26332421826e-03 1.79269663811e-03 1.68713538652e-03 + 8.48155257953e-04 1.05263225289e-03 1.11567585491e-03 1.01204776795e-03 9.06224940895e-04 1.05547405991e-03 + 1.63327884324e-03 2.56957756266e-03 3.52210753788e-03 4.11295282088e-03 4.20924577948e-03 3.88548122213e-03 + 3.22479819449e-03 2.32721987137e-03 1.43240736497e-03 8.21137107528e-04 5.89367741321e-04 6.44738849819e-04 + 2.67320498244e-04 2.54798814601e-04 1.86034578323e-04 2.50190925189e-04 6.97004412716e-04 1.65258965004e-03 + 2.95444069056e-03 4.15273343977e-03 4.80072263646e-03 4.76940113328e-03 4.20396502746e-03 3.28759784858e-03 + 2.19861830767e-03 1.19025159053e-03 5.01278108907e-04 1.84775279615e-04 1.29450993638e-04 1.96496572381e-04 + 2.55915322274e-05 2.46400291222e-05 2.91582796660e-04 1.09797235985e-03 2.53393787967e-03 4.32402262496e-03 + 5.83813754875e-03 6.48667128293e-03 6.15525287723e-03 5.13716471752e-03 3.77834160197e-03 2.36549050618e-03 + 1.18661361944e-03 4.37613967386e-04 9.55429380802e-05 4.95847074885e-06 2.45261720709e-05 5.09930074221e-05 + 3.92094703888e-04 1.06438460742e-03 2.50180912228e-03 4.75145893539e-03 7.41337682862e-03 9.57916164656e-03 + 1.03087068943e-02 9.39280307700e-03 7.41263483943e-03 5.10540711136e-03 2.98539096169e-03 1.39083154059e-03 + 4.65436395546e-04 8.44394100960e-05 4.14720982601e-06 4.81138232368e-05 1.17914997000e-04 1.84911800890e-04 + 2.15916790700e-03 4.60887009683e-03 8.27690829975e-03 1.25938272372e-02 1.62333015691e-02 1.75784044539e-02 + 1.59859427096e-02 1.23594597343e-02 8.21274791876e-03 4.62927999637e-03 2.10274258165e-03 6.94830579758e-04 + 1.23602952848e-04 2.03091782620e-07 6.94011435470e-05 2.11003802303e-04 4.12244619404e-04 9.00180709309e-04 + 6.56661086880e-03 1.21782192645e-02 1.91932402373e-02 2.57379218731e-02 2.90369508707e-02 2.73334140279e-02 + 2.15809756270e-02 1.44814482730e-02 8.28551821101e-03 3.95407501317e-03 1.50173027690e-03 4.19121119276e-04 + 7.46434105332e-05 5.93543094293e-05 2.03444373090e-04 4.89326739662e-04 1.19242273020e-03 2.98265598557e-03 + 1.48789730311e-02 2.50999567189e-02 3.60449362861e-02 4.34827869831e-02 4.34844834452e-02 3.60702620700e-02 + 2.52036836956e-02 1.51043759800e-02 7.81066315137e-03 3.47697927674e-03 1.35669858601e-03 4.88492768760e-04 + 1.85577799263e-04 1.55811144618e-04 3.64924880503e-04 1.09688597851e-03 3.12662494737e-03 7.48101490195e-03 + 2.90120465805e-02 4.30853284811e-02 5.21175408623e-02 5.02000656867e-02 3.88097463970e-02 2.51123525819e-02 + 1.45616372413e-02 8.22453682227e-03 4.94035630723e-03 3.28387303784e-03 2.24426507919e-03 1.36360315623e-03 + 5.69709816408e-04 8.16077367919e-05 5.44647341807e-04 2.87375035075e-03 7.89345414468e-03 1.64682859167e-02 + 4.35901829695e-02 5.81918774803e-02 6.22621890421e-02 5.33039441720e-02 3.78173638677e-02 2.38419814204e-02 + 1.45986981313e-02 9.39270548250e-03 6.52632326243e-03 4.64649367492e-03 3.04969673746e-03 1.56758317861e-03 + 3.78722619620e-04 8.09626434922e-05 1.64187696752e-03 5.99613746937e-03 1.40875674170e-02 2.69309354929e-02 + 5.31477254174e-02 6.28491028750e-02 5.99276806772e-02 4.72018102582e-02 3.26637034799e-02 2.16516109269e-02 + 1.48612633227e-02 1.08515221674e-02 8.09108601200e-03 5.68211604375e-03 3.38854641618e-03 1.36477777943e-03 + 1.03047331129e-04 5.12557017721e-04 3.58782508736e-03 1.01472429661e-02 2.11057371412e-02 3.66158748505e-02 + 5.19649026232e-02 5.47422182952e-02 4.80605621656e-02 3.69231914580e-02 2.67771572800e-02 1.97454361036e-02 + 1.52782273369e-02 1.20261675403e-02 9.00530273271e-03 5.96245745379e-03 3.11854436183e-03 9.09137341960e-04 + 8.12599914572e-05 1.59246943536e-03 6.17680281514e-03 1.43410924331e-02 2.63254153962e-02 4.05460046417e-02 + 4.14571221859e-02 4.02002918258e-02 3.44178942374e-02 2.76263199491e-02 2.21456053736e-02 1.83264630426e-02 + 1.53465892430e-02 1.22935089701e-02 8.88363395116e-03 5.43297152676e-03 2.45360690265e-03 5.78412825440e-04 + 6.12905889523e-04 3.21680622942e-03 8.63629238376e-03 1.68017067415e-02 2.69071336873e-02 3.63843027435e-02 + 2.83642214672e-02 2.68056217438e-02 2.39066458158e-02 2.10610284007e-02 1.88221118892e-02 1.68636734419e-02 + 1.44924509817e-02 1.13792630317e-02 7.81878857360e-03 4.41599118004e-03 1.83265758813e-03 7.60485339739e-04 + 1.72431957871e-03 4.83216828002e-03 9.84517612818e-03 1.61878020082e-02 2.25708133952e-02 2.70711519917e-02 + 1.78241120029e-02 1.75113568648e-02 1.70417863153e-02 1.66067453926e-02 1.60086718204e-02 1.47604482574e-02 + 1.25396904239e-02 9.51857110990e-03 6.24320009186e-03 3.40740898518e-03 1.71006530283e-03 1.59332364024e-03 + 3.03324816152e-03 5.71924826419e-03 9.24951003792e-03 1.29620954658e-02 1.59192939637e-02 1.74903801402e-02 + 1.09523235908e-02 1.17447199902e-02 1.25841652079e-02 1.31571536713e-02 1.30265314469e-02 1.18937171121e-02 + 9.83823408326e-03 7.25292452762e-03 4.71851997409e-03 2.91130852086e-03 2.28497838118e-03 2.76390093572e-03 + 3.96448339059e-03 5.58537756938e-03 7.34557817869e-03 8.82426365770e-03 9.75441036390e-03 1.03358586324e-02 + 6.88051704182e-03 8.15708656846e-03 9.34419985195e-03 9.98897560498e-03 9.76046632566e-03 8.67449437873e-03 + 7.02503782333e-03 5.23360560603e-03 3.81653520614e-03 3.17474130801e-03 3.25838986272e-03 3.68904318297e-03 + 4.19905779072e-03 4.69094701298e-03 5.03579201586e-03 5.17253974451e-03 5.33713335979e-03 5.87569587132e-03 + 4.49230662737e-03 5.69134895434e-03 6.62495847078e-03 6.94130281880e-03 6.56578748676e-03 5.73002588109e-03 + 4.78224051661e-03 4.07060405417e-03 3.81632768224e-03 3.91542462175e-03 4.04070777532e-03 4.00132730334e-03 + 3.79901364950e-03 3.43406883220e-03 2.94579977844e-03 2.59496310461e-03 2.71785700678e-03 3.40593342349e-03 + 2.93395216015e-03 3.73354624820e-03 4.20223802111e-03 4.21544205262e-03 3.92690806015e-03 3.64933585129e-03 + 3.65496176041e-03 3.99920772029e-03 4.42231284056e-03 4.55532626517e-03 4.27830082614e-03 3.71453856313e-03 + 2.96770755673e-03 2.11546293736e-03 1.39765570939e-03 1.12968670673e-03 1.40559160399e-03 2.07708219386e-03 + 1.73164945820e-03 2.05703898335e-03 2.15790105939e-03 2.16085256311e-03 2.33254042095e-03 2.89468325650e-03 + 3.81189177871e-03 4.69371170943e-03 5.05490830862e-03 4.74600996535e-03 3.97616844295e-03 2.98346859145e-03 + 1.92373895359e-03 1.01423946346e-03 5.08006713379e-04 4.76665522352e-04 7.84140490299e-04 1.25427557108e-03 + 7.35510819877e-04 7.47372166137e-04 8.52965511812e-04 1.31518946741e-03 2.30190176436e-03 3.69543295303e-03 + 5.00193893760e-03 5.62942980160e-03 5.36590780904e-03 4.45017200825e-03 3.23137719868e-03 1.98090698652e-03 + 9.51032086670e-04 3.37194479473e-04 1.45595143144e-04 2.29835826428e-04 4.33680980723e-04 6.34376563063e-04 + 1.04363259493e-04 2.84907132700e-04 9.94248201380e-04 2.38495354371e-03 4.27898289975e-03 6.03664111853e-03 + 6.87313179615e-03 6.50529203111e-03 5.28039238466e-03 3.70965058942e-03 2.17930967539e-03 9.90572963509e-04 + 3.10231330687e-04 6.46246133334e-05 5.59366715520e-05 1.30818926071e-04 1.87229699795e-04 1.56365000478e-04 + 4.16289854059e-04 1.51144814959e-03 3.46010115688e-03 6.08746794965e-03 8.60943467858e-03 9.83452122573e-03 + 9.17822224485e-03 7.18187633814e-03 4.79900082331e-03 2.67952432145e-03 1.15904091907e-03 3.43304867115e-04 + 6.26364293216e-05 3.22189829831e-05 6.82157163539e-05 8.01572039943e-05 2.60615440106e-05 2.84843277750e-05 + 2.53892301825e-03 5.38473210717e-03 9.25328358301e-03 1.32605295181e-02 1.55921780061e-02 1.48469518056e-02 + 1.15574696038e-02 7.51362028547e-03 4.09081230223e-03 1.79478670354e-03 6.04634248872e-04 1.82571363138e-04 + 1.02501743084e-04 1.07921265873e-04 1.00154261214e-04 5.59511612204e-05 1.57166997861e-04 8.50059554231e-04 + 7.39446959603e-03 1.31145180968e-02 1.97025901120e-02 2.45787481578e-02 2.47950525028e-02 2.01322637316e-02 + 1.34184784062e-02 7.53842495314e-03 3.62540127981e-03 1.55190673037e-03 7.06250879293e-04 4.24032192258e-04 + 3.00088357925e-04 1.96403903701e-04 9.84358832072e-05 2.20425168354e-04 1.12890379899e-03 3.41294788231e-03 + 1.60628726446e-02 2.60075865888e-02 3.52230432000e-02 3.86278083733e-02 3.38088371050e-02 2.39838128094e-02 + 1.43554751750e-02 7.63639482653e-03 3.87605910054e-03 2.11591751711e-03 1.34314617562e-03 8.92896175879e-04 + 5.15162162710e-04 1.90614461510e-04 1.44637804683e-04 1.00974589153e-03 3.57238945733e-03 8.43684618133e-03 + 2.39501384635e-02 3.33174859001e-02 3.59027838527e-02 2.96692333224e-02 1.98498753631e-02 1.23091727361e-02 + 8.40376268176e-03 6.75014559847e-03 5.87728795009e-03 4.93598044839e-03 3.67786847327e-03 2.21341767860e-03 + 8.04027613092e-04 1.59887380787e-05 6.06808849388e-04 2.91178285931e-03 7.12035623595e-03 1.40697022014e-02 + 3.42280507364e-02 4.14694415455e-02 3.91301009462e-02 2.99430537544e-02 2.08106981993e-02 1.51521779858e-02 + 1.22898894631e-02 1.06006266102e-02 8.95940518454e-03 6.90391420001e-03 4.52889190756e-03 2.18537294660e-03 + 4.39830384030e-04 1.34419453908e-04 1.86167993936e-03 5.74568484533e-03 1.23437190242e-02 2.24575744430e-02 + 3.79913728917e-02 4.04135000342e-02 3.53582606830e-02 2.78050794822e-02 2.20353020243e-02 1.86094890617e-02 + 1.63599934032e-02 1.41551349570e-02 1.13642435878e-02 8.01883259633e-03 4.59669129910e-03 1.71711457333e-03 + 1.96015692353e-04 8.34606382264e-04 3.87782902404e-03 9.37607959775e-03 1.78088774251e-02 2.86587493459e-02 + 3.31060135036e-02 3.26793305796e-02 2.92666291330e-02 2.58410643714e-02 2.34274221447e-02 2.15548916765e-02 + 1.94232624194e-02 1.63863059943e-02 1.23720897807e-02 7.96600218830e-03 3.96944801363e-03 1.18654876008e-03 + 4.44097695772e-04 2.19616782753e-03 6.29252296490e-03 1.25146494565e-02 2.05216046421e-02 2.84981294434e-02 + 2.44041619370e-02 2.46866533939e-02 2.46043791835e-02 2.45225898710e-02 2.41545572602e-02 2.30289421382e-02 + 2.06073371487e-02 1.66825860597e-02 1.17912048980e-02 6.94185855014e-03 3.10467513127e-03 1.07838225171e-03 + 1.36088816579e-03 3.86317448436e-03 8.04728607992e-03 1.32757687425e-02 1.85969518947e-02 2.25914862075e-02 + 1.72781081808e-02 1.93888337247e-02 2.15202656266e-02 2.30676712481e-02 2.35492508171e-02 2.24936348478e-02 + 1.95755185412e-02 1.50872387991e-02 1.00100894031e-02 5.53799483487e-03 2.61413140403e-03 1.69813296949e-03 + 2.67962790183e-03 5.03271628376e-03 8.09541547056e-03 1.11736902140e-02 1.36667793938e-02 1.55092738172e-02 + 1.29365735137e-02 1.60452573109e-02 1.89146340008e-02 2.08552733145e-02 2.13226707661e-02 1.99208008554e-02 + 1.66810128711e-02 1.22708403340e-02 7.83936573961e-03 4.53205878736e-03 2.92961213985e-03 2.85305544920e-03 + 3.74376532223e-03 5.10441227635e-03 6.52859553200e-03 7.71078686755e-03 8.78697957577e-03 1.03907242659e-02 + 1.02472192466e-02 1.34075780969e-02 1.60991447096e-02 1.76670744349e-02 1.76519536394e-02 1.59523214651e-02 + 1.29101961609e-02 9.32339285969e-03 6.26252638257e-03 4.47606412682e-03 3.88364178036e-03 3.88572284724e-03 + 4.04580230057e-03 4.22097529149e-03 4.34952724538e-03 4.57866901892e-03 5.43040269212e-03 7.36861601657e-03 + 8.21634431071e-03 1.08642288543e-02 1.28795513517e-02 1.37509987622e-02 1.33085714570e-02 1.17419927690e-02 + 9.51430515104e-03 7.34056559346e-03 5.87725681509e-03 5.17867415497e-03 4.75808586982e-03 4.23622425740e-03 + 3.59373323654e-03 2.92822781849e-03 2.41361119023e-03 2.46352229018e-03 3.50963754916e-03 5.56666243126e-03 + 6.39388494969e-03 8.26517283633e-03 9.47058900180e-03 9.78105668381e-03 9.31750724324e-03 8.40181459346e-03 + 7.43947140501e-03 6.77242398374e-03 6.36633090172e-03 5.83732694907e-03 4.95514083015e-03 3.84012341219e-03 + 2.68624972556e-03 1.66216525550e-03 1.08806481359e-03 1.34301460290e-03 2.50817420887e-03 4.32231476261e-03 + 4.64616297678e-03 5.72499619873e-03 6.30544934870e-03 6.45786534130e-03 6.44884236825e-03 6.55018635910e-03 + 6.85672504746e-03 7.10359750370e-03 6.81347217951e-03 5.81634822989e-03 4.40451671111e-03 2.93879526431e-03 + 1.62722671683e-03 6.95379254448e-04 4.24165011003e-04 8.98370759739e-04 1.93664350094e-03 3.27766494936e-03 + 2.98367941142e-03 3.46042054687e-03 3.82311194246e-03 4.30790616595e-03 5.11063944458e-03 6.20438083853e-03 + 7.17241532764e-03 7.37940258012e-03 6.54981287580e-03 5.01961007270e-03 3.32387867479e-03 1.81366766463e-03 + 7.06704613311e-04 1.75372783674e-04 2.39164195540e-04 7.40769646083e-04 1.48350078183e-03 2.29137696883e-03 + 1.53314870093e-03 1.84610256873e-03 2.53594330367e-03 3.75000623930e-03 5.37334400202e-03 6.89134273280e-03 + 7.55413295321e-03 6.97756911737e-03 5.46640704113e-03 3.63893367707e-03 1.98044230747e-03 7.78097683267e-04 + 1.56039651725e-04 4.40568997236e-05 2.57044846501e-04 6.28420284683e-04 1.02436513775e-03 1.32633874146e-03 + 7.19903482351e-04 1.46297216516e-03 2.89654946479e-03 4.90686674823e-03 6.90849938419e-03 7.94320783679e-03 + 7.45457365611e-03 5.80563076872e-03 3.78997301635e-03 2.00274363364e-03 7.56468496382e-04 1.41283314652e-04 + 9.20384791516e-06 1.17988814994e-04 3.06449127554e-04 4.71423061922e-04 5.22935133873e-04 5.12439265410e-04 + 1.11604851579e-03 2.67514186804e-03 4.99133844967e-03 7.59722397641e-03 9.25360168648e-03 8.86960521443e-03 + 6.74746507622e-03 4.14522989170e-03 2.01256904922e-03 6.74736905086e-04 1.01713216941e-04 3.27312442073e-05 + 1.46227704277e-04 2.64496081803e-04 3.12527126912e-04 2.31862120160e-04 1.18137825469e-04 3.08601349151e-04 + 2.97254489858e-03 5.64870848338e-03 9.08296300698e-03 1.19351253795e-02 1.21924507008e-02 9.50744095938e-03 + 5.71491633034e-03 2.66024220099e-03 9.20986573311e-04 2.74040044455e-04 2.44597107831e-04 3.76951577142e-04 + 4.45360909911e-04 3.97111725549e-04 2.08498054399e-04 1.84134283331e-05 2.42236757059e-04 1.20652054041e-03 + 6.69906085105e-03 1.13604779428e-02 1.62077518895e-02 1.81974263603e-02 1.54590933546e-02 9.96868246164e-03 + 5.09636322734e-03 2.29555094729e-03 1.21878621791e-03 1.04601202440e-03 1.09179877945e-03 1.01932358485e-03 + 7.80625995526e-04 3.95995177117e-04 3.44409863193e-05 1.92945998171e-04 1.30278986819e-03 3.41429667333e-03 + 1.35636077516e-02 2.11513860932e-02 2.64107382318e-02 2.51558778833e-02 1.82374367088e-02 1.06803441251e-02 + 5.84085425648e-03 3.70595620585e-03 3.02937936022e-03 2.76573932377e-03 2.36920571355e-03 1.73933849482e-03 + 9.51672719469e-04 2.09419676226e-04 6.09868350370e-05 1.10322524602e-03 3.48538637918e-03 7.43798090788e-03 + 1.39376331350e-02 1.69127654979e-02 1.49769196684e-02 1.07162975343e-02 8.47525926614e-03 8.81437361311e-03 + 9.83229494765e-03 1.02008542348e-02 9.48886903210e-03 7.76056155069e-03 5.42998844432e-03 2.98257607661e-03 + 9.85800807160e-04 1.81551648153e-04 8.06315962624e-04 2.33533142403e-03 4.72754018793e-03 8.75630987176e-03 + 1.81302940474e-02 1.90533281411e-02 1.68008907247e-02 1.52937481580e-02 1.59077655692e-02 1.69535529606e-02 + 1.70445546180e-02 1.58200330749e-02 1.32636241342e-02 9.73659208124e-03 5.94335917410e-03 2.63296477703e-03 + 6.21175028169e-04 4.84758972561e-04 1.91675038920e-03 4.35621515405e-03 8.11486883519e-03 1.34120892006e-02 + 1.78048351998e-02 1.85057067653e-02 1.96111864138e-02 2.20485146589e-02 2.41488926714e-02 2.45668099334e-02 + 2.32121378824e-02 2.01611836221e-02 1.56145293597e-02 1.03752420933e-02 5.52646513913e-03 2.02262179254e-03 + 6.12418709633e-04 1.38848110896e-03 3.64898479161e-03 6.85350348990e-03 1.09727554873e-02 1.52301421904e-02 + 1.50008567926e-02 1.85122233959e-02 2.35902193495e-02 2.80271220394e-02 3.00535908476e-02 2.96093369548e-02 + 2.69668391885e-02 2.21764633484e-02 1.59031110990e-02 9.56949621362e-03 4.53448957310e-03 1.66221968956e-03 + 1.24956054146e-03 2.81280658231e-03 5.39261303124e-03 8.25897846311e-03 1.09216594101e-02 1.29842931460e-02 + 1.35825601861e-02 1.99514904929e-02 2.65506735915e-02 3.09545539663e-02 3.25136273950e-02 3.14227406161e-02 + 2.76121809270e-02 2.13729699906e-02 1.41374399177e-02 7.81351564680e-03 3.66420429266e-03 2.01655155920e-03 + 2.46062789957e-03 4.09473388846e-03 5.93521407886e-03 7.31372562879e-03 8.21425844618e-03 9.73050494537e-03 + 1.39008728119e-02 2.09444466445e-02 2.70082604756e-02 3.07098685481e-02 3.17523898285e-02 2.99016967391e-02 + 2.50323820037e-02 1.80956453354e-02 1.11690185294e-02 6.14472603634e-03 3.63418092973e-03 3.10116623899e-03 + 3.61994416238e-03 4.37946432498e-03 4.82656877112e-03 4.90911289501e-03 5.52338070999e-03 8.28087145979e-03 + 1.41211570863e-02 2.02787818991e-02 2.51617492097e-02 2.79414396260e-02 2.81584556575e-02 2.54623467378e-02 + 2.01634734401e-02 1.38206037457e-02 8.58090167143e-03 5.62802488758e-03 4.56077115562e-03 4.27431888227e-03 + 4.01387188573e-03 3.54932177285e-03 2.97048887177e-03 2.85419449760e-03 4.33208079043e-03 8.25391771966e-03 + 1.32732336011e-02 1.80803094841e-02 2.16306727318e-02 2.32693821517e-02 2.26140643491e-02 1.96336114406e-02 + 1.50869944524e-02 1.06219012878e-02 7.70254746555e-03 6.39581512891e-03 5.69022757602e-03 4.76316539307e-03 + 3.51327615688e-03 2.23906786538e-03 1.43134967947e-03 1.83407832021e-03 4.11098476771e-03 8.21601970828e-03 + 1.14603792687e-02 1.48700391488e-02 1.71011799657e-02 1.77772567468e-02 1.68471662055e-02 1.45939939960e-02 + 1.18440644827e-02 9.67126227150e-03 8.41713371411e-03 7.45067626615e-03 6.10610522586e-03 4.33765900356e-03 + 2.50363165477e-03 1.06665779401e-03 5.84001417900e-04 1.54996982689e-03 4.02706712861e-03 7.57321401029e-03 + 9.12459803425e-03 1.12864940650e-02 1.25420167245e-02 1.28830004800e-02 1.25042621527e-02 1.17266690611e-02 + 1.09649054064e-02 1.03175375964e-02 9.34879567884e-03 7.68462626122e-03 5.50560856946e-03 3.27601541766e-03 + 1.41129024315e-03 3.11731976851e-04 3.40891357724e-04 1.56994130933e-03 3.73317784835e-03 6.41952984784e-03 + 6.71332345225e-03 7.97295539642e-03 8.83806375092e-03 9.52542566034e-03 1.02146950176e-02 1.09257951563e-02 + 1.13542562873e-02 1.08930158185e-02 9.22000092978e-03 6.73244341066e-03 4.14871813185e-03 1.98512519846e-03 + 5.42168783236e-04 2.47712879770e-05 4.44606212492e-04 1.59522161804e-03 3.21725775258e-03 5.03833677141e-03 + 4.53696878441e-03 5.41927287301e-03 6.52840495085e-03 8.00501035413e-03 9.71657041701e-03 1.11387500818e-02 + 1.14523906706e-02 1.01724220411e-02 7.68112840025e-03 4.87598994750e-03 2.48241244276e-03 8.51940877148e-04 + 8.45407249449e-05 8.30176453145e-05 6.26445265586e-04 1.51312274360e-03 2.57752032729e-03 3.62685542010e-03 + 2.94511729787e-03 4.09350335195e-03 5.89617065745e-03 8.15301187265e-03 1.02256913612e-02 1.11442919391e-02 + 1.02775459051e-02 7.95280147634e-03 5.13599155978e-03 2.67644958481e-03 1.00229525196e-03 1.84473592480e-04 + 3.66319170585e-05 2.88882905231e-04 7.56908851666e-04 1.31879190717e-03 1.84375836529e-03 2.30790453763e-03 + 2.39848530650e-03 4.16642642439e-03 6.61287639564e-03 9.14049964706e-03 1.05854298051e-02 9.99838109577e-03 + 7.66381324915e-03 4.78454896666e-03 2.37338000795e-03 8.39931095061e-04 1.67561352273e-04 8.15495981761e-05 + 2.58850180740e-04 5.24842668493e-04 7.96999910467e-04 9.76767156147e-04 1.08532127198e-03 1.42977082804e-03 + 2.80839032745e-03 4.97931969058e-03 7.67202066037e-03 9.78562967387e-03 9.75759123040e-03 7.38242706605e-03 + 4.19317861400e-03 1.71153422228e-03 4.04123739449e-04 4.88522496584e-05 1.99183841763e-04 4.51012819931e-04 + 6.35929911154e-04 7.28587442280e-04 6.76442851119e-04 5.34582026431e-04 6.49308468939e-04 1.37422445357e-03 + 3.52751404593e-03 5.92905812085e-03 8.58655784113e-03 9.57562452361e-03 7.58666801100e-03 4.02250133383e-03 + 1.24176529122e-03 1.00783605569e-04 1.40592723549e-04 6.31450836021e-04 1.03333410488e-03 1.16283184155e-03 + 1.07099609808e-03 7.82028966574e-04 3.90447944053e-04 2.93490088853e-04 8.27096460031e-04 1.90720320301e-03 + 4.87505972449e-03 7.89398002452e-03 1.00910165440e-02 9.01681183719e-03 5.21152124093e-03 1.85101441507e-03 + 6.70926844938e-04 1.07347966654e-03 1.91496313700e-03 2.45387057704e-03 2.45402452681e-03 2.04254185619e-03 + 1.37144785339e-03 5.94734031064e-04 1.64419885712e-04 5.09802732965e-04 1.44517092877e-03 2.76231554550e-03 + 8.35563225402e-03 1.20669831186e-02 1.25990812684e-02 9.01468567443e-03 4.83215906545e-03 3.17929380547e-03 + 3.70641445135e-03 4.76836979215e-03 5.33175502239e-03 5.06100866681e-03 4.10058228765e-03 2.76502694806e-03 + 1.33289628590e-03 3.00002876531e-04 2.65316574894e-04 1.15341702151e-03 2.53518792535e-03 4.75023723186e-03 + 4.12368548933e-03 3.37306388143e-03 3.34610664515e-03 6.67954373977e-03 1.19918970688e-02 1.59848713841e-02 + 1.74379020831e-02 1.67091714427e-02 1.42442187476e-02 1.06375053547e-02 6.74199309547e-03 3.36031710579e-03 + 1.25535327017e-03 8.22912714846e-04 1.40854295750e-03 2.03421376429e-03 2.65942072377e-03 3.60752069339e-03 + 4.51331902058e-03 6.17516417595e-03 1.17378157448e-02 1.95804799359e-02 2.52957622525e-02 2.71173172791e-02 + 2.59941057893e-02 2.27555777496e-02 1.77847067327e-02 1.19937890097e-02 6.66169655785e-03 2.83758131037e-03 + 1.15346346066e-03 1.36288481501e-03 2.31165294259e-03 3.13183850888e-03 3.81492345271e-03 4.31281316929e-03 + 5.96134556949e-03 1.32429968266e-02 2.39787366828e-02 3.26545687339e-02 3.61605709708e-02 3.55479373292e-02 + 3.22998996260e-02 2.66694798543e-02 1.92229917609e-02 1.16659750018e-02 5.74327755930e-03 2.37353664799e-03 + 1.57424432669e-03 2.41326003560e-03 3.52882548095e-03 4.06579418505e-03 3.89221853874e-03 3.72856190105e-03 + 1.02993701055e-02 2.20953807119e-02 3.37179786810e-02 4.03928775935e-02 4.19732980827e-02 4.01552400206e-02 + 3.52920405867e-02 2.73415006756e-02 1.79434014323e-02 9.79690113811e-03 4.60243411781e-03 2.49587526328e-03 + 2.60920069718e-03 3.57597048464e-03 4.10087235933e-03 3.54389751122e-03 2.53130732077e-03 3.67225998458e-03 + 1.59167089976e-02 2.81155811637e-02 3.75993586740e-02 4.23810878340e-02 4.32847505534e-02 4.06893476199e-02 + 3.40234907738e-02 2.41749343595e-02 1.43133933818e-02 7.41517604801e-03 4.15563620919e-03 3.43923441993e-03 + 3.77566812108e-03 3.94321828547e-03 3.22414329745e-03 1.85884453280e-03 1.75185518295e-03 6.02758092813e-03 + 1.95737068215e-02 2.95857281099e-02 3.67209170369e-02 4.04051596531e-02 4.06563672027e-02 3.66927765543e-02 + 2.83971027238e-02 1.83082586530e-02 1.02757396512e-02 6.13565241376e-03 4.91185277988e-03 4.69788761743e-03 + 4.23707457860e-03 3.11220359900e-03 1.56856713769e-03 7.79834183726e-04 2.88289884632e-03 9.50672599419e-03 + 2.01648783008e-02 2.76747489676e-02 3.29293858145e-02 3.53837385084e-02 3.43186324178e-02 2.90634789457e-02 + 2.08053828527e-02 1.29502630084e-02 8.31038436101e-03 6.74640549539e-03 6.27645105570e-03 5.35942564110e-03 + 3.68072891500e-03 1.72326340600e-03 4.11220520635e-04 1.05923318293e-03 4.86161044113e-03 1.17981175238e-02 + 1.84093023722e-02 2.37330889784e-02 2.71913787538e-02 2.81816396468e-02 2.61238657902e-02 2.11731079400e-02 + 1.52436850279e-02 1.09547270715e-02 9.09871389781e-03 8.31938504998e-03 7.09430244513e-03 5.00220568978e-03 + 2.54284114549e-03 6.06190023334e-04 1.64827344651e-04 1.98176221086e-03 6.19854413088e-03 1.21153542974e-02 + 1.53048824846e-02 1.87602423888e-02 2.07273252279e-02 2.09428756986e-02 1.93365352204e-02 1.65041392276e-02 + 1.38292485273e-02 1.21850229525e-02 1.09992654280e-02 9.27597029515e-03 6.75608371207e-03 3.88245608400e-03 + 1.39269429434e-03 7.31334512584e-05 4.91385657771e-04 2.73142868257e-03 6.42237559541e-03 1.09045273671e-02 + 1.17927741869e-02 1.39266304703e-02 1.52490522982e-02 1.58717409072e-02 1.59230614876e-02 1.56593233720e-02 + 1.52035820930e-02 1.41158715399e-02 1.19044343599e-02 8.77083377689e-03 5.40179842392e-03 2.47639252786e-03 + 5.60523009018e-04 4.64939928678e-05 9.59443515652e-04 3.00248820143e-03 5.80639087152e-03 8.93128545725e-03 + 8.66513735619e-03 1.02471825616e-02 1.18551946666e-02 1.36316032639e-02 1.54069440628e-02 1.66371481307e-02 + 1.64685826568e-02 1.43745915671e-02 1.08212875312e-02 6.90345115081e-03 3.53792871809e-03 1.22828826368e-03 + 1.79397681911e-04 3.03345778839e-04 1.29465588360e-03 2.87315885619e-03 4.82724869706e-03 6.85760768150e-03 + 6.42291103144e-03 8.25893377018e-03 1.07470815621e-02 1.36442705476e-02 1.61558403433e-02 1.70977321742e-02 + 1.56570628009e-02 1.22073264490e-02 8.03781717615e-03 4.35804598915e-03 1.79559159705e-03 4.80947599290e-04 + 2.07938798123e-04 6.19675210675e-04 1.44767994042e-03 2.55428000068e-03 3.79476386176e-03 5.04547537048e-03 + 5.46500921949e-03 8.10561505040e-03 1.14831696109e-02 1.47440623913e-02 1.64968215556e-02 1.56499592243e-02 + 1.24540129443e-02 8.31347573666e-03 4.61509537486e-03 2.05788053466e-03 7.28465317529e-04 3.37591043242e-04 + 4.82694841036e-04 9.00797590406e-04 1.48028048963e-03 2.12633571899e-03 2.81316744218e-03 3.78299950545e-03 + 5.75310388715e-03 9.04606843221e-03 1.26707221921e-02 1.51609996344e-02 1.49280053090e-02 1.18925542698e-02 + 7.70633322142e-03 4.11266422443e-03 1.84119760539e-03 8.06544126958e-04 5.69991497064e-04 6.73353239016e-04 + 8.81069546015e-04 1.13452632092e-03 1.37182352140e-03 1.60223398176e-03 2.13031628844e-03 3.42361883850e-03 + 6.15596677412e-03 9.34753074518e-03 1.23050102887e-02 1.30691478765e-02 1.06185242812e-02 6.48046746567e-03 + 3.01875608645e-03 1.22471526065e-03 7.80750806818e-04 9.78034967128e-04 1.23720306784e-03 1.34354087950e-03 + 1.33992010182e-03 1.24238958869e-03 1.08998225602e-03 1.21146727737e-03 2.03109161448e-03 3.67991121669e-03 + 5.46929412944e-03 7.88130438297e-03 9.36297968784e-03 8.04682489196e-03 4.54496845012e-03 1.56319200428e-03 + 5.67835430828e-04 1.04253322517e-03 1.93432377986e-03 2.50923996477e-03 2.54892965808e-03 2.22688813124e-03 + 1.71633865474e-03 1.12402783631e-03 8.09611273434e-04 1.19100164105e-03 2.18103036991e-03 3.55029935650e-03 + 4.15437447032e-03 5.43223433246e-03 4.91487153366e-03 2.32460092521e-03 2.35976882732e-04 5.06171591309e-04 + 2.32419244671e-03 4.15387052265e-03 5.13345959551e-03 5.06723538287e-03 4.24270255829e-03 3.06669100213e-03 + 1.80530292414e-03 8.66281526153e-04 7.62536507912e-04 1.35353740268e-03 2.05164180565e-03 2.85443603945e-03 + 3.67820710717e-03 3.59689688604e-03 1.74123318750e-03 5.27236161405e-04 2.24948409541e-03 5.71227730402e-03 + 8.59972032333e-03 9.91706511634e-03 9.62051235246e-03 8.05724276122e-03 5.83314421670e-03 3.49994970909e-03 + 1.57755458636e-03 7.06630094501e-04 9.57095016309e-04 1.52667736327e-03 1.97045489908e-03 2.68343038842e-03 diff --git a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/result.ref b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/result.ref index 40989e00449..9fda46ebbbd 100644 --- a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/result.ref +++ b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/result.ref @@ -1,8 +1,8 @@ -etotref -197.4062591802142 -etotperatomref -98.7031295901 +etotref -197.4062600935836 +etotperatomref -98.7031300468 pchgi4s1_cube_compare 0 pchgi1s1.cube 1.999994607 pchgi2s1.cube 1.999994607 pchgi3s1.cube 1.999994607 pchgi4s1.cube 1.999994607 -totaltimeref 0.23 +totaltimeref 0.34 diff --git a/tests/01_PW/087_PW_get_pchg_kpar_bndpar/threshold b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/threshold new file mode 100644 index 00000000000..b8c87bb4db4 --- /dev/null +++ b/tests/01_PW/087_PW_get_pchg_kpar_bndpar/threshold @@ -0,0 +1 @@ +pchg_threshold 1e-6 diff --git a/tests/01_PW/089_PW_get_wf_kpar_bndpar/INPUT b/tests/01_PW/089_PW_get_wf_kpar_bndpar/INPUT index 9833e7da833..e810ba0a24a 100644 --- a/tests/01_PW/089_PW_get_wf_kpar_bndpar/INPUT +++ b/tests/01_PW/089_PW_get_wf_kpar_bndpar/INPUT @@ -10,7 +10,8 @@ pseudo_dir ../../PP_ORB #Parameters (2.Iteration) ecutwfc 20 -scf_thr 1e-9 +scf_thr 1e-13 +pw_diag_thr 1e-12 scf_nmax 100 #Parameters (3.Basis) diff --git a/tests/01_PW/089_PW_get_wf_kpar_bndpar/result.ref b/tests/01_PW/089_PW_get_wf_kpar_bndpar/result.ref index a4417941264..89cd25c6df5 100644 --- a/tests/01_PW/089_PW_get_wf_kpar_bndpar/result.ref +++ b/tests/01_PW/089_PW_get_wf_kpar_bndpar/result.ref @@ -1,67 +1,67 @@ -etotref -203.8996350848297 -etotperatomref -101.9498175424 -wfi1s1k1.cube 15.53408854 -wfi1s1k2.cube 13.88248279 -wfi4s1k1.cube 12.07618293 -wfi4s1k2.cube 12.56532441 +etotref -203.8996350929646 +etotperatomref -101.9498175465 +wfi1s1k1.cube 15.53408972 +wfi1s1k2.cube 13.88248579 +wfi4s1k1.cube 12.0762079 +wfi4s1k2.cube 12.56531145 wfi4s1k1_wfc_fp_components 1 wfi4s1k1_wfc_fp_nx 24 wfi4s1k1_wfc_fp_ny 24 wfi4s1k1_wfc_fp_nz 24 wfi4s1k1_wfc_fp_voxel 1.919140625000e-02 wfi4s1k1_wfc_fp_rms 6.139453834168e-02 -wfi4s1k1_wfc_fp_power_0 2.019077861556e+00 -wfi4s1k1_wfc_fp_power_1 1.008593934742e+00 -wfi4s1k1_wfc_fp_power_2 2.661152084727e-01 -wfi4s1k1_wfc_fp_power_3 3.885797455412e+00 -wfi4s1k1_wfc_fp_power_4 1.232001753595e+00 -wfi4s1k1_wfc_fp_power_5 2.270953097645e-01 -wfi4s1k1_wfc_fp_power_6 4.552630852640e-01 -wfi4s1k1_wfc_fp_power_7 2.690420391410e-01 -wfi4s1k1_wfc_fp_cross_0_re -1.424657687089e+00 -wfi4s1k1_wfc_fp_cross_0_im -8.234172427052e-02 -wfi4s1k1_wfc_fp_cross_1_re 3.694861343575e-01 -wfi4s1k1_wfc_fp_cross_1_im -3.631558642313e-01 -wfi4s1k1_wfc_fp_cross_2_re 2.962066809499e-01 -wfi4s1k1_wfc_fp_cross_2_im 9.727956630712e-01 -wfi4s1k1_wfc_fp_cross_3_re 2.168938439364e+00 -wfi4s1k1_wfc_fp_cross_3_im -2.881238022710e-01 -wfi4s1k1_wfc_fp_cross_4_re -9.812917447141e-02 -wfi4s1k1_wfc_fp_cross_4_im -5.197619503011e-01 -wfi4s1k1_wfc_fp_cross_5_re -2.602989780532e-01 -wfi4s1k1_wfc_fp_cross_5_im 1.887658692583e-01 -wfi4s1k1_wfc_fp_cross_6_re -3.450029786543e-01 -wfi4s1k1_wfc_fp_cross_6_im -5.880351626178e-02 -wfi4s1k1_wfc_fp_cross_7_re 1.616174873993e-01 -wfi4s1k1_wfc_fp_cross_7_im -7.190943003698e-01 +wfi4s1k1_wfc_fp_power_0 2.019155944307e+00 +wfi4s1k1_wfc_fp_power_1 1.008552114608e+00 +wfi4s1k1_wfc_fp_power_2 2.661108024561e-01 +wfi4s1k1_wfc_fp_power_3 3.885874531110e+00 +wfi4s1k1_wfc_fp_power_4 1.231986575798e+00 +wfi4s1k1_wfc_fp_power_5 2.271122236067e-01 +wfi4s1k1_wfc_fp_power_6 4.552680486160e-01 +wfi4s1k1_wfc_fp_power_7 2.690593727247e-01 +wfi4s1k1_wfc_fp_cross_0_re -1.424655357949e+00 +wfi4s1k1_wfc_fp_cross_0_im -8.234748583495e-02 +wfi4s1k1_wfc_fp_cross_1_re 3.694676488310e-01 +wfi4s1k1_wfc_fp_cross_1_im -3.631532307505e-01 +wfi4s1k1_wfc_fp_cross_2_re 2.961760664596e-01 +wfi4s1k1_wfc_fp_cross_2_im 9.728067266287e-01 +wfi4s1k1_wfc_fp_cross_3_re 2.168938458165e+00 +wfi4s1k1_wfc_fp_cross_3_im -2.881860896261e-01 +wfi4s1k1_wfc_fp_cross_4_re -9.809732557572e-02 +wfi4s1k1_wfc_fp_cross_4_im -5.197846913847e-01 +wfi4s1k1_wfc_fp_cross_5_re -2.602975948365e-01 +wfi4s1k1_wfc_fp_cross_5_im 1.887911570509e-01 +wfi4s1k1_wfc_fp_cross_6_re -3.450116759282e-01 +wfi4s1k1_wfc_fp_cross_6_im -5.883093621080e-02 +wfi4s1k1_wfc_fp_cross_7_re 1.615823138646e-01 +wfi4s1k1_wfc_fp_cross_7_im -7.191411458503e-01 wfi4s1k2_wfc_fp_components 1 wfi4s1k2_wfc_fp_nx 24 wfi4s1k2_wfc_fp_ny 24 wfi4s1k2_wfc_fp_nz 24 wfi4s1k2_wfc_fp_voxel 1.919140625000e-02 wfi4s1k2_wfc_fp_rms 6.139453834168e-02 -wfi4s1k2_wfc_fp_power_0 2.210775444366e+00 -wfi4s1k2_wfc_fp_power_1 4.422482386207e-01 -wfi4s1k2_wfc_fp_power_2 1.311183666610e+00 -wfi4s1k2_wfc_fp_power_3 2.081129905576e-01 -wfi4s1k2_wfc_fp_power_4 2.107277316883e-01 -wfi4s1k2_wfc_fp_power_5 1.578952024869e-01 -wfi4s1k2_wfc_fp_power_6 5.694009207009e-02 -wfi4s1k2_wfc_fp_power_7 1.993940126276e-01 -wfi4s1k2_wfc_fp_cross_0_re 4.090872140258e-01 -wfi4s1k2_wfc_fp_cross_0_im -9.001995320913e-01 -wfi4s1k2_wfc_fp_cross_1_re 5.885539949613e-01 -wfi4s1k2_wfc_fp_cross_1_im 4.831902959306e-01 -wfi4s1k2_wfc_fp_cross_2_re -4.528984441414e-01 -wfi4s1k2_wfc_fp_cross_2_im -2.603024266555e-01 -wfi4s1k2_wfc_fp_cross_3_re 2.093553872554e-01 -wfi4s1k2_wfc_fp_cross_3_im -5.049778433485e-03 -wfi4s1k2_wfc_fp_cross_4_re 1.419206862935e-01 -wfi4s1k2_wfc_fp_cross_4_im 1.145923935805e-01 -wfi4s1k2_wfc_fp_cross_5_re -3.483374662841e-02 -wfi4s1k2_wfc_fp_cross_5_im -8.818830683746e-02 -wfi4s1k2_wfc_fp_cross_6_re 3.471382993746e-02 -wfi4s1k2_wfc_fp_cross_6_im -1.007395823315e-01 -wfi4s1k2_wfc_fp_cross_7_re 5.180925250259e-01 -wfi4s1k2_wfc_fp_cross_7_im -4.152053978252e-01 -totaltimeref 0.29 +wfi4s1k2_wfc_fp_power_0 2.210759823090e+00 +wfi4s1k2_wfc_fp_power_1 4.422431009108e-01 +wfi4s1k2_wfc_fp_power_2 1.311114257940e+00 +wfi4s1k2_wfc_fp_power_3 2.080940511216e-01 +wfi4s1k2_wfc_fp_power_4 2.107287456296e-01 +wfi4s1k2_wfc_fp_power_5 1.579032306523e-01 +wfi4s1k2_wfc_fp_power_6 5.694111320769e-02 +wfi4s1k2_wfc_fp_power_7 1.993934094083e-01 +wfi4s1k2_wfc_fp_cross_0_re 4.091016883918e-01 +wfi4s1k2_wfc_fp_cross_0_im -9.001828081491e-01 +wfi4s1k2_wfc_fp_cross_1_re 5.885509597910e-01 +wfi4s1k2_wfc_fp_cross_1_im 4.831552574574e-01 +wfi4s1k2_wfc_fp_cross_2_re -4.528490376534e-01 +wfi4s1k2_wfc_fp_cross_2_im -2.603129395829e-01 +wfi4s1k2_wfc_fp_cross_3_re 2.093462595369e-01 +wfi4s1k2_wfc_fp_cross_3_im -5.053907767741e-03 +wfi4s1k2_wfc_fp_cross_4_re 1.419227050410e-01 +wfi4s1k2_wfc_fp_cross_4_im 1.145979734554e-01 +wfi4s1k2_wfc_fp_cross_5_re -3.484498639901e-02 +wfi4s1k2_wfc_fp_cross_5_im -8.818737242535e-02 +wfi4s1k2_wfc_fp_cross_6_re 3.472128797451e-02 +wfi4s1k2_wfc_fp_cross_6_im -1.007378521678e-01 +wfi4s1k2_wfc_fp_cross_7_re 5.180876053465e-01 +wfi4s1k2_wfc_fp_cross_7_im -4.152061797410e-01 +totaltimeref 0.33 diff --git a/tests/01_PW/089_PW_get_wf_kpar_bndpar/threshold b/tests/01_PW/089_PW_get_wf_kpar_bndpar/threshold new file mode 100644 index 00000000000..145f85786f9 --- /dev/null +++ b/tests/01_PW/089_PW_get_wf_kpar_bndpar/threshold @@ -0,0 +1 @@ +wfc_threshold 5e-6 diff --git a/tests/01_PW/scf_uspp_bpcg/INPUT b/tests/01_PW/scf_uspp_bpcg/INPUT index c938c190ad9..9dd30779c5e 100644 --- a/tests/01_PW/scf_uspp_bpcg/INPUT +++ b/tests/01_PW/scf_uspp_bpcg/INPUT @@ -11,7 +11,8 @@ pseudo_dir ../../PP_ORB # Parameters (2.Iteration) ecutwfc 8 ecutrho 60 -scf_thr 1e-9 +scf_thr 1e-13 +pw_diag_thr 1e-12 scf_nmax 100 # Parameters (3.Basis) diff --git a/tests/01_PW/scf_uspp_bpcg/result.ref b/tests/01_PW/scf_uspp_bpcg/result.ref index 4805a3840b0..da7d2217bcf 100644 --- a/tests/01_PW/scf_uspp_bpcg/result.ref +++ b/tests/01_PW/scf_uspp_bpcg/result.ref @@ -1,5 +1,5 @@ -etotref -673.8349347374721674 -etotperatomref -673.8349347375 +etotref -673.8349349713665788 +etotperatomref -673.8349349714 totalforceref 0.000000 -totalstressref 66620.137229 -totaltimeref 0.97 +totalstressref 66620.229810 +totaltimeref 1.97 diff --git a/tests/01_PW/scf_uspp_bpcg/threshold b/tests/01_PW/scf_uspp_bpcg/threshold new file mode 100644 index 00000000000..b7aedbc7af4 --- /dev/null +++ b/tests/01_PW/scf_uspp_bpcg/threshold @@ -0,0 +1 @@ +stress_threshold 1e-2 diff --git a/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_1.txt.ref b/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_1.txt.ref index 3824b279feb..4760fa30298 100644 --- a/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_1.txt.ref +++ b/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_1.txt.ref @@ -1,7 +1,8 @@ -0 0 -0.05 0 -0.1 -0.0350185 -0.15 0.27 -0.2 -0.0350185 -0.25 0 -0.3 0 + 0.000000 0.000000000000e+00 + 0.050000 0.000000000000e+00 + 0.100000 -3.501845272301e-02 + 0.150000 2.700000000000e-01 + 0.200000 -3.501845272301e-02 + 0.250000 0.000000000000e+00 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_2.txt.ref b/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_2.txt.ref index 0ec5febc62e..83f36eb516f 100644 --- a/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_2.txt.ref +++ b/tests/05_rtTDDFT/19_NO_SUPERSINE_TDDFT/efield_2.txt.ref @@ -1,7 +1,8 @@ -0 0 -0.05 0 -0.1 1.54425 -0.15 1.10218e-17 -0.2 -1.54425 -0.25 0 -0.3 0 + 0.000000 0.000000000000e+00 + 0.050000 0.000000000000e+00 + 0.100000 1.544251129818e+00 + 0.150000 1.102182119233e-17 + 0.200000 -1.544251129818e+00 + 0.250000 0.000000000000e+00 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_1.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_1.txt.ref index f7029d49cfb..b4e80df658c 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_1.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_1.txt.ref @@ -1,7 +1,8 @@ -0 0.0266495 -0.05 0.0364109 -0.1 0.0398002 -0.15 0.0348135 -0.2 0.0242465 -0.25 0.0132775 -0.3 0.00555872 + 0.000000 2.664950674378e-02 + 0.050000 3.641086506598e-02 + 0.100000 3.980016661112e-02 + 0.150000 3.481348408339e-02 + 0.200000 2.424650679607e-02 + 0.250000 1.327751403966e-02 + 0.300000 5.558724561591e-03 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_10.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_10.txt.ref index c9c61917323..5ff61e446a4 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_10.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_10.txt.ref @@ -1,7 +1,8 @@ -0 -0.00732139 -0.05 -0.013089 -0.1 -0.0135533 -0.15 -0.00763671 -0.2 -0.00015746 -0.25 0.00320401 -0.3 0.00177906 + 0.000000 -7.321387155782e-03 + 0.050000 -1.308904129194e-02 + 0.100000 -1.355332758075e-02 + 0.150000 -7.636709282321e-03 + 0.200000 -1.574600767951e-04 + 0.250000 3.204008572905e-03 + 0.300000 1.779061764225e-03 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_2.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_2.txt.ref index d5fd25849f4..6b9a47dbbd0 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_2.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_2.txt.ref @@ -1,7 +1,8 @@ -0 0 -0.05 0 -0.1 0.031042 -0.15 0.0490033 -0.2 -0.0446739 -0.25 0 -0.3 0 + 0.000000 0.000000000000e+00 + 0.050000 0.000000000000e+00 + 0.100000 3.104196091355e-02 + 0.150000 4.900332889206e-02 + 0.200000 -4.467390243688e-02 + 0.250000 0.000000000000e+00 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_3.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_3.txt.ref index 989ccf3f7e1..291ee866a92 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_3.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_3.txt.ref @@ -1,7 +1,8 @@ -0 0 -0.05 0.0224967 -0.1 0.0190782 -0.15 0.014461 -0.2 0.00446755 -0.25 0 -0.3 -0 + 0.000000 0.000000000000e+00 + 0.050000 2.249672326559e-02 + 0.100000 1.907823022520e-02 + 0.150000 1.446098181495e-02 + 0.200000 4.467548366745e-03 + 0.250000 0.000000000000e+00 + 0.300000 -0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_4.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_4.txt.ref index 47ba81f3d5b..36556a33159 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_4.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_4.txt.ref @@ -1,7 +1,8 @@ -0 0.00381989 -0.05 -0.00302697 -0.1 -0.0122172 -0.15 -0.0213628 -0.2 -0.0276318 -0.25 -0.0290339 -0.3 -0.0253607 + 0.000000 3.819888601740e-03 + 0.050000 -3.026970038439e-03 + 0.100000 -1.221724563800e-02 + 0.150000 -2.136280624345e-02 + 0.200000 -2.763182982009e-02 + 0.250000 -2.903394376196e-02 + 0.300000 -2.536069172914e-02 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_5.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_5.txt.ref index bc3b37422d8..e5bd7ef0add 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_5.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_5.txt.ref @@ -1,7 +1,8 @@ -0 0.01 -0.05 0.01 -0.1 0.01 -0.15 0 -0.2 0 -0.25 0 -0.3 0 + 0.000000 1.000000000000e-02 + 0.050000 1.000000000000e-02 + 0.100000 1.000000000000e-02 + 0.150000 0.000000000000e+00 + 0.200000 0.000000000000e+00 + 0.250000 0.000000000000e+00 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_6.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_6.txt.ref index d29952a4c9a..f74e2e88f63 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_6.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_6.txt.ref @@ -1,7 +1,8 @@ -0 0.000142823 -0.05 0.00477471 -0.1 0.00864368 -0.15 0.00584356 -0.2 0.00103323 -0.25 -9.65006e-05 -0.3 -0.000733575 + 0.000000 1.428234415606e-04 + 0.050000 4.774713083834e-03 + 0.100000 8.643680264292e-03 + 0.150000 5.843555737827e-03 + 0.200000 1.033233769422e-03 + 0.250000 -9.650057692743e-05 + 0.300000 -7.335746621943e-04 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_7.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_7.txt.ref index a316aa5db4d..4595393a176 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_7.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_7.txt.ref @@ -1,7 +1,8 @@ -0 0 -0.05 -0 -0.1 -0 -0.15 0.0327856 -0.2 -0.0351033 -0.25 -0.0452257 -0.3 -0 + 0.000000 0.000000000000e+00 + 0.050000 -0.000000000000e+00 + 0.100000 -0.000000000000e+00 + 0.150000 3.278561314636e-02 + 0.200000 -3.510330247561e-02 + 0.250000 -4.522572821072e-02 + 0.300000 -0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_8.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_8.txt.ref index 558f86c14b7..ea5ca90be1a 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_8.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_8.txt.ref @@ -1,7 +1,8 @@ -0 -0 -0.05 -0.00981702 -0.1 -0.0195318 -0.15 -0.0162167 -0.2 -0.0102341 -0.25 -0.00128406 -0.3 0 + 0.000000 -0.000000000000e+00 + 0.050000 -9.817021455967e-03 + 0.100000 -1.953175510842e-02 + 0.150000 -1.621667428502e-02 + 0.200000 -1.023410056816e-02 + 0.250000 -1.284055993631e-03 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_9.txt.ref b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_9.txt.ref index a58d4028d6c..dafaf3e4866 100644 --- a/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_9.txt.ref +++ b/tests/05_rtTDDFT/20_NO_MIXED_EFIELD_TDDFT/efield_9.txt.ref @@ -1,7 +1,8 @@ -0 -0.012 -0.05 -0.012 -0.1 -0.012 -0.15 -0.012 -0.2 -0.012 -0.25 0 -0.3 0 + 0.000000 -1.200000000000e-02 + 0.050000 -1.200000000000e-02 + 0.100000 -1.200000000000e-02 + 0.150000 -1.200000000000e-02 + 0.200000 -1.200000000000e-02 + 0.250000 0.000000000000e+00 + 0.300000 0.000000000000e+00 + 0.350000 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/INPUT b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/INPUT new file mode 100644 index 00000000000..fa3b0adf05a --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/INPUT @@ -0,0 +1,61 @@ +INPUT_PARAMETERS +suffix autotest +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +dft_functional PBE +gga_grad 1 +ecutwfc 20 +ecutrho 80 +nbands 12 +kpar 2 +nspin 4 +noncolin 1 +lspinorb 1 +symmetry -1 +init_wfc atomic+random +pw_seed 1 +ks_solver cg +pw_diag_thr 1e-13 +scf_thr 1e-12 +scf_nmax 150 +mixing_type broyden +mixing_beta 0.5 +mixing_beta_mag 0.5 +mixing_gg0 0 +mixing_gg0_mag 0 +smearing_method fd +smearing_sigma 0.002 +md_type nve +init_vel 1 +td_dt 0.002 +md_nstep 1 +estep_per_md 5 +cal_force 0 +cal_stress 0 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 1.5707963267948966 +td_gauss_sigma 0.04 +td_gauss_t0 0 +td_gauss_amp 0.1 +lin_solver bicgstab +lin_precond kinetic +lin_thr 1e-13 +lin_maxiter 100 +td_cn_init 0 +lin_reconstruct 0 +td_out_torque 1 +td_out_spincur 1 +out_current 1 +out_level ie +td_stype 0 +td_out_mag voronoi diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/KPT b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/README b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/README new file mode 100644 index 00000000000..5cf04d9fdb4 --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/README @@ -0,0 +1 @@ +Test nspin=4 PW RT-TDDFT with SOC in the length gauge using Voronoi magnetic moments. diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/STRU b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/STRU new file mode 100644 index 00000000000..139b8c551ed --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/STRU @@ -0,0 +1,21 @@ +ATOMIC_SPECIES +Si 28 Si_dojo_soc.upf upf201 + +NUMERICAL_ORBITAL +Si_dojo_6au.orb + +LATTICE_CONSTANT +10.2 + +LATTICE_VECTORS +0.0 0.5 0.5 +0.5 0.0 0.5 +0.5 0.5 0.0 + +ATOMIC_POSITIONS +Direct +Si +0.0 +2 +0.00 0.00 0.00 0 0 0 v 0 0 0 +0.25 0.25 0.25 0 0 0 v 0 0 0 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..e3f89d80b4e --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/current_tot.txt.ref @@ -0,0 +1,6 @@ + 1 2.289540486381e-14 2.466371358853e-13 -4.322199982921e-13 + 2 1.562262789043e-08 -2.583938069128e-11 3.356100270946e-11 + 3 6.239644885742e-08 -1.032314740651e-10 1.348687369519e-10 + 4 1.399851370645e-07 -2.294087173190e-10 3.010488410832e-10 + 5 2.477204874654e-07 -4.005758998224e-10 5.279601386958e-10 + 6 3.844843676686e-07 -6.122000986244e-10 8.097312782081e-10 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_atom.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_atom.txt.ref new file mode 100644 index 00000000000..f5623d5b304 --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_atom.txt.ref @@ -0,0 +1,14 @@ +# method=voronoi; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +#step time_fs atom Mx My Mz + 1 0.000000 1 9.688147526310e-11 3.770607647993e-11 2.128422814803e-09 + 1 0.000000 2 -9.604735803907e-11 -3.839591778316e-11 -2.128529273649e-09 + 2 0.002000 1 8.539427389207e-11 3.884726156062e-11 2.137434253980e-09 + 2 0.002000 2 -9.445069996995e-11 -3.969803210671e-11 -2.137047195265e-09 + 3 0.004000 1 6.047128818960e-11 3.909235016855e-11 2.147458676175e-09 + 3 0.004000 2 -7.921511486490e-11 -4.011686659959e-11 -2.146556076116e-09 + 4 0.006000 1 2.495133773993e-11 3.819630426244e-11 2.159145272901e-09 + 4 0.006000 2 -5.282085091925e-11 -3.942860167351e-11 -2.157666045077e-09 + 5 0.008000 1 -1.508797726460e-11 3.623372709274e-11 2.172333075148e-09 + 5 0.008000 2 -2.079044574547e-11 -3.774360104556e-11 -2.170151148038e-09 + 6 0.010000 1 -4.949855664212e-11 3.435012111971e-11 2.186333023229e-09 + 6 0.010000 2 7.433319529666e-12 -3.625400515907e-11 -2.183238486660e-09 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_tot.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_tot.txt.ref new file mode 100644 index 00000000000..4ee8773f48c --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/mag_tot.txt.ref @@ -0,0 +1,8 @@ +# method=voronoi; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +#step time_fs Mx My Mz M_norm M_abs_integral N_elec + 1 0.000000 8.341172240297e-13 -6.898413032241e-13 -1.064588455753e-13 1.087642428769e-12 5.505863834088e-09 8.000000000000e+00 + 2 0.002000 -9.056426077882e-12 -8.507705460825e-13 3.870587151793e-13 9.104530645520e-12 1.145327466665e-08 8.000000000000e+00 + 3 0.004000 -1.874382667530e-11 -1.024516431041e-12 9.026000588120e-13 1.879349246993e-11 3.611909443096e-08 8.000000000000e+00 + 4 0.006000 -2.786951317932e-11 -1.232297411070e-12 1.479227824074e-12 2.793593450588e-11 7.588204424652e-08 8.000000000000e+00 + 5 0.008000 -3.587842301006e-11 -1.509873952813e-12 2.181927110568e-12 3.597640564256e-11 1.311753129465e-07 8.000000000000e+00 + 6 0.010000 -4.206523711245e-11 -1.903884039364e-12 3.094536569146e-12 4.222185576618e-11 2.105217060092e-07 8.000000000000e+00 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/result.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/result.ref new file mode 100644 index 00000000000..e40f0dd93d9 --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/result.ref @@ -0,0 +1,9 @@ +etotref -218.5380463230584 +etotperatomref -109.2690231615 +Comparemag_tot_txt_pass 0 +Comparemag_atom_txt_pass 0 +Comparetorque_tot_txt_pass 0 +Comparetorque_atom_txt_pass 0 +Comparespincur_tot_txt_pass 0 +CompareCurrent_pass 0 +totaltimeref 1.84 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/spincur_tot.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/spincur_tot.txt.ref new file mode 100644 index 00000000000..fcafaa8f4ab --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/spincur_tot.txt.ref @@ -0,0 +1,8 @@ +# S=M/2; unit=hbar/(Bohr^2*Hartree_atomic_time); flow_index_first +#step time_fs Jxx Jxy Jxz Jyx Jyy Jyz Jzx Jzy Jzz + 1 0.000000 2.576695605481e-13 -4.742647922919e-14 9.611979317132e-14 1.530638900597e-13 -5.854886400028e-14 -1.909896222278e-13 4.600179363465e-13 -7.668010812926e-14 -7.381817189594e-14 + 2 0.002000 2.666244553670e-13 -4.566801709470e-14 6.881527168337e-14 1.594035634671e-13 -1.060391529299e-13 3.158170743608e-13 4.597429491125e-13 -5.645242488122e-13 -6.178048811495e-14 + 3 0.004000 3.194417445462e-13 -3.290708233150e-14 2.223295211368e-14 1.788246042956e-13 -3.359365445450e-13 2.735281517485e-12 4.640285387289e-13 -2.947878631628e-12 7.714946482476e-14 + 4 0.006000 4.737689539638e-13 2.488245661390e-15 -5.499124485891e-14 2.124186851534e-13 -8.666675894213e-13 8.819369272723e-12 4.771283582899e-13 -8.952673404709e-12 4.136128867866e-13 + 5 0.008000 8.233776327372e-13 6.543659216163e-14 -1.649578619439e-13 2.606045836353e-13 -1.730620705866e-12 2.000822579890e-11 4.967411833514e-13 -1.999969346430e-11 9.363914618553e-13 + 6 0.010000 1.485002580136e-12 1.643233710189e-13 -2.951824996434e-13 3.085249972122e-13 -2.850602556591e-12 3.737866329105e-11 5.439058945035e-13 -3.712068776630e-11 1.523132392515e-12 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_atom.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_atom.txt.ref new file mode 100644 index 00000000000..d13902a5df7 --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_atom.txt.ref @@ -0,0 +1,15 @@ +# SOC_pseudopotential_atom_decomposition; unit=hbar/Hartree_atomic_time +# not_the_derivative_of_atomic_moments +#step time_fs atom tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 1 -2.995874673439e-11 -5.723169571643e-13 1.571952691671e-12 + 1 0.000000 2 -3.009781223775e-11 -3.855840343387e-13 1.389312398266e-12 + 2 0.002000 1 -2.984644608980e-11 -5.771777980337e-13 1.591897847631e-12 + 2 0.002000 2 -2.981260130952e-11 -4.067947693300e-13 1.411974598751e-12 + 3 0.004000 1 -2.929531796337e-11 -6.112015326554e-13 1.687776576578e-12 + 3 0.004000 2 -2.845512812076e-11 -4.872891471761e-13 1.522043087905e-12 + 4 0.006000 1 -2.789617528015e-11 -7.069464405613e-13 1.932946454901e-12 + 4 0.006000 2 -2.511199481477e-11 -6.816847298422e-13 1.802468307083e-12 + 5 0.008000 1 -2.526376886166e-11 -8.982945714778e-13 2.392423288787e-12 + 5 0.008000 2 -1.910729440220e-11 -1.032876122974e-12 2.325937738134e-12 + 6 0.010000 1 -2.104367580952e-11 -1.220256785447e-12 3.122243721933e-12 + 6 0.010000 2 -1.003619544124e-11 -1.570323217182e-12 3.147485191953e-12 diff --git a/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_tot.txt.ref b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_tot.txt.ref new file mode 100644 index 00000000000..c7b30fe4c8b --- /dev/null +++ b/tests/05_rtTDDFT/29_PW_soc_len_TDDFT/torque_tot.txt.ref @@ -0,0 +1,8 @@ +# torque=dS/dt; S=M/2; unit=hbar/Hartree_atomic_time +#step time_fs tau_xc_x tau_xc_y tau_xc_z tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 1.874501167490e-38 -2.980082427274e-38 3.637993661690e-39 -6.005655897214e-11 -9.579009915030e-13 2.961265089937e-12 + 2 0.002000 -2.543729223323e-36 2.483042096919e-36 -3.734690595686e-36 -5.965904739932e-11 -9.839725673636e-13 3.003872446382e-12 + 3 0.004000 -2.413108644475e-35 4.864211530974e-35 -1.596348454371e-36 -5.775044608414e-11 -1.098490679832e-12 3.209819664483e-12 + 4 0.006000 -1.644709518019e-34 4.132866997294e-34 2.582675062921e-35 -5.300817009492e-11 -1.388631170403e-12 3.735414761984e-12 + 5 0.008000 -1.887940273325e-33 6.111686779488e-34 8.355449444240e-35 -4.437106326385e-11 -1.931170694452e-12 4.718361026921e-12 + 6 0.010000 -1.081988789974e-33 -2.628252615571e-33 -8.160792640079e-34 -3.107987125076e-11 -2.790580002629e-12 6.269728913885e-12 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/INPUT b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/INPUT new file mode 100644 index 00000000000..231830bf5c2 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/INPUT @@ -0,0 +1,64 @@ +INPUT_PARAMETERS +suffix autotest +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +dft_functional PBE +ecutwfc 20 +ecutrho 80 +nbands 40 +kpar 2 +nspin 4 +noncolin 1 +lspinorb 1 +symmetry -1 +init_wfc file binary +init_chg wfc +read_file_dir ./ +ks_solver cg +pw_diag_thr 1e-8 +scf_thr 1e-8 +# Accept the saved magnetic state after one initial SCF iteration. +scf_nmax 1 +td_scf_nmax 100 +mixing_type broyden +mixing_beta 0.2 +mixing_beta_mag 0.2 +mixing_gg0 0 +mixing_gg0_mag 0 +smearing_method gauss +smearing_sigma 0.01 +md_type nve +init_vel 1 +td_dt 0.002 +md_nstep 1 +estep_per_md 5 +cal_force 0 +cal_stress 0 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 1.5707963267948966 +td_gauss_sigma 0.04 +td_gauss_t0 0 +td_gauss_amp 0.1 +lin_solver bicgstab +lin_precond kinetic +lin_thr 1e-13 +lin_maxiter 100 +td_cn_init 0 +lin_reconstruct 0 +td_out_torque 1 +td_out_spincur 1 +out_current 1 +out_level ie +td_stype 1 +td_out_mag onsite +onsite_radius 3.0 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/KPT b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/README b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/README new file mode 100644 index 00000000000..6d117912bb4 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/README @@ -0,0 +1 @@ +Test magnetic Fe PW RT-TDDFT from saved spinors with one initial SCF iteration, SOC, onsite moments, spin currents, torques, and default gga_grad=2. diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/STRU b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/STRU new file mode 100644 index 00000000000..bfb07d6c4e3 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/STRU @@ -0,0 +1,21 @@ +ATOMIC_SPECIES +Fe 55.845 Fe.upf upf201 + +NUMERICAL_ORBITAL +Fe_gga_6au_100Ry_4s2p2d1f.orb + +LATTICE_CONSTANT +5.423505388 + +LATTICE_VECTORS +1 0 0 +0 1 0 +0 0 1 + +ATOMIC_POSITIONS +Direct +Fe +0.0 +2 +0.00 0.00 0.00 0 0 0 mag 1.32 1.056 1.408 v 0 0 0 +0.503 0.502 0.499 0 0 0 mag 1.32 1.056 1.408 v 0 0 0 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..cb6e43ade7c --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/current_tot.txt.ref @@ -0,0 +1,6 @@ + 1 1.667223544724e-08 -1.907183457471e-08 -9.789339696873e-10 + 2 -2.231802487713e-07 -2.065310142550e-08 -1.500332021533e-09 + 3 -1.206223312222e-06 -2.039502062807e-08 -8.713934652629e-11 + 4 -2.890823316261e-06 -1.945776271036e-08 2.640895051575e-09 + 5 -5.200804782617e-06 -1.977848103787e-08 5.599453551769e-09 + 6 -8.036923610234e-06 -2.365415764288e-08 7.512132076906e-09 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/eig.txt b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/eig.txt new file mode 100644 index 00000000000..543fdd8a5c6 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/eig.txt @@ -0,0 +1,85 @@ + Electronic state energy (eV) and occupations + Spin number 4 + spin=1 k-point=1/2 Cartesian=0.17000000 0.11000000 0.070000000 (241 plane wave) + 1 -103.9078833243627 0.5000000000000000 + 2 -103.8854764766162 0.5000000000000000 + 3 -103.2256496595237 0.5000000000000000 + 4 -103.1959453039100 0.5000000000000000 + 5 -48.93341254797411 0.5000000000000000 + 6 -47.95642695804461 0.5000000000000000 + 7 -47.36874565615719 0.5000000000000000 + 8 -46.46247354343243 0.5000000000000000 + 9 -46.17470988875323 0.5000000000000000 + 10 -45.91537808882194 0.5000000000000000 + 11 -45.65769953674243 0.5000000000000000 + 12 -45.08397573701200 0.5000000000000000 + 13 -44.57331936998738 0.5000000000000000 + 14 -44.42748857372715 0.5000000000000000 + 15 -43.84137557100731 0.5000000000000000 + 16 -42.87814707649200 0.5000000000000000 + 17 10.53396047873180 0.5000000000000000 + 18 11.30687387042842 0.5000000000000000 + 19 17.73964008910495 0.5000000000000000 + 20 17.96801319562652 0.5000000000000000 + 21 18.83289370704967 0.5000000000000000 + 22 19.18126072343309 0.5000000000000000 + 23 19.44489182879610 0.5000000000000000 + 24 19.83721119680212 0.5000000000000000 + 25 20.40163573729119 0.5000000000000000 + 26 22.05746081789694 0.5000000000000000 + 27 22.49028420913443 0.5000000000000000 + 28 23.98740818932617 0.5000000000000000 + 29 24.12410525745961 0.5000000000000000 + 30 24.39415331423380 0.5000000000000000 + 31 24.41696976212447 0.5000000000000000 + 32 25.50145054806425 0.4972978624366441 + 33 25.99187533487810 0.002702500630739632 + 34 26.24026477829464 7.220140136999545e-08 + 35 26.44769856398476 7.939029176750601e-14 + 36 26.65239203769734 0.000000000000000 + 37 27.49805904945316 0.000000000000000 + 38 27.67235947107097 0.000000000000000 + 39 28.55674943722372 0.000000000000000 + 40 29.58027259681982 0.000000000000000 + + spin=1 k-point=2/2 Cartesian=-0.17000000 -0.11000000 -0.070000000 (241 plane wave) + 1 -103.9078833560056 0.5000000000000000 + 2 -103.8854763904223 0.5000000000000000 + 3 -103.2256497240819 0.5000000000000000 + 4 -103.1959453193953 0.5000000000000000 + 5 -48.93342148595356 0.5000000000000000 + 6 -47.95642352154820 0.5000000000000000 + 7 -47.36868020094718 0.5000000000000000 + 8 -46.46255738822804 0.5000000000000000 + 9 -46.17468741564642 0.5000000000000000 + 10 -45.91542301367310 0.5000000000000000 + 11 -45.65760662269145 0.5000000000000000 + 12 -45.08410652846837 0.5000000000000000 + 13 -44.57312612224105 0.5000000000000000 + 14 -44.42760140975067 0.5000000000000000 + 15 -43.84137930297437 0.5000000000000000 + 16 -42.87813890569722 0.5000000000000000 + 17 10.53396130857515 0.5000000000000000 + 18 11.30687377574026 0.5000000000000000 + 19 17.73964028731759 0.5000000000000000 + 20 17.96801315983495 0.5000000000000000 + 21 18.83289274945842 0.5000000000000000 + 22 19.18125908409684 0.5000000000000000 + 23 19.44489465285591 0.5000000000000000 + 24 19.83721432500865 0.5000000000000000 + 25 20.40163810461241 0.5000000000000000 + 26 22.05745519750796 0.5000000000000000 + 27 22.49028479580295 0.5000000000000000 + 28 23.98740175831127 0.5000000000000000 + 29 24.12411601754403 0.5000000000000000 + 30 24.39412520558515 0.5000000000000000 + 31 24.41699316319984 0.5000000000000000 + 32 25.50146383668007 0.4972967920817186 + 33 25.99187285378963 0.002702700469629673 + 34 26.24027021292831 7.217973523159532e-08 + 35 26.44769374955129 7.941977293577905e-14 + 36 26.65238908228155 0.000000000000000 + 37 27.49806794541136 0.000000000000000 + 38 27.67235593055364 0.000000000000000 + 39 28.55671826770196 0.000000000000000 + 40 29.58027547094388 0.000000000000000 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_atom.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_atom.txt.ref new file mode 100644 index 00000000000..59debd4df00 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_atom.txt.ref @@ -0,0 +1,16 @@ +# method=onsite; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +# onsite_radius(Bohr)=3.000000000000e+00; projector=q(k+G+A); atom_phase_cancels +# orbital=../../PP_ORB/Fe_gga_6au_100Ry_4s2p2d1f.orb +#step time_fs atom Mx My Mz + 1 0.000000 1 8.853507019723e-01 7.101962618766e-01 9.388102141133e-01 + 1 0.000000 2 8.821497466354e-01 7.074788394935e-01 9.355889220868e-01 + 2 0.002000 1 8.853506747607e-01 7.101961385004e-01 9.388103355654e-01 + 2 0.002000 2 8.821497160899e-01 7.074787186621e-01 9.355890397806e-01 + 3 0.004000 1 8.853506427236e-01 7.101960208834e-01 9.388104625409e-01 + 3 0.004000 2 8.821496772577e-01 7.074785994255e-01 9.355891578494e-01 + 4 0.006000 1 8.853506042325e-01 7.101959111672e-01 9.388105971534e-01 + 4 0.006000 2 8.821496261681e-01 7.074784821072e-01 9.355892759383e-01 + 5 0.008000 1 8.853505583444e-01 7.101958112816e-01 9.388107409538e-01 + 5 0.008000 2 8.821495595372e-01 7.074783668488e-01 9.355893931777e-01 + 6 0.010000 1 8.853505065629e-01 7.101957217336e-01 9.388108941318e-01 + 6 0.010000 2 8.821494766630e-01 7.074782524705e-01 9.355895075212e-01 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_tot.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_tot.txt.ref new file mode 100644 index 00000000000..04b71ff006b --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/mag_tot.txt.ref @@ -0,0 +1,10 @@ +# method=onsite; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +# onsite_radius(Bohr)=3.000000000000e+00; projector=q(k+G+A); atom_phase_cancels +# orbital=../../PP_ORB/Fe_gga_6au_100Ry_4s2p2d1f.orb +#step time_fs Mx My Mz M_norm M_abs_integral N_elec + 1 0.000000 2.393521343807e+00 1.918240587757e+00 2.541936337072e+00 3.983720838300e+00 3.989052149093e+00 3.200000000000e+01 + 2 0.002000 2.393521277797e+00 1.918240275644e+00 2.541936634873e+00 3.983720838372e+00 3.989052149265e+00 3.200000000000e+01 + 3 0.004000 2.393521211784e+00 1.918239963548e+00 2.541936932663e+00 3.983720838443e+00 3.989052148929e+00 3.200000000000e+01 + 4 0.006000 2.393521145768e+00 1.918239651473e+00 2.541937230437e+00 3.983720838514e+00 3.989052148163e+00 3.200000000000e+01 + 5 0.008000 2.393521079752e+00 1.918239339415e+00 2.541937528199e+00 3.983720838584e+00 3.989052147237e+00 3.200000000000e+01 + 6 0.010000 2.393521013734e+00 1.918239027362e+00 2.541937825959e+00 3.983720838653e+00 3.989052146436e+00 3.200000000000e+01 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/result.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/result.ref new file mode 100644 index 00000000000..947946ac86e --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/result.ref @@ -0,0 +1,9 @@ +etotref -6386.641176765657 +etotperatomref -3193.3205883828 +Comparemag_tot_txt_pass 0 +Comparemag_atom_txt_pass 0 +Comparetorque_tot_txt_pass 0 +Comparetorque_atom_txt_pass 0 +Comparespincur_tot_txt_pass 0 +CompareCurrent_pass 0 +totaltimeref 0.95 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/spincur_tot.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/spincur_tot.txt.ref new file mode 100644 index 00000000000..2e8dae631d8 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/spincur_tot.txt.ref @@ -0,0 +1,8 @@ +# S=M/2; unit=hbar/(Bohr^2*Hartree_atomic_time); flow_index_first +#step time_fs Jxx Jxy Jxz Jyx Jyy Jyz Jzx Jzy Jzz + 1 0.000000 -7.602185574873e-09 8.593057712214e-09 -1.263186510480e-08 -8.145880523770e-09 1.946906005781e-08 1.430565358403e-08 -3.358093369857e-09 2.918986468760e-09 4.374482462116e-09 + 2 0.002000 5.705694443641e-09 1.935388319769e-08 1.644694083772e-09 -6.994933104519e-09 2.036532161758e-08 1.554332632098e-08 -2.970479362501e-09 3.255664140579e-09 4.783326800826e-09 + 3 0.004000 5.329709056954e-08 5.757504927961e-08 5.234332894293e-08 -5.334943694092e-09 2.168610329214e-08 1.717896226127e-08 -2.535982368921e-09 3.735577971231e-09 5.244810202112e-09 + 4 0.006000 1.338779952304e-07 1.222087563349e-07 1.380878722254e-07 -2.917673966995e-09 2.361350584819e-08 1.942364137901e-08 -1.970582465381e-09 4.515568020639e-09 5.866643223112e-09 + 5 0.008000 2.449649740174e-07 2.112568941935e-07 2.562414689176e-07 6.758340209514e-10 2.645913225180e-08 2.270178821134e-08 -1.118231684103e-09 5.785378037743e-09 6.831186208857e-09 + 6 0.010000 3.832047679173e-07 3.220277360726e-07 4.032469121097e-07 5.995959475555e-09 3.063570032078e-08 2.760236926138e-08 2.273116647381e-10 7.753618287229e-09 8.372038643110e-09 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_atom.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_atom.txt.ref new file mode 100644 index 00000000000..15aeb161fb0 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_atom.txt.ref @@ -0,0 +1,15 @@ +# SOC_pseudopotential_atom_decomposition; unit=hbar/Hartree_atomic_time +# not_the_derivative_of_atomic_moments +#step time_fs atom tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 1 -1.881970328497e-07 -9.309314936335e-07 9.547393774714e-07 + 1 0.000000 2 -2.115217317654e-07 -9.592262877870e-07 8.487126132886e-07 + 2 0.002000 1 -1.882056398037e-07 -9.309067155825e-07 9.547401976288e-07 + 2 0.002000 2 -2.115473358855e-07 -9.592169193106e-07 8.487097034251e-07 + 3 0.004000 1 -1.882106057428e-07 -9.308858680836e-07 9.547407353859e-07 + 3 0.004000 2 -2.115761487202e-07 -9.592031904027e-07 8.487071020804e-07 + 4 0.006000 1 -1.882128749321e-07 -9.308706490943e-07 9.547411441746e-07 + 4 0.006000 2 -2.116056008691e-07 -9.591888396507e-07 8.487074644192e-07 + 5 0.008000 1 -1.882142905166e-07 -9.308595806842e-07 9.547407223264e-07 + 5 0.008000 2 -2.116302286989e-07 -9.591793997900e-07 8.487125619965e-07 + 6 0.010000 1 -1.882181317617e-07 -9.308472706832e-07 9.547378595347e-07 + 6 0.010000 2 -2.116427322731e-07 -9.591821153713e-07 8.487231376542e-07 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_tot.txt.ref b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_tot.txt.ref new file mode 100644 index 00000000000..d1fba354c19 --- /dev/null +++ b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/torque_tot.txt.ref @@ -0,0 +1,8 @@ +# torque=dS/dt; S=M/2; unit=hbar/Hartree_atomic_time +#step time_fs tau_xc_x tau_xc_y tau_xc_z tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 -3.510254781217e-18 5.880494794026e-19 2.832312219438e-18 -3.997187646151e-07 -1.890157781421e-06 1.803451990760e-06 + 2 0.002000 -1.410431426153e-18 -7.427038165335e-20 1.538219221622e-18 -3.997529756893e-07 -1.890123634893e-06 1.803449901054e-06 + 3 0.004000 -2.306964507027e-18 3.602498050136e-19 1.776139515398e-18 -3.997867544630e-07 -1.890089058486e-06 1.803447837466e-06 + 4 0.006000 2.482140430757e-19 -2.221538828401e-18 1.000716467945e-18 -3.998184758012e-07 -1.890059488745e-06 1.803448608594e-06 + 5 0.008000 -8.732496375496e-19 5.656086023583e-19 4.135207780210e-19 -3.998445192155e-07 -1.890038980474e-06 1.803453284323e-06 + 6 0.010000 1.487624396363e-18 3.642230911274e-18 -4.028771362904e-18 -3.998608640348e-07 -1.890029386054e-06 1.803460997189e-06 diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk1s4_pw.dat b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk1s4_pw.dat new file mode 100644 index 00000000000..1c8e2b9a6cb Binary files /dev/null and b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk1s4_pw.dat differ diff --git a/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk2s4_pw.dat b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk2s4_pw.dat new file mode 100644 index 00000000000..06378cb4acc Binary files /dev/null and b/tests/05_rtTDDFT/30_PW_soc_onsite_TDDFT/wfk2s4_pw.dat differ diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/INPUT b/tests/05_rtTDDFT/31_PW_retry_TDDFT/INPUT new file mode 100644 index 00000000000..8fae3711ed0 --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/INPUT @@ -0,0 +1,54 @@ +INPUT_PARAMETERS + +suffix autotest +pseudo_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +ecutwfc 20 +ecutrho 80 +nbands 6 +nspin 1 +kpar 2 +symmetry 0 +init_wfc atomic+random +pw_seed 1 +pw_diag_thr 1e-14 +scf_thr 1e-14 +scf_nmax 100 +mixing_type broyden +mixing_beta 0.5 +mixing_gg0 0 +smearing_method gauss +smearing_sigma 0.002 +md_type nve +init_vel 1 +td_dt 0.01 +md_nstep 1 +estep_per_md 2 +cal_force 0 +cal_stress 0 +td_stype 1 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 0 +td_gauss_sigma 0.04 +td_gauss_t0 4 +td_gauss_amp 0.1 +lin_solver bicgstab +lin_precond kinetic +lin_thr 1e-14 +lin_maxiter 100 +td_cn_init 0 +lin_reconstruct 0 +out_current 1 +out_level ie +td_scf_nmax 2 +td_max_halvings 1 +out_vecpot 1 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/KPT b/tests/05_rtTDDFT/31_PW_retry_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/README b/tests/05_rtTDDFT/31_PW_retry_TDDFT/README new file mode 100644 index 00000000000..39590d9ef9b --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/README @@ -0,0 +1 @@ +CN rollback and two accepted half steps after a rejected full step. diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/STRU b/tests/05_rtTDDFT/31_PW_retry_TDDFT/STRU new file mode 100644 index 00000000000..e059e5d6062 --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/STRU @@ -0,0 +1,18 @@ +ATOMIC_SPECIES +Si 28 Si.pz-n-nc.UPF upf201 + +LATTICE_CONSTANT +10.2 + +LATTICE_VECTORS +0.0 0.5 0.5 +0.5 0.0 0.5 +0.5 0.5 0.0 + +ATOMIC_POSITIONS +Direct +Si +0.0 +2 +0.00 0.00 0.00 0 0 0 v 0 0 0 +0.25 0.25 0.25 0 0 0 v 0 0 0 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/31_PW_retry_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..476c6886e4e --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/current_tot.txt.ref @@ -0,0 +1,3 @@ + 1 -6.663532778066e-11 4.887391160452e-11 -5.307373793645e-11 + 2 1.378429778724e-05 1.617326170941e-09 -9.117934784250e-10 + 3 3.035454377592e-05 6.377589400826e-09 -6.017071519211e-10 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/result.ref b/tests/05_rtTDDFT/31_PW_retry_TDDFT/result.ref new file mode 100644 index 00000000000..d2ae790ec47 --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/result.ref @@ -0,0 +1,5 @@ +etotref -251.7683038351815 +etotperatomref -125.8841519176 +CompareCurrent_pass 0 +CompareVectorPot_pass 0 +totaltimeref 0.60 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/threshold b/tests/05_rtTDDFT/31_PW_retry_TDDFT/threshold new file mode 100644 index 00000000000..a8bf1288dee --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/threshold @@ -0,0 +1,2 @@ +# Allow platform-dependent residual currents in the CN half-step retry regression. +current_threshold 5e-10 diff --git a/tests/05_rtTDDFT/31_PW_retry_TDDFT/vector_pot.txt.ref b/tests/05_rtTDDFT/31_PW_retry_TDDFT/vector_pot.txt.ref new file mode 100644 index 00000000000..91c8736625c --- /dev/null +++ b/tests/05_rtTDDFT/31_PW_retry_TDDFT/vector_pot.txt.ref @@ -0,0 +1,4 @@ +#istep A_x A_y A_z # endpoint values, Hartree atomic units + 1 0.000000000000e+00 0.000000000000e+00 0.000000000000e+00 + 2 -4.959777768934e-04 0.000000000000e+00 0.000000000000e+00 + 3 -1.123854083691e-03 0.000000000000e+00 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/INPUT b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/INPUT new file mode 100644 index 00000000000..341b231dc79 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/INPUT @@ -0,0 +1,57 @@ +INPUT_PARAMETERS +suffix autotest +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +dft_functional PBE +gga_grad 1 +ecutwfc 20 +ecutrho 80 +nbands 12 +kpar 2 +nspin 4 +noncolin 1 +lspinorb 1 +symmetry -1 +init_wfc atomic+random +pw_seed 1 +ks_solver cg +pw_diag_thr 1e-13 +scf_thr 1e-12 +scf_nmax 150 +mixing_type broyden +mixing_beta 0.5 +mixing_beta_mag 0.5 +mixing_gg0 0 +mixing_gg0_mag 0 +smearing_method fd +smearing_sigma 0.002 +md_type nve +init_vel 1 +td_dt 0.002 +md_nstep 1 +estep_per_md 2 +cal_force 0 +cal_stress 0 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 1.5707963267948966 +td_gauss_sigma 0.04 +td_gauss_t0 0 +td_gauss_amp 0.1 +td_out_torque 1 +td_out_spincur 1 +out_current 1 +out_level ie +td_stype 0 +td_out_mag voronoi +td_propagator 2 +td_exp_method lanczos diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/KPT b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/README b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/README new file mode 100644 index 00000000000..be8b6ce0a7d --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/README @@ -0,0 +1 @@ +PW ETRS with Lanczos exponentials, SOC spinors, and length-gauge observables. diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/STRU b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/STRU new file mode 100644 index 00000000000..139b8c551ed --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/STRU @@ -0,0 +1,21 @@ +ATOMIC_SPECIES +Si 28 Si_dojo_soc.upf upf201 + +NUMERICAL_ORBITAL +Si_dojo_6au.orb + +LATTICE_CONSTANT +10.2 + +LATTICE_VECTORS +0.0 0.5 0.5 +0.5 0.0 0.5 +0.5 0.5 0.0 + +ATOMIC_POSITIONS +Direct +Si +0.0 +2 +0.00 0.00 0.00 0 0 0 v 0 0 0 +0.25 0.25 0.25 0 0 0 v 0 0 0 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..657fc28c1e9 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/current_tot.txt.ref @@ -0,0 +1,3 @@ + 1 8.346916421568e-13 -3.644420840810e-13 5.472776569248e-13 + 2 1.562307811783e-08 -2.662220923960e-11 3.476005420532e-11 + 3 6.240155549478e-08 -1.044462928688e-10 1.365536172091e-10 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_atom.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_atom.txt.ref new file mode 100644 index 00000000000..705d3eb33ea --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_atom.txt.ref @@ -0,0 +1,8 @@ +# method=voronoi; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +#step time_fs atom Mx My Mz + 1 0.000000 1 1.177025800765e-10 9.970419779322e-11 2.113907267441e-09 + 1 0.000000 2 -1.189354448948e-10 -1.002641160646e-10 -2.114796830022e-09 + 2 0.002000 1 1.085351767468e-10 1.022288489815e-10 2.113262988996e-09 + 2 0.002000 2 -1.197178364281e-10 -1.029410352339e-10 -2.113661836848e-09 + 3 0.004000 1 8.670318211369e-11 1.036770757901e-10 2.113310126670e-09 + 3 0.004000 2 -1.076915164488e-10 -1.045493576988e-10 -2.113203545705e-09 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_tot.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_tot.txt.ref new file mode 100644 index 00000000000..210b6f9a702 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/mag_tot.txt.ref @@ -0,0 +1,5 @@ +# method=voronoi; total=density_integral; M=ABACUS_Pauli_moment(mu_B); no_electron_minus_sign +#step time_fs Mx My Mz M_norm M_abs_integral N_elec + 1 0.000000 -1.232864818329e-12 -5.599182713832e-13 -8.895625810865e-13 1.620119043951e-12 5.503821331260e-09 8.000000000000e+00 + 2 0.002000 -1.118265968130e-11 -7.121862524545e-13 -3.988478519339e-13 1.121241126676e-11 1.166414660609e-08 8.000000000000e+00 + 3 0.004000 -2.098833433509e-11 -8.722819086693e-13 1.065809653229e-13 2.100672305220e-11 3.705155731334e-08 8.000000000000e+00 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/result.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/result.ref new file mode 100644 index 00000000000..7f2fb249f19 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/result.ref @@ -0,0 +1,9 @@ +etotref -218.4046782984434 +etotperatomref -109.2023391492 +Comparemag_tot_txt_pass 0 +Comparemag_atom_txt_pass 0 +Comparetorque_tot_txt_pass 0 +Comparetorque_atom_txt_pass 0 +Comparespincur_tot_txt_pass 0 +CompareCurrent_pass 0 +totaltimeref 1.29 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/spincur_tot.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/spincur_tot.txt.ref new file mode 100644 index 00000000000..5acbeb4c566 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/spincur_tot.txt.ref @@ -0,0 +1,5 @@ +# S=M/2; unit=hbar/(Bohr^2*Hartree_atomic_time); flow_index_first +#step time_fs Jxx Jxy Jxz Jyx Jyy Jyz Jzx Jzy Jzz + 1 0.000000 1.859077495368e-13 8.526814815197e-14 -1.860620491824e-13 -1.306729619305e-13 5.519297114688e-14 -2.764062734902e-14 -4.795053561659e-14 -6.445645299704e-15 4.152336329892e-14 + 2 0.002000 1.915436065379e-13 8.702021137592e-14 -2.048851445560e-13 -1.294838712425e-13 2.860844356380e-14 2.352088876453e-13 -4.984949425441e-14 -2.548311377977e-13 4.328114214190e-14 + 3 0.004000 2.340287009975e-13 9.960395459336e-14 -2.426694255743e-13 -1.137775332460e-13 -1.988087124708e-13 2.461600921603e-12 -5.312188516685e-14 -2.447910192201e-12 1.899872041638e-13 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_atom.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_atom.txt.ref new file mode 100644 index 00000000000..f02138456d7 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_atom.txt.ref @@ -0,0 +1,9 @@ +# SOC_pseudopotential_atom_decomposition; unit=hbar/Hartree_atomic_time +# not_the_derivative_of_atomic_moments +#step time_fs atom tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 1 -3.016287850338e-11 -4.414642547657e-13 1.463844284191e-12 + 1 0.000000 2 -3.004690151897e-11 -4.736198616105e-13 1.495463319381e-12 + 2 0.002000 1 -3.010134936602e-11 -4.417659001389e-13 1.475222396457e-12 + 2 0.002000 2 -2.989205187512e-11 -4.873992546830e-13 1.508822492632e-12 + 3 0.004000 1 -2.959723834443e-11 -4.699140823018e-13 1.562935778614e-12 + 3 0.004000 2 -2.862180975779e-11 -5.629465128838e-13 1.612074426545e-12 diff --git a/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_tot.txt.ref b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_tot.txt.ref new file mode 100644 index 00000000000..a3077b961a9 --- /dev/null +++ b/tests/05_rtTDDFT/32_PW_ETRS_lanczos_TDDFT/torque_tot.txt.ref @@ -0,0 +1,5 @@ +# torque=dS/dt; S=M/2; unit=hbar/Hartree_atomic_time +#step time_fs tau_xc_x tau_xc_y tau_xc_z tau_soc_x tau_soc_y tau_soc_z + 1 0.000000 -2.057950508879e-38 -1.013851825821e-37 3.832544962797e-39 -6.020978002235e-11 -9.150841163762e-13 2.959307603572e-12 + 2 0.002000 1.902795731857e-36 4.462790076828e-36 -4.882736102721e-36 -5.999340124114e-11 -9.291651548219e-13 2.984044889089e-12 + 3 0.004000 1.264236073095e-34 7.714219943401e-35 3.287948203490e-35 -5.821904810222e-11 -1.032860595186e-12 3.175010205159e-12 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/INPUT b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/INPUT new file mode 100644 index 00000000000..f3624af9950 --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/INPUT @@ -0,0 +1,49 @@ +INPUT_PARAMETERS + +suffix autotest +pseudo_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +ecutwfc 20 +ecutrho 80 +nbands 6 +nspin 1 +kpar 2 +symmetry 0 +init_wfc atomic+random +pw_seed 1 +pw_diag_thr 1e-14 +scf_thr 1e-12 +scf_nmax 100 +mixing_type broyden +mixing_beta 0.5 +mixing_gg0 0 +smearing_method gauss +smearing_sigma 0.002 +md_type nve +init_vel 1 +td_dt 0.01 +md_nstep 1 +estep_per_md 2 +cal_force 0 +cal_stress 0 +td_stype 1 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 0 +td_gauss_sigma 0.04 +td_gauss_t0 4 +td_gauss_amp 0.001 +out_current 1 +out_level ie +td_propagator 2 +td_exp_method taylor +td_exp_order 4 +out_vecpot 1 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/KPT b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/README b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/README new file mode 100644 index 00000000000..e4647c621da --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/README @@ -0,0 +1 @@ +PW ETRS with fourth-order Taylor exponentials and velocity-gauge current. diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/STRU b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/STRU new file mode 100644 index 00000000000..e059e5d6062 --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/STRU @@ -0,0 +1,18 @@ +ATOMIC_SPECIES +Si 28 Si.pz-n-nc.UPF upf201 + +LATTICE_CONSTANT +10.2 + +LATTICE_VECTORS +0.0 0.5 0.5 +0.5 0.0 0.5 +0.5 0.5 0.0 + +ATOMIC_POSITIONS +Direct +Si +0.0 +2 +0.00 0.00 0.00 0 0 0 v 0 0 0 +0.25 0.25 0.25 0 0 0 v 0 0 0 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..0d8bc108dd7 --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/current_tot.txt.ref @@ -0,0 +1,3 @@ + 1 -7.675792081022e-13 5.456748969816e-14 -8.794013212544e-13 + 2 1.383341747462e-07 1.354579554469e-11 -1.075264988975e-11 + 3 3.036909428735e-07 6.138129509335e-11 -7.848342998581e-12 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/result.ref b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/result.ref new file mode 100644 index 00000000000..75dc8f29420 --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/result.ref @@ -0,0 +1,5 @@ +etotref -251.7684289155609 +etotperatomref -125.8842144578 +CompareCurrent_pass 0 +CompareVectorPot_pass 0 +totaltimeref 0.41 diff --git a/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/vector_pot.txt.ref b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/vector_pot.txt.ref new file mode 100644 index 00000000000..1d89655bf1a --- /dev/null +++ b/tests/05_rtTDDFT/33_PW_ETRS_taylor_TDDFT/vector_pot.txt.ref @@ -0,0 +1,4 @@ +#istep A_x A_y A_z # endpoint values, Hartree atomic units + 1 0.000000000000e+00 0.000000000000e+00 0.000000000000e+00 + 2 -4.959777768934e-06 0.000000000000e+00 0.000000000000e+00 + 3 -1.123854083691e-05 0.000000000000e+00 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/INPUT b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/INPUT new file mode 100644 index 00000000000..914ad487b66 --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/INPUT @@ -0,0 +1,50 @@ +INPUT_PARAMETERS + +suffix autotest +pseudo_dir ../../PP_ORB +esolver_type tddft +basis_type pw +calculation md +device cpu +precision double +ecutwfc 20 +ecutrho 80 +nbands 6 +nspin 1 +kpar 2 +symmetry 0 +init_wfc atomic+random +pw_seed 1 +pw_diag_thr 1e-14 +scf_thr 1e-14 +scf_nmax 100 +mixing_type broyden +mixing_beta 0.5 +mixing_gg0 0 +smearing_method gauss +smearing_sigma 0.002 +md_type nve +init_vel 1 +td_dt 0.01 +md_nstep 1 +estep_per_md 2 +cal_force 0 +cal_stress 0 +td_stype 1 +td_vext 1 +td_vext_dire 1 +td_ttype 0 +td_tstart 0 +td_tend 100 +td_gauss_freq 2 +td_gauss_phase 0 +td_gauss_sigma 0.04 +td_gauss_t0 4 +td_gauss_amp 0.1 +out_current 1 +out_level ie +td_propagator 2 +td_exp_method lanczos +td_scf_nmax 2 +td_max_halvings 1 +out_vecpot 1 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/KPT b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/KPT new file mode 100644 index 00000000000..23f1466d0f8 --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/KPT @@ -0,0 +1,5 @@ +K_POINTS +2 +Direct +0.17 0.11 0.07 0.5 +-0.17 -0.11 -0.07 0.5 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/README b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/README new file mode 100644 index 00000000000..a93ab130d21 --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/README @@ -0,0 +1 @@ +ETRS rollback and rebuilding the left half-step after a rejected full step. diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/STRU b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/STRU new file mode 100644 index 00000000000..e059e5d6062 --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/STRU @@ -0,0 +1,18 @@ +ATOMIC_SPECIES +Si 28 Si.pz-n-nc.UPF upf201 + +LATTICE_CONSTANT +10.2 + +LATTICE_VECTORS +0.0 0.5 0.5 +0.5 0.0 0.5 +0.5 0.5 0.0 + +ATOMIC_POSITIONS +Direct +Si +0.0 +2 +0.00 0.00 0.00 0 0 0 v 0 0 0 +0.25 0.25 0.25 0 0 0 v 0 0 0 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/current_tot.txt.ref b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/current_tot.txt.ref new file mode 100644 index 00000000000..15f12d0501b --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/current_tot.txt.ref @@ -0,0 +1,3 @@ + 1 -6.663532778066e-11 4.887391160452e-11 -5.307373793645e-11 + 2 1.380219064060e-05 1.534993735131e-09 -9.581662699563e-10 + 3 3.035552361407e-05 6.279641504215e-09 -6.909372404875e-10 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/result.ref b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/result.ref new file mode 100644 index 00000000000..6ff7228b620 --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/result.ref @@ -0,0 +1,5 @@ +etotref -251.7683034865009 +etotperatomref -125.8841517433 +CompareCurrent_pass 0 +CompareVectorPot_pass 0 +totaltimeref 0.50 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/threshold b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/threshold new file mode 100644 index 00000000000..0eefe69df0a --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/threshold @@ -0,0 +1,2 @@ +# Parallel-layout and threading sweeps measured current deviations up to 3.005e-10. +current_threshold 5e-10 diff --git a/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/vector_pot.txt.ref b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/vector_pot.txt.ref new file mode 100644 index 00000000000..91c8736625c --- /dev/null +++ b/tests/05_rtTDDFT/34_PW_ETRS_retry_TDDFT/vector_pot.txt.ref @@ -0,0 +1,4 @@ +#istep A_x A_y A_z # endpoint values, Hartree atomic units + 1 0.000000000000e+00 0.000000000000e+00 0.000000000000e+00 + 2 -4.959777768934e-04 0.000000000000e+00 0.000000000000e+00 + 3 -1.123854083691e-03 0.000000000000e+00 0.000000000000e+00 diff --git a/tests/05_rtTDDFT/CASES_CPU.txt b/tests/05_rtTDDFT/CASES_CPU.txt index 8cbca6fadab..e3615075024 100644 --- a/tests/05_rtTDDFT/CASES_CPU.txt +++ b/tests/05_rtTDDFT/CASES_CPU.txt @@ -26,3 +26,9 @@ 26_PW_single_TDDFT 27_PW_gmres_recycle_TDDFT 28_PW_gmres_subspace_TDDFT +29_PW_soc_len_TDDFT +30_PW_soc_onsite_TDDFT +31_PW_retry_TDDFT +32_PW_ETRS_lanczos_TDDFT +33_PW_ETRS_taylor_TDDFT +34_PW_ETRS_retry_TDDFT diff --git a/tests/05_rtTDDFT/CASES_GPU.txt b/tests/05_rtTDDFT/CASES_GPU.txt index c2cf48ba997..e8808ed7ba0 100644 --- a/tests/05_rtTDDFT/CASES_GPU.txt +++ b/tests/05_rtTDDFT/CASES_GPU.txt @@ -26,3 +26,9 @@ 26_PW_single_TDDFT 27_PW_gmres_recycle_TDDFT 28_PW_gmres_subspace_TDDFT +29_PW_soc_len_TDDFT +30_PW_soc_onsite_TDDFT +31_PW_retry_TDDFT +32_PW_ETRS_lanczos_TDDFT +33_PW_ETRS_taylor_TDDFT +34_PW_ETRS_retry_TDDFT diff --git a/tests/11_PW_GPU/scf_bpcg/result.ref b/tests/11_PW_GPU/scf_bpcg/result.ref index a4c2417f26a..d5fb85432ea 100644 --- a/tests/11_PW_GPU/scf_bpcg/result.ref +++ b/tests/11_PW_GPU/scf_bpcg/result.ref @@ -5,4 +5,4 @@ totalstressref 37241.465646 pointgroupref C_1 spacegroupref C_1 nksibzref 8 -totaltimeref 10.28 +totaltimeref 8.47 diff --git a/tests/integrate/Autotest.sh b/tests/integrate/Autotest.sh index 4f49b3ade9b..950febe09ac 100755 --- a/tests/integrate/Autotest.sh +++ b/tests/integrate/Autotest.sh @@ -181,6 +181,7 @@ check_out(){ stress_thr=$4 fatal_thr=$5 descriptor_thr=$6 + wfc_thr=${7:-$thr} #------------------------------------------------------ # outfile = result.out @@ -240,6 +241,8 @@ check_out(){ compare_thr=$thr if [[ $key == ml_desc_mean_* ]]; then compare_thr=$descriptor_thr + elif [[ $key == wfi*.cube || $key == *_wfc_fp_rms || $key == *_wfc_fp_power_* || $key == *_wfc_fp_cross_* ]]; then + compare_thr=$wfc_thr fi if [ $(check_deviation_pass $deviation $compare_thr) = 0 ]; then if [ $key == "totalforceref" ]; then @@ -384,7 +387,8 @@ run_case() my_stress_threshold=$(get_threshold $threshold_file "stress_threshold" $stress_threshold) my_fatal_threshold=$(get_threshold $threshold_file "fatal_threshold" $fatal_threshold) my_descriptor_threshold=$(get_threshold $threshold_file "descriptor_threshold" $descriptor_threshold) - check_out result.out $my_threshold $my_force_threshold $my_stress_threshold $my_fatal_threshold $my_descriptor_threshold + my_wfc_threshold=$(get_threshold $threshold_file "wfc_threshold" $my_threshold) + check_out result.out $my_threshold $my_force_threshold $my_stress_threshold $my_fatal_threshold $my_descriptor_threshold $my_wfc_threshold fi else bash -e ../../integrate/validation_tools/catch_properties.sh result.ref diff --git a/tests/integrate/validation_tools/CompareFile.py b/tests/integrate/validation_tools/CompareFile.py index 4aa6cb13547..ea425babcc3 100755 --- a/tests/integrate/validation_tools/CompareFile.py +++ b/tests/integrate/validation_tools/CompareFile.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +import math import sys usage = ''' -python CompareFile.py file1 file2 [accuracy] [-abs 0] [-com_type 1] +python CompareFile.py file1 file2 [accuracy] [-abs 0] [-com_type 1] [-tol value] accuracy - the accuracy of two float value. default value is 8, which means @@ -12,6 +13,8 @@ -com_type - 0: assure the relative difference of two float value is smaller than accuracy - 1: assure the absolute difference of two float value is smaller than accuracy - Default is 1 +-tol - finite positive comparison tolerance, overriding accuracy + in either absolute or relative difference mode This script is used to compare whether two files are the same. If compared two strings are different OR the difference @@ -23,17 +26,28 @@ ''' def ReadParam(): - if len(sys.argv) not in [3,4,5,6,7,8]: + if len(sys.argv) < 3: print(usage) sys.exit(1) file1 = sys.argv[1] file2 = sys.argv[2] accur = 8 + tolerance = None useAbsoluteVal = False compareAbsoluteDiff = True argi = 3 while argi < len(sys.argv): - if sys.argv[argi] == '-abs': + if sys.argv[argi] == '-tol': + argi += 1 + if argi >= len(sys.argv): + sys.exit('Error: -tol requires a finite positive number.') + try: + tolerance = float(sys.argv[argi]) + except ValueError: + sys.exit('Error: -tol requires a finite positive number.') + if not math.isfinite(tolerance) or tolerance <= 0: + sys.exit('Error: -tol requires a finite positive number.') + elif sys.argv[argi] == '-abs': argi += 1 useAbsoluteVal = bool(int(sys.argv[argi])) elif sys.argv[argi] == '-com_type': @@ -42,7 +56,7 @@ def ReadParam(): else: accur = int(sys.argv[argi]) argi += 1 - epsilon = 0.1**accur + epsilon = 0.1**accur if tolerance is None else tolerance return file1,file2,epsilon,useAbsoluteVal,compareAbsoluteDiff def is_two_data_diff(data1,data2,epsilon,compareAbsoluteDiff): diff --git a/tests/integrate/validation_tools/props_cube.sh b/tests/integrate/validation_tools/props_cube.sh index 1dfd83270ff..68134aa6ffb 100644 --- a/tests/integrate/validation_tools/props_cube.sh +++ b/tests/integrate/validation_tools/props_cube.sh @@ -197,10 +197,23 @@ fi # 2. out_wfc_norm/out_wfc_re_im/out_pchg (PW) #-------------------------------------------- shopt -s nullglob +local pchg_tol=1e-6 +if [ -f threshold ]; then + local configured_tol + configured_tol=$(get_input_key_value pchg_threshold threshold) + if [ -n "$configured_tol" ]; then + pchg_tol=$configured_tol + fi +fi for pchg_ref in pchgi*.cube.ref; do pchg_cube=${pchg_ref%.ref} pchg_key=$(sanitize_result_key "${pchg_cube}_compare") - record_compare_result "$props_result_file" "$pchg_key" "$pchg_ref" "OUT.autotest/$pchg_cube" 6 + if [ ! -f "OUT.autotest/$pchg_cube" ]; then + echo "$pchg_key 1" >> "$props_result_file" + continue + fi + python3 "$COMPARE_SCRIPT" "$pchg_ref" "OUT.autotest/$pchg_cube" -tol "$pchg_tol" + echo "$pchg_key $?" >> "$props_result_file" done shopt -u nullglob diff --git a/tests/integrate/validation_tools/props_tddft.sh b/tests/integrate/validation_tools/props_tddft.sh index 5d3f7d1eace..d3b30991fda 100644 --- a/tests/integrate/validation_tools/props_tddft.sh +++ b/tests/integrate/validation_tools/props_tddft.sh @@ -9,12 +9,30 @@ run_tddft_props(){ #-------------------------------------------- -# check currents in rt-TDDFT +# Check spin observables in rt-TDDFT +#-------------------------------------------- +for spin_file in mag_tot.txt mag_atom.txt torque_tot.txt torque_atom.txt spincur_tot.txt; do + if [ -f "$spin_file.ref" ]; then + spin_key=$(sanitize_result_key "$spin_file") + record_compare_result "$props_result_file" "Compare${spin_key}_pass" "$spin_file.ref" "OUT.autotest/$spin_file" 8 + fi +done + +#-------------------------------------------- +# Check currents in rt-TDDFT #-------------------------------------------- if ! test -z "$out_current" && [ $out_current ]; then current1ref=current_tot.txt.ref current1cal=OUT.autotest/current_tot.txt - python3 $COMPARE_SCRIPT $current1ref $current1cal 10 + local current_tol=1e-10 + if [ -f threshold ]; then + local configured_tol + configured_tol=$(get_input_key_value current_threshold threshold) + if [ -n "$configured_tol" ]; then + current_tol=$configured_tol + fi + fi + python3 "$COMPARE_SCRIPT" "$current1ref" "$current1cal" -tol "$current_tol" echo "CompareCurrent_pass $?" >>$props_result_file fi