Skip to content

Commit

Permalink
Merge branch 'spin_orbit_coupling' into 'master'
Browse files Browse the repository at this point in the history
Spin orbit coupling

See merge request npneq/inq!1176
  • Loading branch information
xavierandrade committed Dec 14, 2024
2 parents 9c400b7 + d38a616 commit dd00951
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 55 deletions.
2 changes: 1 addition & 1 deletion external_libs/pseudopod
Submodule pseudopod updated from ca895c to 4ea662
Binary file added share/unit_tests_data/pseudodojo_Xe_fr.upf.gz
Binary file not shown.
47 changes: 32 additions & 15 deletions src/hamiltonian/relativistic_projector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class relativistic_projector {

basis::spherical_grid sphere_;
int nproj_;
gpu::array<double, 3> beta_;
gpu::array<complex, 3> beta_;
gpu::array<double, 1> kb_coeff_;
int iatom_;

Expand All @@ -46,6 +46,8 @@ class relativistic_projector {

beta_.reextent({nproj_, sphere_.size(), 2});
kb_coeff_.reextent(nproj_);

std::cout << "NUM " << ps.num_projectors_l() << std::endl;

int iproj_lm = 0;
for(int iproj = 0; iproj < ps.num_projectors_l(); iproj++){
Expand All @@ -54,20 +56,24 @@ class relativistic_projector {
int const jj = ps.projector_2j(iproj);

assert(jj%2 == 1);

// std::cout << "LL = " << ll << " JJ = " << jj/2.0 << std::endl;

auto sgn = 1.0;
if(jj == 2*ll - 1.0) sgn = -1.0;
assert(jj == 2*ll + 1 or jj == 2*ll - 1);

// std::cout << "PROJ " << iproj << '\t' << ll << '\t' << jj/2.0 << '\t' << ps.kb_coeff(iproj) << '\t' << ps.projector(iproj).function()(0.5)<< std::endl;

for(auto mj = -jj; mj <= jj; mj += 2){

auto den = sqrt(jj - sgn + 1);
auto cc0 = sgn*sqrt(jj/2.0 - 0.5*sgn + sgn*mj/2.0 + 0.5)/den;
auto cc1 = sqrt(jj/2.0 - 0.5*sgn - sgn*mj/2.0 + 0.5)/den;
// These come from https://en.wikipedia.org/wiki/Spinor_spherical_harmonics
// we use that '2*ll = jj - sgn' to simplify the expressions
auto sgn = double(jj - 2*ll);
auto den = 2*ll + 1;
auto cc0 = sgn*sqrt((ll + sgn*mj/2.0 + 0.5)/den);
auto cc1 = sqrt((ll - sgn*mj/2.0 + 0.5)/den);
auto ml0 = (mj - 1)/2;
auto ml1 = (mj + 1)/2;

if(abs(ml0) > ll) assert(fabs(cc0) < 1e-14);
if(abs(ml1) > ll) assert(fabs(cc1) < 1e-14);

// std::cout << cc0 << '\t' << cc1 << '\t' << ml0 << '\t' << ml1 << std::endl;

gpu::run(sphere_.size(),
Expand All @@ -76,13 +82,15 @@ class relativistic_projector {
sph = sphere_.ref(), cc0, cc1, ml0, ml1, ll, iproj_lm,
metric = basis.cell().metric()] GPU_LAMBDA (auto ipoint) {

auto radial = spline(sph.distance(ipoint));

if(abs(ml0) <= ll) {
bet[iproj_lm][ipoint][0] = cc0*spline(sph.distance(ipoint))*pseudo::math::sharmonic(ll, ml0, metric.to_cartesian(sph.point_pos(ipoint)));
bet[iproj_lm][ipoint][0] = cc0*radial*pseudo::math::sharmonic_complex<complex>(ll, ml0, metric.to_cartesian(sph.point_pos(ipoint)));
} else {
bet[iproj_lm][ipoint][0] = 0.0;
}
if(abs(ml1) <= ll) {
bet[iproj_lm][ipoint][1] = cc1*spline(sph.distance(ipoint))*pseudo::math::sharmonic(ll, ml1, metric.to_cartesian(sph.point_pos(ipoint)));
bet[iproj_lm][ipoint][1] = cc1*radial*pseudo::math::sharmonic_complex<complex>(ll, ml1, metric.to_cartesian(sph.point_pos(ipoint)));
} else {
bet[iproj_lm][ipoint][1] = 0.0;
}
Expand Down Expand Up @@ -154,7 +162,7 @@ class relativistic_projector {
[proj = begin(projections), sgr = begin(sphere_phi), bet = begin(beta_), np = sphere_.size(), vol = phi.basis().volume_element()] GPU_LAMBDA (auto ist, auto iproj) {
proj[iproj][ist] = 0.0;
for(int ip = 0; ip < np; ip++) {
proj[iproj][ist] += bet[iproj][ip][0]*sgr[ip][ist][0] + bet[iproj][ip][1]*sgr[ip][ist][1];
proj[iproj][ist] += conj(bet[iproj][ip][0])*sgr[ip][ist][0] + conj(bet[iproj][ip][1])*sgr[ip][ist][1];
}
proj[iproj][ist] *= vol;
});
Expand Down Expand Up @@ -186,8 +194,8 @@ class relativistic_projector {
auto red1 = complex(0.0, 0.0);
for(int iproj = 0; iproj < nproj; iproj++) {
auto pp = proj[iproj][ist];
red0 += conj(bet[iproj][ip][0])*pp;
red1 += conj(bet[iproj][ip][1])*pp;
red0 += bet[iproj][ip][0]*pp;
red1 += bet[iproj][ip][1]*pp;
}

gpu::atomic::add(&gr[point[0]][point[1]][point[2]][0][ist], red0);
Expand Down Expand Up @@ -264,7 +272,7 @@ TEST_CASE(INQ_TEST_FILE, INQ_TEST_TAG) {
}


SECTION("Xe") {
SECTION("Xe UPF1") {

hamiltonian::atomic_potential::pseudopotential_type ps(config::path::unit_tests_data() + "Xe_fr.UPF.gz", sep, rs.gcutoff());

Expand All @@ -273,7 +281,16 @@ TEST_CASE(INQ_TEST_FILE, INQ_TEST_TAG) {
CHECK(proj.num_projectors() == 16);

}

SECTION("Xe pseudodojo") {

hamiltonian::atomic_potential::pseudopotential_type ps(config::path::unit_tests_data() + "pseudodojo_Xe_fr.upf.gz", sep, rs.gcutoff());

hamiltonian::relativistic_projector proj(rs, dg, ps, vector3<double>(0.0, 0.0, 0.0), 77);

CHECK(proj.num_projectors() == 36);

}


}
Expand Down
39 changes: 0 additions & 39 deletions tests/helium_fr.cpp

This file was deleted.

58 changes: 58 additions & 0 deletions tests/xe_fr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* -*- indent-tabs-mode: t -*- */

// Copyright (C) 2019-2023 Lawrence Livermore National Security, LLC., Xavier Andrade, Alfredo A. Correa
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#include <inq/inq.hpp>

int main(int argc, char ** argv){

using namespace inq;
using namespace inq::magnitude;

utils::match energy_match(3.0e-5);

systems::ions ions(systems::cell::cubic(10.0_b).finite());
ions.species_list().pseudopotentials() = pseudo::set_id::pseudodojo_rel_pbe();
// ions.species_list().insert(ionic::species("Xe").pseudo_file(config::path::unit_tests_data() + "Xe_fr.UPF.gz"));
ions.insert("Xe", {0.0_b, 0.0_b, 0.0_b});

systems::electrons electrons(ions, options::electrons{}.cutoff(40.0_Ha).spin_non_collinear().extra_states(3));
ground_state::initial_guess(ions, electrons);

//we use LDA for now since PBE has some convergence issues
auto result = ground_state::calculate(ions, electrons, options::theory{}.lda(), options::ground_state{}.energy_tolerance(1e-8_Ha));

auto all_eigenvalues = parallel::gather(+electrons.eigenvalues().flatted(), electrons.kpin_states_comm(), 0);

if(electrons.kpin_states_comm().root()){
energy_match.check("eigenvalue 0", all_eigenvalues[ 0], -0.712820889809);
energy_match.check("eigenvalue 1", all_eigenvalues[ 1], -0.712820889809);
energy_match.check("eigenvalue 2", all_eigenvalues[ 2], -0.322520169668);
energy_match.check("eigenvalue 3", all_eigenvalues[ 3], -0.322520169668);
energy_match.check("eigenvalue 4", all_eigenvalues[ 4], -0.277257682172);
energy_match.check("eigenvalue 5", all_eigenvalues[ 5], -0.277257682172);
energy_match.check("eigenvalue 6", all_eigenvalues[ 6], -0.277257669711);
energy_match.check("eigenvalue 7", all_eigenvalues[ 7], -0.277257669711);
energy_match.check("eigenvalue 8", all_eigenvalues[ 8], -0.063230692730);
energy_match.check("eigenvalue 9", all_eigenvalues[ 9], -0.063230692417);
energy_match.check("eigenvalue 10", all_eigenvalues[10], 0.046161112021);
}

energy_match.check("total energy", result.energy.total(), -18.661808075647);
energy_match.check("kinetic energy", result.energy.kinetic(), 4.169408422510);
energy_match.check("eigenvalues", result.energy.eigenvalues(), -3.179712822721);
energy_match.check("Hartree energy", result.energy.hartree(), 13.167234189885);
energy_match.check("external energy", result.energy.external(), -32.516230615704);
energy_match.check("non-local energy", result.energy.non_local(), 2.758847694594);
energy_match.check("XC energy", result.energy.xc(), -6.241067766933);
energy_match.check("XC density integral", result.energy.nvxc(), -3.926206703892);
energy_match.check("HF exchange energy", result.energy.exact_exchange(), 0.000000000000);
energy_match.check("ion-ion energy", result.energy.ion(), 0.000000000000);

return energy_match.fail();

}

0 comments on commit dd00951

Please sign in to comment.