45 std::string functional_identifier =
"") {
46 exchange_id_ = exchange_id;
47 correlation_id_ = correlation_id;
50 if (functional_identifier.empty()) {
51 functional_identifier =
52 "libxc:" + std::to_string(exchange_id) +
":" + std::to_string(correlation_id);
55 int libxc_spin_polarization =
59 if (xc_func_init(&func_x_, exchange_id, libxc_spin_polarization) != 0) {
60 throw std::runtime_error(
"LibXC: failed to initialize exchange functional id=" +
61 std::to_string(exchange_id));
65 if (xc_func_init(&func_c_, correlation_id, libxc_spin_polarization) != 0) {
66 xc_func_end(&func_x_);
67 throw std::runtime_error(
"LibXC: failed to initialize correlation functional id=" +
68 std::to_string(correlation_id));
71 int exchange_family = func_x_.info->family;
72 int correlation_family = func_c_.info->family;
75 ensure_supported_family(
76 functional_identifier,
"exchange", exchange_id, func_x_, exchange_family);
77 ensure_supported_family(
78 functional_identifier,
"correlation", correlation_id, func_c_, correlation_family);
80 xc_func_end(&func_c_);
81 xc_func_end(&func_x_);
85 exchange_requires_gradient_ = exchange_family == XC_FAMILY_GGA;
86 correlation_requires_gradient_ = correlation_family == XC_FAMILY_GGA;
93 constexpr double libxc_density_threshold = 1e-10;
94 xc_func_set_dens_threshold(&func_x_, libxc_density_threshold);
95 xc_func_set_dens_threshold(&func_c_, libxc_density_threshold);
97 functional_name_ = std::string(func_x_.info->name) +
"+" + std::string(func_c_.info->name);
118 void compute(
const std::vector<Real>& density,
119 std::vector<Real>& xc_potential,
120 std::vector<Real>& xc_energy_density)
const override {
121 int number_of_grid_points =
static_cast<int>(density.size());
122 xc_potential.resize(number_of_grid_points);
123 xc_energy_density.resize(number_of_grid_points);
125 std::vector<Real> exchange_energies(number_of_grid_points);
126 std::vector<Real> correlation_energies(number_of_grid_points);
127 std::vector<Real> exchange_potentials(number_of_grid_points);
128 std::vector<Real> correlation_potentials(number_of_grid_points);
130 std::vector<Real> absolute_density(number_of_grid_points);
133 auto* non_const_exchange =
const_cast<xc_func_type*
>(&func_x_);
134 auto* non_const_correlation =
const_cast<xc_func_type*
>(&func_c_);
136 for_each_grid_slice(number_of_grid_points, [&](
int offset,
int count) {
137 for (
int grid_point_index = offset; grid_point_index < offset + count;
138 grid_point_index++) {
139 absolute_density[grid_point_index] = std::abs(density[grid_point_index]);
141 xc_lda_exc_vxc(non_const_exchange,
143 absolute_density.data() + offset,
144 exchange_energies.data() + offset,
145 exchange_potentials.data() + offset);
146 xc_lda_exc_vxc(non_const_correlation,
148 absolute_density.data() + offset,
149 correlation_energies.data() + offset,
150 correlation_potentials.data() + offset);
151 for (
int grid_point_index = offset; grid_point_index < offset + count;
152 grid_point_index++) {
153 xc_energy_density[grid_point_index] =
155 (exchange_energies[grid_point_index] + correlation_energies[grid_point_index]);
157 (exchange_potentials[grid_point_index] +
158 correlation_potentials[grid_point_index]);
170 for (
int grid_point_index = 0; grid_point_index < number_of_grid_points;
171 grid_point_index++) {
173 {xc_energy_density[grid_point_index], xc_potential[grid_point_index]})) {
174 throw_non_finite_output(
"unpolarized LDA",
176 {{
"rho", absolute_density[grid_point_index]}});
183 const std::vector<Real>& density_down,
184 std::vector<Real>& xc_potential_up,
185 std::vector<Real>& xc_potential_down,
186 std::vector<Real>& xc_energy_density)
const override {
187 int number_of_grid_points =
static_cast<int>(density_up.size());
188 xc_potential_up.resize(number_of_grid_points);
189 xc_potential_down.resize(number_of_grid_points);
190 xc_energy_density.resize(number_of_grid_points);
192 std::vector<Real> density_array(2 * number_of_grid_points);
193 std::vector<Real> exchange_energies(number_of_grid_points);
194 std::vector<Real> correlation_energies(number_of_grid_points);
195 std::vector<Real> exchange_potentials(2 * number_of_grid_points);
196 std::vector<Real> correlation_potentials(2 * number_of_grid_points);
198 auto* non_const_exchange =
const_cast<xc_func_type*
>(&func_x_);
199 auto* non_const_correlation =
const_cast<xc_func_type*
>(&func_c_);
206 for_each_grid_slice(number_of_grid_points, [&](
int offset,
int count) {
207 for (
int grid_point_index = offset; grid_point_index < offset + count;
208 grid_point_index++) {
209 density_array[2 * grid_point_index] = std::max(
211 density_array[2 * grid_point_index + 1] = std::max(
214 xc_lda_exc_vxc(non_const_exchange,
216 density_array.data() + 2 * offset,
217 exchange_energies.data() + offset,
218 exchange_potentials.data() + 2 * offset);
219 xc_lda_exc_vxc(non_const_correlation,
221 density_array.data() + 2 * offset,
222 correlation_energies.data() + offset,
223 correlation_potentials.data() + 2 * offset);
224 for (
int grid_point_index = offset; grid_point_index < offset + count;
225 grid_point_index++) {
226 xc_energy_density[grid_point_index] =
228 (exchange_energies[grid_point_index] + correlation_energies[grid_point_index]);
230 (exchange_potentials[2 * grid_point_index] +
231 correlation_potentials[2 * grid_point_index]);
232 xc_potential_down[grid_point_index] =
234 (exchange_potentials[2 * grid_point_index + 1] +
235 correlation_potentials[2 * grid_point_index + 1]);
240 for (
int grid_point_index = 0; grid_point_index < number_of_grid_points;
241 grid_point_index++) {
242 if (!all_finite({xc_energy_density[grid_point_index],
243 xc_potential_up[grid_point_index],
244 xc_potential_down[grid_point_index]})) {
245 throw_non_finite_output(
"spin-polarized LDA",
247 {{
"rho_up", density_array[2 * grid_point_index]},
248 {
"rho_down", density_array[2 * grid_point_index + 1]}});
255 const std::vector<Real>& gradient_density_squared,
256 std::vector<Real>& xc_potential,
257 std::vector<Real>& gradient_correction_density,
258 std::vector<Real>& xc_energy_density)
const override {
259 int number_of_grid_points =
static_cast<int>(density.size());
260 xc_potential.resize(number_of_grid_points);
261 gradient_correction_density.resize(number_of_grid_points);
262 xc_energy_density.resize(number_of_grid_points);
264 constexpr Real rho_threshold_lda = 1e-10;
265 constexpr Real rho_threshold_gga = 1e-6;
266 constexpr Real gradient_threshold_gga = 1e-10;
268 ensure_work_buffers_size(number_of_grid_points);
269 auto& exchange_energies = work_exchange_energies_;
270 auto& correlation_energies = work_correlation_energies_;
271 auto& exchange_potentials = work_exchange_potentials_;
272 auto& correlation_potentials = work_correlation_potentials_;
273 auto& vsigma_exchange = work_vsigma_exchange_;
274 auto& vsigma_correlation = work_vsigma_correlation_;
275 auto& absolute_density = work_absolute_density_;
276 auto& density_gradient_squared_clamped = work_density_gradient_squared_clamped_;
278 auto* non_const_exchange =
const_cast<xc_func_type*
>(&func_x_);
279 auto* non_const_correlation =
const_cast<xc_func_type*
>(&func_c_);
281 for_each_grid_slice(number_of_grid_points, [&](
int offset,
int count) {
282 for (
int grid_point_index = offset; grid_point_index < offset + count;
283 grid_point_index++) {
284 absolute_density[grid_point_index] = std::abs(density[grid_point_index]);
285 density_gradient_squared_clamped[grid_point_index] =
286 std::max(gradient_density_squared[grid_point_index], 0.0);
289 if (exchange_requires_gradient_) {
290 xc_gga_exc_vxc(non_const_exchange,
292 absolute_density.data() + offset,
293 density_gradient_squared_clamped.data() + offset,
294 exchange_energies.data() + offset,
295 exchange_potentials.data() + offset,
296 vsigma_exchange.data() + offset);
298 xc_lda_exc_vxc(non_const_exchange,
300 absolute_density.data() + offset,
301 exchange_energies.data() + offset,
302 exchange_potentials.data() + offset);
303 std::fill_n(vsigma_exchange.begin() + offset, count, 0.0);
306 if (correlation_requires_gradient_) {
307 xc_gga_exc_vxc(non_const_correlation,
309 absolute_density.data() + offset,
310 density_gradient_squared_clamped.data() + offset,
311 correlation_energies.data() + offset,
312 correlation_potentials.data() + offset,
313 vsigma_correlation.data() + offset);
315 xc_lda_exc_vxc(non_const_correlation,
317 absolute_density.data() + offset,
318 correlation_energies.data() + offset,
319 correlation_potentials.data() + offset);
320 std::fill_n(vsigma_correlation.begin() + offset, count, 0.0);
324 for (
int grid_point_index = 0; grid_point_index < number_of_grid_points;
325 grid_point_index++) {
326 if (absolute_density[grid_point_index] <= rho_threshold_lda) {
327 xc_energy_density[grid_point_index] = 0.0;
328 xc_potential[grid_point_index] = 0.0;
329 gradient_correction_density[grid_point_index] = 0.0;
333 xc_energy_density[grid_point_index] =
335 (exchange_energies[grid_point_index] + correlation_energies[grid_point_index]);
336 xc_potential[grid_point_index] =
338 (exchange_potentials[grid_point_index] + correlation_potentials[grid_point_index]);
340 if (absolute_density[grid_point_index] <= rho_threshold_gga ||
341 std::abs(density_gradient_squared_clamped[grid_point_index]) <=
342 gradient_threshold_gga) {
343 gradient_correction_density[grid_point_index] = 0.0;
345 gradient_correction_density[grid_point_index] =
347 (vsigma_exchange[grid_point_index] + vsigma_correlation[grid_point_index]);
349 if (!all_finite({xc_energy_density[grid_point_index],
350 xc_potential[grid_point_index],
351 gradient_correction_density[grid_point_index]})) {
352 throw_non_finite_output(
355 {{
"rho", absolute_density[grid_point_index]},
356 {
"sigma", density_gradient_squared_clamped[grid_point_index]}});
364 const std::vector<Real>& density_down,
365 const std::vector<Real>& gradient_density_squared_up_up,
366 const std::vector<Real>& gradient_density_squared_up_down,
367 const std::vector<Real>& gradient_density_squared_down_down,
368 std::vector<Real>& xc_potential_up,
369 std::vector<Real>& xc_potential_down,
370 std::vector<Real>& gradient_correction_up_up,
371 std::vector<Real>& gradient_correction_up_down,
372 std::vector<Real>& gradient_correction_down_down,
373 std::vector<Real>& xc_energy_density)
const override {
374 int total_grid_points =
static_cast<int>(density_up.size());
375 xc_potential_up.resize(total_grid_points);
376 xc_potential_down.resize(total_grid_points);
377 gradient_correction_up_up.resize(total_grid_points);
378 gradient_correction_up_down.resize(total_grid_points);
379 gradient_correction_down_down.resize(total_grid_points);
380 xc_energy_density.resize(total_grid_points);
382 constexpr Real rho_threshold_lda = 1e-10;
383 constexpr Real rho_threshold_gga = 1e-6;
384 constexpr Real gradient_threshold_gga = 1e-10;
386 std::vector<Real> density_array(2 * total_grid_points);
387 std::vector<Real> gradient_squared_array(3 * total_grid_points);
388 for (
int grid_point_index = 0; grid_point_index < total_grid_points; grid_point_index++) {
389 density_array[2 * grid_point_index] = std::abs(density_up[grid_point_index]);
390 density_array[2 * grid_point_index + 1] = std::abs(density_down[grid_point_index]);
392 gradient_squared_array[3 * grid_point_index] =
393 std::max(gradient_density_squared_up_up[grid_point_index], 0.0);
394 gradient_squared_array[3 * grid_point_index + 1] =
395 gradient_density_squared_up_down[grid_point_index];
396 gradient_squared_array[3 * grid_point_index + 2] =
397 std::max(gradient_density_squared_down_down[grid_point_index], 0.0);
400 std::vector<Real> exchange_energies(total_grid_points);
401 std::vector<Real> correlation_energies(total_grid_points);
402 std::vector<Real> exchange_density_potential(2 * total_grid_points, 0.0);
403 std::vector<Real> correlation_density_potential(2 * total_grid_points, 0.0);
404 std::vector<Real> exchange_gradient_potential(3 * total_grid_points, 0.0);
405 std::vector<Real> correlation_gradient_potential(3 * total_grid_points, 0.0);
407 auto* non_const_exchange =
const_cast<xc_func_type*
>(&func_x_);
408 auto* non_const_correlation =
const_cast<xc_func_type*
>(&func_c_);
410 if (exchange_requires_gradient_) {
411 xc_gga_exc_vxc(non_const_exchange,
413 density_array.data(),
414 gradient_squared_array.data(),
415 exchange_energies.data(),
416 exchange_density_potential.data(),
417 exchange_gradient_potential.data());
419 xc_lda_exc_vxc(non_const_exchange,
421 density_array.data(),
422 exchange_energies.data(),
423 exchange_density_potential.data());
426 if (correlation_requires_gradient_) {
427 xc_gga_exc_vxc(non_const_correlation,
429 density_array.data(),
430 gradient_squared_array.data(),
431 correlation_energies.data(),
432 correlation_density_potential.data(),
433 correlation_gradient_potential.data());
435 xc_lda_exc_vxc(non_const_correlation,
437 density_array.data(),
438 correlation_energies.data(),
439 correlation_density_potential.data());
442 for (
int grid_point_index = 0; grid_point_index < total_grid_points; grid_point_index++) {
443 Real density_up = density_array[2 * grid_point_index];
444 Real density_down = density_array[2 * grid_point_index + 1];
445 Real gradient_squared_up = std::abs(gradient_squared_array[3 * grid_point_index]);
446 Real gradient_squared_down = std::abs(gradient_squared_array[3 * grid_point_index + 2]);
448 if (density_up <= rho_threshold_lda || density_down <= rho_threshold_lda) {
449 xc_energy_density[grid_point_index] = 0.0;
450 xc_potential_up[grid_point_index] = xc_potential_down[grid_point_index] = 0.0;
451 gradient_correction_up_up[grid_point_index] =
452 gradient_correction_up_down[grid_point_index] =
453 gradient_correction_down_down[grid_point_index] = 0.0;
457 xc_energy_density[grid_point_index] =
459 (exchange_energies[grid_point_index] + correlation_energies[grid_point_index]);
460 xc_potential_up[grid_point_index] =
462 (exchange_density_potential[2 * grid_point_index] +
463 correlation_density_potential[2 * grid_point_index]);
464 xc_potential_down[grid_point_index] =
466 (exchange_density_potential[2 * grid_point_index + 1] +
467 correlation_density_potential[2 * grid_point_index + 1]);
469 if (density_up <= rho_threshold_gga || density_down <= rho_threshold_gga ||
470 gradient_squared_up <= gradient_threshold_gga ||
471 gradient_squared_down <= gradient_threshold_gga) {
472 gradient_correction_up_up[grid_point_index] =
473 gradient_correction_up_down[grid_point_index] =
474 gradient_correction_down_down[grid_point_index] = 0.0;
476 gradient_correction_up_up[grid_point_index] =
478 (exchange_gradient_potential[3 * grid_point_index] +
479 correlation_gradient_potential[3 * grid_point_index]);
480 gradient_correction_up_down[grid_point_index] =
482 (exchange_gradient_potential[3 * grid_point_index + 1] +
483 correlation_gradient_potential[3 * grid_point_index + 1]);
484 gradient_correction_down_down[grid_point_index] =
486 (exchange_gradient_potential[3 * grid_point_index + 2] +
487 correlation_gradient_potential[3 * grid_point_index + 2]);
491 auto clamp_potential_value = [](
Real& value,
Real limit) {
492 if (std::abs(value) > limit) {
493 value = (value > 0) ? limit : -limit;
496 clamp_potential_value(xc_potential_up[grid_point_index], 100.0);
497 clamp_potential_value(xc_potential_down[grid_point_index], 100.0);
498 clamp_potential_value(gradient_correction_up_up[grid_point_index], 100.0);
499 clamp_potential_value(gradient_correction_up_down[grid_point_index], 100.0);
500 clamp_potential_value(gradient_correction_down_down[grid_point_index], 100.0);
502 if (!all_finite({xc_energy_density[grid_point_index],
503 xc_potential_up[grid_point_index],
504 xc_potential_down[grid_point_index],
505 gradient_correction_up_up[grid_point_index],
506 gradient_correction_up_down[grid_point_index],
507 gradient_correction_down_down[grid_point_index]})) {
508 throw_non_finite_output(
509 "spin-polarized GGA",
511 {{
"rho_up", density_up},
512 {
"rho_down", density_down},
513 {
"sigma_up_up", gradient_squared_array[3 * grid_point_index]},
514 {
"sigma_up_down", gradient_squared_array[3 * grid_point_index + 1]},
515 {
"sigma_down_down", gradient_squared_array[3 * grid_point_index + 2]}});