| 2130 | }; |
| 2131 | |
| 2132 | DensityGradient compute_density_gradient( |
| 2133 | const PlaneWaveBasis& pw, |
| 2134 | const std::vector<double>& rho_r |
| 2135 | ) { |
| 2136 | const int nx = pw.fft_size[0]; |
| 2137 | const int ny = pw.fft_size[1]; |
| 2138 | const int nz = pw.fft_size[2]; |
| 2139 | const int n_grid = nx * ny * nz; |
| 2140 | if (static_cast<int>(rho_r.size()) != n_grid) { |
| 2141 | throw std::invalid_argument("compute_density_gradient: rho_r size mismatch with FFT grid"); |
| 2142 | } |
| 2143 | |
| 2144 | FFT3D fft(nx, ny, nz); |
| 2145 | std::vector<Vec3d> gcart_by_idx(static_cast<std::size_t>(n_grid), Vec3d{0.0, 0.0, 0.0}); |
| 2146 | for (int ix = 0; ix < nx; ++ix) { |
| 2147 | const int gx = signed_miller_from_fft_index(ix, nx); |
| 2148 | for (int iy = 0; iy < ny; ++iy) { |
| 2149 | const int gy = signed_miller_from_fft_index(iy, ny); |
| 2150 | for (int iz = 0; iz < nz; ++iz) { |
| 2151 | const int gz = signed_miller_from_fft_index(iz, nz); |
| 2152 | const int idx = flat_index_3d(ix, iy, iz, ny, nz); |
| 2153 | gcart_by_idx[static_cast<std::size_t>(idx)] = matvec(pw.lattice.G, Vec3i{gx, gy, gz}); |
| 2154 | } |
| 2155 | } |
| 2156 | } |
| 2157 | |
| 2158 | std::vector<Complex> rho_c(static_cast<std::size_t>(n_grid), Complex{0.0, 0.0}); |
| 2159 | std::vector<Complex> rho_g(static_cast<std::size_t>(n_grid), Complex{0.0, 0.0}); |
| 2160 | for (int i = 0; i < n_grid; ++i) { |
| 2161 | rho_c[static_cast<std::size_t>(i)] = Complex{rho_r[static_cast<std::size_t>(i)], 0.0}; |
| 2162 | } |
| 2163 | fft.forward(rho_c.data(), rho_g.data()); |
| 2164 | |
| 2165 | const Complex imag_unit{0.0, 1.0}; |
| 2166 | std::vector<Complex> grad_g(static_cast<std::size_t>(n_grid), Complex{0.0, 0.0}); |
| 2167 | std::vector<Complex> grad_r_c(static_cast<std::size_t>(n_grid), Complex{0.0, 0.0}); |
| 2168 | std::vector<Vec3d> grad(static_cast<std::size_t>(n_grid), Vec3d{0.0, 0.0, 0.0}); |
| 2169 | for (int comp = 0; comp < 3; ++comp) { |
| 2170 | for (int idx = 0; idx < n_grid; ++idx) { |
| 2171 | const double g_comp = gcart_by_idx[static_cast<std::size_t>(idx)][comp]; |
| 2172 | grad_g[static_cast<std::size_t>(idx)] = imag_unit * g_comp * rho_g[static_cast<std::size_t>(idx)]; |
| 2173 | } |
| 2174 | fft.backward(grad_g.data(), grad_r_c.data()); |
| 2175 | for (int idx = 0; idx < n_grid; ++idx) { |
| 2176 | grad[static_cast<std::size_t>(idx)][comp] = std::real(grad_r_c[static_cast<std::size_t>(idx)]); |
| 2177 | } |
| 2178 | } |
| 2179 | |
| 2180 | DensityGradient out; |
| 2181 | out.grad = std::move(grad); |
| 2182 | out.gcart_by_idx = std::move(gcart_by_idx); |
| 2183 | return out; |
| 2184 | } |
| 2185 | |
| 2186 | XcEvaluation evaluate_gga_xc_unpolarized( |
| 2187 | const PlaneWaveBasis& pw, |
no test coverage detected