37using namespace nlcglib;
43template <
class wfc_ptr_t>
44std::shared_ptr<Matrix>
45make_vector(std::vector<wfc_ptr_t>
const& wfct, Simulation_context
const& ctx, K_point_set
const& kset,
46 nlcglib::memory_type memory = nlcglib::memory_type::none)
48 std::map<sddk::memory_t, nlcglib::memory_type> memtype = {
49 {sddk::memory_t::device, nlcglib::memory_type::device},
50 {sddk::memory_t::host, nlcglib::memory_type::host},
51 {sddk::memory_t::host_pinned, nlcglib::memory_type::host}};
52 std::map<nlcglib::memory_type, sddk::memory_t> memtype_lookup = {
53 {nlcglib::memory_type::none, sddk::memory_t::none},
54 {nlcglib::memory_type::device, sddk::memory_t::device},
55 {nlcglib::memory_type::host, sddk::memory_t::host},
56 {nlcglib::memory_type::host, sddk::memory_t::host_pinned}};
58 sddk::memory_t target_memory = memtype_lookup.at(memory);
59 if (target_memory == sddk::memory_t::none) {
60 target_memory = ctx.processing_unit_memory_t();
63 std::vector<Matrix::buffer_t> data;
64 std::vector<std::pair<int, int>> kpoint_indices;
66 int num_spins = ctx.num_spins();
67 int nb = ctx.num_bands();
68 for (
auto i = 0u; i < wfct.size(); ++i) {
69 auto gidk = kset.spl_num_kpoints().global_index(
typename kp_index_t::local(i));
70 for (
int ispn = 0; ispn < num_spins; ++ispn) {
71 auto&
array = wfct[i]->pw_coeffs(wf::spin_index(ispn));
72 int lda =
array.size(0);
73 MPI_Comm comm = wfct[i]->comm().native();
77 if (!
array.on_device()) {
78 RTE_THROW(
"Error: expected device storage, but got nullptr");
81 kpoint_indices.emplace_back(std::make_pair(gidk, ispn));
82 data.emplace_back(std::array<int, 2>{1, lda},
83 std::array<int, 2>{lda, nb},
84 array.at(target_memory),
85 memtype.at(target_memory), comm );
88 return std::make_shared<Matrix>(std::move(data), std::move(kpoint_indices), kset.comm().native());
98Matrix::get(
int i)
const
103Energy::Energy(K_point_set& kset, Density& density, Potential& potential)
106 , potential_(potential)
108 int nk = kset.spl_num_kpoints().local_size();
109 auto& ctx = kset.ctx();
112 for (
auto it : kset.spl_num_kpoints()) {
113 auto& kp = *kset.get<
double>(it.i);
114 sddk::memory_t preferred_memory_t = ctx.processing_unit_memory_t();
115 auto num_mag_dims = wf::num_mag_dims(ctx.num_mag_dims());
116 auto num_bands = wf::num_bands(ctx.num_bands());
119 std::make_shared<wf::Wave_functions<prec_t>>(kp.gkvec_sptr(), num_mag_dims, num_bands, preferred_memory_t);
120 cphis_[it.li] = &kp.spinor_wave_functions();
121 hphis_[it.li]->allocate(sddk::memory_t::host);
129 auto& ctx = kset_.ctx();
130 int num_spins = ctx.num_spins();
131 int num_bands = ctx.num_bands();
133 density_.generate<prec_t>(kset_, ctx.use_symmetry(),
true ,
true );
135 potential_.generate(density_, ctx.use_symmetry(),
true);
138 auto H0 = Hamiltonian0<double>(potential_,
true);
140 auto proc_mem_t = ctx.processing_unit_memory_t();
143 for (
auto it : kset_.spl_num_kpoints()) {
144 auto& kp = *kset_.get<prec_t>(it.i);
145 std::vector<double> band_energies(num_bands);
147 auto mem_guard = cphis_[it.li]->memory_guard(proc_mem_t, wf::copy_to::device);
148 auto mem_guard_h = hphis_[it.li]->memory_guard(proc_mem_t, wf::copy_to::host);
150 auto null_ptr_wfc = std::shared_ptr<wf::Wave_functions<prec_t>>();
151 apply_hamiltonian(H0, kp, *hphis_[it.li], kp.spinor_wave_functions(), null_ptr_wfc);
153 for (
int ispn = 0; ispn < num_spins; ++ispn) {
154 for (
int jj = 0; jj < num_bands; ++jj) {
155 la::dmatrix<std::complex<double>> dmat(1, 1, sddk::memory_t::host);
156 dmat.allocate(sddk::memory_t::device);
157 wf::band_range bandr{jj, jj + 1};
158 wf::inner(ctx.spla_context(), proc_mem_t, wf::spin_range(ispn),
159 kp.spinor_wave_functions(), bandr,
160 *hphis_[it.li], bandr,
162 kp.band_energy(jj, ispn, dmat(0, 0).real());
167 kset_.sync_band<double, sync_band_t::energy>();
170 double eewald =
ewald_energy(ctx, ctx.gvec(), ctx.unit_cell());
171 energy_components_ = total_energy_components(ctx, kset_, density_, potential_, eewald);
172 etot_ = ks_energy(ctx, this->energy_components_);
178 return kset_.ctx().max_occupancy();
184 return kset_.unit_cell().num_electrons();
187std::shared_ptr<nlcglib::MatrixBaseZ>
188Energy::get_hphi(nlcglib::memory_type memory = nlcglib::memory_type::none)
190 return make_vector(this->hphis_, this->kset_.ctx(), this->kset_, memory);
193std::shared_ptr<nlcglib::MatrixBaseZ>
194Energy::get_sphi(nlcglib::memory_type memory = nlcglib::memory_type::none)
196 return make_vector(this->sphis_, this->kset_.ctx(), this->kset_, memory);
199std::shared_ptr<nlcglib::MatrixBaseZ>
200Energy::get_C(nlcglib::memory_type memory = nlcglib::memory_type::none)
202 return make_vector(this->cphis_, this->kset_.ctx(), this->kset_, memory);
205std::shared_ptr<nlcglib::VectorBaseZ>
208 const int ns = kset_.ctx().num_spins();
209 int nbands = kset_.ctx().num_bands();
210 std::vector<std::vector<double>> fn;
211 std::vector<std::pair<int, int>> kindices;
212 for (
auto it : kset_.spl_num_kpoints()) {
213 auto& kp = *kset_.get<prec_t>(it.i);
214 for (
int ispn = 0; ispn < ns; ++ispn) {
215 std::vector<double> fn_local(nbands);
216 for (
int i = 0; i < nbands; ++i) {
217 fn_local[i] = kp.band_occupancy(i, ispn);
219 fn.push_back(std::move(fn_local));
220 kindices.emplace_back(it.i, ispn);
223 return std::make_shared<Array1d>(fn, kindices, kset_.comm().native());
227Energy::set_fn(
const std::vector<std::pair<int, int>>& keys,
const std::vector<std::vector<double>>& fn)
229 const int nbands = kset_.ctx().num_bands();
231 const int ns = kset_.ctx().num_spins();
232 auto nk = kset_.spl_num_kpoints().local_size();
233 const double max_occ = ns == 1 ? 2.0 : 1.0;
236 assert(
static_cast<int>(fn.size()) == nk * ns);
237 for (
auto iloc = 0u; iloc < fn.size(); ++iloc) {
239 int gidk = keys[iloc].first;
240 int ispn = keys[iloc].second;
241 auto& kp = *kset_.get<prec_t>(gidk);
242 const auto& fn_loc = fn[iloc];
243 assert(
static_cast<int>(fn_loc.size()) == nbands);
244 for (
int i = 0; i < nbands; ++i) {
245 assert(fn_loc[i] >= 0);
246 kp.band_occupancy(i, ispn, fn_loc[i]);
249 kset_.sync_band<double, sync_band_t::occupancy>();
252std::shared_ptr<nlcglib::VectorBaseZ>
255 const int ns = kset_.ctx().num_spins();
256 int nbands = kset_.ctx().num_bands();
257 std::vector<std::vector<double>> ek;
258 std::vector<std::pair<int, int>> kindices;
259 for (
auto it : kset_.spl_num_kpoints()) {
260 auto& kp = *kset_.get<prec_t>(it.i);
261 for (
int ispn = 0; ispn < ns; ++ispn) {
262 std::vector<double> ek_local(nbands);
263 for (
int i = 0; i < nbands; ++i) {
264 ek_local[i] = kp.band_energy(i, ispn);
266 ek.push_back(std::move(ek_local));
267 kindices.emplace_back(it.i.get(), ispn);
270 return std::make_shared<Array1d>(ek, kindices, kset_.comm().native());
273std::shared_ptr<nlcglib::VectorBaseZ>
274Energy::get_gkvec_ekin()
276 const int ns = kset_.ctx().num_spins();
277 std::vector<std::vector<double>> gkvec_cart;
278 std::vector<std::pair<int, int>> kindices;
279 for (
auto it : kset_.spl_num_kpoints()) {
280 auto& kp = *kset_.get<prec_t>(it.i);
281 for (
int ispn = 0; ispn < ns; ++ispn) {
282 int gkvec_count = kp.gkvec().count();
283 auto& gkvec = kp.gkvec();
284 std::vector<double> gkvec_local(gkvec_count);
285 for (
int i = 0; i < gkvec_count; ++i) {
286 gkvec_local[i] = gkvec.gkvec_cart<index_domain_t::global>(i).length();
288 gkvec_cart.push_back(std::move(gkvec_local));
289 kindices.emplace_back(it.i.get(), ispn);
292 return std::make_shared<Array1d>(gkvec_cart, kindices, kset_.comm().native());
295std::shared_ptr<nlcglib::ScalarBaseZ>
296Energy::get_kpoint_weights()
298 const int ns = kset_.ctx().num_spins();
299 std::vector<double> weights;
300 std::vector<std::pair<int, int>> kindices;
301 for (
auto it : kset_.spl_num_kpoints()) {
302 auto& kp = *kset_.get<
double>(it.i);
305 for (
int ispn = 0; ispn < ns; ++ispn) {
306 weights.push_back(kp.weight());
307 kindices.emplace_back(it.i.get(), ispn);
310 return std::make_shared<Scalar>(weights, kindices, kset_.comm().native());
314Energy::get_total_energy()
319std::map<std::string, double>
320Energy::get_energy_components()
322 return energy_components_;
326Energy::print_info()
const
328 auto& ctx = kset_.ctx();
329 auto& unit_cell = kset_.unit_cell();
331 auto result_mag = density_.get_magnetisation();
332 auto mt_mag = std::get<2>(result_mag);
334 if (ctx.num_mag_dims() && ctx.comm().rank() == 0) {
335 std::printf(
"atom moment |moment|");
337 for (
int i = 0; i < 80; i++) {
342 for (
int ia = 0; ia < unit_cell.num_atoms(); ia++) {
343 r3::vector<double> v(mt_mag[ia]);
344 std::printf(
"%4i [%8.4f, %8.4f, %8.4f] %10.6f", ia, v[0], v[1], v[2], v.length());
353Energy::set_chemical_potential(
double mu)
356 kset_.set_energy_fermi(mu);
360Energy::get_chemical_potential()
362 return kset_.energy_fermi();
369 return buffer_t(data[i].size(), data[i].data(), nlcglib::memory_type::host);
372const Array1d::buffer_t
373Array1d::get(
int i)
const
376 return buffer_t(data[i].size(),
const_cast<double*
>(data[i].data()), nlcglib::memory_type::host);
Contains defintion of nlcglib interface.
Helper function for nlcglib.
Contains declaration and definition of sirius::Hamiltonian class.
Declaration of sirius::Local_operator class.
Memory management functions and classes.
bool is_device_memory(memory_t mem__)
Check if this is a valid device memory (memory, accessible by the device).
@ array
array (ordered collection of values)
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.
Namespace of the SIRIUS library.
double ewald_energy(const Simulation_context &ctx, const fft::Gvec &gvec, const Unit_cell &unit_cell)
Compute the ion-ion electrostatic energy using Ewald method.
Eror and warning handling during run-time execution.
Contains declaration and implementation of Wave_functions class.