25#ifndef __MULTI_CG_HPP__
26#define __MULTI_CG_HPP__
46repack(std::vector<T> &data, std::vector<int>
const&ids)
48 for (
size_t i = 0; i < ids.size(); ++i) {
49 data[i] = data[ids[i]];
53template<
typename Matrix,
typename Prec,
typename StateVec>
55multi_cg(
Matrix &A, Prec &P, StateVec &X, StateVec &B, StateVec &U, StateVec &C,
56 int maxiters = 10,
double tol = 1e-3,
bool initial_guess_is_zero =
false) {
58 PROFILE(
"sirius::multi_cg");
60 auto const n = X.cols();
69 if (!initial_guess_is_zero) {
70 A.multiply(-1.0, X, 1.0, R, n);
73 auto rhos = std::vector<typename StateVec::value_type>(n);
80 auto ids = std::vector<int>(n);
81 std::iota(ids.begin(), ids.end(), 0);
83 size_t num_unconverged = n;
87 auto residual_history = std::vector<std::vector<typename StateVec::value_type>>(n);
89 for (
int iter = 0; iter < maxiters; ++iter) {
103 C.block_dot(R, rhos, num_unconverged);
105 for (
size_t i = 0; i < num_unconverged; ++i) {
106 residual_history[ids[i]].push_back(std::sqrt(std::abs(rhos[i])));
109 auto not_converged = std::vector<int>{};
110 for (
size_t i = 0; i < num_unconverged; ++i) {
111 if (std::abs(rhos[i]) > tol * tol) {
112 not_converged.push_back(i);
116 num_unconverged = not_converged.size();
118 niter_eff +=
static_cast<double>(num_unconverged) / n;
120 if (not_converged.empty()) {
126 repack(ids, not_converged);
127 repack(rhos, not_converged);
128 repack(rhos_old, not_converged);
130 U.repack(not_converged);
131 C.repack(not_converged);
132 R.repack(not_converged);
134 A.repack(not_converged);
135 P.repack(not_converged);
140 if (sddk::is_device_memory(P.mem)) {
141 P.eigvals.copy_to(sddk::memory_t::device);
146 U.copy(C, num_unconverged);
148 for (
size_t i = 0; i < num_unconverged; ++i) {
149 alphas[i] = rhos[i] / rhos_old[i];
153 U.block_xpby(C, alphas, num_unconverged);
157 A.multiply(1.0, U, 0.0, C, num_unconverged);
161 U.block_dot(C, sigmas, num_unconverged);
164 for (
size_t i = 0; i < num_unconverged; ++i) {
165 alphas[i] = rhos[i] / sigmas[i];
169 X.block_axpy_scatter(alphas, U, ids, num_unconverged);
171 for (
size_t i = 0; i < num_unconverged; ++i) {
176 R.block_axpy(alphas, C, num_unconverged);
179 std::vector<std::vector<typename StateVec::value_type>> residual_history;
180 int niter;
int niter_eff;} result{residual_history, niter,
static_cast<int>(niter_eff)};
192 typedef std::complex<double> value_type;
204 void block_dot(
Wave_functions_wrap const& y__, std::vector<value_type>& rhos__,
size_t N__)
206 rhos__ = wf::inner_diag<double, value_type>(mem, *x, *y__.x,
wf::spin_range(0),
210 void repack(std::vector<int>
const& ids__)
212 PROFILE(
"sirius::Wave_functions_wrap::repack");
214 for (
auto i : ids__) {
229 void block_xpby(
Wave_functions_wrap const &y__, std::vector<value_type>
const &alphas,
int N__) {
230 std::vector<value_type> ones(N__, 1.0);
234 void block_axpy_scatter(std::vector<value_type>
const& alphas__,
Wave_functions_wrap const &y__,
235 std::vector<int>
const &idx__,
int n__)
237 wf::axpy_scatter<double, value_type, int>(mem,
wf::spin_range(0), alphas__.data(), y__.x, idx__.data(), x, n__);
240 void block_axpy(std::vector<value_type>
const &alphas__,
Wave_functions_wrap const &y__,
int N__) {
241 std::vector<value_type> ones(N__, 1.0);
250 x.copy(y, num_active);
253 void repack(std::vector<int>
const &ids) {
254 num_active = ids.size();
268 x.copy(y, num_active);
279 void repack(std::vector<int>
const &ids) {
280 num_active = ids.size();
281 for (
size_t i = 0; i < ids.size(); ++i) {
282 eigvals[i] = eigvals[ids[i]];
290 std::vector<double> min_eigenvals;
304 std::vector<double>
const &eigvals,
313 : ctx(ctx), Hk(Hk), min_eigenvals(eigvals), Hphi(Hphi), Sphi(Sphi), evq(evq), tmp(tmp),
314 alpha_pv(alpha_pv), br(br), sr(sr), mem(mem), overlap(br.size(), br.size())
323 for (
auto &e : min_eigenvals) {
328 void repack(std::vector<int>
const &ids) {
329 for (
size_t i = 0; i < ids.size(); ++i) {
330 min_eigenvals[i] = min_eigenvals[ids[i]];
337 PROFILE(
"sirius::Linear_response_operator::multiply");
347 std::vector<double> ones(num_active, 1.0);
351 min_eigenvals.data(), Sphi, ones.data(), Hphi);
372 std::vector<double> alpha_pvs(num_active, alpha_pv);
374 alpha_pvs.data(), Sphi, ones.data(), tmp);
376 std::vector<double> alphas(num_active, alpha);
377 std::vector<double> betas(num_active, beta);
379 alphas.data(), tmp, betas.data(), y.x);
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > apply_h_s(wf::spin_range spins__, wf::band_range br__, wf::Wave_functions< T > const &phi__, wf::Wave_functions< T > *hphi__, wf::Wave_functions< T > *sphi__) const
Apply pseudopotential H and S operators to the wavefunctions.
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > apply_s(wf::spin_range spin__, wf::band_range br__, wf::Wave_functions< T > const &phi__, wf::Wave_functions< T > &sphi__) const
apply S operator
Simulation context is a set of parameters and objects describing a single simulation.
auto num_wf() const
Return number of wave-functions.
void zero(sddk::memory_t mem__, spin_index s__, band_range br__)
Zero a spin component of the wave-functions in a band range.
Describe a range of bands.
Describe a range of spins.
Contains declaration and definition of sirius::Hamiltonian class.
Contains definition of sirius::K_point class.
memory_t
Memory types where the code can store data.
void axpby(sddk::memory_t mem__, wf::spin_range spins__, wf::band_range br__, F const *alpha__, wf::Wave_functions< T > const *x__, F const *beta__, wf::Wave_functions< T > *y__)
Perform y <- a * x + b * y type of operation.
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > inner(::spla::Context &spla_ctx__, sddk::memory_t mem__, spin_range spins__, W const &wf_i__, band_range br_i__, Wave_functions< T > const &wf_j__, band_range br_j__, la::dmatrix< F > &result__, int irow0__, int jcol0__)
Compute inner product between the two sets of wave-functions.
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > transform(::spla::Context &spla_ctx__, sddk::memory_t mem__, la::dmatrix< F > const &M__, int irow0__, int jcol0__, real_type< F > alpha__, Wave_functions< T > const &wf_in__, spin_index s_in__, band_range br_in__, real_type< F > beta__, Wave_functions< T > &wf_out__, spin_index s_out__, band_range br_out__)
Apply linear transformation to the wave-functions.
void copy(sddk::memory_t mem__, Wave_functions< T > const &in__, wf::spin_index s_in__, wf::band_range br_in__, Wave_functions< F > &out__, wf::spin_index s_out__, wf::band_range br_out__)
Copy wave-functions.
Namespace of the SIRIUS library.
void apply_preconditioner(sddk::memory_t mem__, wf::spin_range spins__, wf::num_bands num_bands__, wf::Wave_functions< T > &res__, sddk::mdarray< T, 2 > const &h_diag__, sddk::mdarray< T, 2 > const &o_diag__, sddk::mdarray< T, 1 > const &eval__)
Apply preconditioner to the residuals.
Contains declaration of sirius::Non_local_operator class.
Compute residuals from the eigen-vectors and basis functions.
Contains declaration and implementation of Wave_functions class.