Skip to content

Commit d16f50f

Browse files
committed
Merge branch 'relativistic_projector' into 'master'
Relativistic projectors See merge request npneq/inq!1172
2 parents 0bce1cd + 9031cb2 commit d16f50f

File tree

8 files changed

+355
-20
lines changed

8 files changed

+355
-20
lines changed

external_libs/pseudopod

Submodule pseudopod updated from e01fb91 to 53d14d6

share/unit_tests_data/He_fr.upf.gz

22.9 KB
Binary file not shown.

share/unit_tests_data/Xe_fr.UPF.gz

112 KB
Binary file not shown.

src/hamiltonian/ks_hamiltonian.hpp

+20-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <hamiltonian/projector.hpp>
1717
#include <hamiltonian/projector_all.hpp>
1818
#include <hamiltonian/projector_fourier.hpp>
19+
#include <hamiltonian/relativistic_projector.hpp>
1920
#include <hamiltonian/scalar_potential.hpp>
2021
#include <input/environment.hpp>
2122
#include <operations/transform.hpp>
@@ -48,6 +49,7 @@ class ks_hamiltonian {
4849
bool non_local_in_fourier_;
4950
std::unordered_map<std::string, projector_fourier> projectors_fourier_map_;
5051
std::vector<std::unordered_map<std::string, projector_fourier>::iterator> projectors_fourier_;
52+
std::list<relativistic_projector> projectors_rel_;
5153
states::ks_states states_;
5254

5355
#ifdef ENABLE_CUDA
@@ -72,15 +74,20 @@ class ks_hamiltonian {
7274

7375
std::list<projector> projectors;
7476

75-
projectors_fourier_map_.clear();
77+
projectors_fourier_map_.clear();
7678

7779
for(int iatom = 0; iatom < ions.size(); iatom++){
78-
if(non_local_in_fourier_){
79-
auto insert = projectors_fourier_map_.emplace(ions.symbol(iatom), projector_fourier(basis, pot.pseudo_for_element(ions.species(iatom))));
80+
auto && ps = pot.pseudo_for_element(ions.species(iatom));
81+
82+
if(ps.has_total_angular_momentum()){
83+
projectors_rel_.emplace_back(basis, pot.double_grid(), ps, ions.positions()[iatom], iatom);
84+
if(projectors_rel_.back().empty()) projectors_rel_.pop_back();
85+
} else if(non_local_in_fourier_){
86+
auto insert = projectors_fourier_map_.emplace(ions.symbol(iatom), projector_fourier(basis, ps));
8087
insert.first->second.add_coord(basis.cell().metric().to_contravariant(ions.positions()[iatom]));
8188
} else {
82-
projectors.emplace_back(basis, pot.double_grid(), pot.pseudo_for_element(ions.species(iatom)), ions.positions()[iatom], iatom);
83-
if(projectors.back().empty()) projectors.pop_back();
89+
projectors.emplace_back(basis, pot.double_grid(), ps, ions.positions()[iatom], iatom);
90+
if(projectors.back().empty()) projectors.pop_back();
8491
}
8592
}
8693

@@ -136,6 +143,8 @@ class ks_hamiltonian {
136143
vnlphi.fill(0.0);
137144

138145
projectors_all_.apply(proj, vnlphi, phi.kpoint() + uniform_vector_potential_);
146+
147+
for(auto & pr : projectors_rel_) pr.apply(phi, vnlphi, phi.kpoint() + uniform_vector_potential_);
139148

140149
return vnlphi;
141150
}
@@ -156,7 +165,9 @@ class ks_hamiltonian {
156165
return en;
157166

158167
} else {
159-
return projectors_all_.energy(phi, phi.kpoint() + uniform_vector_potential_, occupations, reduce_states);
168+
auto en = projectors_all_.energy(phi, phi.kpoint() + uniform_vector_potential_, occupations, reduce_states);
169+
for(auto & pr : projectors_rel_) en += pr.energy(phi, occupations, phi.kpoint() + uniform_vector_potential_);
170+
return en;
160171
}
161172

162173
}
@@ -180,6 +191,7 @@ class ks_hamiltonian {
180191
hamiltonian::scalar_potential_add(scalar_potential_, phi.spin_index(), 0.5*phi.basis().cell().metric().norm(phi.kpoint() + uniform_vector_potential_), phi, hphi);
181192
exchange_(phi, hphi);
182193

194+
for(auto & pr : projectors_rel_) pr.apply(phi, hphi, phi.kpoint() + uniform_vector_potential_);
183195
projectors_all_.apply(proj, hphi, phi.kpoint() + uniform_vector_potential_);
184196

185197
return hphi;
@@ -198,7 +210,8 @@ class ks_hamiltonian {
198210
auto hphi_rs = hamiltonian::scalar_potential(scalar_potential_, phi.spin_index(), 0.5*phi.basis().cell().metric().norm(phi.kpoint() + uniform_vector_potential_), phi_rs);
199211

200212
exchange_(phi_rs, hphi_rs);
201-
213+
214+
for(auto & pr : projectors_rel_) pr.apply(phi_rs, hphi_rs, phi.kpoint() + uniform_vector_potential_);
202215
projectors_all_.apply(proj, hphi_rs, phi.kpoint() + uniform_vector_potential_);
203216

204217
auto hphi = operations::transform::to_fourier(hphi_rs);

src/hamiltonian/projector.hpp

-10
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,6 @@ class projector {
9090
return nproj_ == 0 or sphere_.size() == 0;
9191
}
9292

93-
template <typename OcType, typename PhiType, typename GPhiType>
94-
struct force_term {
95-
OcType oc;
96-
PhiType phi;
97-
GPhiType gphi;
98-
constexpr auto operator()(int ist, int ip) const {
99-
return -2.0*oc[ist]*real(phi[ip][ist]*conj(gphi[ip][ist]));
100-
}
101-
};
102-
10393
int num_projectors() const {
10494
return nproj_;
10595
}
+275
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/* -*- indent-tabs-mode: t -*- */
2+
3+
#ifndef INQ__HAMILTONIAN__RELATIVISTIC_PROJECTOR
4+
#define INQ__HAMILTONIAN__RELATIVISTIC_PROJECTOR
5+
6+
// Copyright (C) 2019-2023 Lawrence Livermore National Security, LLC., Xavier Andrade, Alfredo A. Correa
7+
//
8+
// This Source Code Form is subject to the terms of the Mozilla Public
9+
// License, v. 2.0. If a copy of the MPL was not distributed with this
10+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
11+
12+
#include <pseudopod/math/sharmonic.hpp>
13+
14+
#include <gpu/array.hpp>
15+
#include <math/vector3.hpp>
16+
#include <basis/double_grid.hpp>
17+
#include <basis/real_space.hpp>
18+
#include <basis/spherical_grid.hpp>
19+
#include <hamiltonian/atomic_potential.hpp>
20+
#include <utils/profiling.hpp>
21+
#include <utils/raw_pointer_cast.hpp>
22+
23+
namespace inq {
24+
namespace hamiltonian {
25+
26+
class relativistic_projector {
27+
28+
basis::spherical_grid sphere_;
29+
int nproj_;
30+
gpu::array<double, 3> beta_;
31+
gpu::array<double, 1> kb_coeff_;
32+
int iatom_;
33+
34+
public: // for CUDA
35+
36+
void build(basis::real_space const & basis, basis::double_grid const & double_grid, atomic_potential::pseudopotential_type const & ps) {
37+
38+
CALI_CXX_MARK_SCOPE("relativistic_projector::build");
39+
40+
assert(ps.has_total_angular_momentum());
41+
42+
nproj_ = 0.0;
43+
for(int iproj = 0; iproj < ps.num_projectors_l(); iproj++){
44+
nproj_ += ps.projector_2j(iproj) + 1;
45+
}
46+
47+
beta_.reextent({nproj_, sphere_.size(), 2});
48+
kb_coeff_.reextent(nproj_);
49+
50+
int iproj_lm = 0;
51+
for(int iproj = 0; iproj < ps.num_projectors_l(); iproj++){
52+
53+
auto ll = ps.projector_l(iproj);
54+
int const jj = ps.projector_2j(iproj);
55+
56+
assert(jj%2 == 1);
57+
58+
// std::cout << "LL = " << ll << " JJ = " << jj/2.0 << std::endl;
59+
60+
auto sgn = 1.0;
61+
if(jj == 2*ll - 1.0) sgn = -1.0;
62+
63+
for(auto mj = -jj; mj <= jj; mj += 2){
64+
65+
auto den = sqrt(jj - sgn + 1);
66+
auto cc0 = sgn*sqrt(jj/2.0 - 0.5*sgn + sgn*mj/2.0 + 0.5)/den;
67+
auto cc1 = sqrt(jj/2.0 - 0.5*sgn - sgn*mj/2.0 + 0.5)/den;
68+
auto ml0 = (mj - 1)/2;
69+
auto ml1 = (mj + 1)/2;
70+
71+
// std::cout << cc0 << '\t' << cc1 << '\t' << ml0 << '\t' << ml1 << std::endl;
72+
73+
gpu::run(sphere_.size(),
74+
[bet = begin(beta_),
75+
spline = ps.projector(iproj).function(),
76+
sph = sphere_.ref(), cc0, cc1, ml0, ml1, ll, iproj_lm,
77+
metric = basis.cell().metric()] GPU_LAMBDA (auto ipoint) {
78+
79+
if(abs(ml0) <= ll) {
80+
bet[iproj_lm][ipoint][0] = cc0*spline(sph.distance(ipoint))*pseudo::math::sharmonic(ll, ml0, metric.to_cartesian(sph.point_pos(ipoint)));
81+
} else {
82+
bet[iproj_lm][ipoint][0] = 0.0;
83+
}
84+
if(abs(ml1) <= ll) {
85+
bet[iproj_lm][ipoint][1] = cc1*spline(sph.distance(ipoint))*pseudo::math::sharmonic(ll, ml1, metric.to_cartesian(sph.point_pos(ipoint)));
86+
} else {
87+
bet[iproj_lm][ipoint][1] = 0.0;
88+
}
89+
});
90+
91+
kb_coeff_[iproj_lm] = ps.kb_coeff(iproj);
92+
93+
iproj_lm++;
94+
}
95+
96+
}
97+
}
98+
99+
public:
100+
relativistic_projector(const basis::real_space & basis, basis::double_grid const & double_grid, atomic_potential::pseudopotential_type const & ps, vector3<double> atom_position, int iatom):
101+
sphere_(basis, atom_position, ps.projector_radius()),
102+
iatom_(iatom){
103+
104+
build(basis, double_grid, ps);
105+
}
106+
107+
relativistic_projector(relativistic_projector const &) = delete;
108+
109+
auto empty() const {
110+
return nproj_ == 0;
111+
}
112+
113+
auto locally_empty() const {
114+
return nproj_ == 0 or sphere_.size() == 0;
115+
}
116+
117+
int num_projectors() const {
118+
return nproj_;
119+
}
120+
121+
auto kb_coeff(int iproj){
122+
return kb_coeff_[iproj];
123+
}
124+
125+
auto iatom() const {
126+
return iatom_;
127+
}
128+
129+
auto & sphere() const {
130+
return sphere_;
131+
}
132+
133+
auto & beta() const {
134+
return beta_;
135+
}
136+
137+
template <typename KpointType>
138+
gpu::array<complex, 3> project(states::orbital_set<basis::real_space, complex> const & phi, KpointType const & kpoint) const {
139+
140+
gpu::array<complex, 3> sphere_phi({sphere_.size(), phi.local_spinor_set_size(), 2});
141+
142+
gpu::run(phi.local_spinor_set_size(), sphere_.size(),
143+
[gr = begin(phi.spinor_hypercubic()), sph = sphere_.ref(), sgr = begin(sphere_phi)] GPU_LAMBDA (auto ist, auto ipoint){
144+
auto point = sph.grid_point(ipoint);
145+
sgr[ipoint][ist][0] = gr[point[0]][point[1]][point[2]][0][ist];
146+
sgr[ipoint][ist][1] = gr[point[0]][point[1]][point[2]][1][ist];
147+
});
148+
149+
gpu::array<complex, 3> projections({nproj_, phi.local_spinor_set_size(), 2});
150+
151+
gpu::run(phi.local_spinor_set_size(), nproj_,
152+
[proj = begin(projections), sgr = begin(sphere_phi), bet = begin(beta_), np = sphere_.size(), vol = phi.basis().volume_element()] GPU_LAMBDA (auto ist, auto iproj) {
153+
proj[iproj][ist][0] = 0.0;
154+
proj[iproj][ist][1] = 0.0;
155+
for(int ip = 0; ip < np; ip++) {
156+
proj[iproj][ist][0] += bet[iproj][ip][0]*sgr[ip][ist][0];
157+
proj[iproj][ist][1] += bet[iproj][ip][1]*sgr[ip][ist][1];
158+
}
159+
proj[iproj][ist][0] *= vol;
160+
proj[iproj][ist][1] *= vol;
161+
});
162+
163+
//missing parallel reduction of projections
164+
165+
return projections;
166+
}
167+
168+
template <typename KpointType>
169+
void apply(states::orbital_set<basis::real_space, complex> const & phi, states::orbital_set<basis::real_space, complex> & vnlphi, KpointType const & kpoint) const {
170+
171+
auto projections = project(phi, kpoint);
172+
173+
gpu::run(phi.local_spinor_set_size(), nproj_,
174+
[proj = begin(projections), coe = begin(kb_coeff_)] GPU_LAMBDA (auto ist, auto iproj) {
175+
176+
// std::cout << "PROJ " << iproj << '\t' << proj[iproj][ist][0] << '\t' << proj[iproj][ist][1] << '\t' << coe[iproj] << std::endl;
177+
178+
proj[iproj][ist][0] *= coe[iproj];
179+
proj[iproj][ist][1] *= coe[iproj];
180+
181+
});
182+
183+
gpu::run(phi.local_spinor_set_size(), sphere_.size(),
184+
[gr = begin(vnlphi.spinor_hypercubic()), sph = sphere_.ref(), nproj = nproj_, bet = begin(beta_), proj = begin(projections)] GPU_LAMBDA (auto ist, auto ip){
185+
auto point = sph.grid_point(ip);
186+
for(int iproj = 0; iproj < nproj; iproj++) {
187+
gr[point[0]][point[1]][point[2]][0][ist] += conj(bet[iproj][ip][0])*(proj[iproj][ist][0] + proj[iproj][ist][1]);
188+
gr[point[0]][point[1]][point[2]][1][ist] += conj(bet[iproj][ip][1])*(proj[iproj][ist][0] + proj[iproj][ist][1]);
189+
}
190+
});
191+
}
192+
193+
template <typename Occupations, typename KpointType>
194+
double energy(states::orbital_set<basis::real_space, complex> const & phi, Occupations const & occupations, KpointType const & kpoint) const {
195+
auto projections = project(phi, kpoint);
196+
197+
return gpu::run(gpu::reduce(phi.local_spinor_set_size()), gpu::reduce(nproj_), 0.0,
198+
[proj = begin(projections), coe = begin(kb_coeff_), occ = begin(occupations)] GPU_LAMBDA (auto ist, auto iproj) {
199+
auto pp = proj[iproj][ist][0] + proj[iproj][ist][1];
200+
return real(conj(pp)*pp)*coe[iproj]*occ[ist];
201+
});
202+
}
203+
204+
205+
friend class projector_all;
206+
207+
208+
};
209+
210+
}
211+
}
212+
#endif
213+
214+
#ifdef INQ_HAMILTONIAN_RELATIVISTIC_PROJECTOR_UNIT_TEST
215+
#undef INQ_HAMILTONIAN_RELATIVISTIC_PROJECTOR_UNIT_TEST
216+
217+
#include <config/path.hpp>
218+
219+
#include <catch2/catch_all.hpp>
220+
221+
TEST_CASE(INQ_TEST_FILE, INQ_TEST_TAG) {
222+
223+
using namespace inq;
224+
using namespace inq::magnitude;
225+
using namespace Catch::literals;
226+
227+
pseudo::math::erf_range_separation const sep(0.625);
228+
229+
parallel::communicator comm{boost::mpi3::environment::get_world_instance()};
230+
231+
basis::real_space rs(systems::cell::cubic(10.0_b), /*spacing = */ 0.49672941, comm);
232+
basis::double_grid dg(false);
233+
234+
SECTION("He") {
235+
236+
hamiltonian::atomic_potential::pseudopotential_type ps(config::path::unit_tests_data() + "He_fr.upf.gz", sep, rs.gcutoff());
237+
238+
hamiltonian::relativistic_projector proj(rs, dg, ps, vector3<double>(0.0, 0.0, 0.0), 77);
239+
240+
CHECK(proj.num_projectors() == 10);
241+
/*
242+
if(not proj.empty()){
243+
CHECK(proj.kb_coeff(0) == 7.494508815_a);
244+
CHECK(proj.kb_coeff(1) == 0.6363049519_a);
245+
CHECK(proj.kb_coeff(2) == -4.2939052122_a);
246+
CHECK(proj.kb_coeff(3) == -4.2939052122_a);
247+
CHECK(proj.kb_coeff(4) == -4.2939052122_a);
248+
CHECK(proj.kb_coeff(5) == -1.0069878791_a);
249+
CHECK(proj.kb_coeff(6) == -1.0069878791_a);
250+
CHECK(proj.kb_coeff(7) == -1.0069878791_a);
251+
}
252+
253+
CHECK(proj.iatom() == 77);
254+
*/
255+
256+
}
257+
258+
259+
SECTION("Xe") {
260+
261+
hamiltonian::atomic_potential::pseudopotential_type ps(config::path::unit_tests_data() + "Xe_fr.UPF.gz", sep, rs.gcutoff());
262+
263+
hamiltonian::relativistic_projector proj(rs, dg, ps, vector3<double>(0.0, 0.0, 0.0), 77);
264+
265+
CHECK(proj.num_projectors() == 16);
266+
267+
}
268+
269+
270+
271+
}
272+
273+
274+
#endif
275+

0 commit comments

Comments
 (0)