SIRIUS 7.5.0
Electronic structure library and applications
sirius_api.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-2021 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file sirius_api.cpp
21 *
22 * \brief Fortran API.
23 */
24
25#include <ctype.h>
26#include <iostream>
27#include "SDDK/memory.hpp"
28#include "core/any_ptr.hpp"
29#include "core/profiler.hpp"
30#include "error_codes.hpp"
31#ifdef SIRIUS_NLCGLIB
32#include "nlcglib/adaptor.hpp"
33#include "nlcglib/nlcglib.hpp"
35#include "nlcglib/overlap.hpp"
37#endif
39#include "multi_cg/multi_cg.hpp"
44#include "sirius.hpp"
45
46using namespace sirius;
47
49{
50 void* handler_ptr_{nullptr};
51};
52
54{
55 void* handler_ptr_{nullptr};
56};
57
59{
60 void* handler_ptr_{nullptr};
61};
62
63Simulation_context& get_sim_ctx(void* const* h);
64
65enum class option_type_t : int
66{
67 INTEGER_TYPE = 1,
68 LOGICAL_TYPE = 2,
69 STRING_TYPE = 3,
70 NUMBER_TYPE = 4,
71 OBJECT_TYPE = 5,
72 ARRAY_TYPE = 6,
73 INTEGER_ARRAY_TYPE = 7,
74 LOGICAL_ARRAY_TYPE = 8,
75 NUMBER_ARRAY_TYPE = 9,
76 STRING_ARRAY_TYPE = 10,
77 OBJECT_ARRAY_TYPE = 11,
78 ARRAY_ARRAY_TYPE = 12
79};
80
81template <typename T>
82void
83sirius_option_set_value(Simulation_context& sim_ctx__, std::string section__, std::string name__,
84 T const* values__, int const* max_length__)
85{
86 std::transform(section__.begin(), section__.end(), section__.begin(), ::tolower);
87
88 auto& conf_dict = const_cast<nlohmann::json&>(sim_ctx__.cfg().dict());
89
90 const auto& section_schema = get_section_options(section__);
91
92 if (!section_schema.count(name__)) {
93 std::transform(name__.begin(), name__.end(), name__.begin(), ::tolower);
94 }
95 if (!section_schema.count(name__)) {
96 RTE_THROW("section : " + section__ + ", option : " + name__ + " is invalid");
97 }
98
99 if (section_schema[name__]["type"] == "array") {
100 if (max_length__ == nullptr) {
101 RTE_THROW("maximum length of the input buffer is not provided");
102 }
103 std::vector<T> v(values__, values__ + *max_length__);
104 conf_dict[section__][name__] = v;
105 } else {
106 conf_dict[section__][name__] = *values__;
107 }
108}
109
110void
111sirius_option_set_value(Simulation_context& sim_ctx__, std::string section__, std::string name__,
112 char const* values__, int const* max_length__, bool append__)
113{
114 std::transform(section__.begin(), section__.end(), section__.begin(), ::tolower);
115
116 auto& conf_dict = const_cast<nlohmann::json&>(sim_ctx__.cfg().dict());
117
118 const auto& section_schema = get_section_options(section__);
119
120 if (!section_schema.count(name__)) {
121 std::transform(name__.begin(), name__.end(), name__.begin(), ::tolower);
122 }
123 if (!section_schema.count(name__)) {
124 RTE_THROW("section : " + section__ + ", option : " + name__ + " is invalid");
125 }
126
127 if (max_length__ == nullptr) {
128 RTE_THROW("maximum length of the input string is not provided");
129 }
130 auto st = std::string(values__, *max_length__);
131 if (!append__) {
132 conf_dict[section__][name__] = st;
133 } else {
134 conf_dict[section__][name__].push_back(st);
135 }
136}
137
138template <typename T>
139void
140sirius_option_get_value(std::string section__, std::string name__, T* default_value__, int const* max_length__)
141{
142 const auto& section_schema = get_section_options(section__);
143
144 if (!section_schema.count(name__)) {
145 std::transform(name__.begin(), name__.end(), name__.begin(), ::tolower);
146 }
147 if (!section_schema.count(name__)) {
148 RTE_THROW("section : " + section__ + ", option : " + name__ + " is invalid");
149 }
150
151 if (!section_schema[name__].count("default")) {
152 RTE_THROW("default value for '" + name__ + "' is missing");
153 }
154
155 if (section_schema[name__]["type"] == "array") {
156 if (max_length__ == nullptr) {
157 RTE_THROW("maximum length of the output buffer is not provided");
158 }
159 if (section_schema[name__]["items"] != "array") {
160 std::vector<T> v = section_schema[name__]["default"].get<std::vector<T>>();
161 int l = static_cast<int>(v.size());
162 if (l > *max_length__) {
163 RTE_THROW("not enough space to store '" + name__ + "' values");
164 }
165 std::copy(v.begin(), v.end(), default_value__);
166 }
167 } else {
168 *default_value__ = section_schema[name__]["default"].get<T>();
169 }
170}
171
172void
173sirius_option_get_value(std::string section__, std::string name__, char* default_value__, int const* max_length__,
174 int const* enum_idx__)
175{
176 const auto& section_schema = get_section_options(section__);
177
178 if (!section_schema.count(name__)) {
179 std::transform(name__.begin(), name__.end(), name__.begin(), ::tolower);
180 }
181 if (!section_schema.count(name__)) {
182 RTE_THROW("section : " + section__ + ", option : " + name__ + " is invalid");
183 }
184
185 if (!section_schema[name__].count("default")) {
186 RTE_THROW("default value for '" + name__ + "' is missing");
187 }
188
189 if (section_schema[name__]["type"] == "array") {
190 RTE_THROW("array of strings is not supported");
191 } else {
192 if (section_schema[name__]["type"] != "string") {
193 RTE_THROW("not a string type");
194 }
195 std::string v;
196 if (enum_idx__ == nullptr) {
197 v = section_schema[name__]["default"].get<std::string>();
198 } else {
199 if (section_schema[name__].count("enum")) {
200 v = section_schema[name__]["enum"][*enum_idx__ - 1].get<std::string>();
201 } else{
202 RTE_THROW("not an enum type");
203 }
204 }
205 if (max_length__ == nullptr) {
206 RTE_THROW("length of the string is not provided");
207 }
208 if (static_cast<int>(v.size()) > *max_length__) {
209 std::stringstream s;
210 s << "option '" << name__ << "' is too large to fit into output string of size " << *max_length__;
211 RTE_THROW(s);
212 }
213 std::fill(default_value__, default_value__ + *max_length__, ' ');
214 std::copy(v.begin(), v.end(), default_value__);
215 }
216}
217
218static inline void
219sirius_print_error(int error_code__, std::string msg__ = "")
220{
221 switch (error_code__) {
222 case SIRIUS_ERROR_UNKNOWN: {
223 printf("SIRIUS: unknown error\n");
224 break;
225 }
226 case SIRIUS_ERROR_RUNTIME: {
227 printf("SIRIUS: run-time error\n");
228 break;
229 }
230 case SIRIUS_ERROR_EXCEPTION: {
231 printf("SIRIUS: exception\n");
232 break;
233 }
234 default: {
235 printf("SIRIUS: unknown error code: %i\n", error_code__);
236 break;
237 }
238 }
239
240 if (msg__.size()) {
241 printf("%s\n", msg__.c_str());
242 }
243 fflush(stdout);
244 std::cout << std::flush;
245}
246
247static inline void
248sirius_exit(int error_code__, std::string msg__ = "")
249{
250 sirius_print_error(error_code__, msg__);
251 if (!mpi::Communicator::is_finalized()) {
252 mpi::Communicator::world().abort(error_code__);
253 } else {
254 std::exit(error_code__);
255 }
256}
257
258template <typename F>
259static void
260call_sirius(F&& f__, int* error_code__)
261{
262 try {
263 f__();
264 if (error_code__) {
265 *error_code__ = SIRIUS_SUCCESS;
266 return;
267 }
268 } catch (std::runtime_error const& e) {
269 if (error_code__) {
270 *error_code__ = SIRIUS_ERROR_RUNTIME;
271 sirius_print_error(*error_code__, e.what());
272 return;
273 } else {
274 sirius_exit(SIRIUS_ERROR_RUNTIME, e.what());
275 }
276 } catch (std::exception const& e) {
277 if (error_code__) {
278 *error_code__ = SIRIUS_ERROR_EXCEPTION;
279 sirius_print_error(*error_code__, e.what());
280 return;
281 } else {
282 sirius_exit(SIRIUS_ERROR_EXCEPTION, e.what());
283 }
284 } catch (...) {
285 if (error_code__) {
286 *error_code__ = SIRIUS_ERROR_UNKNOWN;
287 sirius_print_error(*error_code__);
288 return;
289 } else {
290 sirius_exit(SIRIUS_ERROR_UNKNOWN);
291 }
292 }
293}
294
295template <typename T>
296auto get_value(T const* ptr__, T v0__ = T())
297{
298 return (ptr__) ? *ptr__ : v0__;
299}
300
302get_sim_ctx(void* const* h)
303{
304 if (h == nullptr || *h == nullptr) {
305 RTE_THROW("Non-existing simulation context handler");
306 }
307 return static_cast<any_ptr*>(*h)->get<Simulation_context>();
308}
309
311get_gs(void* const* h)
312{
313 if (h == nullptr || *h == nullptr) {
314 RTE_THROW("Non-existing DFT ground state handler");
315 }
316 return static_cast<any_ptr*>(*h)->get<DFT_ground_state>();
317}
318
320get_ks(void* const* h)
321{
322 if (h == nullptr || *h == nullptr) {
323 RTE_THROW("Non-existing K-point set handler");
324 }
325 return static_cast<any_ptr*>(*h)->get<K_point_set>();
326}
327
328/// Index of Rlm in QE in the block of lm coefficients for a given l.
329static inline int
330idx_m_qe(int m__)
331{
332 return (m__ > 0) ? 2 * m__ - 1 : -2 * m__;
333}
334
335/// Mapping of atomic indices from SIRIUS to QE order.
336static inline std::vector<int>
338{
339 int nbf = type__.mt_basis_size();
340
341 std::vector<int> idx_map(nbf);
342 for (int xi = 0; xi < nbf; xi++) {
343 int m = type__.indexb(xi).m;
344 auto idxrf = type__.indexb(xi).idxrf;
345 idx_map[xi] =
346 type__.indexb().index_of(rf_index(idxrf)) + idx_m_qe(m); /* beginning of lm-block + new offset in lm block */
347 }
348 return idx_map;
349}
350
351static inline int
352phase_Rlm_QE(Atom_type const& type__, int xi__)
353{
354 return (type__.indexb(xi__).m < 0 && (-type__.indexb(xi__).m) % 2 == 0) ? -1 : 1;
355}
356
357extern "C" {
358
359/*
360@api begin
361sirius_initialize:
362 doc: Initialize the SIRIUS library.
363 arguments:
364 call_mpi_init:
365 type: bool
366 attr: in, required
367 doc: If .true. then MPI_Init must be called prior to initialization.
368 error_code:
369 type: int
370 attr: out, optional
371 doc: Error code.
372@api end
373*/
374void
375sirius_initialize(bool const* call_mpi_init__, int* error_code__)
376{
377 call_sirius([&]() {
378 sirius::initialize(*call_mpi_init__);
379#ifdef SIRIUS_NLCGLIB
381#endif
382 }, error_code__);
383}
384
385/*
386@api begin
387sirius_finalize:
388 doc: Shut down the SIRIUS library
389 arguments:
390 call_mpi_fin:
391 type: bool
392 attr: in, optional
393 doc: If .true. then MPI_Finalize must be called after the shutdown.
394 call_device_reset:
395 type: bool
396 attr: in, optional
397 doc: If .true. then cuda device is reset after shutdown.
398 call_fftw_fin:
399 type: bool
400 attr: in, optional
401 doc: If .true. then fft_cleanup must be called after the shutdown.
402 error_code:
403 type: int
404 attr: out, optional
405 doc: Error code.
406@api end
407*/
408void
409sirius_finalize(bool const* call_mpi_fin__, bool const* call_device_reset__, bool const* call_fftw_fin__,
410 int* error_code__)
411{
412 call_sirius(
413 [&]() {
414#ifdef SIRIUS_NLCGLIB
415 nlcglib::finalize();
416#endif
417 bool mpi_fin{true};
418 bool device_reset{true};
419 bool fftw_fin{true};
420
421 if (call_mpi_fin__ != nullptr) {
422 mpi_fin = *call_mpi_fin__;
423 }
424
425 if (call_device_reset__ != nullptr) {
426 device_reset = *call_device_reset__;
427 }
428
429 if (call_fftw_fin__ != nullptr) {
430 fftw_fin = *call_fftw_fin__;
431 }
432
433 sirius::finalize(mpi_fin, device_reset, fftw_fin);
434 },
435 error_code__);
436}
437
438/*
439@api begin
440sirius_start_timer:
441 doc: Start the timer.
442 arguments:
443 name:
444 type: string
445 attr: in, required
446 doc: Timer label.
447 error_code:
448 type: int
449 attr: out, optional
450 doc: Error code.
451@api end
452*/
453void
454sirius_start_timer(char const* name__, int* error_code__)
455{
456 call_sirius([&]() { global_rtgraph_timer.start(name__); }, error_code__);
457}
458
459/*
460@api begin
461sirius_stop_timer:
462 doc: Stop the running timer.
463 arguments:
464 name:
465 type: string
466 attr: in, required
467 doc: Timer label.
468 error_code:
469 type: int
470 attr: out, optional
471 doc: Error code.
472@api end
473*/
474void
475sirius_stop_timer(char const* name__, int* error_code__)
476{
477 call_sirius([&]() { global_rtgraph_timer.stop(name__); }, error_code__);
478}
479
480/*
481@api begin
482sirius_print_timers:
483 doc: Print all timers.
484 arguments:
485 flatten:
486 type: bool
487 attr: in, required
488 doc: If true, flat list of timers is printed.
489 error_code:
490 type: int
491 attr: out, optional
492 doc: Error code.
493@api end
494*/
495void
496sirius_print_timers(bool* flatten__, int* error_code__)
497{
498 call_sirius(
499 [&]() {
500 auto timing_result = global_rtgraph_timer.process();
501 if (*flatten__) {
502 timing_result = timing_result.flatten(1).sort_nodes();
503 }
504 std::cout << timing_result.print({rt_graph::Stat::Count, rt_graph::Stat::Total, rt_graph::Stat::Percentage,
505 rt_graph::Stat::SelfPercentage, rt_graph::Stat::Median,
506 rt_graph::Stat::Min, rt_graph::Stat::Max});
507 },
508 error_code__);
509}
510
511/*
512@api begin
513sirius_serialize_timers:
514 doc: Save all timers to JSON file.
515 arguments:
516 fname:
517 type: string
518 attr: in, required
519 doc: Name of the output JSON file.
520 error_code:
521 type: int
522 attr: out, optional
523 doc: Error code.
524@api end
525*/
526void
527sirius_serialize_timers(char const* fname__, int* error_code__)
528{
529 call_sirius(
530 [&]() {
531 auto timing_result = global_rtgraph_timer.process();
532 std::ofstream ofs(fname__, std::ofstream::out | std::ofstream::trunc);
533 ofs << timing_result.json();
534 },
535 error_code__);
536}
537
538/*
539@api begin
540sirius_context_initialized:
541 doc: Check if the simulation context is initialized.
542 arguments:
543 handler:
544 type: ctx_handler
545 attr: in, required
546 doc: Simulation context handler.
547 status:
548 type: bool
549 attr: out, required
550 doc: Status of the library (true if initialized)
551 error_code:
552 type: int
553 attr: out, optional
554 doc: Error code.
555@api end
556*/
557void
558sirius_context_initialized(void* const* handler__, bool* status__, int* error_code__)
559{
560 call_sirius(
561 [&]() {
562 auto& sim_ctx = get_sim_ctx(handler__);
563 *status__ = sim_ctx.initialized();
564 },
565 error_code__);
566}
567
568/*
569@api begin
570sirius_create_context:
571 doc: Create context of the simulation.
572 full_doc: Simulation context is the complex data structure that holds all the parameters of the
573 individual simulation.
574
575 The context must be created, populated with the correct parameters and
576 initialized before using all subsequent SIRIUS functions.
577 arguments:
578 fcomm:
579 type: int
580 attr: in, required, value
581 doc: Entire communicator of the simulation.
582 handler:
583 type: ctx_handler
584 attr: out, required
585 doc: New empty simulation context.
586 fcomm_k:
587 type: int
588 attr: in, optional
589 doc: Communicator for k-point parallelization.
590 fcomm_band:
591 type: int
592 attr: in, optional
593 doc: Communicator for band parallelization.
594 error_code:
595 type: int
596 attr: out, optional
597 doc: Error code.
598@api end
599*/
600void
601sirius_create_context(int fcomm__, void** handler__, int* fcomm_k__, int* fcomm_band__, int* error_code__)
602{
603 call_sirius(
604 [&]() {
605 auto& comm = mpi::Communicator::map_fcomm(fcomm__);
606 auto& comm_k = (fcomm_k__) ? mpi::Communicator::map_fcomm(*fcomm_k__) : mpi::Communicator();
607 auto const& comm_band =
608 (fcomm_band__) ? mpi::Communicator::map_fcomm(*fcomm_band__) : mpi::Communicator();
609 *handler__ = new any_ptr(new Simulation_context(comm, comm_k, comm_band));
610 },
611 error_code__);
612}
613
614/*
615@api begin
616sirius_import_parameters:
617 doc: Import parameters of simulation from a JSON string
618 arguments:
619 handler:
620 type: ctx_handler
621 attr: in, required
622 doc: Simulation context handler.
623 str:
624 type: string
625 attr: in, required
626 doc: JSON string with parameters or a JSON file.
627 error_code:
628 type: int
629 attr: out, optional
630 doc: Error code
631@api end
632*/
633void
634sirius_import_parameters(void* const* handler__, char const* str__, int* error_code__)
635{
636 call_sirius(
637 [&]() {
638 auto& sim_ctx = get_sim_ctx(handler__);
639 sim_ctx.import(std::string(str__));
640 },
641 error_code__);
642}
643
644/*
645@api begin
646sirius_set_parameters:
647 doc: Set parameters of the simulation.
648 arguments:
649 handler:
650 type: ctx_handler
651 attr: in, required
652 doc: Simulation context handler
653 lmax_apw:
654 type: int
655 attr: in, optional
656 doc: Maximum orbital quantum number for APW functions.
657 lmax_rho:
658 type: int
659 attr: in, optional
660 doc: Maximum orbital quantum number for density.
661 lmax_pot:
662 type: int
663 attr: in, optional
664 doc: Maximum orbital quantum number for potential.
665 num_fv_states:
666 type: int
667 attr: in, optional
668 doc: Number of first-variational states.
669 num_bands:
670 type: int
671 attr: in, optional
672 doc: Number of bands.
673 num_mag_dims:
674 type: int
675 attr: in, optional
676 doc: Number of magnetic dimensions.
677 pw_cutoff:
678 type: double
679 attr: in, optional
680 doc: Cutoff for G-vectors.
681 gk_cutoff:
682 type: double
683 attr: in, optional
684 doc: Cutoff for G+k-vectors.
685 fft_grid_size:
686 type: int
687 attr: in, optional, dimension(3)
688 doc: Size of the fine-grain FFT grid.
689 auto_rmt:
690 type: int
691 attr: in, optional
692 doc: Set the automatic search of muffin-tin radii.
693 gamma_point:
694 type: bool
695 attr: in, optional
696 doc: True if this is a Gamma-point calculation.
697 use_symmetry:
698 type: bool
699 attr: in, optional
700 doc: True if crystal symmetry is taken into account.
701 so_correction:
702 type: bool
703 attr: in, optional
704 doc: True if spin-orbit correnctio is enabled.
705 valence_rel:
706 type: string
707 attr: in, optional
708 doc: Valence relativity treatment.
709 core_rel:
710 type: string
711 attr: in, optional
712 doc: Core relativity treatment.
713 iter_solver_tol_empty:
714 type: double
715 attr: in, optional
716 doc: Tolerance for the empty states.
717 iter_solver_type:
718 type: string
719 attr: in, optional
720 doc: Type of iterative solver.
721 verbosity:
722 type: int
723 attr: in, optional
724 doc: Verbosity level.
725 hubbard_correction:
726 type: bool
727 attr: in, optional
728 doc: True if LDA+U correction is enabled.
729 hubbard_correction_kind:
730 type: int
731 attr: in, optional
732 doc: Type of LDA+U implementation (simplified or full).
733 hubbard_full_orthogonalization:
734 type: bool
735 attr: in, optional
736 doc: Use all atomic orbitals found in all ps potentials to compute the orthogonalization operator.
737 hubbard_orbitals:
738 type: string
739 attr: in, optional
740 doc: Type of localized orbitals.
741 sht_coverage:
742 type: int
743 attr: in, optional
744 doc: Type of spherical coverage (0 for Lebedev-Laikov, 1 for uniform).
745 min_occupancy:
746 type: double
747 attr: in, optional
748 doc: Minimum band occupancy to trat is as "occupied".
749 smearing:
750 type: string
751 attr: in, optional
752 doc: Type of occupancy smearing.
753 smearing_width:
754 type: double
755 attr: in, optional
756 doc: Smearing width
757 spglib_tol:
758 type: double
759 attr: in, optional
760 doc: Tolerance for the spglib symmetry search.
761 electronic_structure_method:
762 type: string
763 attr: in, optional
764 doc: Type of electronic structure method.
765 error_code:
766 type: int
767 attr: out, optional
768 doc: Error code.
769@api end
770*/
771void
772sirius_set_parameters(void* const* handler__, int const* lmax_apw__, int const* lmax_rho__, int const* lmax_pot__,
773 int const* num_fv_states__, int const* num_bands__, int const* num_mag_dims__,
774 double const* pw_cutoff__, double const* gk_cutoff__, int const* fft_grid_size__,
775 int const* auto_rmt__, bool const* gamma_point__, bool const* use_symmetry__,
776 bool const* so_correction__, char const* valence_rel__, char const* core_rel__,
777 double const* iter_solver_tol_empty__,
778 char const* iter_solver_type__, int const* verbosity__, bool const* hubbard_correction__,
779 int const* hubbard_correction_kind__, bool const* hubbard_full_orthogonalization__,
780 char const* hubbard_orbitals__, int const* sht_coverage__, double const* min_occupancy__,
781 char const* smearing__, double const* smearing_width__, double const* spglib_tol__,
782 char const* electronic_structure_method__, int* error_code__)
783{
784 call_sirius(
785 [&]() {
786 auto& sim_ctx = get_sim_ctx(handler__);
787 if (lmax_apw__ != nullptr) {
788 sim_ctx.lmax_apw(*lmax_apw__);
789 }
790 if (lmax_rho__ != nullptr) {
791 sim_ctx.lmax_rho(*lmax_rho__);
792 }
793 if (lmax_pot__ != nullptr) {
794 sim_ctx.lmax_pot(*lmax_pot__);
795 }
796 if (num_fv_states__ != nullptr) {
797 sim_ctx.num_fv_states(*num_fv_states__);
798 }
799 if (num_bands__ != nullptr) {
800 sim_ctx.num_bands(*num_bands__);
801 }
802 if (num_mag_dims__ != nullptr) {
803 sim_ctx.set_num_mag_dims(*num_mag_dims__);
804 }
805 if (pw_cutoff__ != nullptr) {
806 sim_ctx.pw_cutoff(*pw_cutoff__);
807 }
808 if (gk_cutoff__ != nullptr) {
809 sim_ctx.gk_cutoff(*gk_cutoff__);
810 }
811 if (auto_rmt__ != nullptr) {
812 sim_ctx.set_auto_rmt(*auto_rmt__);
813 }
814 if (gamma_point__ != nullptr) {
815 sim_ctx.gamma_point(*gamma_point__);
816 }
817 if (use_symmetry__ != nullptr) {
818 sim_ctx.use_symmetry(*use_symmetry__);
819 }
820 if (so_correction__ != nullptr) {
821 sim_ctx.so_correction(*so_correction__);
822 }
823 if (valence_rel__ != nullptr) {
824 sim_ctx.valence_relativity(valence_rel__);
825 }
826 if (core_rel__ != nullptr) {
827 sim_ctx.core_relativity(core_rel__);
828 }
829 if (iter_solver_tol_empty__ != nullptr) {
830 sim_ctx.empty_states_tolerance(*iter_solver_tol_empty__);
831 }
832 if (iter_solver_type__ != nullptr) {
833 sim_ctx.iterative_solver_type(std::string(iter_solver_type__));
834 }
835 if (verbosity__ != nullptr) {
836 sim_ctx.verbosity(*verbosity__);
837 }
838 if (hubbard_correction__ != nullptr) {
839 sim_ctx.set_hubbard_correction(*hubbard_correction__);
840 }
841 if (hubbard_correction_kind__ != nullptr) {
842 if (*hubbard_correction_kind__ == 0) {
843 sim_ctx.cfg().hubbard().simplified(true);
844 }
845 }
846 if (hubbard_full_orthogonalization__ != nullptr) {
847 if (*hubbard_full_orthogonalization__) {
848 sim_ctx.cfg().hubbard().full_orthogonalization(true);
849 }
850 }
851 if (hubbard_orbitals__ != nullptr) {
852 std::string s(hubbard_orbitals__);
853 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
854 if (s == "ortho-atomic") {
855 sim_ctx.cfg().hubbard().orthogonalize(true);
856 sim_ctx.cfg().hubbard().full_orthogonalization(true);
857 }
858 if (s == "norm-atomic") {
859 sim_ctx.cfg().hubbard().normalize(true);
860 }
861 }
862 if (fft_grid_size__ != nullptr) {
863 sim_ctx.fft_grid_size({fft_grid_size__[0], fft_grid_size__[1], fft_grid_size__[2]});
864 }
865 if (sht_coverage__ != nullptr) {
866 sim_ctx.sht_coverage(*sht_coverage__);
867 }
868 if (min_occupancy__ != nullptr) {
869 sim_ctx.min_occupancy(*min_occupancy__);
870 }
871 if (smearing__ != nullptr) {
872 sim_ctx.smearing(smearing__);
873 }
874 if (smearing_width__ != nullptr) {
875 sim_ctx.smearing_width(*smearing_width__);
876 }
877 if (spglib_tol__ != nullptr) {
878 sim_ctx.cfg().control().spglib_tolerance(*spglib_tol__);
879 }
880 if (electronic_structure_method__ != nullptr) {
881 sim_ctx.cfg().parameters().electronic_structure_method(electronic_structure_method__);
882 }
883 },
884 error_code__);
885}
886
887/*
888@api begin
889sirius_get_parameters:
890 doc: Get parameters of the simulation.
891 arguments:
892 handler:
893 type: ctx_handler
894 attr: in, required
895 doc: Simulation context handler
896 lmax_apw:
897 type: int
898 attr: out, optional
899 doc: Maximum orbital quantum number for APW functions.
900 lmax_rho:
901 type: int
902 attr: out, optional
903 doc: Maximum orbital quantum number for density.
904 lmax_pot:
905 type: int
906 attr: out, optional
907 doc: Maximum orbital quantum number for potential.
908 num_fv_states:
909 type: int
910 attr: out, optional
911 doc: Number of first-variational states.
912 num_bands:
913 type: int
914 attr: out, optional
915 doc: Number of bands.
916 num_spins:
917 type: int
918 attr: out, optional
919 doc: Number of spins.
920 num_mag_dims:
921 type: int
922 attr: out, optional
923 doc: Number of magnetic dimensions.
924 pw_cutoff:
925 type: double
926 attr: out, optional
927 doc: Cutoff for G-vectors.
928 gk_cutoff:
929 type: double
930 attr: out, optional
931 doc: Cutoff for G+k-vectors.
932 fft_grid_size:
933 type: int
934 attr: out, optional, dimension(3)
935 doc: Size of the fine-grain FFT grid.
936 auto_rmt:
937 type: int
938 attr: out, optional
939 doc: Set the automatic search of muffin-tin radii.
940 gamma_point:
941 type: bool
942 attr: out, optional
943 doc: True if this is a Gamma-point calculation.
944 use_symmetry:
945 type: bool
946 attr: out, optional
947 doc: True if crystal symmetry is taken into account.
948 so_correction:
949 type: bool
950 attr: out, optional
951 doc: True if spin-orbit correnctio is enabled.
952 iter_solver_tol:
953 type: double
954 attr: out, optional
955 doc: Tolerance of the iterative solver (deprecated).
956 iter_solver_tol_empty:
957 type: double
958 attr: out, optional
959 doc: Tolerance for the empty states.
960 verbosity:
961 type: int
962 attr: out, optional
963 doc: Verbosity level.
964 hubbard_correction:
965 type: bool
966 attr: out, optional
967 doc: True if LDA+U correction is enabled.
968 evp_work_count:
969 type: double
970 attr: out, optional
971 doc: Internal counter of total eigen-value problem work.
972 num_loc_op_applied:
973 type: int
974 attr: out, optional
975 doc: Internal counter of the number of wave-functions to which Hamiltonian was applied.
976 num_sym_op:
977 type: int
978 attr: out, optional
979 doc: Number of symmetry operations discovered by spglib
980 electronic_structure_method:
981 type: string
982 attr: out, optional
983 doc: Type of electronic structure method.
984 error_code:
985 type: int
986 attr: out, optional
987 doc: Error code.
988@api end
989*/
990void
991sirius_get_parameters(void* const* handler__, int* lmax_apw__, int* lmax_rho__, int* lmax_pot__, int* num_fv_states__,
992 int* num_bands__, int* num_spins__, int* num_mag_dims__, double* pw_cutoff__, double* gk_cutoff__,
993 int* fft_grid_size__, int* auto_rmt__, bool* gamma_point__, bool* use_symmetry__,
994 bool* so_correction__, double* iter_solver_tol__, double* iter_solver_tol_empty__,
995 int* verbosity__, bool* hubbard_correction__, double* evp_work_count__, int* num_loc_op_applied__,
996 int* num_sym_op__, char* electronic_structure_method__, int* error_code__)
997{
998 call_sirius(
999 [&]() {
1000 auto& sim_ctx = get_sim_ctx(handler__);
1001 if (lmax_apw__) {
1002 *lmax_apw__ = sim_ctx.unit_cell().lmax_apw();
1003 }
1004 if (lmax_rho__) {
1005 *lmax_rho__ = sim_ctx.lmax_rho();
1006 }
1007 if (lmax_pot__) {
1008 *lmax_pot__ = sim_ctx.lmax_pot();
1009 }
1010 if (num_fv_states__) {
1011 *num_fv_states__ = sim_ctx.num_fv_states();
1012 }
1013 if (num_bands__) {
1014 *num_bands__ = sim_ctx.num_bands();
1015 }
1016 if (num_spins__) {
1017 *num_spins__ = sim_ctx.num_spins();
1018 }
1019 if (num_mag_dims__) {
1020 *num_mag_dims__ = sim_ctx.num_mag_dims();
1021 }
1022 if (pw_cutoff__) {
1023 *pw_cutoff__ = sim_ctx.pw_cutoff();
1024 }
1025 if (gk_cutoff__) {
1026 *gk_cutoff__ = sim_ctx.gk_cutoff();
1027 }
1028 if (auto_rmt__) {
1029 *auto_rmt__ = sim_ctx.auto_rmt();
1030 }
1031 if (gamma_point__) {
1032 *gamma_point__ = sim_ctx.gamma_point();
1033 }
1034 if (use_symmetry__) {
1035 *use_symmetry__ = sim_ctx.use_symmetry();
1036 }
1037 if (so_correction__) {
1038 *so_correction__ = sim_ctx.so_correction();
1039 }
1040 if (iter_solver_tol_empty__) {
1041 *iter_solver_tol_empty__ = sim_ctx.cfg().iterative_solver().empty_states_tolerance();
1042 }
1043 if (verbosity__) {
1044 *verbosity__ = sim_ctx.verbosity();
1045 }
1046 if (hubbard_correction__) {
1047 *hubbard_correction__ = sim_ctx.hubbard_correction();
1048 }
1049 if (fft_grid_size__) {
1050 for (int x : {0, 1, 2}) {
1051 fft_grid_size__[x] = sim_ctx.fft_grid()[x];
1052 }
1053 }
1054 if (evp_work_count__) {
1055 *evp_work_count__ = sim_ctx.evp_work_count();
1056 }
1057 if (num_loc_op_applied__) {
1058 *num_loc_op_applied__ = sim_ctx.num_loc_op_applied();
1059 }
1060 if (num_sym_op__) {
1061 if (sim_ctx.use_symmetry()) {
1062 *num_sym_op__ = sim_ctx.unit_cell().symmetry().size();
1063 } else {
1064 *num_sym_op__ = 0;
1065 }
1066 }
1067 if (electronic_structure_method__) {
1068 auto str = sim_ctx.cfg().parameters().electronic_structure_method();
1069 std::copy(str.c_str(), str.c_str() + str.length() + 1, electronic_structure_method__);
1070 }
1071 },
1072 error_code__);
1073}
1074
1075/*
1076@api begin
1077sirius_add_xc_functional:
1078 doc: Add one of the XC functionals.
1079 arguments:
1080 handler:
1081 type: ctx_handler
1082 attr: in, required
1083 doc: Simulation context handler
1084 name:
1085 type: string
1086 attr: in, required
1087 doc: LibXC label of the functional.
1088 error_code:
1089 type: int
1090 attr: out, optional
1091 doc: Error code.
1092@api end
1093*/
1094void
1095sirius_add_xc_functional(void* const* handler__, char const* name__, int* error_code__)
1096{
1097 call_sirius(
1098 [&]() {
1099 auto& sim_ctx = get_sim_ctx(handler__);
1100 sim_ctx.add_xc_functional(std::string(name__));
1101 },
1102 error_code__);
1103}
1104
1105/*
1106@api begin
1107sirius_set_mpi_grid_dims:
1108 doc: Set dimensions of the MPI grid.
1109 arguments:
1110 handler:
1111 type: ctx_handler
1112 attr: in, required
1113 doc: Simulation context handler
1114 ndims:
1115 type: int
1116 attr: in, required
1117 doc: Number of dimensions.
1118 dims:
1119 type: int
1120 attr: in, required, dimension(ndims)
1121 doc: Size of each dimension.
1122 error_code:
1123 type: int
1124 attr: out, optional
1125 doc: Error code.
1126@api end
1127*/
1128void
1129sirius_set_mpi_grid_dims(void* const* handler__, int const* ndims__, int const* dims__, int* error_code__)
1130{
1131 call_sirius(
1132 [&]() {
1133 RTE_ASSERT(*ndims__ > 0);
1134 auto& sim_ctx = get_sim_ctx(handler__);
1135 std::vector<int> dims(dims__, dims__ + *ndims__);
1136 sim_ctx.mpi_grid_dims(dims);
1137 },
1138 error_code__);
1139}
1140
1141/*
1142@api begin
1143sirius_set_lattice_vectors:
1144 doc: Set vectors of the unit cell.
1145 arguments:
1146 handler:
1147 type: ctx_handler
1148 attr: in, required
1149 doc: Simulation context handler
1150 a1:
1151 type: double
1152 attr: in, required, dimension(3)
1153 doc: 1st vector
1154 a2:
1155 type: double
1156 attr: in, required, dimension(3)
1157 doc: 2nd vector
1158 a3:
1159 type: double
1160 attr: in, required, dimension(3)
1161 doc: 3rd vector
1162 error_code:
1163 type: int
1164 attr: out, optional
1165 doc: Error code.
1166@api end
1167*/
1168void
1169sirius_set_lattice_vectors(void* const* handler__, double const* a1__, double const* a2__, double const* a3__,
1170 int* error_code__)
1171{
1172 call_sirius(
1173 [&]() {
1174 auto& sim_ctx = get_sim_ctx(handler__);
1175 sim_ctx.unit_cell().set_lattice_vectors(r3::vector<double>(a1__), r3::vector<double>(a2__),
1176 r3::vector<double>(a3__));
1177 },
1178 error_code__);
1179}
1180
1181/*
1182@api begin
1183sirius_initialize_context:
1184 doc: Initialize simulation context.
1185 arguments:
1186 handler:
1187 type: ctx_handler
1188 attr: in, required
1189 doc: Simulation context handler.
1190 error_code:
1191 type: int
1192 attr: out, optional
1193 doc: Error code.
1194@api end
1195*/
1196void
1197sirius_initialize_context(void* const* handler__, int* error_code__)
1198{
1199 call_sirius(
1200 [&]() {
1201 auto& sim_ctx = get_sim_ctx(handler__);
1202 sim_ctx.initialize();
1203 return 0;
1204 },
1205 error_code__);
1206}
1207
1208/*
1209@api begin
1210sirius_update_context:
1211 doc: Update simulation context after changing lattice or atomic positions.
1212 arguments:
1213 handler:
1214 type: ctx_handler
1215 attr: in, required
1216 doc: Simulation context handler.
1217 error_code:
1218 type: int
1219 attr: out, optional
1220 doc: Error code.
1221@api end
1222*/
1223void
1224sirius_update_context(void* const* handler__, int* error_code__)
1225{
1226 call_sirius(
1227 [&]() {
1228 auto& sim_ctx = get_sim_ctx(handler__);
1229 sim_ctx.update();
1230 return 0;
1231 },
1232 error_code__);
1233}
1234
1235/*
1236@api begin
1237sirius_print_info:
1238 doc: Print basic info
1239 arguments:
1240 handler:
1241 type: ctx_handler
1242 attr: in, required
1243 doc: Simulation context handler.
1244 error_code:
1245 type: int
1246 attr: out, optional
1247 doc: Error code.
1248@api end
1249*/
1250void
1251sirius_print_info(void* const* handler__, int* error_code__)
1252{
1253 call_sirius(
1254 [&]() {
1255 auto& sim_ctx = get_sim_ctx(handler__);
1256 sim_ctx.print_info(sim_ctx.out());
1257 },
1258 error_code__);
1259}
1260
1261/*
1262@api begin
1263sirius_free_object_handler:
1264 doc: Free any object handler created by SIRIUS.
1265 full_doc: This is an internal function. Use sirius_free_handler() in your code.
1266 arguments:
1267 handler:
1268 type: void*
1269 attr: inout, required
1270 doc: Handler of the object.
1271 error_code:
1272 type: int
1273 attr: out, optional
1274 doc: Error code
1275@api end
1276*/
1277void
1278sirius_free_object_handler(void** handler__, int* error_code__)
1279{
1280 call_sirius(
1281 [&]() {
1282 if (*handler__ != nullptr) {
1283 delete static_cast<any_ptr*>(*handler__);
1284 }
1285 *handler__ = nullptr;
1286 },
1287 error_code__);
1288}
1289
1290/*
1291@api begin
1292sirius_set_periodic_function_ptr:
1293 doc: Set pointer to density or magnetization.
1294 arguments:
1295 handler:
1296 type: ctx_handler
1297 attr: in, required
1298 doc: Simulation context handler.
1299 label:
1300 type: string
1301 attr: in, required
1302 doc: Label of the function.
1303 f_mt:
1304 type: double
1305 attr: in, optional, dimension(:,:,:)
1306 doc: Pointer to the muffin-tin part of the function.
1307 lmmax:
1308 type: int
1309 attr: in, optional
1310 doc: Number of lm components.
1311 nrmtmax:
1312 type: int
1313 attr: in, optional
1314 doc: Maximum number of muffin-tin points.
1315 num_atoms:
1316 type: int
1317 attr: in, optional
1318 doc: Total number of atoms.
1319 f_rg:
1320 type: double
1321 attr: in, optional, dimension(:)
1322 doc: Pointer to the regular-grid part of the function.
1323 size_x:
1324 type: int
1325 attr: in, optional
1326 doc: Size of X-dimension of FFT grid.
1327 size_y:
1328 type: int
1329 attr: in, optional
1330 doc: Size of Y-dimension of FFT grid.
1331 size_z:
1332 type: int
1333 attr: in, optional
1334 doc: Local or global size of Z-dimension of FFT grid depending on offset_z
1335 offset_z:
1336 type: int
1337 attr: in, optional
1338 doc: Offset in the Z-dimension of FFT grid for this MPI rank.
1339 error_code:
1340 type: int
1341 attr: out, optional
1342 doc: Error code
1343@api end
1344*/
1345void
1346sirius_set_periodic_function_ptr(void* const* handler__, char const* label__, double* f_mt__, int const* lmmax__,
1347 int const* nrmtmax__, int const* num_atoms__, double* f_rg__, int const* size_x__, int const* size_y__,
1348 int const* size_z__, int const* offset_z__, int* error_code__)
1349{
1350 call_sirius(
1351 [&]() {
1352 auto& sim_ctx = get_sim_ctx(handler__);
1353 std::string label(label__);
1354
1355 int lmmax = get_value(lmmax__);
1356 int nrmtmax = get_value(nrmtmax__);
1357 int num_atoms = get_value(num_atoms__);
1358 int size_x = get_value(size_x__);
1359 int size_y = get_value(size_y__);
1360 int size_z = get_value(size_z__);
1361 int offset_z = get_value(offset_z__, -1);
1362
1363 spheric_function_set_ptr_t<double> mt_ptr(f_mt__, lmmax, nrmtmax, num_atoms);
1364 smooth_periodic_function_ptr_t<double> rg_ptr(f_rg__, size_x, size_y, size_z, offset_z);
1365
1366 sim_ctx.set_periodic_function_ptr(label, periodic_function_ptr_t<double>(mt_ptr, rg_ptr));
1367 },
1368 error_code__);
1369}
1370
1371/*
1372@api begin
1373sirius_set_periodic_function:
1374 doc: Set values of the periodic function.
1375 arguments:
1376 handler:
1377 type: gs_handler
1378 attr: in, required
1379 doc: Handler of the DFT ground state object.
1380 label:
1381 type: string
1382 attr: in, required
1383 doc: Label of the function.
1384 f_mt:
1385 type: double
1386 attr: in, optional, dimension(:,:,:)
1387 doc: Pointer to the muffin-tin part of the function.
1388 lmmax:
1389 type: int
1390 attr: in, optional
1391 doc: Number of lm components.
1392 nrmtmax:
1393 type: int
1394 attr: in, optional
1395 doc: Maximum number of muffin-tin points.
1396 num_atoms:
1397 type: int
1398 attr: in, optional
1399 doc: Total number of atoms.
1400 f_rg:
1401 type: double
1402 attr: in, optional, dimension(:)
1403 doc: Pointer to the regular-grid part of the function.
1404 size_x:
1405 type: int
1406 attr: in, optional
1407 doc: Size of X-dimension of FFT grid.
1408 size_y:
1409 type: int
1410 attr: in, optional
1411 doc: Size of Y-dimension of FFT grid.
1412 size_z:
1413 type: int
1414 attr: in, optional
1415 doc: Local or global size of Z-dimension of FFT grid depending on offset_z
1416 offset_z:
1417 type: int
1418 attr: in, optional
1419 doc: Offset in the Z-dimension of FFT grid for this MPI rank.
1420 error_code:
1421 type: int
1422 attr: out, optional
1423 doc: Error code.
1424@api end
1425*/
1426void
1427sirius_set_periodic_function(void* const* handler__, char const* label__, double* f_mt__, int const* lmmax__,
1428 int const* nrmtmax__, int const* num_atoms__, double* f_rg__, int const* size_x__,
1429 int const* size_y__, int const* size_z__, int const* offset_z__, int* error_code__)
1430{
1431 call_sirius(
1432 [&]() {
1433 auto& gs = get_gs(handler__);
1434 std::string label(label__);
1435 std::map<std::string, Periodic_function<double>*> func_map = {
1436 {"rho", &gs.density().component(0)}, {"magz", &gs.density().component(1)},
1437 {"magx", &gs.density().component(2)}, {"magy", &gs.density().component(3)},
1438 {"veff", &gs.potential().component(0)}, {"bz", &gs.potential().component(1)},
1439 {"bx", &gs.potential().component(2)}, {"by", &gs.potential().component(3)},
1440 {"vha", &gs.potential().hartree_potential()}};
1441
1442 if (!func_map.count(label)) {
1443 RTE_THROW("wrong label (" + label + ") for the periodic function");
1444 }
1445
1446 int lmmax = get_value(lmmax__);
1447 int nrmtmax = get_value(nrmtmax__);
1448 int num_atoms = get_value(num_atoms__);
1449 int size_x = get_value(size_x__);
1450 int size_y = get_value(size_y__);
1451 int size_z = get_value(size_z__);
1452 int offset_z = get_value(offset_z__, -1);
1453
1454 if (f_mt__) {
1455 spheric_function_set_ptr_t<double> mt_ptr(f_mt__, lmmax, nrmtmax, num_atoms);
1456 copy(mt_ptr, func_map[label]->mt());
1457 }
1458 if (f_rg__) {
1459 smooth_periodic_function_ptr_t<double> rg_ptr(f_rg__, size_x, size_y, size_z, offset_z);
1460 copy(rg_ptr, func_map[label]->rg());
1461 }
1462 },
1463 error_code__);
1464}
1465
1466/*
1467@api begin
1468sirius_get_periodic_function:
1469 doc: Get values of the periodic function.
1470 arguments:
1471 handler:
1472 type: gs_handler
1473 attr: in, required
1474 doc: Handler of the DFT ground state object.
1475 label:
1476 type: string
1477 attr: in, required
1478 doc: Label of the function.
1479 f_mt:
1480 type: double
1481 attr: in, optional, dimension(:,:,:)
1482 doc: Pointer to the muffin-tin part of the function.
1483 lmmax:
1484 type: int
1485 attr: in, optional
1486 doc: Number of lm components.
1487 nrmtmax:
1488 type: int
1489 attr: in, optional
1490 doc: Maximum number of muffin-tin points.
1491 num_atoms:
1492 type: int
1493 attr: in, optional
1494 doc: Total number of atoms.
1495 f_rg:
1496 type: double
1497 attr: in, optional, dimension(:)
1498 doc: Pointer to the regular-grid part of the function.
1499 size_x:
1500 type: int
1501 attr: in, optional
1502 doc: Size of X-dimension of FFT grid.
1503 size_y:
1504 type: int
1505 attr: in, optional
1506 doc: Size of Y-dimension of FFT grid.
1507 size_z:
1508 type: int
1509 attr: in, optional
1510 doc: Local or global size of Z-dimension of FFT grid depending on offset_z
1511 offset_z:
1512 type: int
1513 attr: in, optional
1514 doc: Offset in the Z-dimension of FFT grid for this MPI rank.
1515 error_code:
1516 type: int
1517 attr: out, optional
1518 doc: Error code
1519@api end
1520*/
1521void
1522sirius_get_periodic_function(void* const* handler__, char const* label__, double* f_mt__, int const* lmmax__,
1523 int const* nrmtmax__, int const* num_atoms__, double* f_rg__, int const* size_x__,
1524 int const* size_y__, int const* size_z__, int const* offset_z__, int* error_code__)
1525{
1526 call_sirius(
1527 [&]() {
1528 auto& gs = get_gs(handler__);
1529 std::string label(label__);
1530 std::map<std::string, Periodic_function<double>*> func_map = {
1531 {"rho", &gs.density().component(0)}, {"magz", &gs.density().component(1)},
1532 {"magx", &gs.density().component(2)}, {"magy", &gs.density().component(3)},
1533 {"veff", &gs.potential().component(0)}, {"bz", &gs.potential().component(1)},
1534 {"bx", &gs.potential().component(2)}, {"by", &gs.potential().component(3)},
1535 {"vha", &gs.potential().hartree_potential()}, {"exc", &gs.potential().xc_energy_density()},
1536 {"vxc", &gs.potential().xc_potential()}};
1537
1538 if (!func_map.count(label)) {
1539 RTE_THROW("wrong label (" + label + ") for the periodic function");
1540 }
1541
1542 int lmmax = get_value(lmmax__);
1543 int nrmtmax = get_value(nrmtmax__);
1544 int num_atoms = get_value(num_atoms__);
1545 int size_x = get_value(size_x__);
1546 int size_y = get_value(size_y__);
1547 int size_z = get_value(size_z__);
1548 int offset_z = get_value(offset_z__, -1);
1549
1550 if (f_mt__) {
1551 spheric_function_set_ptr_t<double> mt_ptr(f_mt__, lmmax, nrmtmax, num_atoms);
1552 copy(func_map[label]->mt(), mt_ptr);
1553 }
1554 if (f_rg__) {
1555 smooth_periodic_function_ptr_t<double> rg_ptr(f_rg__, size_x, size_y, size_z, offset_z);
1556 copy(func_map[label]->rg(), rg_ptr);
1557 }
1558 },
1559 error_code__);
1560}
1561
1562/*
1563@api begin
1564sirius_create_kset:
1565 doc: Create k-point set from the list of k-points.
1566 arguments:
1567 handler:
1568 type: ctx_handler
1569 attr: in, required
1570 doc: Simulation context handler.
1571 num_kpoints:
1572 type: int
1573 attr: in, required
1574 doc: Total number of k-points in the set.
1575 kpoints:
1576 type: double
1577 attr: in, required, dimension(3,num_kpoints)
1578 doc: List of k-points in lattice coordinates.
1579 kpoint_weights:
1580 type: double
1581 attr: in, required, dimension(num_kpoints)
1582 doc: Weights of k-points.
1583 init_kset:
1584 type: bool
1585 attr: in, required
1586 doc: If .true. k-set will be initialized.
1587 kset_handler:
1588 type: ks_handler
1589 attr: out, required
1590 doc: Handler of the newly created k-point set.
1591 error_code:
1592 type: int
1593 attr: out, optional
1594 doc: Error code.
1595@api end
1596*/
1597void
1598sirius_create_kset(void* const* handler__, int const* num_kpoints__, double* kpoints__, double const* kpoint_weights__,
1599 bool const* init_kset__, void** kset_handler__, int* error_code__)
1600{
1601 call_sirius(
1602 [&]() {
1603 auto& sim_ctx = get_sim_ctx(handler__);
1604
1605 sddk::mdarray<double, 2> kpoints(kpoints__, 3, *num_kpoints__);
1606
1607 K_point_set* new_kset = new K_point_set(sim_ctx);
1608 new_kset->add_kpoints(kpoints, kpoint_weights__);
1609 if (*init_kset__) {
1610 new_kset->initialize();
1611 }
1612 *kset_handler__ = new any_ptr(new_kset);
1613 },
1614 error_code__);
1615}
1616
1617/*
1618@api begin
1619sirius_create_kset_from_grid:
1620 doc: Create k-point set from a grid.
1621 arguments:
1622 handler:
1623 type: ctx_handler
1624 attr: in, required
1625 doc: Simulation context handler.
1626 k_grid:
1627 type: int
1628 attr: in, required, dimension(3)
1629 doc: dimensions of the k points grid.
1630 k_shift:
1631 type: int
1632 attr: in, required, dimension(3)
1633 doc: k point shifts.
1634 use_symmetry:
1635 type: bool
1636 attr: in, required
1637 doc: If .true. k-set will be generated using symmetries.
1638 kset_handler:
1639 type: ks_handler
1640 attr: out, required
1641 doc: Handler of the newly created k-point set.
1642 error_code:
1643 type: int
1644 attr: out, optional
1645 doc: Error code.
1646@api end
1647*/
1648void
1649sirius_create_kset_from_grid(void* const* handler__, int const* k_grid__, int const* k_shift__,
1650 bool const* use_symmetry, void** kset_handler__, int* error_code__)
1651{
1652 call_sirius(
1653 [&]() {
1654 auto& sim_ctx = get_sim_ctx(handler__);
1655 std::vector<int> k_grid(3);
1656 std::vector<int> k_shift(3);
1657
1658 k_grid[0] = k_grid__[0];
1659 k_grid[1] = k_grid__[1];
1660 k_grid[2] = k_grid__[2];
1661
1662 k_shift[0] = k_shift__[0];
1663 k_shift[1] = k_shift__[1];
1664 k_shift[2] = k_shift__[2];
1665
1666 K_point_set* new_kset = new K_point_set(sim_ctx, k_grid, k_shift, *use_symmetry);
1667
1668 *kset_handler__ = new any_ptr(new_kset);
1669 },
1670 error_code__);
1671}
1672
1673/*
1674@api begin
1675sirius_create_ground_state:
1676 doc: Create a ground state object.
1677 arguments:
1678 ks_handler:
1679 type: ks_handler
1680 attr: in, required
1681 doc: Handler of the k-point set.
1682 gs_handler:
1683 type: gs_handler
1684 attr: out, required
1685 doc: Handler of the newly created ground state object.
1686 error_code:
1687 type: int
1688 attr: out, optional
1689 doc: Error code.
1690@api end
1691*/
1692void
1693sirius_create_ground_state(void* const* ks_handler__, void** gs_handler__, int* error_code__)
1694{
1695 call_sirius(
1696 [&]() {
1697 auto& ks = get_ks(ks_handler__);
1698
1699 *gs_handler__ = new any_ptr(new DFT_ground_state(ks));
1700 },
1701 error_code__);
1702}
1703
1704/*
1705@api begin
1706sirius_initialize_kset:
1707 doc: Initialize k-point set.
1708 arguments:
1709 ks_handler:
1710 type: ks_handler
1711 attr: in, required
1712 doc: K-point set handler.
1713 count:
1714 type: int
1715 attr: in, optional, dimension(:)
1716 doc: Local number of k-points for each MPI rank.
1717 error_code:
1718 type: int
1719 attr: out, optional
1720 doc: Error code.
1721@api end
1722*/
1723void
1724sirius_initialize_kset(void* const* ks_handler__, int* count__, int* error_code__)
1725{
1726 call_sirius(
1727 [&]() {
1728 auto& ks = get_ks(ks_handler__);
1729 if (count__) {
1730 std::vector<int> count(count__, count__ + ks.comm().size());
1731 ks.initialize(count);
1732 } else {
1733 ks.initialize();
1734 }
1735 },
1736 error_code__);
1737}
1738
1739/*
1740@api begin
1741sirius_find_ground_state:
1742 doc: Find the ground state.
1743 arguments:
1744 gs_handler:
1745 type: gs_handler
1746 attr: in, required
1747 doc: Handler of the ground state.
1748 density_tol:
1749 type: double
1750 attr: in, optional
1751 doc: Tolerance on RMS in density.
1752 energy_tol:
1753 type: double
1754 attr: in, optional
1755 doc: Tolerance in total energy difference.
1756 iter_solver_tol:
1757 type: double
1758 attr: in, optional
1759 doc: Initial tolerance of the iterative solver.
1760 initial_guess:
1761 type: bool
1762 attr: in, optional
1763 doc: Boolean variable indicating if we want to start from the initial guess or from previous state.
1764 max_niter:
1765 type: int
1766 attr: in, optional
1767 doc: Maximum number of SCF iterations.
1768 save_state:
1769 type: bool
1770 attr: in, optional
1771 doc: Boolean variable indicating if we want to save the ground state.
1772 converged:
1773 type: bool
1774 attr: out, optional
1775 doc: Boolean variable indicating if the calculation has converged
1776 niter:
1777 type: int
1778 attr: out, optional
1779 doc: Actual number of SCF iterations.
1780 rho_min:
1781 type: double
1782 attr: out, optional
1783 doc: Minimum value of density on the real-space grid. If negative, total energy can't be trusted. Valid only if SCF calculation is converged.
1784 error_code:
1785 type: int
1786 attr: out, optional
1787 doc: Error code.
1788@api end
1789*/
1790void
1791sirius_find_ground_state(void* const* gs_handler__, double const* density_tol__, double const* energy_tol__,
1792 double const* iter_solver_tol__, bool const* initial_guess__, int const* max_niter__,
1793 bool const* save_state__, bool* converged__, int* niter__, double* rho_min__,
1794 int* error_code__)
1795{
1796 call_sirius(
1797 [&]() {
1798 auto& gs = get_gs(gs_handler__);
1799 auto& ctx = gs.ctx();
1800 auto& inp = ctx.cfg().parameters();
1801
1802 bool initial_guess = (initial_guess__) ? *initial_guess__ : true;
1803 if (initial_guess) {
1804 gs.initial_state();
1805 }
1806
1807 double rho_tol = (density_tol__) ? *density_tol__ : inp.density_tol();
1808
1809 double etol = (energy_tol__) ? *energy_tol__ : inp.energy_tol();
1810
1811 double iter_solver_tol = (iter_solver_tol__) ? *iter_solver_tol__
1812 : ctx.cfg().iterative_solver().energy_tolerance();
1813
1814 int max_niter = (max_niter__) ? * max_niter__ : inp.num_dft_iter();
1815
1816 bool save = (save_state__) ? *save_state__ : false;
1817
1818 auto result = gs.find(rho_tol, etol, iter_solver_tol, max_niter, save);
1819
1820 if (result["converged"].get<bool>()) {
1821 if (converged__) {
1822 *converged__ = true;
1823 }
1824 if (niter__) {
1825 *niter__ = result["num_scf_iterations"].get<int>();
1826 }
1827 if (rho_min__) {
1828 *rho_min__ = result["rho_min"].get<double>();
1829 }
1830 } else {
1831 if (converged__) {
1832 *converged__ = false;
1833 }
1834 if (niter__) {
1835 *niter__ = max_niter;
1836 }
1837 if (rho_min__) {
1838 *rho_min__ = 0;
1839 }
1840 }
1841 },
1842 error_code__);
1843}
1844
1845/*
1846@api begin
1847sirius_check_scf_density:
1848 doc: Check the self-consistent density
1849 arguments:
1850 gs_handler:
1851 type: gs_handler
1852 attr: in, required
1853 doc: Handler of the ground state.
1854 error_code:
1855 type: int
1856 attr: out, optional
1857 doc: Error code
1858@api end
1859*/
1860void
1861sirius_check_scf_density(void* const* gs_handler__, int* error_code__)
1862{
1863 call_sirius(
1864 [&]() {
1865 auto& gs = get_gs(gs_handler__);
1866 gs.check_scf_density();
1867 },
1868 error_code__);
1869}
1870
1871
1872/*
1873@api begin
1874sirius_update_ground_state:
1875 doc: Update a ground state object after change of atomic coordinates or lattice vectors.
1876 arguments:
1877 gs_handler:
1878 type: gs_handler
1879 attr: in, required
1880 doc: Ground-state handler.
1881 error_code:
1882 type: int
1883 attr: out, optional
1884 doc: Error code
1885@api end
1886*/
1887void
1888sirius_update_ground_state(void** handler__, int* error_code__)
1889{
1890 call_sirius(
1891 [&]() {
1892 auto& gs = get_gs(handler__);
1893 gs.update();
1894 },
1895 error_code__);
1896}
1897
1898/*
1899@api begin
1900sirius_add_atom_type:
1901 doc: Add new atom type to the unit cell.
1902 arguments:
1903 handler:
1904 type: ctx_handler
1905 attr: in, required
1906 doc: Simulation context handler.
1907 label:
1908 type: string
1909 attr: in, required
1910 doc: Atom type unique label.
1911 fname:
1912 type: string
1913 attr: in, optional
1914 doc: Species file name (in JSON format).
1915 zn:
1916 type: int
1917 attr: in, optional
1918 doc: Nucleus charge.
1919 symbol:
1920 type: string
1921 attr: in, optional
1922 doc: Atomic symbol.
1923 mass:
1924 type: double
1925 attr: in, optional
1926 doc: Atomic mass.
1927 spin_orbit:
1928 type: bool
1929 attr: in, optional
1930 doc: True if spin-orbit correction is enabled for this atom type.
1931 error_code:
1932 type: int
1933 attr: out, optional
1934 doc: Error code.
1935@api end
1936*/
1937void
1938sirius_add_atom_type(void* const* handler__, char const* label__, char const* fname__, int const* zn__,
1939 char const* symbol__, double const* mass__, bool const* spin_orbit__, int* error_code__)
1940{
1941 call_sirius(
1942 [&]() {
1943 auto& sim_ctx = get_sim_ctx(handler__);
1944
1945 std::string label = std::string(label__);
1946 std::string fname = (fname__ == nullptr) ? std::string("") : std::string(fname__);
1947 sim_ctx.unit_cell().add_atom_type(label, fname);
1948
1949 auto& type = sim_ctx.unit_cell().atom_type(label);
1950 if (zn__ != nullptr) {
1951 type.set_zn(*zn__);
1952 }
1953 if (symbol__ != nullptr) {
1954 type.set_symbol(std::string(symbol__));
1955 }
1956 if (mass__ != nullptr) {
1957 type.set_mass(*mass__);
1958 }
1959 if (spin_orbit__ != nullptr) {
1960 type.spin_orbit_coupling(*spin_orbit__);
1961 }
1962
1963 return 0;
1964 },
1965 error_code__);
1966}
1967
1968/*
1969@api begin
1970sirius_set_atom_type_radial_grid:
1971 doc: Set radial grid of the atom type.
1972 arguments:
1973 handler:
1974 type: ctx_handler
1975 attr: in, required
1976 doc: Simulation context handler.
1977 label:
1978 type: string
1979 attr: in, required
1980 doc: Atom type label.
1981 num_radial_points:
1982 type: int
1983 attr: in, required
1984 doc: Number of radial grid points.
1985 radial_points:
1986 type: double
1987 attr: in, required, dimension(num_radial_points)
1988 doc: List of radial grid points.
1989 error_code:
1990 type: int
1991 attr: out, optional
1992 doc: Error code.
1993@api end
1994*/
1995void
1996sirius_set_atom_type_radial_grid(void* const* handler__, char const* label__, int const* num_radial_points__,
1997 double const* radial_points__, int* error_code__)
1998{
1999 call_sirius(
2000 [&]() {
2001 auto& sim_ctx = get_sim_ctx(handler__);
2002
2003 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
2004 type.set_radial_grid(*num_radial_points__, radial_points__);
2005 },
2006 error_code__);
2007}
2008
2009/*
2010@api begin
2011sirius_set_atom_type_radial_grid_inf:
2012 doc: Set radial grid of the free atom (up to effectice infinity).
2013 arguments:
2014 handler:
2015 type: ctx_handler
2016 attr: in, required
2017 doc: Simulation context handler.
2018 label:
2019 type: string
2020 attr: in, required
2021 doc: Atom type label.
2022 num_radial_points:
2023 type: int
2024 attr: in, required
2025 doc: Number of radial grid points.
2026 radial_points:
2027 type: double
2028 attr: in, required, dimension(num_radial_points)
2029 doc: List of radial grid points.
2030 error_code:
2031 type: int
2032 attr: out, optional
2033 doc: Error code.
2034@api end
2035*/
2036void
2037sirius_set_atom_type_radial_grid_inf(void* const* handler__, char const* label__, int const* num_radial_points__,
2038 double const* radial_points__, int* error_code__)
2039{
2040 call_sirius(
2041 [&]() {
2042 auto& sim_ctx = get_sim_ctx(handler__);
2043
2044 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
2045 type.set_free_atom_radial_grid(*num_radial_points__, radial_points__);
2046 },
2047 error_code__);
2048}
2049
2050/*
2051@api begin
2052sirius_add_atom_type_radial_function:
2053 doc: Add one of the radial functions.
2054 arguments:
2055 handler:
2056 type: ctx_handler
2057 attr: in, required
2058 doc: Simulation context handler.
2059 atom_type:
2060 type: string
2061 attr: in, required
2062 doc: Label of the atom type.
2063 label:
2064 type: string
2065 attr: in, required
2066 doc: Label of the radial function.
2067 rf:
2068 type: double
2069 attr: in, required, dimension(num_points)
2070 doc: Array with radial function values.
2071 num_points:
2072 type: int
2073 attr: in, required
2074 doc: Length of radial function array.
2075 n:
2076 type: int
2077 attr: in, optional
2078 doc: Orbital quantum number.
2079 l:
2080 type: int
2081 attr: in, optional
2082 doc: angular momentum.
2083 idxrf1:
2084 type: int
2085 attr: in, optional
2086 doc: First index of radial function (for Q-operator). Indices start from 1.
2087 idxrf2:
2088 type: int
2089 attr: in, optional
2090 doc: Second index of radial function (for Q-operator). Indices start form 1.
2091 occ:
2092 type: double
2093 attr: in, optional
2094 doc: Occupancy of the wave-function.
2095 error_code:
2096 type: int
2097 attr: out, optional
2098 doc: Error code.
2099@api end
2100*/
2101void
2102sirius_add_atom_type_radial_function(void* const* handler__, char const* atom_type__, char const* label__,
2103 double const* rf__, int const* num_points__, int const* n__, int const* l__,
2104 int const* idxrf1__, int const* idxrf2__, double const* occ__, int* error_code__)
2105{
2106 call_sirius(
2107 [&]() {
2108 auto& sim_ctx = get_sim_ctx(handler__);
2109
2110 auto& type = sim_ctx.unit_cell().atom_type(std::string(atom_type__));
2111 std::string label(label__);
2112
2113 if (label == "beta") { /* beta-projectors */
2114 if (l__ == nullptr) {
2115 RTE_THROW("orbital quantum number must be provided for beta-projector");
2116 }
2117 int l = *l__;
2118 if (type.spin_orbit_coupling()) {
2119 if (l >= 0) {
2120 type.add_beta_radial_function(angular_momentum(l, 1), std::vector<double>(rf__, rf__ + *num_points__));
2121 } else {
2122 type.add_beta_radial_function(angular_momentum(-l, -1), std::vector<double>(rf__, rf__ + *num_points__));
2123 }
2124 } else {
2125 type.add_beta_radial_function(angular_momentum(l), std::vector<double>(rf__, rf__ + *num_points__));
2126 }
2127 } else if (label == "ps_atomic_wf") { /* pseudo-atomic wave functions */
2128 if (l__ == nullptr) {
2129 RTE_THROW("orbital quantum number must be provided for pseudo-atomic radial function");
2130 }
2131 int n = (n__) ? *n__ : -1;
2132 double occ = (occ__) ? *occ__ : 0.0;
2133 type.add_ps_atomic_wf(n, angular_momentum(*l__),
2134 std::vector<double>(rf__, rf__ + *num_points__), occ);
2135 } else if (label == "ps_rho_core") {
2136 type.ps_core_charge_density(std::vector<double>(rf__, rf__ + *num_points__));
2137 } else if (label == "ps_rho_total") {
2138 type.ps_total_charge_density(std::vector<double>(rf__, rf__ + *num_points__));
2139 } else if (label == "vloc") {
2140 type.local_potential(std::vector<double>(rf__, rf__ + *num_points__));
2141 } else if (label == "q_aug") { /* augmentation charge */
2142 if (l__ == nullptr) {
2143 RTE_THROW("orbital quantum number must be provided for augmentation charge radial function");
2144 }
2145 if (idxrf1__ == nullptr || idxrf2__ == nullptr) {
2146 RTE_THROW("both radial-function indices must be provided for augmentation charge radial function");
2147 }
2148 type.add_q_radial_function(*idxrf1__ - 1, *idxrf2__ - 1, *l__,
2149 std::vector<double>(rf__, rf__ + *num_points__));
2150 } else if (label == "ae_paw_wf") {
2151 type.add_ae_paw_wf(std::vector<double>(rf__, rf__ + *num_points__));
2152 } else if (label == "ps_paw_wf") {
2153 type.add_ps_paw_wf(std::vector<double>(rf__, rf__ + *num_points__));
2154 } else if (label == "ae_paw_core") {
2155 type.paw_ae_core_charge_density(std::vector<double>(rf__, rf__ + *num_points__));
2156 } else if (label == "ae_rho") {
2157 type.free_atom_density(std::vector<double>(rf__, rf__ + *num_points__));
2158 } else {
2159 std::stringstream s;
2160 s << "wrong label of radial function: " << label__;
2161 RTE_THROW(s);
2162 }
2163 },
2164 error_code__);
2165}
2166
2167/*
2168@api begin
2169sirius_set_atom_type_hubbard:
2170 doc: Set the hubbard correction for the atomic type.
2171 arguments:
2172 handler:
2173 type: ctx_handler
2174 attr: in, required
2175 doc: Simulation context handler.
2176 label:
2177 type: string
2178 attr: in, required
2179 doc: Atom type label.
2180 l:
2181 type: int
2182 attr: in, required
2183 doc: Orbital quantum number.
2184 n:
2185 type: int
2186 attr: in, required
2187 doc: principal quantum number (s, p, d, f)
2188 occ:
2189 type: double
2190 attr: in, required
2191 doc: Atomic shell occupancy.
2192 U:
2193 type: double
2194 attr: in, required
2195 doc: Hubbard U parameter.
2196 J:
2197 type: double
2198 attr: in, required
2199 doc: Exchange J parameter for the full interaction treatment.
2200 alpha:
2201 type: double
2202 attr: in, required
2203 doc: J_alpha for the simple interaction treatment.
2204 beta:
2205 type: double
2206 attr: in, required
2207 doc: J_beta for the simple interaction treatment.
2208 J0:
2209 type: double
2210 attr: in, required
2211 doc: J0 for the simple interaction treatment.
2212 error_code:
2213 type: int
2214 attr: out, optional
2215 doc: Error code.
2216@api end
2217*/
2218void
2219sirius_set_atom_type_hubbard(void* const* handler__, char const* label__, int const* l__, int const* n__,
2220 double const* occ__, double const* U__, double const* J__, double const* alpha__,
2221 double const* beta__, double const* J0__, int* error_code__)
2222{
2223 call_sirius(
2224 [&]() {
2225 auto& sim_ctx = get_sim_ctx(handler__);
2226 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
2227 type.hubbard_correction(true);
2228 type.add_hubbard_orbital(*n__, *l__, *occ__, *U__, J__[1], J__, *alpha__, *beta__, *J0__,
2229 std::vector<double>(), true);
2230 },
2231 error_code__);
2232}
2233
2234/*
2235@api begin
2236sirius_set_atom_type_dion:
2237 doc: Set ionic part of D-operator matrix.
2238 arguments:
2239 handler:
2240 type: ctx_handler
2241 attr: in, required
2242 doc: Simulation context handler.
2243 label:
2244 type: string
2245 attr: in, required
2246 doc: Atom type label.
2247 num_beta:
2248 type: int
2249 attr: in, required
2250 doc: Number of beta-projectors.
2251 dion:
2252 type: double
2253 attr: in, required, dimension(num_beta, num_beta)
2254 doc: Ionic part of D-operator matrix.
2255 error_code:
2256 type: int
2257 attr: out, optional
2258 doc: Error code.
2259@api end
2260*/
2261void
2262sirius_set_atom_type_dion(void* const* handler__, char const* label__, int const* num_beta__, double* dion__,
2263 int* error_code__)
2264{
2265 call_sirius(
2266 [&]() {
2267 auto& sim_ctx = get_sim_ctx(handler__);
2268 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
2269 sddk::matrix<double> dion(dion__, *num_beta__, *num_beta__);
2270 type.d_mtrx_ion(dion);
2271 },
2272 error_code__);
2273}
2274
2275/*
2276@api begin
2277sirius_set_atom_type_paw:
2278 doc: Set PAW related data.
2279 arguments:
2280 handler:
2281 type: ctx_handler
2282 attr: in, required
2283 doc: Simulation context handler.
2284 label:
2285 type: string
2286 attr: in, required
2287 doc: Atom type label.
2288 core_energy:
2289 type: double
2290 attr: in, required
2291 doc: Core-electrons energy contribution.
2292 occupations:
2293 type: double
2294 attr: in, required, dimension(num_occ)
2295 doc: array of orbital occupancies
2296 num_occ:
2297 type: int
2298 attr: in, required
2299 doc: size of the occupations array
2300 error_code:
2301 type: int
2302 attr: out, optional
2303 doc: Error code.
2304@api end
2305*/
2306void
2307sirius_set_atom_type_paw(void* const* handler__, char const* label__, double const* core_energy__,
2308 double const* occupations__, int const* num_occ__, int* error_code__)
2309{
2310 call_sirius(
2311 [&]() {
2312 auto& sim_ctx = get_sim_ctx(handler__);
2313
2314 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
2315
2316 if (*num_occ__ != type.num_beta_radial_functions()) {
2317 RTE_THROW("PAW error: different number of occupations and wave functions!");
2318 }
2319
2320 /* we load PAW, so we set is_paw to true */
2321 type.is_paw(true);
2322
2323 type.paw_core_energy(*core_energy__);
2324
2325 type.paw_wf_occ(std::vector<double>(occupations__, occupations__ + type.num_beta_radial_functions()));
2326 },
2327 error_code__);
2328}
2329
2330/*
2331@api begin
2332sirius_add_atom:
2333 doc: Add atom to the unit cell.
2334 arguments:
2335 handler:
2336 type: ctx_handler
2337 attr: in, required
2338 doc: Simulation context handler.
2339 label:
2340 type: string
2341 attr: in, required
2342 doc: Atom type label.
2343 position:
2344 type: double
2345 attr: in, required, dimension(3)
2346 doc: Atom position in lattice coordinates.
2347 vector_field:
2348 type: double
2349 attr: in, optional, dimension(3)
2350 doc: Starting magnetization.
2351 error_code:
2352 type: int
2353 attr: out, optional
2354 doc: Error code.
2355@api end
2356*/
2357void
2358sirius_add_atom(void* const* handler__, char const* label__, double const* position__, double const* vector_field__,
2359 int* error_code__)
2360{
2361 call_sirius(
2362 [&]() {
2363 auto& sim_ctx = get_sim_ctx(handler__);
2364 if (vector_field__ != nullptr) {
2365 sim_ctx.unit_cell().add_atom(std::string(label__), std::vector<double>(position__, position__ + 3),
2366 vector_field__);
2367 } else {
2368 sim_ctx.unit_cell().add_atom(std::string(label__), std::vector<double>(position__, position__ + 3));
2369 }
2370 },
2371 error_code__);
2372}
2373
2374/*
2375@api begin
2376sirius_set_atom_position:
2377 doc: Set new atomic position.
2378 arguments:
2379 handler:
2380 type: ctx_handler
2381 attr: in, required
2382 doc: Simulation context handler.
2383 ia:
2384 type: int
2385 attr: in, required
2386 doc: Index of atom; index starts form 1
2387 position:
2388 type: double
2389 attr: in, required, dimension(3)
2390 doc: Atom position in lattice coordinates.
2391 error_code:
2392 type: int
2393 attr: out, optional
2394 doc: Error code.
2395@api end
2396*/
2397void
2398sirius_set_atom_position(void* const* handler__, int const* ia__, double const* position__, int* error_code__)
2399{
2400 call_sirius(
2401 [&]() {
2402 auto& sim_ctx = get_sim_ctx(handler__);
2403 sim_ctx.unit_cell().atom(*ia__ - 1).set_position(std::vector<double>(position__, position__ + 3));
2404 },
2405 error_code__);
2406}
2407
2408/*
2409@api begin
2410sirius_set_pw_coeffs:
2411 doc: Set plane-wave coefficients of a periodic function.
2412 arguments:
2413 handler:
2414 type: gs_handler
2415 attr: in, required
2416 doc: Ground state handler.
2417 label:
2418 type: string
2419 attr: in, required
2420 doc: Label of the function.
2421 pw_coeffs:
2422 type: complex
2423 attr: in, required, dimension(:)
2424 doc: Local array of plane-wave coefficients.
2425 transform_to_rg:
2426 type: bool
2427 attr: in, optional
2428 doc: True if function has to be transformed to real-space grid.
2429 ngv:
2430 type: int
2431 attr: in, optional
2432 doc: Local number of G-vectors.
2433 gvl:
2434 type: int
2435 attr: in, optional, dimension(:,:)
2436 doc: List of G-vectors in lattice coordinates (Miller indices).
2437 comm:
2438 type: int
2439 attr: in, optional
2440 doc: MPI communicator used in distribution of G-vectors
2441 error_code:
2442 type: int
2443 attr: out, optional
2444 doc: Error code.
2445@api end
2446*/
2447void
2448sirius_set_pw_coeffs(void* const* handler__, char const* label__, std::complex<double> const* pw_coeffs__,
2449 bool const* transform_to_rg__, int const* ngv__, int* gvl__, int const* comm__, int* error_code__)
2450{
2451 PROFILE("sirius_api::sirius_set_pw_coeffs");
2452 call_sirius(
2453 [&]() {
2454 auto& gs = get_gs(handler__);
2455
2456 std::string label(label__);
2457
2458 if (gs.ctx().full_potential()) {
2459 if (label == "veff") {
2460 gs.potential().set_veff_pw(pw_coeffs__);
2461 } else if (label == "rm_inv") {
2462 gs.potential().set_rm_inv_pw(pw_coeffs__);
2463 } else if (label == "rm2_inv") {
2464 gs.potential().set_rm2_inv_pw(pw_coeffs__);
2465 } else {
2466 RTE_THROW("wrong label: " + label);
2467 }
2468 } else {
2469 RTE_ASSERT(ngv__ != nullptr);
2470 RTE_ASSERT(gvl__ != nullptr);
2471 RTE_ASSERT(comm__ != nullptr);
2472
2473 mpi::Communicator comm(MPI_Comm_f2c(*comm__));
2474 sddk::mdarray<int, 2> gvec(gvl__, 3, *ngv__);
2475
2476 std::vector<std::complex<double>> v(gs.ctx().gvec().num_gvec(), 0);
2477 #pragma omp parallel for schedule(static)
2478 for (int i = 0; i < *ngv__; i++) {
2479 r3::vector<int> G(gvec(0, i), gvec(1, i), gvec(2, i));
2480 // auto gvc = gs.ctx().unit_cell().reciprocal_lattice_vectors() * r3::vector<double>(G[0], G[1],
2481 // G[2]); if (gvc.length() > gs.ctx().pw_cutoff()) {
2482 // continue;
2483 //}
2484 int ig = gs.ctx().gvec().index_by_gvec(G);
2485 if (ig >= 0) {
2486 v[ig] = pw_coeffs__[i];
2487 } else {
2488 if (gs.ctx().gamma_point()) {
2489 ig = gs.ctx().gvec().index_by_gvec(G * (-1));
2490 if (ig == -1) {
2491 std::stringstream s;
2492 auto gvc = dot(gs.ctx().unit_cell().reciprocal_lattice_vectors(),
2493 r3::vector<double>(G[0], G[1], G[2]));
2494 s << "wrong index of G-vector" << std::endl
2495 << "input G-vector: " << G << " (length: " << gvc.length() << " [a.u.^-1])"
2496 << std::endl;
2497 RTE_THROW(s);
2498 } else {
2499 v[ig] = std::conj(pw_coeffs__[i]);
2500 }
2501 }
2502 }
2503 }
2504 comm.allreduce(v.data(), gs.ctx().gvec().num_gvec());
2505
2506 std::map<std::string, Smooth_periodic_function<double>*> func = {
2507 {"rho", &gs.density().rho().rg()},
2508 {"rhoc", &gs.density().rho_pseudo_core()},
2509 {"magz", &gs.density().mag(0).rg()},
2510 {"magx", &gs.density().mag(1).rg()},
2511 {"magy", &gs.density().mag(2).rg()},
2512 {"veff", &gs.potential().effective_potential().rg()},
2513 {"bz", &gs.potential().effective_magnetic_field(0).rg()},
2514 {"bx", &gs.potential().effective_magnetic_field(1).rg()},
2515 {"by", &gs.potential().effective_magnetic_field(2).rg()},
2516 {"vloc", &gs.potential().local_potential()},
2517 {"vxc", &gs.potential().xc_potential().rg()},
2518 {"dveff", &gs.potential().dveff()},
2519 };
2520
2521 if (!func.count(label)) {
2522 RTE_THROW("wrong label: " + label);
2523 }
2524
2525 func.at(label)->scatter_f_pw(v);
2526
2527 if (transform_to_rg__ && *transform_to_rg__) {
2528 func.at(label)->fft_transform(1);
2529 }
2530 }
2531 },
2532 error_code__);
2533}
2534
2535/*
2536@api begin
2537sirius_get_pw_coeffs:
2538 doc: Get plane-wave coefficients of a periodic function.
2539 arguments:
2540 handler:
2541 type: gs_handler
2542 attr: in, required
2543 doc: Ground state handler.
2544 label:
2545 type: string
2546 attr: in, required
2547 doc: Label of the function.
2548 pw_coeffs:
2549 type: complex
2550 attr: in, required, dimension(:)
2551 doc: Local array of plane-wave coefficients.
2552 ngv:
2553 type: int
2554 attr: in, optional
2555 doc: Local number of G-vectors.
2556 gvl:
2557 type: int
2558 attr: in, optional, dimension(:,:)
2559 doc: List of G-vectors in lattice coordinates (Miller indices).
2560 comm:
2561 type: int
2562 attr: in, optional
2563 doc: MPI communicator used in distribution of G-vectors
2564 error_code:
2565 type: int
2566 attr: out, optional
2567 doc: Error code.
2568@api end
2569*/
2570void
2571sirius_get_pw_coeffs(void* const* handler__, char const* label__, std::complex<double>* pw_coeffs__, int const* ngv__,
2572 int* gvl__, int const* comm__, int* error_code__)
2573{
2574 PROFILE("sirius_api::sirius_get_pw_coeffs");
2575
2576 call_sirius(
2577 [&]() {
2578 auto& gs = get_gs(handler__);
2579
2580 std::string label(label__);
2581 if (gs.ctx().full_potential()) {
2582 RTE_THROW("not implemented");
2583 } else {
2584 RTE_ASSERT(ngv__ != NULL);
2585 RTE_ASSERT(gvl__ != NULL);
2586 RTE_ASSERT(comm__ != NULL);
2587
2588 mpi::Communicator comm(MPI_Comm_f2c(*comm__));
2589 sddk::mdarray<int, 2> gvec(gvl__, 3, *ngv__);
2590
2591 std::map<std::string, Smooth_periodic_function<double>*> func = {
2592 {"rho", &gs.density().rho().rg()},
2593 {"magz", &gs.density().mag(0).rg()},
2594 {"magx", &gs.density().mag(1).rg()},
2595 {"magy", &gs.density().mag(2).rg()},
2596 {"veff", &gs.potential().effective_potential().rg()},
2597 {"vloc", &gs.potential().local_potential()},
2598 {"rhoc", &gs.density().rho_pseudo_core()}};
2599
2600 if (!func.count(label)) {
2601 RTE_THROW("wrong label: " + label);
2602 }
2603 auto v = func.at(label)->gather_f_pw();
2604
2605 for (int i = 0; i < *ngv__; i++) {
2606 r3::vector<int> G(gvec(0, i), gvec(1, i), gvec(2, i));
2607
2608 // auto gvc = gs.ctx().unit_cell().reciprocal_lattice_vectors() * r3::vector<double>(G[0], G[1],
2609 // G[2]); if (gvc.length() > gs.ctx().pw_cutoff()) {
2610 // pw_coeffs__[i] = 0;
2611 // continue;
2612 //}
2613
2614 bool is_inverse{false};
2615 int ig = gs.ctx().gvec().index_by_gvec(G);
2616 if (ig == -1 && gs.ctx().gvec().reduced()) {
2617 ig = gs.ctx().gvec().index_by_gvec(G * (-1));
2618 is_inverse = true;
2619 }
2620 if (ig == -1) {
2621 std::stringstream s;
2622 auto gvc =
2623 dot(gs.ctx().unit_cell().reciprocal_lattice_vectors(), r3::vector<double>(G[0], G[1], G[2]));
2624 s << "wrong index of G-vector" << std::endl
2625 << "input G-vector: " << G << " (length: " << gvc.length() << " [a.u.^-1])" << std::endl;
2626 RTE_WARNING(s);
2627 pw_coeffs__[i] = 0;
2628 //RTE_THROW(s);
2629 } else {
2630 if (is_inverse) {
2631 pw_coeffs__[i] = std::conj(v[ig]);
2632 } else {
2633 pw_coeffs__[i] = v[ig];
2634 }
2635 }
2636 }
2637 }
2638 },
2639 error_code__);
2640}
2641
2642/*
2643@api begin
2644sirius_initialize_subspace:
2645 doc: Initialize the subspace of wave-functions.
2646 arguments:
2647 gs_handler:
2648 type: gs_handler
2649 attr: in, required
2650 doc: Ground state handler.
2651 ks_handler:
2652 type: ks_handler
2653 attr: in, required
2654 doc: K-point set handler.
2655 error_code:
2656 type: int
2657 attr: out, optional
2658 doc: Error code.
2659@api end
2660*/
2661void
2662sirius_initialize_subspace(void* const* gs_handler__, void* const* ks_handler__, int* error_code__)
2663{
2664 call_sirius(
2665 [&]() {
2666 auto& gs = get_gs(gs_handler__);
2667 auto& ks = get_ks(ks_handler__);
2668 Hamiltonian0<double> H0(gs.potential(), true);
2669 initialize_subspace(ks, H0);
2670 },
2671 error_code__);
2672}
2673
2674/*
2675@api begin
2676sirius_find_eigen_states:
2677 doc: Find eigen-states of the Hamiltonian
2678 arguments:
2679 gs_handler:
2680 type: gs_handler
2681 attr: in, required
2682 doc: Ground state handler.
2683 ks_handler:
2684 type: ks_handler
2685 attr: in, required
2686 doc: K-point set handler.
2687 precompute_pw:
2688 type: bool
2689 attr: in, optional
2690 doc: Generate plane-wave coefficients of the potential
2691 precompute_rf:
2692 type: bool
2693 attr: in, optional
2694 doc: Generate radial functions
2695 precompute_ri:
2696 type: bool
2697 attr: in, optional
2698 doc: Generate radial integrals
2699 iter_solver_tol:
2700 type: double
2701 attr: in, optional
2702 doc: Iterative solver tolerance.
2703 error_code:
2704 type: int
2705 attr: out, optional
2706 doc: Error code.
2707@api end
2708*/
2709void
2710sirius_find_eigen_states(void* const* gs_handler__, void* const* ks_handler__, bool const* precompute_pw__,
2711 bool const* precompute_rf__, bool const* precompute_ri__, double const* iter_solver_tol__,
2712 int* error_code__)
2713{
2714 call_sirius(
2715 [&]() {
2716 auto& gs = get_gs(gs_handler__);
2717 auto& ks = get_ks(ks_handler__);
2718 double tol = (iter_solver_tol__) ? *iter_solver_tol__ : ks.ctx().cfg().iterative_solver().energy_tolerance();
2719 if (precompute_pw__ && *precompute_pw__) {
2720 gs.potential().generate_pw_coefs();
2721 }
2722 if ((precompute_rf__ && *precompute_rf__) || (precompute_ri__ && *precompute_ri__)) {
2723 gs.potential().update_atomic_potential();
2724 }
2725 if (precompute_rf__ && *precompute_rf__) {
2726 const_cast<Unit_cell&>(gs.ctx().unit_cell()).generate_radial_functions(gs.ctx().out());
2727 }
2728 if (precompute_ri__ && *precompute_ri__) {
2729 const_cast<Unit_cell&>(gs.ctx().unit_cell()).generate_radial_integrals();
2730 }
2731 Hamiltonian0<double> H0(gs.potential(), false);
2732 diagonalize<double, double>(H0, ks, tol);
2733 },
2734 error_code__);
2735}
2736
2737/*
2738@api begin
2739sirius_generate_initial_density:
2740 doc: Generate initial density.
2741 arguments:
2742 handler:
2743 type: gs_handler
2744 attr: in, required
2745 doc: Ground state handler.
2746 error_code:
2747 type: int
2748 attr: out, optional
2749 doc: Error code.
2750@api end
2751*/
2752void
2753sirius_generate_initial_density(void* const* handler__, int* error_code__)
2754{
2755 call_sirius(
2756 [&]() {
2757 auto& gs = get_gs(handler__);
2758 gs.density().initial_density();
2759 },
2760 error_code__);
2761}
2762
2763/*
2764@api begin
2765sirius_generate_effective_potential:
2766 doc: Generate effective potential and magnetic field.
2767 arguments:
2768 handler:
2769 type: gs_handler
2770 attr: in, required
2771 doc: Ground state handler.
2772 error_code:
2773 type: int
2774 attr: out, optional
2775 doc: Error code.
2776@api end
2777*/
2778void
2779sirius_generate_effective_potential(void* const* handler__, int* error_code__)
2780{
2781 call_sirius(
2782 [&]() {
2783 auto& gs = get_gs(handler__);
2784 gs.potential().generate(gs.density(), gs.ctx().use_symmetry(), false);
2785 },
2786 error_code__);
2787}
2788
2789/*
2790@api begin
2791sirius_generate_density:
2792 doc: Generate charge density and magnetization.
2793 arguments:
2794 gs_handler:
2795 type: gs_handler
2796 attr: in, required
2797 doc: Ground state handler.
2798 add_core:
2799 type: bool
2800 attr: in, optional
2801 doc: Add core charge density in the muffin-tins.
2802 transform_to_rg:
2803 type: bool
2804 attr: in, optional
2805 doc: If true, density and magnetization are transformed to real-space grid.
2806 paw_only:
2807 type: bool
2808 attr: in, optional
2809 doc: it true, only local PAW density is generated
2810 error_code:
2811 type: int
2812 attr: out, optional
2813 doc: Error code.
2814@api end
2815*/
2816void
2817sirius_generate_density(void* const* gs_handler__, bool const* add_core__, bool const* transform_to_rg__,
2818 bool const* paw_only__, int* error_code__)
2819{
2820 call_sirius(
2821 [&]() {
2822 auto& gs = get_gs(gs_handler__);
2823 auto add_core = get_value<bool>(add_core__, false);
2824 auto transform_to_rg = get_value<bool>(transform_to_rg__, false);
2825 auto paw_only = get_value<bool>(paw_only__, false);
2826
2827 if (paw_only) {
2828 gs.density().generate_paw_density();
2829 } else {
2830 gs.density().generate<double>(gs.k_point_set(), gs.ctx().use_symmetry(), add_core, transform_to_rg);
2831 }
2832 },
2833 error_code__);
2834}
2835
2836/*
2837@api begin
2838sirius_set_band_occupancies:
2839 doc: Set band occupancies.
2840 arguments:
2841 ks_handler:
2842 type: ks_handler
2843 attr: in, required
2844 doc: K-point set handler.
2845 ik:
2846 type: int
2847 attr: in, required
2848 doc: Global index of k-point.
2849 ispn:
2850 type: int
2851 attr: in, required
2852 doc: Spin component index.
2853 band_occupancies:
2854 type: double
2855 attr: in, required, dimension(:)
2856 doc: Array of band occupancies.
2857 error_code:
2858 type: int
2859 attr: out, optional
2860 doc: Error code.
2861@api end
2862*/
2863void
2864sirius_set_band_occupancies(void* const* ks_handler__, int const* ik__, int const* ispn__,
2865 double const* band_occupancies__, int* error_code__)
2866{
2867 call_sirius(
2868 [&]() {
2869 auto& ks = get_ks(ks_handler__);
2870 int ik = *ik__ - 1;
2871 for (int i = 0; i < ks.ctx().num_bands(); i++) {
2872 ks.get<double>(ik)->band_occupancy(i, *ispn__ - 1, band_occupancies__[i]);
2873 }
2874 },
2875 error_code__);
2876}
2877
2878/*
2879@api begin
2880sirius_get_band_occupancies:
2881 doc: Set band occupancies.
2882 arguments:
2883 ks_handler:
2884 type: ks_handler
2885 attr: in, required
2886 doc: K-point set handler.
2887 ik:
2888 type: int
2889 attr: in, required
2890 doc: Global index of k-point.
2891 ispn:
2892 type: int
2893 attr: in, required
2894 doc: Spin component.
2895 band_occupancies:
2896 type: double
2897 attr: out, required, dimension(:)
2898 doc: Array of band occupancies.
2899 error_code:
2900 type: int
2901 attr: out, optional
2902 doc: Error code.
2903@api end
2904*/
2905void
2906sirius_get_band_occupancies(void* const* ks_handler__, int const* ik__, int const* ispn__, double* band_occupancies__,
2907 int* error_code__)
2908{
2909 call_sirius(
2910 [&]() {
2911 auto& ks = get_ks(ks_handler__);
2912 int ik = *ik__ - 1;
2913 for (int i = 0; i < ks.ctx().num_bands(); i++) {
2914 band_occupancies__[i] = ks.get<double>(ik)->band_occupancy(i, *ispn__ - 1);
2915 }
2916 },
2917 error_code__);
2918}
2919
2920/*
2921@api begin
2922sirius_get_band_energies:
2923 doc: Get band energies.
2924 arguments:
2925 ks_handler:
2926 type: ks_handler
2927 attr: in, required
2928 doc: K-point set handler.
2929 ik:
2930 type: int
2931 attr: in, required
2932 doc: Global index of k-point.
2933 ispn:
2934 type: int
2935 attr: in, required
2936 doc: Spin component.
2937 band_energies:
2938 type: double
2939 attr: out, required, dimension(:)
2940 doc: Array of band energies.
2941 error_code:
2942 type: int
2943 attr: out, optional
2944 doc: Error code.
2945@api end
2946*/
2947void
2948sirius_get_band_energies(void* const* ks_handler__, int const* ik__, int const* ispn__, double* band_energies__,
2949 int* error_code__)
2950{
2951 call_sirius(
2952 [&]() {
2953 auto& ks = get_ks(ks_handler__);
2954 int ik = *ik__ - 1;
2955 for (int i = 0; i < ks.ctx().num_bands(); i++) {
2956 band_energies__[i] = ks.get<double>(ik)->band_energy(i, *ispn__ - 1);
2957 }
2958 },
2959 error_code__);
2960}
2961
2962/*
2963@api begin
2964sirius_get_energy:
2965 doc: Get one of the total energy components.
2966 arguments:
2967 handler:
2968 type: gs_handler
2969 attr: in, required
2970 doc: DFT ground state handler.
2971 label:
2972 type: string
2973 attr: in, required
2974 doc: Label of the energy component to get.
2975 energy:
2976 type: double
2977 attr: out, required
2978 doc: Total energy component.
2979 error_code:
2980 type: int
2981 attr: out, optional
2982 doc: Error code.
2983@api end
2984*/
2985void
2986sirius_get_energy(void* const* handler__, char const* label__, double* energy__, int* error_code__)
2987{
2988 call_sirius(
2989 [&]() {
2990 auto& gs = get_gs(handler__);
2991
2992 auto& kset = gs.k_point_set();
2993 auto& ctx = kset.ctx();
2994 auto& unit_cell = kset.unit_cell();
2995 auto& potential = gs.potential();
2996 auto& density = gs.density();
2997
2998 std::string label(label__);
2999
3000 std::map<std::string, std::function<double()>> func = {
3001 {"total", [&]() { return sirius::total_energy(ctx, kset, density, potential, gs.ewald_energy()); }},
3002 {"evalsum", [&]() { return sirius::eval_sum(unit_cell, kset); }},
3003 {"exc", [&]() { return sirius::energy_exc(density, potential); }},
3004 {"vxc", [&]() { return sirius::energy_vxc(density, potential); }},
3005 {"bxc", [&]() { return sirius::energy_bxc(density, potential); }},
3006 {"veff", [&]() { return sirius::energy_veff(density, potential); }},
3007 {"vloc", [&]() { return sirius::energy_vloc(density, potential); }},
3008 {"vha", [&]() { return sirius::energy_vha(potential); }},
3009 {"enuc", [&]() { return sirius::energy_enuc(ctx, potential); }},
3010 {"kin", [&]() { return sirius::energy_kin(ctx, kset, density, potential); }},
3011 {"one-el", [&]() { return sirius::one_electron_energy(density, potential); }},
3012 {"descf", [&]() { return gs.scf_correction_energy(); }},
3013 {"demet", [&]() { return kset.entropy_sum(); }},
3014 {"paw-one-el", [&]() { return potential.PAW_one_elec_energy(density); }},
3015 {"paw", [&]() { return potential.PAW_total_energy(density); }},
3016 {"fermi", [&]() { return kset.energy_fermi(); }},
3017 {"hubbard", [&]() { return sirius::hubbard_energy(density); }}};
3018
3019 if (!func.count(label)) {
3020 RTE_THROW("wrong label: " + label);
3021 }
3022
3023 *energy__ = func.at(label)();
3024 },
3025 error_code__);
3026}
3027
3028/*
3029@api begin
3030sirius_get_forces:
3031 doc: Get one of the total force components.
3032 arguments:
3033 handler:
3034 type: gs_handler
3035 attr: in, required
3036 doc: DFT ground state handler.
3037 label:
3038 type: string
3039 attr: in, required
3040 doc: Label of the force component to get.
3041 forces:
3042 type: double
3043 attr: out, required, dimension(:,:)
3044 doc: Total force component for each atom.
3045 error_code:
3046 type: int
3047 attr: out, optional
3048 doc: Error code.
3049@api end
3050*/
3051void
3052sirius_get_forces(void* const* handler__, char const* label__, double* forces__, int* error_code__)
3053{
3054 call_sirius(
3055 [&]() {
3056 std::string label(label__);
3057
3058 auto& gs = get_gs(handler__);
3059
3060 auto get_forces = [&](sddk::mdarray<double, 2> const& sirius_forces__) {
3061 for (size_t i = 0; i < sirius_forces__.size(); i++) {
3062 forces__[i] = sirius_forces__[i];
3063 }
3064 };
3065
3066 auto& forces = gs.forces();
3067
3068 std::map<std::string, sddk::mdarray<double, 2> const& (sirius::Force::*)(void)> func = {
3069 {"total", &sirius::Force::calc_forces_total}, {"vloc", &sirius::Force::calc_forces_vloc},
3070 {"core", &sirius::Force::calc_forces_core}, {"ewald", &sirius::Force::calc_forces_ewald},
3071 {"nonloc", &sirius::Force::calc_forces_nonloc}, {"us", &sirius::Force::calc_forces_us},
3072 {"usnl", &sirius::Force::calc_forces_usnl}, {"scf_corr", &sirius::Force::calc_forces_scf_corr},
3073 {"hubbard", &sirius::Force::calc_forces_hubbard}, {"ibs", &sirius::Force::calc_forces_ibs},
3074 {"hf", &sirius::Force::calc_forces_hf}, {"rho", &sirius::Force::calc_forces_rho}};
3075
3076 if (!func.count(label)) {
3077 RTE_THROW("wrong label (" + label + ") for the component of forces");
3078 }
3079
3080 get_forces((forces.*func.at(label))());
3081 },
3082 error_code__);
3083}
3084
3085/*
3086@api begin
3087sirius_get_stress_tensor:
3088 doc: Get one of the stress tensor components.
3089 arguments:
3090 handler:
3091 type: gs_handler
3092 attr: in, required
3093 doc: DFT ground state handler.
3094 label:
3095 type: string
3096 attr: in, required
3097 doc: Label of the stress tensor component to get.
3098 stress_tensor:
3099 type: double
3100 attr: out, required, dimension(3, 3)
3101 doc: Component of the total stress tensor.
3102 error_code:
3103 type: int
3104 attr: out, optional
3105 doc: Error code.
3106@api end
3107*/
3108void
3109sirius_get_stress_tensor(void* const* handler__, char const* label__, double* stress_tensor__, int* error_code__)
3110{
3111 call_sirius(
3112 [&]() {
3113 std::string label(label__);
3114
3115 auto& gs = get_gs(handler__);
3116
3117 auto& stress_tensor = gs.stress();
3118
3119 std::map<std::string, r3::matrix<double> (sirius::Stress::*)(void)> func = {
3120 {"total", &sirius::Stress::calc_stress_total}, {"vloc", &sirius::Stress::calc_stress_vloc},
3122 {"kin", &sirius::Stress::calc_stress_kin}, {"nonloc", &sirius::Stress::calc_stress_nonloc},
3124 {"core", &sirius::Stress::calc_stress_core}, {"hubbard", &sirius::Stress::calc_stress_hubbard},
3125 };
3126
3127 if (!func.count(label)) {
3128 RTE_THROW("wrong label (" + label + ") for the component of stress tensor");
3129 }
3130
3132
3133 s = (stress_tensor.*func.at(label))();
3134
3135 for (int mu = 0; mu < 3; mu++) {
3136 for (int nu = 0; nu < 3; nu++) {
3137 stress_tensor__[nu + mu * 3] = s(mu, nu);
3138 }
3139 }
3140 },
3141 error_code__);
3142}
3143
3144/*
3145@api begin
3146sirius_get_num_beta_projectors:
3147 doc: Get the number of beta-projectors for an atom type.
3148 arguments:
3149 handler:
3150 type: ctx_handler
3151 attr: in, required
3152 doc: Simulation context handler.
3153 label:
3154 type: string
3155 attr: in, required
3156 doc: Atom type label.
3157 num_bp:
3158 type: int
3159 attr: out, required
3160 doc: Number of beta projectors for each atom type.
3161 error_code:
3162 type: int
3163 attr: out, optional
3164 doc: Error code.
3165@api end
3166*/
3167void
3168sirius_get_num_beta_projectors(void* const* handler__, char const* label__, int* num_bp__, int* error_code__)
3169{
3170 call_sirius(
3171 [&]() {
3172 auto& sim_ctx = get_sim_ctx(handler__);
3173
3174 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
3175
3176 *num_bp__ = type.mt_basis_size();
3177 },
3178 error_code__);
3179}
3180
3181/*
3182@api begin
3183sirius_get_wave_functions:
3184 doc: Get wave-functions.
3185 arguments:
3186 ks_handler:
3187 type: ks_handler
3188 attr: in, required
3189 doc: K-point set handler.
3190 vkl:
3191 type: double
3192 attr: in, optional, dimension(3)
3193 doc: Latttice coordinates of the k-point.
3194 spin:
3195 type: int
3196 attr: in, optional
3197 doc: Spin index in case of collinear magnetism.
3198 num_gvec_loc:
3199 type: int
3200 attr: in, optional
3201 doc: Local number of G-vectors for a k-point.
3202 gvec_loc:
3203 type: int
3204 attr: in, optional, dimension(:,:)
3205 doc: List of G-vectors.
3206 evec:
3207 type: complex
3208 attr: out, optional, dimension(:,:)
3209 doc: Wave-functions.
3210 ld:
3211 type: int
3212 attr: in, optional
3213 doc: Leading dimension of evec array.
3214 num_spin_comp:
3215 type: int
3216 attr: in, optional
3217 doc: Number of spin components.
3218 error_code:
3219 type: int
3220 attr: out, optional
3221 doc: Error code
3222@api end
3223*/
3224void
3225sirius_get_wave_functions(void* const* ks_handler__, double const* vkl__, int const* spin__,
3226 int const* num_gvec_loc__, int const* gvec_loc__, std::complex<double>* evec__,
3227 int const* ld__, int const* num_spin_comp__, int* error_code__)
3228{
3229 PROFILE("sirius_api::sirius_get_wave_functions");
3230
3231 // TODO: refactor this part; use QE order of G-vectors
3232
3233 auto gvec_mapping = [&](sirius::fft::Gvec const& gkvec) {
3234 std::vector<int> igm(*num_gvec_loc__);
3235
3236 sddk::mdarray<int, 2> gv(const_cast<int*>(gvec_loc__), 3, *num_gvec_loc__);
3237
3238 /* go in the order of host code */
3239 for (int ig = 0; ig < *num_gvec_loc__; ig++) {
3240 ///* G vector of host code */
3241 // auto gvc = dot(kset.ctx().unit_cell().reciprocal_lattice_vectors(),
3242 // (r3::vector<double>(gvec_k(0, ig), gvec_k(1, ig), gvec_k(2, ig)) + gkvec.vk()));
3243 // if (gvc.length() > kset.ctx().gk_cutoff()) {
3244 // continue;
3245 //}
3246 int ig1 = gkvec.index_by_gvec({gv(0, ig), gv(1, ig), gv(2, ig)});
3247 /* index of G was not found */
3248 if (ig1 < 0) {
3249 /* try -G */
3250 ig1 = gkvec.index_by_gvec({-gv(0, ig), -gv(1, ig), -gv(2, ig)});
3251 /* index of -G was not found */
3252 if (ig1 < 0) {
3253 RTE_THROW("index of G-vector is not found");
3254 } else {
3255 /* this will tell to conjugate PW coefficients as we take them from -G index */
3256 igm[ig] = -ig1;
3257 }
3258 } else {
3259 igm[ig] = ig1;
3260 }
3261 }
3262 return igm;
3263 };
3264
3265 call_sirius(
3266 [&]() {
3267 auto& ks = get_ks(ks_handler__);
3268
3269 auto& sim_ctx = ks.ctx();
3270
3271 std::vector<int> buf(ks.comm().size());
3272
3273 int jk{-1};
3274 if (vkl__) {
3275 jk = ks.find_kpoint(vkl__);
3276 if (jk == -1) {
3277 std::stringstream s;
3278 s << "k-point is not found";
3279 RTE_THROW(s);
3280 }
3281 }
3282 ks.comm().allgather(&jk, buf.data(), 1, ks.comm().rank());
3283 int dest_rank{-1};
3284 for (int i = 0; i < ks.comm().size(); i++) {
3285 if (buf[i] >= 0) {
3286 dest_rank = i;
3287 jk = buf[i];
3288 break;
3289 }
3290 }
3291 int num_spin_comp{-1};
3292 if (num_spin_comp__) {
3293 num_spin_comp = *num_spin_comp__;
3294 if (!(num_spin_comp == 1 || num_spin_comp == 2)) {
3295 RTE_THROW("wrong number of spin components");
3296 }
3297 }
3298 ks.comm().bcast(&num_spin_comp, 1, dest_rank);
3299 if ((sim_ctx.num_mag_dims() == 3 && num_spin_comp != 2) ||
3300 (sim_ctx.num_mag_dims() != 3 && num_spin_comp == 2)) {
3301 RTE_THROW("inconsistent number of spin components");
3302 }
3303
3304 int spin{-1};
3305 if (spin__) {
3306 spin = *spin__ - 1;
3307 if (!(spin == 0 || spin == 1)) {
3308 RTE_THROW("wrong spin index");
3309 }
3310 }
3311 ks.comm().bcast(&spin, 1, dest_rank);
3312
3313 /* rank where k-point vkl resides on the SIRIUS side */
3314 int src_rank = ks.spl_num_kpoints().location(typename sirius::kp_index_t::global(jk)).ib;
3315
3316 if (ks.comm().rank() == src_rank || ks.comm().rank() == dest_rank) {
3317 /* send G+k copy to destination rank (where host code receives the data) */
3318 auto gkvec = ks.get_gkvec(typename sirius::kp_index_t::global(jk), dest_rank);
3319
3321 if (ks.comm().rank() == dest_rank) {
3322 /* check number of G+k vectors */
3323 int ngk = *num_gvec_loc__;
3324 gkvec.comm().allreduce(&ngk, 1);
3325 if (ngk != gkvec.num_gvec()) {
3326 r3::vector<double> vkl(vkl__);
3327 std::stringstream s;
3328 s << "wrong number of G+k vectors for k-point " << vkl << ", jk = " << jk << std::endl
3329 << "expected number : " << gkvec.num_gvec() << std::endl
3330 << "actual number : " << ngk << std::endl
3331 << "local number of G+k vectors passed by rank " << gkvec.comm().rank() << " is "
3332 << *num_gvec_loc__;
3333 RTE_THROW(s);
3334 }
3335 wf = sddk::mdarray<std::complex<double>, 2>(gkvec.count(), sim_ctx.num_bands());
3336 }
3337
3338 int ispn0{0};
3339 int ispn1{1};
3340 /* fetch two components in non-collinear case, otherwise fetch only one component */
3341 if (sim_ctx.num_mag_dims() != 3) {
3342 ispn0 = ispn1 = spin;
3343 }
3344 /* send wave-functions for each spin channel */
3345 for (int s = ispn0; s <= ispn1; s++) {
3346 int tag = mpi::Communicator::get_tag(src_rank, dest_rank) + s;
3347 mpi::Request req;
3348
3349 /* send wave-functions */
3350 if (ks.comm().rank() == src_rank) {
3351 auto kp = ks.get<double>(jk);
3352 int count = kp->spinor_wave_functions().ld();
3353 req = ks.comm().isend(kp->spinor_wave_functions().at(sddk::memory_t::host, 0,
3354 sirius::wf::spin_index(0), sirius::wf::band_index(0)), count * sim_ctx.num_bands(), dest_rank, tag);
3355 }
3356 /* receive wave-functions */
3357 if (ks.comm().rank() == dest_rank) {
3358 int count = gkvec.count();
3359 /* receive the array with wave-functions */
3360 ks.comm().recv(&wf(0, 0), count * sim_ctx.num_bands(), src_rank, tag);
3361
3362 std::vector<std::complex<double>> wf_tmp(gkvec.num_gvec());
3363 int offset = gkvec.offset();
3364 sddk::mdarray<std::complex<double>, 3> evec(evec__, *ld__, num_spin_comp, sim_ctx.num_bands());
3365
3366 auto igmap = gvec_mapping(gkvec);
3367
3368 auto store_wf = [&](std::vector<std::complex<double>>& wf_tmp, int i, int s) {
3369 int ispn = s;
3370 if (sim_ctx.num_mag_dims() == 1) {
3371 ispn = 0;
3372 }
3373 for (int ig = 0; ig < *num_gvec_loc__; ig++) {
3374 int ig1 = igmap[ig];
3375 std::complex<double> z;
3376 if (ig1 < 0) {
3377 z = std::conj(wf_tmp[-ig1]);
3378 } else {
3379 z = wf_tmp[ig1];
3380 }
3381 evec(ig, ispn, i) = z;
3382 }
3383 };
3384
3385 /* store wave-functions */
3386 for (int i = 0; i < sim_ctx.num_bands(); i++) {
3387 /* gather full column of PW coefficients */
3388 sim_ctx.comm_band().allgather(&wf(0, i), wf_tmp.data(), count, offset);
3389 store_wf(wf_tmp, i, s);
3390 }
3391 }
3392 if (ks.comm().rank() == src_rank) {
3393 req.wait();
3394 }
3395 }
3396 }
3397 },
3398 error_code__);
3399}
3400
3401/*
3402@api begin
3403sirius_add_atom_type_aw_descriptor:
3404 doc: Add descriptor of the augmented wave radial function.
3405 arguments:
3406 handler:
3407 type: ctx_handler
3408 attr: in, required
3409 doc: Simulation context handler.
3410 label:
3411 type: string
3412 attr: in, required
3413 doc: Atom type label.
3414 n:
3415 type: int
3416 attr: in, required
3417 doc: Principal quantum number.
3418 l:
3419 type: int
3420 attr: in, required
3421 doc: Orbital quantum number.
3422 enu:
3423 type: double
3424 attr: in, required
3425 doc: Linearization energy.
3426 dme:
3427 type: int
3428 attr: in, required
3429 doc: Order of energy derivative.
3430 auto_enu:
3431 type: bool
3432 attr: in, required
3433 doc: True if automatic search of linearization energy is allowed for this radial solution.
3434 error_code:
3435 type: int
3436 attr: out, optional
3437 doc: Error code
3438@api end
3439*/
3440void
3441sirius_add_atom_type_aw_descriptor(void* const* handler__, char const* label__, int const* n__, int const* l__,
3442 double const* enu__, int const* dme__, bool const* auto_enu__, int* error_code__)
3443{
3444 call_sirius(
3445 [&]() {
3446 auto& sim_ctx = get_sim_ctx(handler__);
3447 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
3448 type.add_aw_descriptor(*n__, *l__, *enu__, *dme__, *auto_enu__);
3449 },
3450 error_code__);
3451}
3452
3453/*
3454@api begin
3455sirius_add_atom_type_lo_descriptor:
3456 doc: Add descriptor of the local orbital radial function.
3457 arguments:
3458 handler:
3459 type: ctx_handler
3460 attr: in, required
3461 doc: Simulation context handler.
3462 label:
3463 type: string
3464 attr: in, required
3465 doc: Atom type label.
3466 ilo:
3467 type: int
3468 attr: in, required
3469 doc: Index of the local orbital to which the descriptor is added.
3470 n:
3471 type: int
3472 attr: in, required
3473 doc: Principal quantum number.
3474 l:
3475 type: int
3476 attr: in, required
3477 doc: Orbital quantum number.
3478 enu:
3479 type: double
3480 attr: in, required
3481 doc: Linearization energy.
3482 dme:
3483 type: int
3484 attr: in, required
3485 doc: Order of energy derivative.
3486 auto_enu:
3487 type: bool
3488 attr: in, required
3489 doc: True if automatic search of linearization energy is allowed for this radial solution.
3490 error_code:
3491 type: int
3492 attr: out, optional
3493 doc: Error code
3494@api end
3495*/
3496void
3497sirius_add_atom_type_lo_descriptor(void* const* handler__, char const* label__, int const* ilo__, int const* n__,
3498 int const* l__, double const* enu__, int const* dme__, bool const* auto_enu__,
3499 int* error_code__)
3500{
3501 call_sirius(
3502 [&]() {
3503 auto& sim_ctx = get_sim_ctx(handler__);
3504 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
3505 type.add_lo_descriptor(*ilo__ - 1, *n__, *l__, *enu__, *dme__, *auto_enu__);
3506 },
3507 error_code__);
3508}
3509
3510/*
3511@api begin
3512sirius_set_atom_type_configuration:
3513 doc: Set configuration of atomic levels.
3514 arguments:
3515 handler:
3516 type: ctx_handler
3517 attr: in, required
3518 doc: Simulation context handler.
3519 label:
3520 type: string
3521 attr: in, required
3522 doc: Atom type label.
3523 n:
3524 type: int
3525 attr: in, required
3526 doc: Principal quantum number.
3527 l:
3528 type: int
3529 attr: in, required
3530 doc: Orbital quantum number.
3531 k:
3532 type: int
3533 attr: in, required
3534 doc: kappa (used in relativistic solver).
3535 occupancy:
3536 type: double
3537 attr: in, required
3538 doc: Level occupancy.
3539 core:
3540 type: bool
3541 attr: in, required
3542 doc: Tru if this is a core state.
3543 error_code:
3544 type: int
3545 attr: out, optional
3546 doc: Error code
3547@api end
3548*/
3549void
3550sirius_set_atom_type_configuration(void* const* handler__, char const* label__, int const* n__, int const* l__,
3551 int const* k__, double const* occupancy__, bool const* core__, int* error_code__)
3552{
3553 call_sirius(
3554 [&]() {
3555 auto& sim_ctx = get_sim_ctx(handler__);
3556 auto& type = sim_ctx.unit_cell().atom_type(std::string(label__));
3557 type.set_configuration(*n__, *l__, *k__, *occupancy__, *core__);
3558 },
3559 error_code__);
3560}
3561
3562/*
3563@api begin
3564sirius_generate_coulomb_potential:
3565 doc: Generate Coulomb potential by solving Poisson equation
3566 arguments:
3567 handler:
3568 type: gs_handler
3569 attr: in, required
3570 doc: DFT ground state handler
3571 vh_el:
3572 type: double
3573 attr: out, optional, dimension(:)
3574 doc: Electronic part of Hartree potential at each atom's origin.
3575 error_code:
3576 type: int
3577 attr: out, optional
3578 doc: Error code
3579@api end
3580*/
3581void
3582sirius_generate_coulomb_potential(void* const* handler__, double* vh_el__, int* error_code__)
3583{
3584 call_sirius(
3585 [&]() {
3586 auto& gs = get_gs(handler__);
3587
3588 gs.density().rho().rg().fft_transform(-1);
3589 gs.potential().poisson(gs.density().rho());
3590
3591 if (vh_el__) {
3592 for (int ia = 0; ia < gs.ctx().unit_cell().num_atoms(); ia++) {
3593 vh_el__[ia] = gs.potential().vh_el(ia);
3594 }
3595 }
3596 },
3597 error_code__);
3598}
3599
3600/*
3601@api begin
3602sirius_generate_xc_potential:
3603 doc: Generate XC potential using LibXC
3604 arguments:
3605 handler:
3606 type: gs_handler
3607 attr: in, required
3608 doc: Ground state handler
3609 error_code:
3610 type: int
3611 attr: out, optional
3612 doc: Error code
3613@api end
3614*/
3615void
3616sirius_generate_xc_potential(void* const* handler__, int* error_code__)
3617{
3618 call_sirius(
3619 [&]() {
3620 auto& gs = get_gs(handler__);
3621 gs.potential().xc(gs.density());
3622 },
3623 error_code__);
3624}
3625
3626/*
3627@api begin
3628sirius_get_kpoint_inter_comm:
3629 doc: Get communicator which is used to split k-points
3630 arguments:
3631 handler:
3632 type: ctx_handler
3633 attr: in, required
3634 doc: Simulation context handler
3635 fcomm:
3636 type: int
3637 attr: out, required
3638 doc: Fortran communicator
3639 error_code:
3640 type: int
3641 attr: out, optional
3642 doc: Error code
3643@api end
3644*/
3645void
3646sirius_get_kpoint_inter_comm(void* const* handler__, int* fcomm__, int* error_code__)
3647{
3648 call_sirius(
3649 [&]() {
3650 auto& sim_ctx = get_sim_ctx(handler__);
3651 *fcomm__ = MPI_Comm_c2f(sim_ctx.comm_k().native());
3652 },
3653 error_code__);
3654}
3655
3656/*
3657@api begin
3658sirius_get_kpoint_inner_comm:
3659 doc: Get communicator which is used to parallise band problem
3660 arguments:
3661 handler:
3662 type: ctx_handler
3663 attr: in, required
3664 doc: Simulation context handler
3665 fcomm:
3666 type: int
3667 attr: out, required
3668 doc: Fortran communicator
3669 error_code:
3670 type: int
3671 attr: out, optional
3672 doc: Error code
3673@api end
3674*/
3675void
3676sirius_get_kpoint_inner_comm(void* const* handler__, int* fcomm__, int* error_code__)
3677{
3678 call_sirius(
3679 [&]() {
3680 auto& sim_ctx = get_sim_ctx(handler__);
3681 *fcomm__ = MPI_Comm_c2f(sim_ctx.comm_band().native());
3682 },
3683 error_code__);
3684}
3685
3686/*
3687@api begin
3688sirius_get_fft_comm:
3689 doc: Get communicator which is used to parallise FFT
3690 arguments:
3691 handler:
3692 type: ctx_handler
3693 attr: in, required
3694 doc: Simulation context handler
3695 fcomm:
3696 type: int
3697 attr: out, required
3698 doc: Fortran communicator
3699 error_code:
3700 type: int
3701 attr: out, optional
3702 doc: Error code
3703@api end
3704*/
3705void
3706sirius_get_fft_comm(void* const* handler__, int* fcomm__, int* error_code__)
3707{
3708 call_sirius(
3709 [&]() {
3710 auto& sim_ctx = get_sim_ctx(handler__);
3711 *fcomm__ = MPI_Comm_c2f(sim_ctx.comm_fft().native());
3712 },
3713 error_code__);
3714}
3715
3716/*
3717@api begin
3718sirius_get_num_gvec:
3719 doc: Get total number of G-vectors on the fine grid.
3720 arguments:
3721 handler:
3722 type: ctx_handler
3723 attr: in, required
3724 doc: Simulation context handler
3725 num_gvec:
3726 type: int
3727 attr: out, required
3728 doc: Total number of G-vectors
3729 error_code:
3730 type: int
3731 attr: out, optional
3732 doc: Error code
3733@api end
3734*/
3735void
3736sirius_get_num_gvec(void* const* handler__, int* num_gvec__, int* error_code__)
3737{
3738 call_sirius(
3739 [&]() {
3740 auto& sim_ctx = get_sim_ctx(handler__);
3741 *num_gvec__ = sim_ctx.gvec().num_gvec();
3742 },
3743 error_code__);
3744}
3745
3746/*
3747@api begin
3748sirius_get_gvec_arrays:
3749 doc: Get G-vector arrays.
3750 arguments:
3751 handler:
3752 type: ctx_handler
3753 attr: in, required
3754 doc: Simulation context handler
3755 gvec:
3756 type: int
3757 attr: in, optional, dimension(:,:)
3758 doc: G-vectors in lattice coordinates.
3759 gvec_cart:
3760 type: double
3761 attr: in, optional, dimension(:,:)
3762 doc: G-vectors in Cartesian coordinates.
3763 gvec_len:
3764 type: double
3765 attr: in, optional, dimension(:)
3766 doc: Length of G-vectors.
3767 index_by_gvec:
3768 type: int
3769 attr: in, optional, dimension(:,:,:)
3770 doc: G-vector index by lattice coordinates.
3771 error_code:
3772 type: int
3773 attr: out, optional
3774 doc: Error code
3775@api end
3776*/
3777void
3778sirius_get_gvec_arrays(void* const* handler__, int* gvec__, double* gvec_cart__, double* gvec_len__,
3779 int* index_by_gvec__, int* error_code__)
3780{
3781 call_sirius(
3782 [&]() {
3783 auto& sim_ctx = get_sim_ctx(handler__);
3784
3785 if (gvec__ != nullptr) {
3786 sddk::mdarray<int, 2> gvec(gvec__, 3, sim_ctx.gvec().num_gvec());
3787 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
3788 auto gv = sim_ctx.gvec().gvec<index_domain_t::global>(ig);
3789 for (int x : {0, 1, 2}) {
3790 gvec(x, ig) = gv[x];
3791 }
3792 }
3793 }
3794 if (gvec_cart__ != nullptr) {
3795 sddk::mdarray<double, 2> gvec_cart(gvec_cart__, 3, sim_ctx.gvec().num_gvec());
3796 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
3797 auto gvc = sim_ctx.gvec().gvec_cart<index_domain_t::global>(ig);
3798 for (int x : {0, 1, 2}) {
3799 gvec_cart(x, ig) = gvc[x];
3800 }
3801 }
3802 }
3803 if (gvec_len__ != nullptr) {
3804 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
3805 gvec_len__[ig] = sim_ctx.gvec().gvec_len<index_domain_t::global>(ig);
3806 }
3807 }
3808 if (index_by_gvec__ != nullptr) {
3809 auto d0 = sim_ctx.fft_grid().limits(0);
3810 auto d1 = sim_ctx.fft_grid().limits(1);
3811 auto d2 = sim_ctx.fft_grid().limits(2);
3812
3813 sddk::mdarray<int, 3> index_by_gvec(index_by_gvec__, d0, d1, d2);
3814 std::fill(index_by_gvec.at(sddk::memory_t::host), index_by_gvec.at(sddk::memory_t::host) + index_by_gvec.size(),
3815 -1);
3816
3817 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
3818 auto G = sim_ctx.gvec().gvec<index_domain_t::global>(ig);
3819
3820 index_by_gvec(G[0], G[1], G[2]) = ig + 1;
3821 }
3822 }
3823 },
3824 error_code__);
3825}
3826
3827/*
3828@api begin
3829sirius_get_num_fft_grid_points:
3830 doc: Get local number of FFT grid points.
3831 arguments:
3832 handler:
3833 type: ctx_handler
3834 attr: in, required
3835 doc: Simulation context handler
3836 num_fft_grid_points:
3837 type: int
3838 attr: out, required
3839 doc: Local number of FFT grid points in the real-space mesh.
3840 error_code:
3841 type: int
3842 attr: out, optional
3843 doc: Error code.
3844@api end
3845*/
3846void
3847sirius_get_num_fft_grid_points(void* const* handler__, int* num_fft_grid_points__, int* error_code__)
3848{
3849 call_sirius(
3850 [&]() {
3851 auto& sim_ctx = get_sim_ctx(handler__);
3852 *num_fft_grid_points__ = sim_ctx.spfft<double>().local_slice_size();
3853 },
3854 error_code__);
3855}
3856
3857/*
3858@api begin
3859sirius_get_fft_index:
3860 doc: Get mapping between G-vector index and FFT index
3861 arguments:
3862 handler:
3863 type: ctx_handler
3864 attr: in, required
3865 doc: Simulation context handler
3866 fft_index:
3867 type: int
3868 attr: out, required, dimension(:)
3869 doc: Index inside FFT buffer
3870 error_code:
3871 type: int
3872 attr: out, optional
3873 doc: Error code.
3874@api end
3875*/
3876void
3877sirius_get_fft_index(void* const* handler__, int* fft_index__, int* error_code__)
3878{
3879 call_sirius(
3880 [&]() {
3881 auto& sim_ctx = get_sim_ctx(handler__);
3882 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
3883 auto G = sim_ctx.gvec().gvec<index_domain_t::global>(ig);
3884 fft_index__[ig] = sim_ctx.fft_grid().index_by_freq(G[0], G[1], G[2]) + 1;
3885 }
3886 },
3887 error_code__);
3888}
3889
3890/*
3891@api begin
3892sirius_get_max_num_gkvec:
3893 doc: Get maximum number of G+k vectors across all k-points in the set
3894 arguments:
3895 ks_handler:
3896 type: ks_handler
3897 attr: in, required
3898 doc: K-point set handler.
3899 max_num_gkvec:
3900 type: int
3901 attr: out, required
3902 doc: Maximum number of G+k vectors
3903 error_code:
3904 type: int
3905 attr: out, optional
3906 doc: Error code.
3907@api end
3908*/
3909void
3910sirius_get_max_num_gkvec(void* const* ks_handler__, int* max_num_gkvec__, int* error_code__)
3911{
3912 call_sirius(
3913 [&]() {
3914 auto& ks = get_ks(ks_handler__);
3915 *max_num_gkvec__ = ks.max_num_gkvec();
3916 },
3917 error_code__);
3918}
3919
3920/*
3921@api begin
3922sirius_get_gkvec_arrays:
3923 doc: Get all G+k vector related arrays
3924 arguments:
3925 ks_handler:
3926 type: ks_handler
3927 attr: in, required
3928 doc: K-point set handler.
3929 ik:
3930 type: int
3931 attr: in, required
3932 doc: Global index of k-point
3933 num_gkvec:
3934 type: int
3935 attr: out, required
3936 doc: Number of G+k vectors.
3937 gvec_index:
3938 type: int
3939 attr: out, required, dimension(:)
3940 doc: Index of the G-vector part of G+k vector.
3941 gkvec:
3942 type: double
3943 attr: out, required, dimension(:,:)
3944 doc: G+k vectors in fractional coordinates.
3945 gkvec_cart:
3946 type: double
3947 attr: out, required, dimension(:,:)
3948 doc: G+k vectors in Cartesian coordinates.
3949 gkvec_len:
3950 type: double
3951 attr: out, required, dimension(:)
3952 doc: Length of G+k vectors.
3953 gkvec_tp:
3954 type: double
3955 attr: out, required, dimension(:,:)
3956 doc: Theta and Phi angles of G+k vectors.
3957 error_code:
3958 type: int
3959 attr: out, optional
3960 doc: Error code.
3961@api end
3962*/
3963void
3964sirius_get_gkvec_arrays(void* const* ks_handler__, int* ik__, int* num_gkvec__, int* gvec_index__, double* gkvec__,
3965 double* gkvec_cart__, double* gkvec_len, double* gkvec_tp__, int* error_code__)
3966{
3967
3968 call_sirius(
3969 [&]() {
3970 auto& ks = get_ks(ks_handler__);
3971
3972 auto kp = ks.get<double>(*ik__ - 1);
3973
3974 /* get rank that stores a given k-point */
3975 int rank = ks.spl_num_kpoints().location(kp_index_t::global(*ik__ - 1)).ib;
3976
3977 auto& comm_k = ks.ctx().comm_k();
3978
3979 if (rank == comm_k.rank()) {
3980 *num_gkvec__ = kp->num_gkvec();
3981 sddk::mdarray<double, 2> gkvec(gkvec__, 3, kp->num_gkvec());
3982 sddk::mdarray<double, 2> gkvec_cart(gkvec_cart__, 3, kp->num_gkvec());
3983 sddk::mdarray<double, 2> gkvec_tp(gkvec_tp__, 2, kp->num_gkvec());
3984
3985 for (int igk = 0; igk < kp->num_gkvec(); igk++) {
3986 auto gkc = kp->gkvec().gkvec_cart<index_domain_t::global>(igk);
3987 auto G = kp->gkvec().gvec<index_domain_t::global>(igk);
3988
3989 gvec_index__[igk] = ks.ctx().gvec().index_by_gvec(G) + 1; // Fortran counts from 1
3990 for (int x : {0, 1, 2}) {
3991 gkvec(x, igk) = kp->gkvec().template gkvec<index_domain_t::global>(igk)[x];
3992 gkvec_cart(x, igk) = gkc[x];
3993 }
3994 auto rtp = r3::spherical_coordinates(gkc);
3995 gkvec_len[igk] = rtp[0];
3996 gkvec_tp(0, igk) = rtp[1];
3997 gkvec_tp(1, igk) = rtp[2];
3998 }
3999 }
4000 comm_k.bcast(num_gkvec__, 1, rank);
4001 comm_k.bcast(gvec_index__, *num_gkvec__, rank);
4002 comm_k.bcast(gkvec__, *num_gkvec__ * 3, rank);
4003 comm_k.bcast(gkvec_cart__, *num_gkvec__ * 3, rank);
4004 comm_k.bcast(gkvec_len, *num_gkvec__, rank);
4005 comm_k.bcast(gkvec_tp__, *num_gkvec__ * 2, rank);
4006 },
4007 error_code__);
4008}
4009
4010/*
4011@api begin
4012sirius_get_step_function:
4013 doc: Get the unit-step function.
4014 arguments:
4015 handler:
4016 type: ctx_handler
4017 attr: in, required
4018 doc: Simulation context handler
4019 cfunig:
4020 type: complex
4021 attr: out, required, dimension(:)
4022 doc: Plane-wave coefficients of step function.
4023 cfunrg:
4024 type: double
4025 attr: out, required, dimension(:)
4026 doc: Values of the step function on the regular grid.
4027 num_rg_points:
4028 type: int
4029 attr: in, required
4030 doc: Number of real-space points.
4031 error_code:
4032 type: int
4033 attr: out, optional
4034 doc: Error code.
4035@api end
4036*/
4037void
4038sirius_get_step_function(void* const* handler__, std::complex<double>* cfunig__, double* cfunrg__, int* num_rg_points__,
4039 int* error_code__) // TODO: generalise with get_periodic_function
4040{
4041 call_sirius(
4042 [&]() {
4043 auto& sim_ctx = get_sim_ctx(handler__);
4044 for (int ig = 0; ig < sim_ctx.gvec().num_gvec(); ig++) {
4045 cfunig__[ig] = sim_ctx.theta_pw(ig);
4046 }
4047 auto& fft = sim_ctx.spfft<double>();
4048
4049 bool is_local_rg;
4050 if (*num_rg_points__ == static_cast<int>(fft::spfft_grid_size(fft))) {
4051 is_local_rg = false;
4052 } else if (*num_rg_points__ == static_cast<int>(fft::spfft_grid_size_local(fft))) {
4053 is_local_rg = true;
4054 } else {
4055 RTE_THROW("wrong number of real space points");
4056 }
4057
4058 int offs = (is_local_rg) ? 0 : fft.dim_x() * fft.dim_y() * fft.local_z_offset();
4059 if (fft.local_slice_size()) {
4060 for (int i = 0; i < fft.local_slice_size(); i++) {
4061 cfunrg__[offs + i] = sim_ctx.theta(i);
4062 }
4063 }
4064 if (!is_local_rg) {
4065 mpi::Communicator(fft.communicator()).allgather(cfunrg__, fft.local_slice_size(), offs);
4066 }
4067 },
4068 error_code__);
4069}
4070
4071/*
4072@api begin
4073sirius_set_h_radial_integrals:
4074 doc: Set LAPW Hamiltonian radial integrals.
4075 arguments:
4076 handler:
4077 type: ctx_handler
4078 attr: in, required
4079 doc: Simulation context handler.
4080 ia:
4081 type: int
4082 attr: in, required
4083 doc: Index of atom.
4084 lmmax:
4085 type: int
4086 attr: in, required
4087 doc: Number of lm-component of the potential.
4088 val:
4089 type: double
4090 attr: in, required
4091 doc: Values of the radial integrals.
4092 l1:
4093 type: int
4094 attr: in, optional
4095 doc: 1st index of orbital quantum number.
4096 o1:
4097 type: int
4098 attr: in, optional
4099 doc: 1st index of radial function order for l1.
4100 ilo1:
4101 type: int
4102 attr: in, optional
4103 doc: 1st index or local orbital.
4104 l2:
4105 type: int
4106 attr: in, optional
4107 doc: 2nd index of orbital quantum number.
4108 o2:
4109 type: int
4110 attr: in, optional
4111 doc: 2nd index of radial function order for l2.
4112 ilo2:
4113 type: int
4114 attr: in, optional
4115 doc: 2nd index or local orbital.
4116 error_code:
4117 type: int
4118 attr: out, optional
4119 doc: Error code.
4120@api end
4121*/
4122void
4123sirius_set_h_radial_integrals(void* const* handler__, int* ia__, int* lmmax__, double* val__, int* l1__, int* o1__,
4124 int* ilo1__, int* l2__, int* o2__, int* ilo2__, int* error_code__)
4125{
4126 call_sirius(
4127 [&]() {
4128 auto& sim_ctx = get_sim_ctx(handler__);
4129 int ia = *ia__ - 1;
4130 int idxrf1{-1};
4131 int idxrf2{-1};
4132 if ((l1__ != nullptr && o1__ != nullptr && ilo1__ != nullptr) ||
4133 (l2__ != nullptr && o2__ != nullptr && ilo2__ != nullptr)) {
4134 RTE_THROW("wrong combination of radial function indices");
4135 }
4136 if (l1__ != nullptr && o1__ != nullptr) {
4137 idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_l_order(*l1__, *o1__ - 1);
4138 } else if (ilo1__ != nullptr) {
4139 idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo1__ - 1);
4140 } else {
4141 RTE_THROW("1st radial function index is not valid");
4142 }
4143
4144 if (l2__ != nullptr && o2__ != nullptr) {
4145 idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_l_order(*l2__, *o2__ - 1);
4146 } else if (ilo2__ != nullptr) {
4147 idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo2__ - 1);
4148 } else {
4149 RTE_THROW("2nd radial function index is not valid");
4150 }
4151
4152 for (int lm = 0; lm < *lmmax__; lm++) {
4153 sim_ctx.unit_cell().atom(ia).h_radial_integrals(idxrf1, idxrf2)[lm] = val__[lm];
4154 }
4155 },
4156 error_code__);
4157}
4158
4159/*
4160@api begin
4161sirius_set_o_radial_integral:
4162 doc: Set LAPW overlap radial integral.
4163 arguments:
4164 handler:
4165 type: ctx_handler
4166 attr: in, required
4167 doc: Simulation context handler.
4168 ia:
4169 type: int
4170 attr: in, required
4171 doc: Index of atom.
4172 val:
4173 type: double
4174 attr: in, required
4175 doc: Value of the radial integral.
4176 l:
4177 type: int
4178 attr: in, required
4179 doc: Orbital quantum number.
4180 o1:
4181 type: int
4182 attr: in, optional
4183 doc: 1st index of radial function order.
4184 ilo1:
4185 type: int
4186 attr: in, optional
4187 doc: 1st index or local orbital.
4188 o2:
4189 type: int
4190 attr: in, optional
4191 doc: 2nd index of radial function order.
4192 ilo2:
4193 type: int
4194 attr: in, optional
4195 doc: 2nd index or local orbital.
4196 error_code:
4197 type: int
4198 attr: out, optional
4199 doc: Error code.
4200@api end
4201*/
4202void
4203sirius_set_o_radial_integral(void* const* handler__, int* ia__, double* val__, int* l__, int* o1__, int* ilo1__,
4204 int* o2__, int* ilo2__, int* error_code__)
4205{
4206
4207 call_sirius(
4208 [&]() {
4209 auto& sim_ctx = get_sim_ctx(handler__);
4210 int ia = *ia__ - 1;
4211 if ((o1__ != nullptr && ilo1__ != nullptr) || (o2__ != nullptr && ilo2__ != nullptr)) {
4212 RTE_THROW("wrong combination of radial function indices");
4213 }
4214
4215 if (o1__ != nullptr && ilo2__ != nullptr) {
4216 int idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo2__ - 1);
4217 int order2 = sim_ctx.unit_cell().atom(ia).type().indexr(idxrf2).order;
4218 sim_ctx.unit_cell().atom(ia).symmetry_class().set_o_radial_integral(*l__, *o1__ - 1, order2, *val__);
4219 }
4220
4221 if (o2__ != nullptr && ilo1__ != nullptr) {
4222 int idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo1__ - 1);
4223 int order1 = sim_ctx.unit_cell().atom(ia).type().indexr(idxrf1).order;
4224 sim_ctx.unit_cell().atom(ia).symmetry_class().set_o_radial_integral(*l__, order1, *o2__ - 1, *val__);
4225 }
4226
4227 if (ilo1__ != nullptr && ilo2__ != nullptr) {
4228 int idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo1__ - 1);
4229 int order1 = sim_ctx.unit_cell().atom(ia).type().indexr(idxrf1).order;
4230 int idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo2__ - 1);
4231 int order2 = sim_ctx.unit_cell().atom(ia).type().indexr(idxrf2).order;
4232 sim_ctx.unit_cell().atom(ia).symmetry_class().set_o_radial_integral(*l__, order1, order2, *val__);
4233 }
4234 },
4235 error_code__);
4236}
4237
4238/*
4239@api begin
4240sirius_set_o1_radial_integral:
4241 doc: Set a correction to LAPW overlap radial integral.
4242 arguments:
4243 handler:
4244 type: ctx_handler
4245 attr: in, required
4246 doc: Simulation context handler.
4247 ia:
4248 type: int
4249 attr: in, required
4250 doc: Index of atom.
4251 val:
4252 type: double
4253 attr: in, required
4254 doc: Value of the radial integral.
4255 l1:
4256 type: int
4257 attr: in, optional
4258 doc: 1st index of orbital quantum number.
4259 o1:
4260 type: int
4261 attr: in, optional
4262 doc: 1st index of radial function order for l1.
4263 ilo1:
4264 type: int
4265 attr: in, optional
4266 doc: 1st index or local orbital.
4267 l2:
4268 type: int
4269 attr: in, optional
4270 doc: 2nd index of orbital quantum number.
4271 o2:
4272 type: int
4273 attr: in, optional
4274 doc: 2nd index of radial function order for l2.
4275 ilo2:
4276 type: int
4277 attr: in, optional
4278 doc: 2nd index or local orbital.
4279 error_code:
4280 type: int
4281 attr: out, optional
4282 doc: Error code.
4283@api end
4284*/
4285void
4286sirius_set_o1_radial_integral(void* const* handler__, int* ia__, double* val__, int* l1__, int* o1__, int* ilo1__,
4287 int* l2__, int* o2__, int* ilo2__, int* error_code__)
4288{
4289 call_sirius(
4290 [&]() {
4291 auto& sim_ctx = get_sim_ctx(handler__);
4292 int ia = *ia__ - 1;
4293 int idxrf1{-1};
4294 int idxrf2{-1};
4295 if ((l1__ != nullptr && o1__ != nullptr && ilo1__ != nullptr) ||
4296 (l2__ != nullptr && o2__ != nullptr && ilo2__ != nullptr)) {
4297 RTE_THROW("wrong combination of radial function indices");
4298 }
4299 if (l1__ != nullptr && o1__ != nullptr) {
4300 idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_l_order(*l1__, *o1__ - 1);
4301 } else if (ilo1__ != nullptr) {
4302 idxrf1 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo1__ - 1);
4303 } else {
4304 RTE_THROW("1st radial function index is not valid");
4305 }
4306
4307 if (l2__ != nullptr && o2__ != nullptr) {
4308 idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_l_order(*l2__, *o2__ - 1);
4309 } else if (ilo2__ != nullptr) {
4310 idxrf2 = sim_ctx.unit_cell().atom(ia).type().indexr_by_idxlo(*ilo2__ - 1);
4311 } else {
4312 RTE_THROW("2nd radial function index is not valid");
4313 }
4314 sim_ctx.unit_cell().atom(ia).symmetry_class().set_o1_radial_integral(idxrf1, idxrf2, *val__);
4315 },
4316 error_code__);
4317}
4318
4319/*
4320@api begin
4321sirius_set_radial_function:
4322 doc: Set LAPW radial functions
4323 arguments:
4324 handler:
4325 type: ctx_handler
4326 attr: in, required
4327 doc: Simulation context handler.
4328 ia:
4329 type: int
4330 attr: in, required
4331 doc: Index of atom.
4332 deriv_order:
4333 type: int
4334 attr: in, required
4335 doc: Radial derivative order.
4336 f:
4337 type: double
4338 attr: in, required, dimension(:)
4339 doc: Values of the radial function.
4340 l:
4341 type: int
4342 attr: in, optional
4343 doc: Orbital quantum number.
4344 o:
4345 type: int
4346 attr: in, optional
4347 doc: Order of radial function for l.
4348 ilo:
4349 type: int
4350 attr: in, optional
4351 doc: Local orbital index.
4352 error_code:
4353 type: int
4354 attr: out, optional
4355 doc: Error code.
4356@api end
4357*/
4358void
4359sirius_set_radial_function(void* const* handler__, int const* ia__, int const* deriv_order__, double const* f__,
4360 int const* l__, int const* o__, int const* ilo__, int* error_code__)
4361{
4362 call_sirius(
4363 [&]() {
4364 auto& sim_ctx = get_sim_ctx(handler__);
4365
4366 int ia = *ia__ - 1;
4367
4368 auto& atom = sim_ctx.unit_cell().atom(ia);
4369 int n = atom.num_mt_points();
4370
4371 if (l__ != nullptr && o__ != nullptr && ilo__ != nullptr) {
4372 RTE_THROW("wrong combination of radial function indices");
4373 }
4374 if (!(*deriv_order__ == 0 || *deriv_order__ == 1)) {
4375 RTE_THROW("wrond radial derivative order");
4376 }
4377
4378 int idxrf{-1};
4379 if (l__ != nullptr && o__ != nullptr) {
4380 idxrf = atom.type().indexr_by_l_order(*l__, *o__ - 1);
4381 } else if (ilo__ != nullptr) {
4382 idxrf = atom.type().indexr_by_idxlo(*ilo__ - 1);
4383 } else {
4384 RTE_THROW("radial function index is not valid");
4385 }
4386
4387 if (*deriv_order__ == 0) {
4388 atom.symmetry_class().radial_function(idxrf, std::vector<double>(f__, f__ + n));
4389 } else {
4390 std::vector<double> f(n);
4391 for (int ir = 0; ir < n; ir++) {
4392 f[ir] = f__[ir] * atom.type().radial_grid()[ir];
4393 }
4394 atom.symmetry_class().radial_function_derivative(idxrf, f);
4395 }
4396 if (l__ != nullptr && o__ != nullptr) {
4397 atom.symmetry_class().aw_surface_deriv(*l__, *o__ - 1, *deriv_order__, f__[n - 1]);
4398 }
4399 },
4400 error_code__);
4401}
4402
4403/*
4404@api begin
4405sirius_set_equivalent_atoms:
4406 doc: Set equivalent atoms.
4407 arguments:
4408 handler:
4409 type: ctx_handler
4410 attr: in, required
4411 doc: Simulation context handler.
4412 equivalent_atoms:
4413 type: int
4414 attr: in, required, dimension(:)
4415 doc: Array with equivalent atom IDs.
4416 error_code:
4417 type: int
4418 attr: out, optional
4419 doc: Error code.
4420@api end
4421*/
4422void
4423sirius_set_equivalent_atoms(void* const* handler__, int* equivalent_atoms__, int* error_code__)
4424{
4425 call_sirius(
4426 [&]() {
4427 auto& sim_ctx = get_sim_ctx(handler__);
4428 sim_ctx.unit_cell().set_equivalent_atoms(equivalent_atoms__);
4429 },
4430 error_code__);
4431}
4432
4433/*
4434@api begin
4435sirius_update_atomic_potential:
4436 doc: Set the new spherical potential.
4437 arguments:
4438 handler:
4439 type: gs_handler
4440 attr: in, required
4441 doc: Ground state handler.
4442 error_code:
4443 type: int
4444 attr: out, optional
4445 doc: Error code.
4446@api end
4447*/
4448void
4449sirius_update_atomic_potential(void* const* handler__, int* error_code__)
4450{
4451 call_sirius(
4452 [&]() {
4453 auto& gs = get_gs(handler__);
4454 gs.potential().update_atomic_potential();
4455 },
4456 error_code__);
4457}
4458
4459/*
4460@api begin
4461sirius_option_get_number_of_sections:
4462 doc: Return the total number of sections defined in the input JSON schema.
4463 arguments:
4464 length:
4465 type: int
4466 attr: out, required
4467 doc: Number of sections.
4468 error_code:
4469 type: int
4470 attr: out, optional
4471 doc: Error code.
4472@api end
4473*/
4474void
4475sirius_option_get_number_of_sections(int* length__, int *error_code__)
4476{
4477 call_sirius(
4478 [&]() {
4479 auto const& dict = get_options_dictionary();
4480 *length__ = static_cast<int>(dict["properties"].size());
4481 }, error_code__);
4482}
4483
4484/*
4485@api begin
4486sirius_option_get_section_name:
4487 doc: Return the name of a given section.
4488 arguments:
4489 elem:
4490 type: int
4491 attr: in, required, value
4492 doc: Index of the section (starting from 1).
4493 section_name:
4494 type: string
4495 attr: out, required
4496 doc: Name of the section
4497 section_name_length:
4498 type: int
4499 attr: in, required, value
4500 doc: Maximum length of the output string. Enough capacity should be provided.
4501 error_code:
4502 type: int
4503 attr: out, optional
4504 doc: Error code.
4505@api end
4506*/
4507void
4508sirius_option_get_section_name(int elem__, char* section_name__, int section_name_length__, int *error_code__)
4509{
4510 call_sirius(
4511 [&]() {
4512 auto const& dict = sirius::get_options_dictionary();
4513
4514 /* initialize the string to zero; the fortran interface takes care of
4515 finishing the string with the proper character for Fortran */
4516
4517 std::fill(section_name__, section_name__ + section_name_length__, 0);
4518 auto it = dict["properties"].begin();
4519 /* we can't do pointer arighmetics on the iterator */
4520 for (int i = 0; i < elem__ - 1; i++, it++);
4521 auto key = it.key();
4522 if (static_cast<int>(key.size()) > section_name_length__ - 1) {
4523 std::stringstream s;
4524 s << "section name '" << key << "' is too large to fit into output string of size " << section_name_length__;
4525 RTE_THROW(s);
4526 }
4527 std::copy(key.begin(), key.end(), section_name__);
4528 }, error_code__);
4529}
4530
4531/*
4532@api begin
4533sirius_option_get_section_length:
4534 doc: Return the number of options in a given section.
4535 arguments:
4536 section:
4537 type: string
4538 attr: in, required
4539 doc: Name of the seciton.
4540 length:
4541 type: int
4542 attr: out, required
4543 doc: Number of options contained in the section.
4544 error_code:
4545 type: int
4546 attr: out, optional
4547 doc: Error code.
4548@api end
4549*/
4550void
4551sirius_option_get_section_length(char const* section__, int* length__, int* error_code__)
4552{
4553 call_sirius(
4554 [&]() {
4555 auto section = std::string(section__);
4556 std::transform(section.begin(), section.end(), section.begin(), ::tolower);
4557 auto const& parser = sirius::get_section_options(section);
4558 *length__ = static_cast<int>(parser.size());
4559 }, error_code__);
4560}
4561
4562/*
4563@api begin
4564sirius_option_get_info:
4565 doc: Return information about the option.
4566 arguments:
4567 section:
4568 type: string
4569 attr: in, required
4570 doc: Name of the section.
4571 elem:
4572 type: int
4573 attr: in, required, value
4574 doc: Index of the option (starting from 1)
4575 key_name:
4576 type: string
4577 attr: out, required
4578 doc: Name of the option.
4579 key_name_len:
4580 type: int
4581 attr: in, required, value
4582 doc: Maximum length for the string (on the caller side). No allocation is done.
4583 type:
4584 type: int
4585 attr: out, required
4586 doc: Type of the option (real, integer, boolean, string, or array of the same types).
4587 length:
4588 type: int
4589 attr: out, required
4590 doc: Length of the default value (1 for the scalar types, otherwise the lenght of the array).
4591 enum_size:
4592 type: int
4593 attr: out, required
4594 doc: Number of elements in the enum type, zero otherwise.
4595 title:
4596 type: string
4597 attr: out, required
4598 doc: Short description of the option (can be empty).
4599 title_len:
4600 type: int
4601 attr: in, required, value
4602 doc: Maximum length for the short description.
4603 description:
4604 type: string
4605 attr: out, required
4606 doc: Detailed description of the option (can be empty).
4607 description_len:
4608 type: int
4609 attr: in, required, value
4610 doc: Maximum length for the detailed description.
4611 error_code:
4612 type: int
4613 attr: out, optional
4614 doc: Error code.
4615@api end
4616*/
4617
4618void
4619sirius_option_get_info(char const* section__, int elem__, char* key_name__, int key_name_len__, int* type__,
4620 int* length__, int* enum_size__, char* title__, int title_len__, char* description__,
4621 int description_len__, int *error_code__)
4622{
4623 call_sirius(
4624 [&]() {
4625 auto section = std::string(section__);
4626 std::transform(section.begin(), section.end(), section.begin(), ::tolower);
4627 auto const& dict = sirius::get_section_options(section);
4628
4629 std::map<std::string, option_type_t> type_list = {
4630 {"string", option_type_t::STRING_TYPE},
4631 {"number", option_type_t::NUMBER_TYPE},
4632 {"integer", option_type_t::INTEGER_TYPE},
4633 {"boolean", option_type_t::LOGICAL_TYPE},
4634 {"array", option_type_t::ARRAY_TYPE},
4635 {"object", option_type_t::OBJECT_TYPE},
4636 {"number_array_type", option_type_t::NUMBER_ARRAY_TYPE},
4637 {"boolean_array_type", option_type_t::LOGICAL_ARRAY_TYPE},
4638 {"integer_array_type", option_type_t::INTEGER_ARRAY_TYPE},
4639 {"string_array_type", option_type_t::STRING_ARRAY_TYPE},
4640 {"object_array_type", option_type_t::OBJECT_ARRAY_TYPE},
4641 {"array_array_type", option_type_t::ARRAY_ARRAY_TYPE}
4642 };
4643
4644 std::fill(key_name__, key_name__ + key_name_len__, 0);
4645 std::fill(title__, title__ + title_len__, 0);
4646 std::fill(description__, description__ + description_len__, 0);
4647
4648 auto it = dict.begin();
4649 /* we can't do pointer arighmetics on the iterator */
4650 for (int i = 0; i < elem__ - 1; i++, it++);
4651 auto key = it.key();
4652 if (!dict[key].count("default")) {
4653 RTE_THROW("the default value is missing for key '" + key + "' in section '" + section + "'");
4654 }
4655 if (dict[key]["type"] == "array") {
4656 std::string tmp = dict[key]["items"]["type"].get<std::string>() + "_array_type";
4657 *type__ = static_cast<int>(type_list[tmp]);
4658 *length__ = static_cast<int>(dict[key]["default"].size());
4659 *enum_size__ = 0;
4660 } else {
4661 *type__ = static_cast<int>(type_list[dict[key]["type"].get<std::string>()]);
4662 *length__ = 1;
4663 if (dict[key].count("enum")) {
4664 *enum_size__ = static_cast<int>(dict[key]["enum"].size());
4665 } else {
4666 *enum_size__ = 0;
4667 }
4668 }
4669 if (static_cast<int>(key.size()) < key_name_len__ - 1) {
4670 std::copy(key.begin(), key.end(), key_name__);
4671 } else {
4672 RTE_THROW("the key_name string variable needs to be large enough to contain the full option name");
4673 }
4674
4675 if (dict[key].count("title")) {
4676 auto title = dict[key].value<std::string>("title", "");
4677 if (title.size()) {
4678 if (static_cast<int>(title.size()) < title_len__ - 1) {
4679 std::copy(title.begin(), title.end(), title__);
4680 } else {
4681 std::copy(title.begin(), title.begin() + title_len__ - 1, title__);
4682 }
4683 }
4684 }
4685
4686 if (dict[key].count("description")) {
4687 auto description = dict[key].value<std::string>("description", "");
4688 if (description.size()) {
4689 if (static_cast<int>(description.size()) < description_len__ - 1) {
4690 std::copy(description.begin(), description.end(), description__);
4691 } else {
4692 std::copy(description.begin(), description.begin() + description_len__ - 1, description__);
4693 }
4694 }
4695 }
4696 }, error_code__);
4697}
4698
4699/*
4700@api begin
4701sirius_option_get:
4702 doc: Return the default value of the option as defined in the JSON schema.
4703 arguments:
4704 section:
4705 type: string
4706 attr: in, required
4707 doc: Name of the section of interest.
4708 name:
4709 type: string
4710 attr: in, required
4711 doc: Name of the element
4712 type:
4713 type: int
4714 attr: in, required
4715 doc: Type of the option (real, integer, boolean)
4716 data_ptr:
4717 type: void*
4718 attr: in, required, value
4719 doc: Output buffer for the default value or list of values.
4720 max_length:
4721 type: int
4722 attr: in, optional
4723 doc: Maximum length of the buffer containing the default values.
4724 enum_idx:
4725 type: int
4726 attr: in, optional
4727 doc: Index of the element in case of the enum type.
4728 error_code:
4729 type: int
4730 attr: out, optional
4731 doc: Error code.
4732@api end
4733*/
4734void
4735sirius_option_get(char const* section__, char const* name__, int const* type__, void* data_ptr__,
4736 int const* max_length__, int const* enum_idx__, int* error_code__)
4737{
4738 /* data_ptr is desctibed as `in, required, value`; this is small hack to allow Fortran to pass C_LOC(var) directly;
4739 * this is justified because pointer itself is really unchanged and thus can be 'in' */
4740 call_sirius(
4741 [&]() {
4742 auto t = static_cast<option_type_t>(*type__);
4743 std::string section(section__);
4744 std::string name(name__);
4745 switch (t) {
4746 case option_type_t::INTEGER_TYPE:
4747 case option_type_t::INTEGER_ARRAY_TYPE: {
4748 sirius_option_get_value<int>(section, name, static_cast<int*>(data_ptr__), max_length__);
4749 break;
4750 }
4751 case option_type_t::NUMBER_TYPE:
4752 case option_type_t::NUMBER_ARRAY_TYPE: {
4753 sirius_option_get_value<double>(section, name, static_cast<double*>(data_ptr__), max_length__);
4754 break;
4755 }
4756 case option_type_t::LOGICAL_TYPE:
4757 case option_type_t::LOGICAL_ARRAY_TYPE: {
4758 sirius_option_get_value<bool>(section, name, static_cast<bool*>(data_ptr__), max_length__);
4759 break;
4760 }
4761 case option_type_t::STRING_TYPE: {
4762 sirius_option_get_value(section, name, static_cast<char*>(data_ptr__), max_length__, enum_idx__);
4763 break;
4764 }
4765 default: {
4766 RTE_THROW("wrong option type");
4767 break;
4768 }
4769 }
4770 }, error_code__);
4771}
4772
4773/*
4774@api begin
4775sirius_option_set:
4776 doc: Set the value of the option name in a (internal) json dictionary
4777 arguments:
4778 handler:
4779 type: ctx_handler
4780 attr: in, required
4781 doc: Simulation context handler.
4782 section:
4783 type: string
4784 attr: in, required
4785 doc: string containing the options in json format
4786 name:
4787 type: string
4788 attr: in, required
4789 doc: name of the element to pick
4790 type:
4791 type: int
4792 attr: in, required
4793 doc: Type of the option (real, integer, boolean)
4794 data_ptr:
4795 type: void*
4796 attr: in, required, value
4797 doc: Buffer for the value or list of values.
4798 max_length:
4799 type: int
4800 attr: in, optional
4801 doc: Maximum length of the buffer containing the default values.
4802 append:
4803 type: bool
4804 attr: in, optional
4805 doc: If true then value is appended to the list of values.
4806 error_code:
4807 type: int
4808 attr: out, optional
4809 doc: Error code.
4810@api end
4811*/
4812void
4813sirius_option_set(void* const* handler__, char const* section__, char const* name__, int const* type__,
4814 void const* data_ptr__, int const* max_length__, bool const* append__, int* error_code__)
4815{
4816 call_sirius(
4817 [&]() {
4818 auto& sim_ctx = get_sim_ctx(handler__);
4819 auto t = static_cast<option_type_t>(*type__);
4820 std::string section(section__);
4821 std::string name(name__);
4822 switch (t) {
4823 case option_type_t::INTEGER_TYPE:
4824 case option_type_t::INTEGER_ARRAY_TYPE: {
4825 sirius_option_set_value<int>(sim_ctx, section, name, static_cast<int const*>(data_ptr__), max_length__);
4826 break;
4827 }
4828 case option_type_t::NUMBER_TYPE:
4829 case option_type_t::NUMBER_ARRAY_TYPE: {
4830 sirius_option_set_value<double>(sim_ctx, section, name, static_cast<double const*>(data_ptr__), max_length__);
4831 break;
4832 }
4833 case option_type_t::LOGICAL_TYPE:
4834 case option_type_t::LOGICAL_ARRAY_TYPE: {
4835 sirius_option_set_value<bool>(sim_ctx, section, name, static_cast<bool const*>(data_ptr__), max_length__);
4836 break;
4837 }
4838 case option_type_t::STRING_TYPE: {
4839 bool append = (append__ != nullptr) ? *append__ : false;
4840 sirius_option_set_value(sim_ctx, section, name, static_cast<char const*>(data_ptr__), max_length__, append);
4841 break;
4842 }
4843 default: {
4844 RTE_THROW("wrong option type");
4845 break;
4846 }
4847 }
4848 }, error_code__);
4849}
4850
4851/*
4852@api begin
4853sirius_dump_runtime_setup:
4854 doc: Dump the runtime setup in a file.
4855 arguments:
4856 handler:
4857 type: ctx_handler
4858 attr: in, required
4859 doc: Simulation context handler.
4860 filename:
4861 type: string
4862 attr: in, required
4863 doc: String containing the name of the file.
4864 error_code:
4865 type: int
4866 attr: out, optional
4867 doc: Error code
4868@api end
4869*/
4870void
4871sirius_dump_runtime_setup(void* const* handler__, char* filename__, int* error_code__)
4872{
4873 call_sirius(
4874 [&]() {
4875 auto& sim_ctx = get_sim_ctx(handler__);
4876 std::ofstream fi(filename__, std::ofstream::out | std::ofstream::trunc);
4877 auto conf_dict = sim_ctx.serialize();
4878 fi << conf_dict.dump(4);
4879 },
4880 error_code__);
4881}
4882
4883/*
4884@api begin
4885sirius_get_fv_eigen_vectors:
4886 doc: Get the first-variational eigen vectors
4887 arguments:
4888 handler:
4889 type: ks_handler
4890 attr: in, required
4891 doc: K-point set handler
4892 ik:
4893 type: int
4894 attr: in, required
4895 doc: Global index of the k-point
4896 fv_evec:
4897 type: complex
4898 attr: out, required, dimension(:,:)
4899 doc: Output first-variational eigenvector array
4900 ld:
4901 type: int
4902 attr: in, required
4903 doc: Leading dimension of fv_evec
4904 num_fv_states:
4905 type: int
4906 attr: in, required
4907 doc: Number of first-variational states
4908 error_code:
4909 type: int
4910 attr: out, optional
4911 doc: Error code
4912@api end
4913*/
4914void
4915sirius_get_fv_eigen_vectors(void* const* handler__, int const* ik__, std::complex<double>* fv_evec__, int const* ld__,
4916 int const* num_fv_states__, int* error_code__)
4917{
4918 call_sirius(
4919 [&]() {
4920 auto& ks = get_ks(handler__);
4921 sddk::mdarray<std::complex<double>, 2> fv_evec(fv_evec__, *ld__, *num_fv_states__);
4922 int ik = *ik__ - 1;
4923 ks.get<double>(ik)->get_fv_eigen_vectors(fv_evec);
4924 },
4925 error_code__);
4926}
4927
4928/*
4929@api begin
4930sirius_get_fv_eigen_values:
4931 doc: Get the first-variational eigen values
4932 arguments:
4933 handler:
4934 type: ks_handler
4935 attr: in, required
4936 doc: K-point set handler
4937 ik:
4938 type: int
4939 attr: in, required
4940 doc: Global index of the k-point
4941 fv_eval:
4942 type: double
4943 attr: out, required, dimension(:)
4944 doc: Output first-variational eigenvector array
4945 num_fv_states:
4946 type: int
4947 attr: in, required
4948 doc: Number of first-variational states
4949 error_code:
4950 type: int
4951 attr: out, optional
4952 doc: Error code
4953@api end
4954*/
4955void
4956sirius_get_fv_eigen_values(void* const* handler__, int const* ik__, double* fv_eval__, int const* num_fv_states__,
4957 int* error_code__)
4958{
4959 call_sirius(
4960 [&]() {
4961 auto& ks = get_ks(handler__);
4962 if (*num_fv_states__ != ks.ctx().num_fv_states()) {
4963 RTE_THROW("wrong number of first-variational states");
4964 }
4965 int ik = *ik__ - 1;
4966 for (int i = 0; i < *num_fv_states__; i++) {
4967 fv_eval__[i] = ks.get<double>(ik)->fv_eigen_value(i);
4968 }
4969 },
4970 error_code__);
4971}
4972
4973/*
4974@api begin
4975sirius_get_sv_eigen_vectors:
4976 doc: Get the second-variational eigen vectors
4977 arguments:
4978 handler:
4979 type: ks_handler
4980 attr: in, required
4981 doc: K-point set handler
4982 ik:
4983 type: int
4984 attr: in, required
4985 doc: Global index of the k-point
4986 sv_evec:
4987 type: complex
4988 attr: out, required, dimension(:,:)
4989 doc: Output second-variational eigenvector array
4990 num_bands:
4991 type: int
4992 attr: in, required
4993 doc: Number of second-variational bands.
4994 error_code:
4995 type: int
4996 attr: out, optional
4997 doc: Error code
4998@api end
4999*/
5000void
5001sirius_get_sv_eigen_vectors(void* const* handler__, int const* ik__, std::complex<double>* sv_evec__,
5002 int const* num_bands__, int* error_code__)
5003{
5004 call_sirius(
5005 [&]() {
5006 auto& ks = get_ks(handler__);
5007 sddk::mdarray<std::complex<double>, 2> sv_evec(sv_evec__, *num_bands__, *num_bands__);
5008 int ik = *ik__ - 1;
5009 ks.get<double>(ik)->get_sv_eigen_vectors(sv_evec);
5010 },
5011 error_code__);
5012}
5013
5014/*
5015@api begin
5016sirius_set_rg_values:
5017 doc: Set the values of the function on the regular grid.
5018 arguments:
5019 handler:
5020 type: gs_handler
5021 attr: in, required
5022 doc: DFT ground state handler.
5023 label:
5024 type: string
5025 attr: in, required
5026 doc: Label of the function.
5027 grid_dims:
5028 type: int
5029 attr: in, required, dimension(3)
5030 doc: Dimensions of the FFT grid.
5031 local_box_origin:
5032 type: int
5033 attr: in, required, dimension(:,:)
5034 doc: Coordinates of the local box origin for each MPI rank
5035 local_box_size:
5036 type: int
5037 attr: in, required, dimension(:,:)
5038 doc: Dimensions of the local box for each MPI rank.
5039 fcomm:
5040 type: int
5041 attr: in, required
5042 doc: Fortran communicator used to partition FFT grid into local boxes.
5043 values:
5044 type: double
5045 attr: in, required
5046 doc: Values of the function (local buffer for each MPI rank).
5047 transform_to_pw:
5048 type: bool
5049 attr: in, optional
5050 doc: If true, transform function to PW domain.
5051 error_code:
5052 type: int
5053 attr: out, optional
5054 doc: Error code
5055@api end
5056*/
5057void
5058sirius_set_rg_values(void* const* handler__, char const* label__, int const* grid_dims__, int const* local_box_origin__,
5059 int const* local_box_size__, int const* fcomm__, double const* values__,
5060 bool const* transform_to_pw__, int* error_code__)
5061{
5062 PROFILE("sirius_api::sirius_set_rg_values");
5063
5064 call_sirius(
5065 [&]() {
5066 auto& gs = get_gs(handler__);
5067
5068 std::string label(label__);
5069
5070 for (int x : {0, 1, 2}) {
5071 if (grid_dims__[x] != gs.ctx().fft_grid()[x]) {
5072 std::stringstream s;
5073 s << "wrong FFT grid size\n"
5074 " SIRIUS internal: "
5075 << gs.ctx().fft_grid()[0] << " " << gs.ctx().fft_grid()[1] << " " << gs.ctx().fft_grid()[2]
5076 << "\n"
5077 " host code: "
5078 << grid_dims__[0] << " " << grid_dims__[1] << " " << grid_dims__[2];
5079 RTE_THROW(s);
5080 }
5081 }
5082
5083 std::map<std::string, sirius::Smooth_periodic_function<double>*> func = {
5084 {"rho", &gs.density().rho().rg()},
5085 {"magz", &gs.density().mag(0).rg()},
5086 {"magx", &gs.density().mag(1).rg()},
5087 {"magy", &gs.density().mag(2).rg()},
5088 {"veff", &gs.potential().effective_potential().rg()},
5089 {"bz", &gs.potential().effective_magnetic_field(0).rg()},
5090 {"bx", &gs.potential().effective_magnetic_field(1).rg()},
5091 {"by", &gs.potential().effective_magnetic_field(2).rg()},
5092 {"vxc", &gs.potential().xc_potential().rg()},
5093 };
5094 if (!func.count(label)) {
5095 RTE_THROW("wrong label: " + label);
5096 }
5097
5098 auto& f = func.at(label);
5099
5100 auto& comm = mpi::Communicator::map_fcomm(*fcomm__);
5101
5102 sddk::mdarray<int, 2> local_box_size(const_cast<int*>(local_box_size__), 3, comm.size());
5103 sddk::mdarray<int, 2> local_box_origin(const_cast<int*>(local_box_origin__), 3, comm.size());
5104
5105 for (int rank = 0; rank < comm.size(); rank++) {
5106 /* dimensions of this rank's local box */
5107 int nx = local_box_size(0, rank);
5108 int ny = local_box_size(1, rank);
5109 int nz = local_box_size(2, rank);
5110
5111 sddk::mdarray<double, 3> buf(nx, ny, nz);
5112 /* if this is that rank's turn to broadcast */
5113 if (comm.rank() == rank) {
5114 /* copy values to buf */
5115 std::copy(values__, values__ + nx * ny * nz, &buf[0]);
5116 }
5117 /* send a copy of local box to all ranks */
5118 comm.bcast(&buf[0], nx * ny * nz, rank);
5119
5120 for (int iz = 0; iz < nz; iz++) {
5121 /* global z coordinate inside FFT box */
5122 int z = local_box_origin(2, rank) + iz - 1; /* Fortran counts from 1 */
5123 /* each rank on SIRIUS side, for which this condition is fulfilled copies data from the local box */
5124 if (z >= gs.ctx().spfft<double>().local_z_offset() &&
5125 z < gs.ctx().spfft<double>().local_z_offset() + gs.ctx().spfft<double>().local_z_length()) {
5126 /* make z local for SIRIUS FFT partitioning */
5127 z -= gs.ctx().spfft<double>().local_z_offset();
5128 for (int iy = 0; iy < ny; iy++) {
5129 /* global y coordinate inside FFT box */
5130 int y = local_box_origin(1, rank) + iy - 1; /* Fortran counts from 1 */
5131 for (int ix = 0; ix < nx; ix++) {
5132 /* global x coordinate inside FFT box */
5133 int x = local_box_origin(0, rank) + ix - 1; /* Fortran counts from 1 */
5134 f->value(gs.ctx().fft_grid().index_by_coord(x, y, z)) = buf(ix, iy, iz);
5135 }
5136 }
5137 }
5138 }
5139 } /* loop over ranks */
5140 if (transform_to_pw__ && *transform_to_pw__) {
5141 f->fft_transform(-1);
5142 }
5143 },
5144 error_code__);
5145}
5146
5147/*
5148@api begin
5149sirius_get_rg_values:
5150 doc: Get the values of the function on the regular grid.
5151 arguments:
5152 handler:
5153 type: gs_handler
5154 attr: in, required
5155 doc: DFT ground state handler.
5156 label:
5157 type: string
5158 attr: in, required
5159 doc: Label of the function.
5160 grid_dims:
5161 type: int
5162 attr: in, required, dimensions(3)
5163 doc: Dimensions of the FFT grid.
5164 local_box_origin:
5165 type: int
5166 attr: in, required, dimensions(:,:)
5167 doc: Coordinates of the local box origin for each MPI rank
5168 local_box_size:
5169 type: int
5170 attr: in, required, dimensions(:,:)
5171 doc: Dimensions of the local box for each MPI rank.
5172 fcomm:
5173 type: int
5174 attr: in, required
5175 doc: Fortran communicator used to partition FFT grid into local boxes.
5176 values:
5177 type: double
5178 attr: out, required
5179 doc: Values of the function (local buffer for each MPI rank).
5180 transform_to_rg:
5181 type: bool
5182 attr: in, optional
5183 doc: If true, transform function to regular grid before fetching the values.
5184 error_code:
5185 type: int
5186 attr: out, optional
5187 doc: Error code
5188@api end
5189*/
5190void
5191sirius_get_rg_values(void* const* handler__, char const* label__, int const* grid_dims__, int const* local_box_origin__,
5192 int const* local_box_size__, int const* fcomm__, double* values__, bool const* transform_to_rg__,
5193 int* error_code__)
5194{
5195 PROFILE("sirius_api::sirius_get_rg_values");
5196
5197 call_sirius(
5198 [&]() {
5199 auto& gs = get_gs(handler__);
5200
5201 std::string label(label__);
5202
5203 for (int x : {0, 1, 2}) {
5204 if (grid_dims__[x] != gs.ctx().fft_grid()[x]) {
5205 RTE_THROW("wrong FFT grid size");
5206 }
5207 }
5208
5209 std::map<std::string, sirius::Smooth_periodic_function<double>*> func = {
5210 {"rho", &gs.density().rho().rg()},
5211 {"magz", &gs.density().mag(0).rg()},
5212 {"magx", &gs.density().mag(1).rg()},
5213 {"magy", &gs.density().mag(2).rg()},
5214 {"veff", &gs.potential().effective_potential().rg()},
5215 {"bz", &gs.potential().effective_magnetic_field(0).rg()},
5216 {"bx", &gs.potential().effective_magnetic_field(1).rg()},
5217 {"by", &gs.potential().effective_magnetic_field(2).rg()},
5218 {"vxc", &gs.potential().xc_potential().rg()},
5219 };
5220
5221 if (!func.count(label)) {
5222 RTE_THROW("wrong label: " + label);
5223 }
5224
5225 auto& f = func.at(label);
5226
5227 auto& comm = mpi::Communicator::map_fcomm(*fcomm__);
5228
5229 if (transform_to_rg__ && *transform_to_rg__) {
5230 f->fft_transform(1);
5231 }
5232
5233 auto& fft_comm = gs.ctx().comm_fft();
5234 auto spl_z = fft::split_z_dimension(gs.ctx().fft_grid()[2], fft_comm);
5235
5236 sddk::mdarray<int, 2> local_box_size(const_cast<int*>(local_box_size__), 3, comm.size());
5237 sddk::mdarray<int, 2> local_box_origin(const_cast<int*>(local_box_origin__), 3, comm.size());
5238
5239 for (int rank = 0; rank < fft_comm.size(); rank++) {
5240 /* slab of FFT grid for a given rank */
5241 sddk::mdarray<double, 3> buf(f->spfft().dim_x(), f->spfft().dim_y(), spl_z.local_size(block_id(rank)));
5242 if (rank == fft_comm.rank()) {
5243 std::copy(&f->value(0), &f->value(0) + f->spfft().local_slice_size(), &buf[0]);
5244 }
5245 fft_comm.bcast(&buf[0], static_cast<int>(buf.size()), rank);
5246
5247 /* ranks on the F90 side */
5248 int r = comm.rank();
5249
5250 /* dimensions of this rank's local box */
5251 int nx = local_box_size(0, r);
5252 int ny = local_box_size(1, r);
5253 int nz = local_box_size(2, r);
5254 sddk::mdarray<double, 3> values(values__, nx, ny, nz);
5255
5256 for (int iz = 0; iz < nz; iz++) {
5257 /* global z coordinate inside FFT box */
5258 int z = local_box_origin(2, r) + iz - 1; /* Fortran counts from 1 */
5259 if (z >= spl_z.global_offset(block_id(rank)) && z < spl_z.global_offset(block_id(rank)) +
5260 spl_z.local_size(block_id(rank))) {
5261 /* make z local for SIRIUS FFT partitioning */
5262 z -= spl_z.global_offset(block_id(rank));
5263 for (int iy = 0; iy < ny; iy++) {
5264 /* global y coordinate inside FFT box */
5265 int y = local_box_origin(1, r) + iy - 1; /* Fortran counts from 1 */
5266 for (int ix = 0; ix < nx; ix++) {
5267 /* global x coordinate inside FFT box */
5268 int x = local_box_origin(0, r) + ix - 1; /* Fortran counts from 1 */
5269 values(ix, iy, iz) = buf(x, y, z);
5270 }
5271 }
5272 }
5273 }
5274 } /* loop over ranks */
5275 },
5276 error_code__);
5277}
5278
5279/*
5280@api begin
5281sirius_get_total_magnetization:
5282 doc: Get the total magnetization of the system.
5283 arguments:
5284 handler:
5285 type: gs_handler
5286 attr: in, required
5287 doc: DFT ground state handler.
5288 mag:
5289 type: double
5290 attr: out, required
5291 doc: 3D magnetization vector (x,y,z components).
5292 error_code:
5293 type: int
5294 attr: out, optional
5295 doc: Error code
5296@api end
5297*/
5298void
5299sirius_get_total_magnetization(void* const* handler__, double* mag__, int* error_code__)
5300{
5301 call_sirius(
5302 [&]() {
5303 auto& gs = get_gs(handler__);
5304
5305 sddk::mdarray<double, 1> total_mag(mag__, 3);
5306 total_mag.zero();
5307 for (int j = 0; j < gs.ctx().num_mag_dims(); j++) {
5308 auto result = gs.density().mag(j).integrate();
5309 total_mag[j] = std::get<0>(result);
5310 }
5311 if (gs.ctx().num_mag_dims() == 3) {
5312 /* swap z and x and change order from z,x,y to x,z,y */
5313 std::swap(total_mag[0], total_mag[1]);
5314 /* swap z and y and change order x,z,y to x,y,z */
5315 std::swap(total_mag[1], total_mag[2]);
5316 }
5317 },
5318 error_code__);
5319}
5320
5321/*
5322@api begin
5323sirius_get_num_kpoints:
5324 doc: Get the total number of kpoints
5325 arguments:
5326 handler:
5327 type: ks_handler
5328 attr: in, required
5329 doc: Kpoint set handler
5330 num_kpoints:
5331 type: int
5332 attr: out, required
5333 doc: number of kpoints in the set
5334 error_code:
5335 type: int
5336 attr: out, optional
5337 doc: Error code.
5338@api end
5339*/
5340
5341void
5342sirius_get_num_kpoints(void* const* handler__, int* num_kpoints__, int* error_code__)
5343{
5344 call_sirius(
5345 [&]() {
5346 auto& ks = get_ks(handler__);
5347 *num_kpoints__ = ks.num_kpoints();
5348 },
5349 error_code__);
5350}
5351
5352/*
5353@api begin
5354sirius_get_kpoint_properties:
5355 doc: Get the kpoint properties
5356 arguments:
5357 handler:
5358 type: ks_handler
5359 attr: in, required
5360 doc: Kpoint set handler
5361 ik:
5362 type: int
5363 attr: in, required
5364 doc: Index of the kpoint
5365 weight:
5366 type: double
5367 attr: out, required
5368 doc: Weight of the kpoint
5369 coordinates:
5370 type: double
5371 attr: out, optional
5372 doc: Coordinates of the kpoint
5373 error_code:
5374 type: int
5375 attr: out, optional
5376 doc: Error code.
5377@api end
5378*/
5379void
5380sirius_get_kpoint_properties(void* const* handler__, int const* ik__, double* weight__, double* coordinates__,
5381 int* error_code__)
5382{
5383 call_sirius(
5384 [&]() {
5385 auto& ks = get_ks(handler__);
5386 int ik = *ik__ - 1;
5387 *weight__ = ks.get<double>(ik)->weight();
5388
5389 if (coordinates__) {
5390 coordinates__[0] = ks.get<double>(ik)->vk()[0];
5391 coordinates__[1] = ks.get<double>(ik)->vk()[1];
5392 coordinates__[2] = ks.get<double>(ik)->vk()[2];
5393 }
5394 },
5395 error_code__);
5396}
5397
5398/*
5399@api begin
5400sirius_set_callback_function:
5401 doc: Set callback function to compute various radial integrals.
5402 arguments:
5403 handler:
5404 type: ctx_handler
5405 attr: in, required
5406 doc: Simulation context handler.
5407 label:
5408 type: string
5409 attr: in, required
5410 doc: Lable of the callback function.
5411 fptr:
5412 type: func
5413 attr: in, required, value
5414 doc: Pointer to callback function.
5415 error_code:
5416 type: int
5417 attr: out, optional
5418 doc: Error code.
5419@api end
5420*/
5421void
5422sirius_set_callback_function(void* const* handler__, char const* label__, void (*fptr__)(), int* error_code__)
5423{
5424 call_sirius(
5425 [&]() {
5426 auto label = std::string(label__);
5427 std::transform(label.begin(), label.end(), label.begin(), ::tolower);
5428 auto& sim_ctx = get_sim_ctx(handler__);
5429 if (label == "beta_ri") {
5430 sim_ctx.cb().beta_ri_ = reinterpret_cast<void (*)(int, double, double*, int)>(fptr__);
5431 } else if (label == "beta_ri_djl") {
5432 sim_ctx.cb().beta_ri_djl_ = reinterpret_cast<void (*)(int, double, double*, int)>(fptr__);
5433 } else if (label == "aug_ri") {
5434 sim_ctx.cb().aug_ri_ = reinterpret_cast<void (*)(int, double, double*, int, int)>(fptr__);
5435 } else if (label == "aug_ri_djl") {
5436 sim_ctx.cb().aug_ri_djl_ = reinterpret_cast<void (*)(int, double, double*, int, int)>(fptr__);
5437 } else if (label == "vloc_ri") {
5438 sim_ctx.cb().vloc_ri_ = reinterpret_cast<void (*)(int, int, double*, double*)>(fptr__);
5439 } else if (label == "vloc_ri_djl") {
5440 sim_ctx.cb().vloc_ri_djl_ = reinterpret_cast<void (*)(int, int, double*, double*)>(fptr__);
5441 } else if (label == "rhoc_ri") {
5442 sim_ctx.cb().rhoc_ri_ = reinterpret_cast<void (*)(int, int, double*, double*)>(fptr__);
5443 } else if (label == "rhoc_ri_djl") {
5444 sim_ctx.cb().rhoc_ri_djl_ = reinterpret_cast<void (*)(int, int, double*, double*)>(fptr__);
5445 } else if (label == "band_occ") {
5446 sim_ctx.cb().band_occ_ = reinterpret_cast<void (*)(void)>(fptr__);
5447 } else if (label == "veff") {
5448 sim_ctx.cb().veff_ = reinterpret_cast<void (*)(void)>(fptr__);
5449 } else if (label == "ps_rho_ri") {
5450 sim_ctx.cb().ps_rho_ri_ = reinterpret_cast<void (*)(int, int, double*, double*)>(fptr__);
5451 } else if (label == "ps_atomic_wf_ri") {
5452 sim_ctx.cb().ps_atomic_wf_ri_ = reinterpret_cast<void (*)(int, double, double*, int)>(fptr__);
5453 } else if (label == "ps_atomic_wf_ri_djl") {
5454 sim_ctx.cb().ps_atomic_wf_ri_djl_ = reinterpret_cast<void (*)(int, double, double*, int)>(fptr__);
5455 } else {
5456 RTE_THROW("Wrong label of the callback function: " + label);
5457 }
5458 },
5459 error_code__);
5460}
5461
5462/*
5463@api begin
5464sirius_nlcg:
5465 doc: Robust wave function optimizer.
5466 arguments:
5467 handler:
5468 type: gs_handler
5469 attr: in, required
5470 doc: Ground state handler.
5471 ks_handler:
5472 type: ks_handler
5473 attr: in, required
5474 doc: K-point set handler.
5475 error_code:
5476 type: int
5477 attr: out, optional
5478 doc: Error code.
5479@api end
5480*/
5481
5482void
5483sirius_nlcg(void* const* handler__, void* const* ks_handler__, int* error_code__)
5484{
5485 call_sirius(
5486 [&]() {
5487#if defined(SIRIUS_NLCGLIB)
5488 // call nlcg solver
5489 auto& gs = get_gs(handler__);
5490 auto& potential = gs.potential();
5491 auto& density = gs.density();
5492
5493 auto& kset = get_ks(ks_handler__);
5494 auto& ctx = kset.ctx();
5495
5496 auto nlcg_params = ctx.cfg().nlcg();
5497 double temp = nlcg_params.T();
5498 double tol = nlcg_params.tol();
5499 double kappa = nlcg_params.kappa();
5500 double tau = nlcg_params.tau();
5501 int maxiter = nlcg_params.maxiter();
5502 int restart = nlcg_params.restart();
5503 std::string smear = ctx.cfg().parameters().smearing();
5504 std::string pu = ctx.cfg().control().processing_unit();
5505
5506 nlcglib::smearing_type smearing;
5507 if (smear.compare("FD") == 0) {
5508 smearing = nlcglib::smearing_type::FERMI_DIRAC;
5509 } else if (smear.compare("GS") == 0) {
5510 smearing = nlcglib::smearing_type::GAUSSIAN_SPLINE;
5511 } else {
5512 RTE_THROW("invalid smearing type given: " + smear);
5513 }
5514
5515 sirius::Energy energy(kset, density, potential);
5516 if (is_device_memory(ctx.processing_unit_memory_t())) {
5517 if (pu.empty() || pu.compare("gpu") == 0) {
5518 nlcglib::nlcg_mvp2_device(energy, smearing, temp, tol, kappa, tau, maxiter, restart);
5519 } else if (pu.compare("cpu") == 0) {
5520 nlcglib::nlcg_mvp2_device_cpu(energy, smearing, temp, tol, kappa, tau, maxiter, restart);
5521 } else {
5522 RTE_THROW("invalid processing unit for nlcg given: " + pu);
5523 }
5524 } else {
5525 if (pu.empty() || pu.compare("gpu") == 0) {
5526 nlcglib::nlcg_mvp2_cpu(energy, smearing, temp, tol, kappa, tau, maxiter, restart);
5527 } else if (pu.compare("cpu") == 0) {
5528 nlcglib::nlcg_mvp2_cpu_device(energy, smearing, temp, tol, kappa, tau, maxiter, restart);
5529 } else {
5530 RTE_THROW("invalid processing unit for nlcg given: " + pu);
5531 }
5532 }
5533#else
5534 RTE_THROW("SIRIUS was not compiled with NLCG option.");
5535#endif
5536 },
5537 error_code__);
5538}
5539
5540/*
5541@api begin
5542sirius_nlcg_params:
5543 doc: Robust wave function optimizer
5544 arguments:
5545 handler:
5546 type: gs_handler
5547 attr: in, required
5548 doc: Ground state handler.
5549 ks_handler:
5550 type: ks_handler
5551 attr: in, required
5552 doc: K-point set handler.
5553 temp:
5554 type: double
5555 attr: in, required
5556 doc: Temperature in Kelvin
5557 smearing:
5558 type: string
5559 attr: in, required
5560 doc: smearing label
5561 kappa:
5562 type: double
5563 attr: in, required
5564 doc: pseudo-Hamiltonian scalar preconditioner
5565 tau:
5566 type: double
5567 attr: in, required
5568 doc: backtracking search reduction parameter
5569 tol:
5570 type: double
5571 attr: in, required
5572 doc: CG tolerance
5573 maxiter:
5574 type: int
5575 attr: in, required
5576 doc: CG maxiter
5577 restart:
5578 type: int
5579 attr: in, required
5580 doc: CG restart
5581 processing_unit:
5582 type: string
5583 attr: in, required
5584 doc: processing_unit = ["cpu"|"gpu"|"none"]
5585 converged:
5586 type: bool
5587 attr: out, required
5588 doc: Boolean variable indicating if the calculation has converged
5589 doc:
5590 error_code:
5591 type: int
5592 attr: out, optional
5593 doc: Error code.
5594@api end
5595*/
5596
5597void
5598sirius_nlcg_params(void* const* handler__, void* const* ks_handler__, double const* temp__, char const* smearing__,
5599 double const* kappa__, double const* tau__, double const* tol__, int const* maxiter__,
5600 int const* restart__, char const* processing_unit__, bool* converged__, int* error_code__)
5601{
5602 call_sirius(
5603 [&]() {
5604#if defined(SIRIUS_NLCGLIB)
5605 PROFILE("sirius::nlcglib");
5606 // call nlcg solver
5607 auto& gs = get_gs(handler__);
5608 auto& potential = gs.potential();
5609 auto& density = gs.density();
5610
5611 auto& kset = get_ks(ks_handler__);
5612 auto& ctx = kset.ctx();
5613
5614 double temp = *temp__;
5615 double kappa = *kappa__;
5616 double tau = *tau__;
5617 double tol = *tol__;
5618 int maxiter = *maxiter__;
5619 int restart = *restart__;
5620
5621 std::string smear(smearing__);
5622 std::string pu(processing_unit__);
5623
5624 sddk::device_t processing_unit{ctx.processing_unit()};
5625
5626 if (pu.compare("none") != 0) {
5627 processing_unit = sddk::get_device_t(pu);
5628 }
5629
5630 nlcglib::smearing_type smearing_t;
5631 if (smear.compare("FD") == 0) {
5632 smearing_t = nlcglib::smearing_type::FERMI_DIRAC;
5633 } else if (smear.compare("GS") == 0) {
5634 smearing_t = nlcglib::smearing_type::GAUSSIAN_SPLINE;
5635 } else if (smear.compare("GAUSS") == 0) {
5636 smearing_t = nlcglib::smearing_type::GAUSS;
5637 } else if (smear.compare("MP") == 0) {
5638 smearing_t = nlcglib::smearing_type::METHFESSEL_PAXTON;
5639 } else if (smear.compare("COLD") == 0) {
5640 smearing_t = nlcglib::smearing_type::COLD;
5641 } else {
5642 RTE_THROW("invalid smearing type given: " + smear);
5643 }
5644
5645 if (pu.compare("none") == 0) {
5646 // use same processing unit as SIRIUS
5647 pu = ctx.cfg().control().processing_unit();
5648 }
5649
5650 sirius::Energy energy(kset, density, potential);
5651
5652 sirius::Hamiltonian0<double> H0(potential, false);
5653
5654 sirius::UltrasoftPrecond us_precond(kset, ctx, H0.Q());
5655 sirius::Overlap_operators<sirius::S_k<std::complex<double>>> S(kset, ctx, H0.Q());
5656
5657 // ultrasoft pp
5658 nlcglib::nlcg_info info;
5659 switch (processing_unit) {
5660 case sddk::device_t::CPU: {
5661 info = nlcglib::nlcg_us_cpu(energy, us_precond, S, smearing_t, temp, tol, kappa, tau, maxiter, restart);
5662 break;
5663 }
5664 case sddk::device_t::GPU: {
5665 info = nlcglib::nlcg_us_device(energy, us_precond, S, smearing_t, temp, tol, kappa, tau, maxiter, restart);
5666 break;
5667 }
5668 }
5669
5670 // return exit state of nlcglib to QE
5671 *converged__ = info.converged;
5672#else /* SIRIUS_NLCGLIB */
5673 RTE_THROW("SIRIUS was not compiled with NLCG option.");
5674#endif /* SIRIUS_NLCGLIB */
5675 },
5676 error_code__);
5677}
5678
5679
5680/*
5681@api begin
5682sirius_add_hubbard_atom_pair:
5683 doc: Add a non-local Hubbard interaction V for a pair of atoms.
5684 arguments:
5685 handler:
5686 type: ctx_handler
5687 attr: in, required
5688 doc: Simulation context handler.
5689 atom_pair:
5690 type: int
5691 attr: in, required, dimension(2)
5692 doc: atom pair for the V term
5693 translation:
5694 type: int
5695 attr: in, required, dimension(3)
5696 doc: translation vector between the two unit cells containing the atoms
5697 n:
5698 type: int
5699 attr: in, required, dimension(2)
5700 doc: principal quantum number of the atomic levels involved in the V correction
5701 l:
5702 type: int
5703 attr: in, required, dimension(2)
5704 doc: angular momentum of the atomic levels
5705 coupling:
5706 type: double
5707 attr: in, required
5708 doc: value of the V constant
5709 error_code:
5710 type: int
5711 attr: out, optional
5712 doc: Error code.
5713@api end
5714*/
5715void
5716sirius_add_hubbard_atom_pair(void* const* handler__, int* const atom_pair__, int* const translation__, int* const n__,
5717 int* const l__, const double* const coupling__, int *error_code__)
5718{
5719 call_sirius(
5720 [&]() {
5721 auto& sim_ctx = get_sim_ctx(handler__);
5722 auto conf_dict = sim_ctx.cfg().hubbard();
5723
5724 json elem;
5725 std::vector<int> atom_pair(atom_pair__, atom_pair__ + 2);
5726 /* Fortran indices start from 1 */
5727 atom_pair[0] -= 1;
5728 atom_pair[1] -= 1;
5729 std::vector<int> n(n__, n__ + 2);
5730 std::vector<int> l(l__, l__ + 2);
5731 std::vector<int> translation(translation__, translation__ + 3);
5732
5733 elem["atom_pair"] = atom_pair;
5734 elem["T"] = translation;
5735 elem["n"] = n;
5736 elem["l"] = l;
5737 elem["V"] = *coupling__;
5738
5739 bool test{false};
5740
5741 auto v = conf_dict.nonlocal();
5742
5743 for (int idx = 0; idx < v.size(); idx++) {
5744 auto v = conf_dict.nonlocal(idx);
5745 auto at_pr = v.atom_pair();
5746 /* search if the pair is already present */
5747 if ((at_pr[0] == atom_pair[0]) && (at_pr[1] == atom_pair[1])) {
5748 auto tr = v.T();
5749 if ((tr[0] = translation[0]) && (tr[1] = translation[1]) && (tr[2] = translation[2])) {
5750 auto lvl = v.n();
5751 if ((lvl[0] == n[0]) && (lvl[0] == n[1])) {
5752 auto li = v.l();
5753 if ((li[0] == l[0]) && (li[1] == l[1])) {
5754 test = true;
5755 break;
5756 }
5757 }
5758 }
5759 }
5760 }
5761
5762 if (!test) {
5763 conf_dict.nonlocal().append(elem);
5764 } else {
5765 RTE_THROW("Atom pair for hubbard correction is already present");
5766 }
5767 }
5768 , error_code__);
5769}
5770
5771/*
5772@api begin
5773sirius_create_H0:
5774 doc: Generate H0.
5775 arguments:
5776 handler:
5777 type: gs_handler
5778 attr: in, required
5779 doc: Ground state handler.
5780 error_code:
5781 type: int
5782 attr: out, optional
5783 doc: Error code
5784@api end
5785*/
5786void sirius_create_H0(void* const* handler__, int* error_code__)
5787{
5788 call_sirius(
5789 [&]() {
5790 auto& gs = get_gs(handler__);
5791 gs.create_H0();
5792 }, error_code__);
5793}
5794
5795/*
5796@api begin
5797sirius_linear_solver:
5798 doc: Interface to linear solver.
5799 arguments:
5800 handler:
5801 type: gs_handler
5802 attr: in, required
5803 doc: DFT ground state handler.
5804 vkq:
5805 type: double
5806 attr: in, required, dimension(3)
5807 doc: K+q-point in lattice coordinates
5808 num_gvec_kq_loc:
5809 type: int
5810 attr: in, required
5811 doc: Local number of G-vectors for k+q-point
5812 gvec_kq_loc:
5813 type: int
5814 attr: in, required, dimension(3, num_gvec_kq_loc)
5815 doc: Local list of G-vectors for k+q-point.
5816 dpsi:
5817 type: complex
5818 attr: inout, required, dimension(ld, num_spin_comp)
5819 doc: Left-hand side of the linear equation.
5820 psi:
5821 type: complex
5822 attr: in, required, dimension(ld, num_spin_comp)
5823 doc: Unperturbed eigenvectors.
5824 eigvals:
5825 type: double
5826 attr: in, required, dimension(*)
5827 doc: Unperturbed eigenvalues.
5828 dvpsi:
5829 type: complex
5830 attr: inout, required, dimension(ld, num_spin_comp)
5831 doc: Right-hand side of the linear equation (dV * psi)
5832 ld:
5833 type: int
5834 attr: in, required
5835 doc: Leading dimension of dpsi, psi, dvpsi.
5836 num_spin_comp:
5837 type: int
5838 attr: in, required
5839 doc: Number of spin components.
5840 alpha_pv:
5841 type: double
5842 attr: in, required
5843 doc: Constant for the projector.
5844 spin:
5845 type: int
5846 attr: in, required
5847 doc: Current spin channel.
5848 nbnd_occ:
5849 type: int
5850 attr: in, required
5851 doc: Number of occupied bands.
5852 tol:
5853 type: double
5854 attr: in, required
5855 doc: Tolerance for the unconverged residuals (residual L2-norm should be below this value).
5856 niter:
5857 type: int
5858 attr: out, required
5859 doc: Average number of iterations.
5860 error_code:
5861 type: int
5862 attr: out, optional
5863 doc: Error code
5864@api end
5865*/
5866void sirius_linear_solver(void* const* handler__, double const* vkq__, int const* num_gvec_kq_loc__,
5867 int const* gvec_kq_loc__, std::complex<double>* dpsi__, std::complex<double> * psi__, double* eigvals__,
5868 std::complex<double>* dvpsi__, int const* ld__, int const* num_spin_comp__, double const * alpha_pv__,
5869 int const* spin__, int const* nbnd_occ__, double const* tol__, int* niter__, int* error_code__)
5870{
5871 using namespace sirius;
5872 PROFILE("sirius_api::sirius_linear_solver");
5873 call_sirius(
5874 [&]() {
5875 /* works for non-magnetic and collinear cases */
5876 RTE_ASSERT(*num_spin_comp__ == 1);
5877
5878 int nbnd_occ = *nbnd_occ__;
5879
5880 if (nbnd_occ == 0) {
5881 return;
5882 }
5883
5884 auto& gs = get_gs(handler__);
5885 auto& sctx = gs.ctx();
5886
5887 wf::spin_range sr(0);
5888 if (sctx.num_mag_dims() == 1) {
5889 if (!(*spin__ == 1 || *spin__ == 2)) {
5890 RTE_THROW("wrong spin channel");
5891 }
5892 sr = wf::spin_range(*spin__ - 1);
5893 }
5894
5895 std::shared_ptr<fft::Gvec> gvkq_in;
5896 gvkq_in = std::make_shared<fft::Gvec>(r3::vector<double>(vkq__),
5897 sctx.unit_cell().reciprocal_lattice_vectors(), *num_gvec_kq_loc__, gvec_kq_loc__,
5898 sctx.comm_band(), false);
5899
5900 int num_gvec_kq_loc = *num_gvec_kq_loc__;
5901 int num_gvec_kq = num_gvec_kq_loc;
5902 sctx.comm_band().allreduce(&num_gvec_kq, 1);
5903
5904 if (num_gvec_kq != gvkq_in->num_gvec()) {
5905 RTE_THROW("wrong number of G+k vectors for k");
5906 }
5907
5908 auto& H0 = gs.get_H0();
5909
5910 sirius::K_point<double> kp(const_cast<sirius::Simulation_context&>(sctx), gvkq_in, 1.0);
5911 kp.initialize();
5912
5913 auto Hk = H0(kp);
5914
5915 /* copy eigenvalues (factor 2 for rydberg/hartree) */
5916 std::vector<double> eigvals_vec(eigvals__, eigvals__ + nbnd_occ);
5917 for (auto &val : eigvals_vec) {
5918 val /= 2;
5919 }
5920
5921 // Setup dpsi (unknown), psi (part of projector), and dvpsi (right-hand side)
5922 sddk::mdarray<std::complex<double>, 3> psi(psi__, *ld__, *num_spin_comp__, nbnd_occ);
5923 sddk::mdarray<std::complex<double>, 3> dpsi(dpsi__, *ld__, *num_spin_comp__, nbnd_occ);
5924 sddk::mdarray<std::complex<double>, 3> dvpsi(dvpsi__, *ld__, *num_spin_comp__, nbnd_occ);
5925
5926 auto dpsi_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5927 auto psi_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5928 auto dvpsi_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5929 auto tmp_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5930
5931 for (int ispn = 0; ispn < *num_spin_comp__; ispn++) {
5932 for (int i = 0; i < nbnd_occ; i++) {
5933 for (int ig = 0; ig < kp.gkvec().count(); ig++) {
5934 psi_wf->pw_coeffs(ig, wf::spin_index(ispn), wf::band_index(i)) = psi(ig, ispn, i);
5935 dpsi_wf->pw_coeffs(ig, wf::spin_index(ispn), wf::band_index(i)) = dpsi(ig, ispn, i);
5936 // divide by two to account for hartree / rydberg, this is
5937 // dv * psi and dv should be 2x smaller in sirius.
5938 dvpsi_wf->pw_coeffs(ig, wf::spin_index(ispn), wf::band_index(i)) = dvpsi(ig, ispn, i) / 2.0;
5939 }
5940 }
5941 }
5942
5943 /* check residuals H|psi> - e * S |psi> */
5944 if (sctx.cfg().control().verification() >= 1) {
5945 sirius::K_point<double> kp(const_cast<sirius::Simulation_context&>(sctx), gvkq_in, 1.0);
5946 kp.initialize();
5947 auto Hk = H0(kp);
5948 sirius::check_wave_functions<double, std::complex<double>>(Hk, *psi_wf, sr, wf::band_range(0, nbnd_occ),
5949 eigvals_vec.data());
5950 }
5951
5952 /* setup auxiliary state vectors for CG */
5953 auto U = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5954 auto C = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5955
5956 auto Hphi_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5957 auto Sphi_wf = sirius::wave_function_factory<double>(sctx, kp, wf::num_bands(nbnd_occ), wf::num_mag_dims(0), false);
5958
5959 auto mem = sctx.processing_unit_memory_t();
5960
5961 std::vector<wf::device_memory_guard> mg;
5962
5963 mg.emplace_back(psi_wf->memory_guard(mem, wf::copy_to::device));
5964 mg.emplace_back(dpsi_wf->memory_guard(mem, wf::copy_to::device | wf::copy_to::host));
5965 mg.emplace_back(dvpsi_wf->memory_guard(mem, wf::copy_to::device));
5966 mg.emplace_back(tmp_wf->memory_guard(mem, wf::copy_to::device));
5967
5968 mg.emplace_back(U->memory_guard(mem, wf::copy_to::device));
5969 mg.emplace_back(C->memory_guard(mem, wf::copy_to::device));
5970 mg.emplace_back(Hphi_wf->memory_guard(mem, wf::copy_to::device));
5971 mg.emplace_back(Sphi_wf->memory_guard(mem, wf::copy_to::device));
5972
5974 const_cast<sirius::Simulation_context&>(sctx),
5975 Hk,
5976 eigvals_vec,
5977 Hphi_wf.get(),
5978 Sphi_wf.get(),
5979 psi_wf.get(),
5980 tmp_wf.get(),
5981 *alpha_pv__ / 2, // rydberg/hartree factor
5982 wf::band_range(0, nbnd_occ),
5983 sr,
5984 mem);
5985 /* CG state vectors */
5986 auto X_wrap = sirius::lr::Wave_functions_wrap{dpsi_wf.get(), mem};
5987 auto B_wrap = sirius::lr::Wave_functions_wrap{dvpsi_wf.get(), mem};
5988 auto U_wrap = sirius::lr::Wave_functions_wrap{U.get(), mem};
5989 auto C_wrap = sirius::lr::Wave_functions_wrap{C.get(), mem};
5990
5991 /* set up the diagonal preconditioner */
5992 auto h_o_diag = Hk.get_h_o_diag_pw<double, 3>(); // already on the GPU if mem=GPU
5993 sddk::mdarray<double, 1> eigvals_mdarray(eigvals_vec.size());
5994 eigvals_mdarray = [&](sddk::mdarray_index_descriptor::index_type i) {
5995 return eigvals_vec[i];
5996 };
5997 /* allocate and copy eigvals_mdarray to GPU if running on GPU */
5998 if (is_device_memory(mem)) {
5999 eigvals_mdarray.allocate(mem).copy_to(mem);
6000 }
6001
6003 std::move(h_o_diag.first),
6004 std::move(h_o_diag.second),
6005 std::move(eigvals_mdarray),
6006 nbnd_occ,
6007 mem,
6008 sr
6009 };
6010
6011 // Identity_preconditioner preconditioner{static_cast<size_t>(nbnd_occ)};
6012
6013 auto result = sirius::cg::multi_cg(
6014 linear_operator,
6015 preconditioner,
6016 X_wrap, B_wrap, U_wrap, C_wrap, // state vectors
6017 100, // iters
6018 *tol__);
6019
6020 *niter__ = result.niter_eff;
6021
6022 mg.clear();
6023
6024 /* bring wave functions back in order of QE */
6025 for (int ispn = 0; ispn < *num_spin_comp__; ispn++) {
6026 for (int i = 0; i < nbnd_occ; i++) {
6027 for (int ig = 0; ig < kp.gkvec().count(); ig++) {
6028 dpsi(ig, ispn, i) = dpsi_wf->pw_coeffs(ig, wf::spin_index(ispn), wf::band_index(i));
6029 }
6030 }
6031 }
6032
6033 }, error_code__);
6034}
6035
6036/*
6037@api begin
6038sirius_generate_d_operator_matrix:
6039 doc: Generate D-operator matrix.
6040 arguments:
6041 handler:
6042 type: gs_handler
6043 attr: in, required
6044 doc: Ground state handler.
6045 error_code:
6046 type: int
6047 attr: out, optional
6048 doc: Error code
6049@api end
6050*/
6051void sirius_generate_d_operator_matrix(void* const* handler__, int* error_code__)
6052{
6053 call_sirius(
6054 [&]() {
6055 auto& gs = get_gs(handler__);
6056 gs.potential().generate_D_operator_matrix();
6057 }, error_code__);
6058}
6059
6060/*
6061@api begin
6062sirius_save_state:
6063 doc: Save DFT ground state (density and potential)
6064 arguments:
6065 gs_handler:
6066 type: gs_handler
6067 attr: in, required
6068 doc: Ground-state handler.
6069 file_name:
6070 type: string
6071 attr: in, required
6072 doc: Name of the file that stores the saved data.
6073 error_code:
6074 type: int
6075 attr: out, optional
6076 doc: Error code
6077@api end
6078*/
6079void
6080sirius_save_state(void** handler__, const char* file_name__, int* error_code__)
6081{
6082 call_sirius(
6083 [&]() {
6084 auto& gs = get_gs(handler__);
6085 std::string file_name(file_name__);
6086 gs.ctx().create_storage_file(file_name);
6087 gs.potential().save(file_name);
6088 gs.density().save(file_name);
6089 },
6090 error_code__);
6091}
6092
6093/*
6094@api begin
6095sirius_load_state:
6096 doc: Save DFT ground state (density and potential)
6097 arguments:
6098 handler:
6099 type: gs_handler
6100 attr: in, required
6101 doc: Ground-state handler.
6102 file_name:
6103 type: string
6104 attr: in, required
6105 doc: Name of the file that stores the saved data.
6106 error_code:
6107 type: int
6108 attr: out, optional
6109 doc: Error code
6110@api end
6111*/
6112void
6113sirius_load_state(void** handler__, const char* file_name__, int* error_code__)
6114{
6115 call_sirius(
6116 [&]() {
6117 auto& gs = get_gs(handler__);
6118 std::string file_name(file_name__);
6119 gs.potential().load(file_name);
6120 gs.density().load(file_name);
6121 },
6122 error_code__);
6123}
6124
6125/*
6126@api begin
6127sirius_set_density_matrix:
6128 doc: Set density matrix.
6129 arguments:
6130 handler:
6131 type: gs_handler
6132 attr: in, required
6133 doc: Ground-state handler.
6134 ia:
6135 type: int
6136 attr: in, required
6137 doc: Index of atom.
6138 dm:
6139 type: complex
6140 attr: in, required, dimension(ld, ld, 3)
6141 doc: Input density matrix.
6142 ld:
6143 type: int
6144 attr: in, required
6145 doc: Leading dimension of the density matrix.
6146 error_code:
6147 type: int
6148 attr: out, optional
6149 doc: Error code.
6150@api end
6151*/
6152void
6153sirius_set_density_matrix(void** handler__, int const* ia__, std::complex<double>* dm__, int const* ld__, int* error_code__)
6154{
6155 call_sirius(
6156 [&]() {
6157 auto& gs = get_gs(handler__);
6158 sddk::mdarray<std::complex<double>, 3> dm(dm__, *ld__, *ld__, 3);
6159 int ia = *ia__ - 1;
6160 auto& atom = gs.ctx().unit_cell().atom(ia);
6161 auto idx_map = atomic_orbital_index_map_QE(atom.type());
6162 int nbf = atom.mt_basis_size();
6163 RTE_ASSERT(nbf <= *ld__);
6164
6165 for (int icomp = 0; icomp < gs.ctx().num_mag_comp(); icomp++) {
6166 for (int xi1 = 0; xi1 < nbf; xi1++) {
6167 int p1 = phase_Rlm_QE(atom.type(), xi1);
6168 for (int xi2 = 0; xi2 < nbf; xi2++) {
6169 int p2 = phase_Rlm_QE(atom.type(), xi2);
6170 gs.density().density_matrix(ia)(xi1, xi2, icomp) = dm(idx_map[xi1], idx_map[xi2], icomp) *
6171 static_cast<double>(p1 * p2);
6172 }
6173 }
6174 }
6175 },
6176 error_code__);
6177}
6178
6179} // extern "C"
Contains defintion of nlcglib interface.
Implementation of pointer to any object.
Check orthogonality of wave-functions and their residuals.
namespace for Niels Lohmann
Defines the properties of atom type.
Definition: atom_type.hpp:93
int mt_basis_size() const
Total number of muffin-tin basis functions (APW + LO).
Definition: atom_type.hpp:880
The whole DFT ground state implementation.
Kohn-Sham energy.
Definition: adaptor.hpp:192
Compute atomic forces.
Definition: force.hpp:44
sddk::mdarray< double, 2 > const & calc_forces_scf_corr()
Calculate SCF correction to the forces.
Definition: force.cpp:470
Set of k-points.
Definition: k_point_set.hpp:41
void initialize(std::vector< int > const &counts={})
Initialize the k-point set.
void add_kpoints(sddk::mdarray< double, 2 > const &kpoints__, double const *weights__)
Add multiple k-points to the set.
Simulation context is a set of parameters and objects describing a single simulation.
Stress tensor.
Definition: stress.hpp:97
r3::matrix< double > calc_stress_xc()
XC contribution to stress.
Definition: stress.cpp:284
r3::matrix< double > calc_stress_ewald()
Ewald energy contribution to stress.
Definition: stress.cpp:490
r3::matrix< double > calc_stress_us()
Contribution to the stress tensor from the augmentation operator.
Definition: stress.cpp:371
r3::matrix< double > calc_stress_vloc()
Local potential contribution to stress.
Definition: stress.cpp:706
r3::matrix< double > calc_stress_har()
Hartree energy contribution to stress.
Definition: stress.cpp:613
r3::matrix< double > calc_stress_core()
Non-linear core correction to stress tensor.
Definition: stress.cpp:217
Representation of a unit cell.
Definition: unit_cell.hpp:43
Angular momentum quantum number.
Handle deallocation of a poiniter to an object of any type.
Definition: any_ptr.hpp:74
T & get() const
Cast pointer to a given type and return a reference.
Definition: any_ptr.hpp:96
A set of G-vectors for FFTs and G+k basis functions.
Definition: gvec.hpp:130
MPI communicator wrapper.
void allgather(T *buffer__, int const *recvcounts__, int const *displs__) const
In-place MPI_Allgatherv.
Describe a range of bands.
Describe a range of spins.
Contains definition and partial implementation of sirius::Crystal_symmetry class.
Contains definition and partial implementation of sirius::DFT_ground_state class.
Entry point for Hamiltonain diagonalization.
Contains declaration and definition of sirius::Hamiltonian class.
Create intial subspace from atomic-like wave-functions.
Memory management functions and classes.
device_t
Type of the main processing unit.
Definition: memory.hpp:120
bool is_device_memory(memory_t mem__)
Check if this is a valid device memory (memory, accessible by the device).
Definition: memory.hpp:93
Linear response functionality.
@ key
the parser read a key of a value in an object
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
size_t spfft_grid_size_local(T const &spfft__)
Local size of the SpFFT transformation grid.
Definition: fft.hpp:228
size_t spfft_grid_size(T const &spfft__)
Total size of the SpFFT transformation grid.
Definition: fft.hpp:221
auto split_z_dimension(int size_z__, mpi::Communicator const &comm_fft__)
Split z-dimenstion of size_z between MPI ranks of the FFT communicator.
Definition: fft.hpp:236
auto spherical_coordinates(vector< double > vc)
Transform Cartesian coordinates [x,y,z] to spherical coordinates [r,theta,phi].
Definition: r3.hpp:590
int lmmax(int lmax)
Maximum number of combinations for a given .
Definition: specfunc.hpp:44
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
Definition: specfunc.hpp:50
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.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
subroutine sirius_get_max_num_gkvec(ks_handler, max_num_gkvec, error_code)
Get maximum number of G+k vectors across all k-points in the set.
Definition: sirius.f90:4056
subroutine sirius_set_atom_position(handler, ia, position, error_code)
Set new atomic position.
Definition: sirius.f90:2583
subroutine sirius_set_callback_function(handler, label, fptr, error_code)
Set callback function to compute various radial integrals.
Definition: sirius.f90:5501
subroutine sirius_option_get(section, name, type, data_ptr, max_length, enum_idx, error_code)
Return the default value of the option as defined in the JSON schema.
Definition: sirius.f90:4854
subroutine sirius_generate_xc_potential(handler, error_code)
Generate XC potential using LibXC.
Definition: sirius.f90:3736
subroutine sirius_set_density_matrix(handler, ia, dm, ld, error_code)
Set density matrix.
Definition: sirius.f90:6014
subroutine sirius_create_kset_from_grid(handler, k_grid, k_shift, use_symmetry, kset_handler, error_code)
Create k-point set from a grid.
Definition: sirius.f90:1690
subroutine sirius_get_kpoint_properties(handler, ik, weight, coordinates, error_code)
Get the kpoint properties.
Definition: sirius.f90:5450
subroutine sirius_set_o_radial_integral(handler, ia, val, l, o1, ilo1, o2, ilo2, error_code)
Set LAPW overlap radial integral.
Definition: sirius.f90:4325
double total_energy(Simulation_context const &ctx, K_point_set const &kset, Density const &density, Potential const &potential, double ewald_energy)
Total energy of the electronic subsystem.
Definition: energy.cpp:186
subroutine sirius_serialize_timers(fname, error_code)
Save all timers to JSON file.
Definition: sirius.f90:276
subroutine sirius_linear_solver(handler, vkq, num_gvec_kq_loc, gvec_kq_loc, dpsi, psi, eigvals, dvpsi, ld, num_spin_comp, alpha_pv, spin, nbnd_occ, tol, niter, error_code)
Interface to linear solver.
Definition: sirius.f90:5794
subroutine sirius_get_num_fft_grid_points(handler, num_fft_grid_points, error_code)
Get local number of FFT grid points.
Definition: sirius.f90:3982
subroutine sirius_set_equivalent_atoms(handler, equivalent_atoms, error_code)
Set equivalent atoms.
Definition: sirius.f90:4568
subroutine sirius_option_get_number_of_sections(length, error_code)
Return the total number of sections defined in the input JSON schema.
Definition: sirius.f90:4635
subroutine sirius_get_fv_eigen_vectors(handler, ik, fv_evec, ld, num_fv_states, error_code)
Get the first-variational eigen vectors.
Definition: sirius.f90:5049
subroutine sirius_get_fft_index(handler, fft_index, error_code)
Get mapping between G-vector index and FFT index.
Definition: sirius.f90:4019
subroutine sirius_set_radial_function(handler, ia, deriv_order, f, l, o, ilo, error_code)
Set LAPW radial functions.
Definition: sirius.f90:4499
subroutine sirius_stop_timer(name, error_code)
Stop the running timer.
Definition: sirius.f90:208
subroutine sirius_add_atom_type_radial_function(handler, atom_type, label, rf, num_points, n, l, idxrf1, idxrf2, occ, error_code)
Add one of the radial functions.
Definition: sirius.f90:2223
double energy_veff(Density const &density, Potential const &potential)
TODO doc.
Definition: energy.cpp:141
subroutine sirius_update_ground_state(gs_handler, error_code)
Update a ground state object after change of atomic coordinates or lattice vectors.
Definition: sirius.f90:1971
subroutine sirius_update_context(handler, error_code)
Update simulation context after changing lattice or atomic positions.
Definition: sirius.f90:1175
subroutine sirius_initialize_context(handler, error_code)
Initialize simulation context.
Definition: sirius.f90:1144
subroutine sirius_get_gkvec_arrays(ks_handler, ik, num_gkvec, gvec_index, gkvec, gkvec_cart, gkvec_len, gkvec_tp, error_code)
Get all G+k vector related arrays.
Definition: sirius.f90:4100
subroutine sirius_get_fft_comm(handler, fcomm, error_code)
Get communicator which is used to parallise FFT.
Definition: sirius.f90:3842
subroutine sirius_create_kset(handler, num_kpoints, kpoints, kpoint_weights, init_kset, kset_handler, error_code)
Create k-point set from the list of k-points.
Definition: sirius.f90:1625
subroutine sirius_create_context(fcomm, handler, fcomm_k, fcomm_band, error_code)
Create context of the simulation.
Definition: sirius.f90:356
subroutine sirius_set_atom_type_radial_grid(handler, label, num_radial_points, radial_points, error_code)
Set radial grid of the atom type.
Definition: sirius.f90:2105
subroutine sirius_generate_effective_potential(handler, error_code)
Generate effective potential and magnetic field.
Definition: sirius.f90:2934
subroutine sirius_nlcg(handler, ks_handler, error_code)
Robust wave function optimizer.
Definition: sirius.f90:5544
subroutine sirius_set_mpi_grid_dims(handler, ndims, dims, error_code)
Set dimensions of the MPI grid.
Definition: sirius.f90:1054
subroutine sirius_add_atom_type(handler, label, fname, zn, symbol, mass, spin_orbit, error_code)
Add new atom type to the unit cell.
Definition: sirius.f90:2008
subroutine sirius_create_ground_state(ks_handler, gs_handler, error_code)
Create a ground state object.
Definition: sirius.f90:1746
subroutine sirius_get_band_occupancies(ks_handler, ik, ispn, band_occupancies, error_code)
Set band occupancies.
Definition: sirius.f90:3088
double eval_sum(Unit_cell const &unit_cell, K_point_set const &kset)
TODO doc.
Definition: energy.cpp:135
subroutine sirius_generate_d_operator_matrix(handler, error_code)
Generate D-operator matrix.
Definition: sirius.f90:5898
subroutine sirius_get_num_gvec(handler, num_gvec, error_code)
Get total number of G-vectors on the fine grid.
Definition: sirius.f90:3879
strong_type< int, struct __block_id_tag > block_id
ID of the block.
Definition: splindex.hpp:108
subroutine sirius_get_fv_eigen_values(handler, ik, fv_eval, num_fv_states, error_code)
Get the first-variational eigen values.
Definition: sirius.f90:5104
subroutine sirius_print_info(handler, error_code)
Print basic info.
Definition: sirius.f90:1206
subroutine sirius_get_forces(handler, label, forces, error_code)
Get one of the total force components.
Definition: sirius.f90:3234
subroutine sirius_finalize(call_mpi_fin, call_device_reset, call_fftw_fin, error_code)
Shut down the SIRIUS library.
Definition: sirius.f90:113
subroutine sirius_check_scf_density(gs_handler, error_code)
Check the self-consistent density.
Definition: sirius.f90:1940
subroutine sirius_add_atom_type_aw_descriptor(handler, label, n, l, enu, dme, auto_enu, error_code)
Add descriptor of the augmented wave radial function.
Definition: sirius.f90:3470
subroutine sirius_option_get_section_length(section, length, error_code)
Return the number of options in a given section.
Definition: sirius.f90:4711
subroutine sirius_get_num_beta_projectors(handler, label, num_bp, error_code)
Get the number of beta-projectors for an atom type.
Definition: sirius.f90:3328
subroutine sirius_update_atomic_potential(handler, error_code)
Set the new spherical potential.
Definition: sirius.f90:4604
subroutine sirius_set_atom_type_radial_grid_inf(handler, label, num_radial_points, radial_points, error_code)
Set radial grid of the free atom (up to effectice infinity).
Definition: sirius.f90:2161
subroutine sirius_import_parameters(handler, str, error_code)
Import parameters of simulation from a JSON string.
Definition: sirius.f90:404
subroutine sirius_set_parameters(handler, lmax_apw, lmax_rho, lmax_pot, num_fv_states, num_bands, num_mag_dims, pw_cutoff, gk_cutoff, fft_grid_size, auto_rmt, gamma_point, use_symmetry, so_correction, valence_rel, core_rel, iter_solver_tol_empty, iter_solver_type, verbosity, hubbard_correction, hubbard_correction_kind, hubbard_full_orthogonalization, hubbard_orbitals, sht_coverage, min_occupancy, smearing, smearing_width, spglib_tol, electronic_structure_method, error_code)
Set parameters of the simulation.
Definition: sirius.f90:477
strong_type< int, struct __rf_index_tag > rf_index
Radial function index.
subroutine sirius_get_gvec_arrays(handler, gvec, gvec_cart, gvec_len, index_by_gvec, error_code)
Get G-vector arrays.
Definition: sirius.f90:3920
subroutine sirius_save_state(gs_handler, file_name, error_code)
Save DFT ground state (density and potential)
Definition: sirius.f90:5930
subroutine sirius_set_atom_type_paw(handler, label, core_energy, occupations, num_occ, error_code)
Set PAW related data.
Definition: sirius.f90:2469
subroutine sirius_set_o1_radial_integral(handler, ia, val, l1, o1, ilo1, l2, o2, ilo2, error_code)
Set a correction to LAPW overlap radial integral.
Definition: sirius.f90:4408
subroutine sirius_dump_runtime_setup(handler, filename, error_code)
Dump the runtime setup in a file.
Definition: sirius.f90:5005
subroutine sirius_option_get_info(section, elem, key_name, key_name_len, type, length, enum_size, title, title_len, description, description_len, error_code)
Return information about the option.
Definition: sirius.f90:4762
void initialize(bool call_mpi_init__=true)
Initialize the library.
Definition: sirius.hpp:82
subroutine sirius_get_band_energies(ks_handler, ik, ispn, band_energies, error_code)
Get band energies.
Definition: sirius.f90:3138
subroutine sirius_get_num_kpoints(handler, num_kpoints, error_code)
Get the total number of kpoints.
Definition: sirius.f90:5411
subroutine sirius_set_atom_type_dion(handler, label, num_beta, dion, error_code)
Set ionic part of D-operator matrix.
Definition: sirius.f90:2414
double energy_vxc(Density const &density, Potential const &potential)
Returns exchange correlation potential.
Definition: energy.cpp:76
subroutine sirius_get_periodic_function(handler, label, f_mt, lmmax, nrmtmax, num_atoms, f_rg, size_x, size_y, size_z, offset_z, error_code)
Get values of the periodic function.
Definition: sirius.f90:1514
subroutine sirius_option_set(handler, section, name, type, data_ptr, max_length, append, error_code)
Set the value of the option name in a (internal) json dictionary.
Definition: sirius.f90:4928
subroutine sirius_context_initialized(handler, status, error_code)
Check if the simulation context is initialized.
Definition: sirius.f90:312
subroutine sirius_load_state(handler, file_name, error_code)
Save DFT ground state (density and potential)
Definition: sirius.f90:5971
subroutine sirius_option_get_section_name(elem, section_name, section_name_length, error_code)
Return the name of a given section.
Definition: sirius.f90:4669
subroutine sirius_print_timers(flatten, error_code)
Print all timers.
Definition: sirius.f90:243
subroutine sirius_set_periodic_function(handler, label, f_mt, lmmax, nrmtmax, num_atoms, f_rg, size_x, size_y, size_z, offset_z, error_code)
Set values of the periodic function.
Definition: sirius.f90:1398
double energy_vloc(Density const &density, Potential const &potential)
TODO doc.
Definition: energy.cpp:119
subroutine sirius_get_stress_tensor(handler, label, stress_tensor, error_code)
Get one of the stress tensor components.
Definition: sirius.f90:3281
subroutine sirius_set_band_occupancies(ks_handler, ik, ispn, band_occupancies, error_code)
Set band occupancies.
Definition: sirius.f90:3038
subroutine sirius_add_atom(handler, label, position, vector_field, error_code)
Add atom to the unit cell.
Definition: sirius.f90:2529
subroutine sirius_add_hubbard_atom_pair(handler, atom_pair, translation, n, l, coupling, error_code)
Add a non-local Hubbard interaction V for a pair of atoms.
Definition: sirius.f90:5690
subroutine sirius_set_lattice_vectors(handler, a1, a2, a3, error_code)
Set vectors of the unit cell.
Definition: sirius.f90:1098
double energy_vha(Potential const &potential)
Returns Hatree potential.
Definition: energy.cpp:88
subroutine sirius_get_parameters(handler, lmax_apw, lmax_rho, lmax_pot, num_fv_states, num_bands, num_spins, num_mag_dims, pw_cutoff, gk_cutoff, fft_grid_size, auto_rmt, gamma_point, use_symmetry, so_correction, iter_solver_tol, iter_solver_tol_empty, verbosity, hubbard_correction, evp_work_count, num_loc_op_applied, num_sym_op, electronic_structure_method, error_code)
Get parameters of the simulation.
Definition: sirius.f90:796
subroutine sirius_add_atom_type_lo_descriptor(handler, label, ilo, n, l, enu, dme, auto_enu, error_code)
Add descriptor of the local orbital radial function.
Definition: sirius.f90:3547
subroutine sirius_free_object_handler(handler, error_code)
Free any object handler created by SIRIUS.
Definition: sirius.f90:1239
subroutine sirius_add_xc_functional(handler, name, error_code)
Add one of the XC functionals.
Definition: sirius.f90:1012
double energy_kin(Simulation_context const &ctx, K_point_set const &kset, Density const &density, Potential const &potential)
Return kinetic energy.
Definition: energy.cpp:147
subroutine sirius_set_rg_values(handler, label, grid_dims, local_box_origin, local_box_size, fcomm, values, transform_to_pw, error_code)
Set the values of the function on the regular grid.
Definition: sirius.f90:5209
subroutine sirius_initialize(call_mpi_init, error_code)
Initialize the SIRIUS library.
Definition: sirius.f90:78
subroutine sirius_get_step_function(handler, cfunig, cfunrg, num_rg_points, error_code)
Get the unit-step function.
Definition: sirius.f90:4171
double energy_enuc(Simulation_context const &ctx, Potential const &potential)
Return nucleus energy in the electrostatic field.
Definition: energy.cpp:104
subroutine sirius_set_periodic_function_ptr(handler, label, f_mt, lmmax, nrmtmax, num_atoms, f_rg, size_x, size_y, size_z, offset_z, error_code)
Set pointer to density or magnetization.
Definition: sirius.f90:1281
subroutine sirius_set_atom_type_hubbard(handler, label, l, n, occ, U, J, alpha, beta, J0, error_code)
Set the hubbard correction for the atomic type.
Definition: sirius.f90:2329
subroutine sirius_get_kpoint_inter_comm(handler, fcomm, error_code)
Get communicator which is used to split k-points.
Definition: sirius.f90:3768
void initialize_subspace(Hamiltonian_k< T > const &Hk__, K_point< T > &kp__, int num_ao__)
Initialize the wave-functions subspace at a given k-point.
double energy_bxc(const Density &density, const Potential &potential)
TODO doc.
Definition: energy.cpp:94
subroutine sirius_start_timer(name, error_code)
Start the timer.
Definition: sirius.f90:173
subroutine sirius_get_total_magnetization(handler, mag, error_code)
Get the total magnetization of the system.
Definition: sirius.f90:5374
void finalize(bool call_mpi_fin__=true, bool reset_device__=true, bool fftw_cleanup__=true)
Shut down the library.
Definition: sirius.hpp:143
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Definition: math_tools.hpp:165
subroutine sirius_generate_coulomb_potential(handler, vh_el, error_code)
Generate Coulomb potential by solving Poisson equation.
Definition: sirius.f90:3698
subroutine sirius_get_sv_eigen_vectors(handler, ik, sv_evec, num_bands, error_code)
Get the second-variational eigen vectors.
Definition: sirius.f90:5154
subroutine sirius_get_rg_values(handler, label, grid_dims, local_box_origin, local_box_size, fcomm, values, transform_to_rg, error_code)
Get the values of the function on the regular grid.
Definition: sirius.f90:5295
subroutine sirius_find_ground_state(gs_handler, density_tol, energy_tol, iter_solver_tol, initial_guess, max_niter, save_state, converged, niter, rho_min, error_code)
Find the ground state.
Definition: sirius.f90:1831
nlohmann::json const & get_section_options(std::string const &section__)
Get all possible options of a given input section. It is a json dictionary.
subroutine sirius_get_energy(handler, label, energy, error_code)
Get one of the total energy components.
Definition: sirius.f90:3187
subroutine sirius_set_atom_type_configuration(handler, label, n, l, k, occupancy, core, error_code)
Set configuration of atomic levels.
Definition: sirius.f90:3628
subroutine sirius_generate_density(gs_handler, add_core, transform_to_rg, paw_only, error_code)
Generate charge density and magnetization.
Definition: sirius.f90:2969
subroutine sirius_nlcg_params(handler, ks_handler, temp, smearing, kappa, tau, tol, maxiter, restart, processing_unit, converged, error_code)
Robust wave function optimizer.
Definition: sirius.f90:5591
double energy_exc(Density const &density, Potential const &potential)
Returns exchange correlation energy.
Definition: energy.cpp:82
subroutine sirius_set_h_radial_integrals(handler, ia, lmmax, val, l1, o1, ilo1, l2, o2, ilo2, error_code)
Set LAPW Hamiltonian radial integrals.
Definition: sirius.f90:4228
subroutine sirius_generate_initial_density(handler, error_code)
Generate initial density.
Definition: sirius.f90:2903
subroutine sirius_get_kpoint_inner_comm(handler, fcomm, error_code)
Get communicator which is used to parallise band problem.
Definition: sirius.f90:3805
subroutine sirius_set_pw_coeffs(handler, label, pw_coeffs, transform_to_rg, ngv, gvl, comm, error_code)
Set plane-wave coefficients of a periodic function.
Definition: sirius.f90:2631
subroutine sirius_get_pw_coeffs(handler, label, pw_coeffs, ngv, gvl, comm, error_code)
Get plane-wave coefficients of a periodic function.
Definition: sirius.f90:2715
subroutine sirius_find_eigen_states(gs_handler, ks_handler, precompute_pw, precompute_rf, precompute_ri, iter_solver_tol, error_code)
Find eigen-states of the Hamiltonian.
Definition: sirius.f90:2825
subroutine sirius_initialize_subspace(gs_handler, ks_handler, error_code)
Initialize the subspace of wave-functions.
Definition: sirius.f90:2783
nlohmann::json const & get_options_dictionary()
Get all possible options for initializing sirius. It is a json dictionary.
subroutine sirius_initialize_kset(ks_handler, count, error_code)
Initialize k-point set.
Definition: sirius.f90:1783
A time-based profiler.
"All-in-one" include file.
void sirius_get_wave_functions(void *const *ks_handler__, double const *vkl__, int const *spin__, int const *num_gvec_loc__, int const *gvec_loc__, std::complex< double > *evec__, int const *ld__, int const *num_spin_comp__, int *error_code__)
static int idx_m_qe(int m__)
Index of Rlm in QE in the block of lm coefficients for a given l.
Definition: sirius_api.cpp:330
static std::vector< int > atomic_orbital_index_map_QE(Atom_type const &type__)
Mapping of atomic indices from SIRIUS to QE order.
Definition: sirius_api.cpp:337
Describe external pointers to periodic function.
Definition: typedefs.hpp:256
Provides preconditioner for ultrasoft case.