SIRIUS 7.5.0
Electronic structure library and applications
sirius.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2019 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.hpp
21 *
22 * \brief "All-in-one" include file.
23 */
24
25#ifndef __SIRIUS_HPP__
26#define __SIRIUS_HPP__
27
28#if defined(__APEX)
29#include <apex_api.hpp>
30#endif
31
32#include "core/omp.hpp"
33#if defined(SIRIUS_GPU) && defined(SIRIUS_CUDA)
34#include "core/acc/cusolver.hpp"
35#endif
37#include "core/cmd_args.hpp"
38#include "core/json.hpp"
39#include "core/profiler.hpp"
40using json = nlohmann::json;
41#if defined(SIRIUS_USE_POWER_COUNTER)
42#include "core/power.hpp"
43#endif
44
45#include "core/sht/sht.hpp"
46#include "core/sht/gaunt.hpp"
47#include "core/hdf5_tree.hpp"
54
55/// Namespace of the SIRIUS library.
56namespace sirius {
57
58extern json sirius_options_parser_;
59
60/// Return the status of the library (initialized or not).
61inline static bool& is_initialized()
62{
63 static bool b{false};
64 return b;
65}
66
67#if defined(SIRIUS_USE_POWER_COUNTER)
68inline static double& energy()
69{
70 static double e__{0};
71 return e__;
72}
73
74inline static double& energy_acc()
75{
76 static double e__{0};
77 return e__;
78}
79#endif
80
81/// Initialize the library.
82inline void initialize(bool call_mpi_init__ = true)
83{
84 PROFILE_START("sirius");
85 PROFILE("sirius::initialize");
86 if (is_initialized()) {
87 RTE_THROW("SIRIUS library is already initialized");
88 }
89#if defined(SIRIUS_USE_POWER_COUNTER)
90 energy() = -power::energy();
91 energy_acc() = -power::device_energy();
92#endif
93 if (call_mpi_init__) {
94 mpi::Communicator::initialize(MPI_THREAD_MULTIPLE);
95 }
96#if defined(__APEX)
97 apex::init("sirius", Communicator::world().rank(), Communicator::world().size());
98#endif
99
100 if (mpi::Communicator::world().rank() == 0) {
101 std::printf("SIRIUS %i.%i.%i, git hash: %s\n", sirius::major_version(), sirius::minor_version(),
102 sirius::revision(), sirius::git_hash().c_str());
103#if !defined(NDEBUG)
104 std::printf("Warning! Compiled in 'debug' mode with assert statements enabled!\n");
105#endif
106 }
107 /* get number of ranks per node during the global call to sirius::initialize() */
109 if (acc::num_devices() > 0) {
111 acc::set_device_id(devid);
112 /* create extensive amount of streams */
113 /* some parts of the code rely on the number of streams not related to the
114 number of OMP threads */
115 acc::create_streams(std::max(omp_get_max_threads(), 6));
116#if defined(SIRIUS_GPU)
117 acc::blas::create_stream_handles();
118#endif
119#if defined(SIRIUS_CUDA)
120 acc::blas::xt::create_handle();
121 acc::cusolver::create_handle();
122#endif
123 }
124 splablas::reset_handle();
125
126#if defined(SIRIUS_MAGMA)
127 magma::init();
128#endif
129#if defined(SIRIUS_ELPA)
130 la::Eigensolver_elpa::initialize();
131#endif
132#if defined(SIRIUS_DLAF)
134#endif
135 /* for the fortran interface to blas/lapack */
136 RTE_ASSERT(sizeof(int) == 4);
137 RTE_ASSERT(sizeof(double) == 8);
138
139 is_initialized() = true;
140}
141
142/// Shut down the library.
143inline void finalize(bool call_mpi_fin__ = true, bool reset_device__ = true, bool fftw_cleanup__ = true)
144{
145 PROFILE_START("sirius::finalize");
146 if (!is_initialized()) {
147 RTE_THROW("SIRIUS library was not initialized");
148 }
149#if defined(SIRIUS_MAGMA)
150 magma::finalize();
151#endif
152
153 /* must be called before device is reset */
154 splablas::reset_handle();
155
156 sddk::get_memory_pool(sddk::memory_t::host).clear();
157
158 if (acc::num_devices()) {
159 sddk::get_memory_pool(sddk::memory_t::host_pinned).clear();
160 sddk::get_memory_pool(sddk::memory_t::device).clear();
161#if defined(SIRIUS_GPU)
162 acc::blas::destroy_stream_handles();
163#endif
164#if defined(SIRIUS_CUDA)
165 acc::cusolver::destroy_handle();
166 acc::blas::xt::destroy_handle();
167#endif
169 if (reset_device__) {
170 acc::reset();
171 }
172 }
173
174#if defined(__APEX)
176#endif
177#if defined(SIRIUS_USE_POWER_COUNTER)
178 double e = energy() + power::energy();
179 double e_acc = energy_acc() + power::device_energy();
180 if (mpi::Communicator::world().rank() == 0) {
181 printf("=== Energy consumption (root MPI rank) ===\n");
182 printf("energy : %9.2f Joules\n", e);
183 printf("energy_acc : %9.2f Joules\n", e_acc);
184 }
185 mpi::Communicator::world().allreduce(&e, 1);
186 mpi::Communicator::world().allreduce(&e_acc, 1);
187 int nn = power::num_nodes();
188 if (Communicator::world().rank() == 0 && nn > 0) {
189 printf("=== Energy consumption (all nodes) ===\n");
190 printf("energy : %9.2f Joules\n", e * nn / Communicator::world().size());
191 printf("energy_acc : %9.2f Joules\n", e_acc * nn / Communicator::world().size());
192 }
193#endif
194 auto rank = mpi::Communicator::world().rank();
195 if (call_mpi_fin__) {
197 }
198#if defined(SIRIUS_ELPA)
199 la::Eigensolver_elpa::finalize();
200#endif
201#if defined(SIRIUS_DLAF)
203#endif
204
205 is_initialized() = false;
206
207 PROFILE_STOP("sirius::finalize");
208 PROFILE_STOP("sirius");
209
210 auto pt = env::print_timing();
211 if (pt && rank == 0) {
212 auto timing_result = global_rtgraph_timer.process();
213
214 if (pt & 1) {
215 std::cout << timing_result.print({rt_graph::Stat::Count, rt_graph::Stat::Total, rt_graph::Stat::Percentage,
216 rt_graph::Stat::SelfPercentage, rt_graph::Stat::Median,
217 rt_graph::Stat::Min, rt_graph::Stat::Max});
218 }
219 if (pt & 2) {
220 timing_result = timing_result.flatten(1).sort_nodes();
221 std::cout << timing_result.print({rt_graph::Stat::Count, rt_graph::Stat::Total, rt_graph::Stat::Percentage,
222 rt_graph::Stat::SelfPercentage, rt_graph::Stat::Median,
223 rt_graph::Stat::Min, rt_graph::Stat::Max});
224 }
225 }
226}
227
228}
229#endif // __SIRIUS_HPP__
230
231/** \mainpage Welcome to SIRIUS
232
233 SIRIUS is a domain specific library for electronic structure calculations. It implements pseudopotential plane
234 wave (PP-PW) and full potential linearized augmented plane wave (FP-LAPW) methods and is designed for
235 GPU acceleration of popular community codes such as Exciting, Elk and Quantum ESPRESSO.
236 SIRIUS is written in C++11 with MPI, OpenMP and CUDA/ROCm programming models. SIRIUS is organised as a
237 collection of classes that abstract away the different building blocks of DFT self-consistency cycle.
238
239 For a quick start please refer to the main development page at
240 <a href="https://github.com/electronic-structure/SIRIUS">GitHub</a>.
241
242 The generated Fortran API is described in the file sirius.f90.
243
244 The frequent variable names are listed on the page \ref stdvarname.
245
246 We use the following \ref coding.
247
248 The library files and directories are organised in the following way:
249 - \b apps -
250 - \b atoms - utility program to generate FP-LAPW atomic species files
251 - \b bands - band plotting
252 - \b cif_input - CIF parser
253 - \b mini_app - DFT miniapp
254 - \b hydrogen - solve hydrogen-like atom using Schrödinger equation
255 - \b tests - tests of various functionality
256 - \b timers - scripts to analyze timer outputs
257 - \b unit_tests - unit tests
258 - \b upf - scripts to parse and convert UPF files
259 - \b utils - utilities to work with unit cell
260 - \b ci - directory with Jenkins, Travis CI and GitHub action scripts
261 - \b cmake - directory with CMake scripts
262 - \b doc - this directory contains configuration file for Doxygen documentation and PNG images
263 - \b examples - examples of input files for pseudopotential and full-potential calculations
264 - \b python_module - Python interface module
265 - \b reframe - ReFrame regression tests description
266 - \b src - main directory with the source code
267 - \b verification - verification tests
268 - .clang-format - source code formatting rules
269 - CMakeLists.txt - CMake file of the project
270 - check_format.py, check_format.x - scripts to check source code formatting
271 - clang_format.x - script to apply Clang format to a file
272
273*/
274
275/**
276\page stdvarname Standard variable names
277
278Below is the list of standard names for some of the loop variables:
279
280l - index of orbital quantum number \n
281m - index of azimutal quantum nuber \n
282lm - combined index of (l,m) quantum numbers \n
283ia - index of atom \n
284ic - index of atom class \n
285iat - index of atom type \n
286ir - index of r-point \n
287ig - index of G-vector \n
288idxlo - index of local orbital \n
289idxrf - index of radial function \n
290xi - combined index of lm and idxrf (product of angular and radial functions) \n
291ik - index of k-point \n
292itp - index of (theta, phi) spherical angles \n
293
294The _loc suffix is often added to the variables to indicate that they represent the local fraction of the elements
295assigned to a given MPI rank.
296*/
297
298/**
299\page coding Coding style
300
301Below are some basic style rules that we follow:
302 - Page width is approximately 120 characters. Screens are wide nowadays and 80 characters is an
303 obsolete restriction. Going slightly over 120 characters is allowed if it is requird for the line continuity.
304 - Indentation: 4 spaces (no tabs)
305
306 Exception: class access modifiers are idented with 2 spaces
307 \code{.cpp}
308 class A
309 {
310 private:
311 int n_;
312 public:
313 A();
314 };
315 \endcode
316
317 - Comments are inserted before the code with slash-star style starting with the lower case:
318 \code{.cpp}
319 // call a very important function
320 do_something();
321 \endcode
322 - Spaces between most operators:
323 \code{.cpp}
324 if (i < 5) {
325 j = 5;
326 }
327
328 for (int k = 0; k < 3; k++)
329
330 int lm = l * l + l + m;
331
332 double d = std::abs(e);
333
334 int k = idx[3];
335 \endcode
336 - Spaces between function arguments:
337 \code{.cpp}
338 double d = some_func(a, b, c);
339 \endcode
340 but not
341 \code{.cpp}
342 double d=some_func(a,b,c);
343 \endcode
344 and not
345 \code{.cpp}
346 double d = some_func( a, b, c );
347 \endcode
348 - Spaces between template arguments, but not between <,> brackets:
349 \code{.cpp}
350 std::vector<std::array<int, 2>> vec;
351 \endcode
352 but not
353 \code{.cpp}
354 std::vector< std::array< int, 2 > > vec;
355 \endcode
356 - Curly braces for classes and functions start form the new line:
357 \code{.cpp}
358 class A
359 {
360 ....
361 };
362
363 inline int num_points()
364 {
365 return num_points_;
366 }
367 \endcode
368 - Curly braces for if-statements, for-loops, switch-case statements, etc. start at the end of the line:
369 \code{.cpp}
370 for (int i: {0, 1, 2}) {
371 some_func(i);
372 }
373
374 if (a == 0) {
375 std::printf("a is zero");
376 } else {
377 std::printf("a is not zero");
378 }
379
380 switch (i) {
381 case 1: {
382 do_something();
383 break;
384 case 2: {
385 do_something_else();
386 break;
387 }
388 }
389 \endcode
390 - Even single line 'if' statements and 'for' loops must have the curly brackes:
391 \code{.cpp}
392 if (i == 4) {
393 some_variable = 5;
394 }
395
396 for (int k = 0; k < 10; k++) {
397 do_something(k);
398 }
399 \endcode
400 - Reference and pointer symbols are part of type:
401 \code{.cpp}
402 std::vector<double>& vec = make_vector();
403
404 double* ptr = &vec[0];
405
406 auto& atom = unit_cell().atom(ia);
407 \endcode
408 - Const modifier follows the type declaration:
409 \code{.cpp}
410 std::vector<int> const& idx() const
411 {
412 return idx_;
413 }
414 // or
415 auto const& atom = unit_cell().atom(ia);
416 \endcode
417 - Names of class members end with underscore:
418 \code{.cpp}
419 class A
420 {
421 private:
422 int lmax_;
423 };
424 \endcode
425 - Setter method starts from set_, getter method is a variable name itself:
426 \code{.cpp}
427 class A
428 {
429 private:
430 int lmax_;
431 public:
432 int lmax() const
433 {
434 return lmax_;
435 }
436 void set_lmax(int lmax__)
437 {
438 lmax_ = lmax__;
439 }
440 };
441 \endcode
442 However, the new style for setter methods is preferable:
443 \code{.cpp}
444 class A
445 {
446 private:
447 int lmax_;
448 public:
449 int lmax() const
450 {
451 return lmax_;
452 }
453 int lmax(int lmax__)
454 {
455 lmax_ = lmax__;
456 return lmax_;
457 }
458 };
459 \endcode
460 - Order of class members: private, protected, public
461 \code{.cpp}
462 class A
463 {
464 private:
465 int lmax_;
466 void bar();
467 protected:
468 void foo();
469 public:
470 int lmax() const
471 {
472 return lmax_;
473 }
474 };
475 \endcode
476 - Single-line functions should not be flattened:
477 \code{.cpp}
478 struct A
479 {
480 int lmax() const
481 {
482 return lmax_;
483 }
484 };
485 \endcode
486 but not
487 \code{.cpp}
488 struct A
489 {
490 int lmax() const { return lmax_; }
491 };
492 \endcode
493 - Header guards have a standard name: double underscore + file name in capital letters + double underscore
494 \code{.cpp}
495 #ifndef __HEADER_HPP__
496 #define __HEADER_HPP__
497 ...
498 #endif // __HEADER_HPP__
499 \endcode
500 - Variable names are all in lowercase and underscore-separated (aka 'snake_case'):
501 \code{.cpp}
502 int num_bands;
503 std::complex<double> beta_psi;
504 \endcode
505 but not
506 \code{.cpp}
507 int NumBands;
508 // or
509 std::complex<double> BetaPsi;
510 // or
511 std::complex<double> Another_BetaPsi;
512 \endcode
513
514We use clang-format utility to enforce the basic formatting style. Please have a look at .clang-format config file
515in the source root folder for the definitions and use helper script 'clang_format.x'.
516
517<b>Class naming convention.</b>
518
519Problem: all 'standard' naming conventions are not satisfactory. For example, we have a class
520which does a DFT ground state. Following the common naming conventions it could be named like this:
521DFTGroundState, DftGroundState, dft_ground_state. Last two are bad, because DFT (and not Dft or dft)
522is a well recognized abbreviation. First one is band because capital G adds to DFT and we automaticaly
523read DFTG round state.
524
525Solution: we can propose the following: DFTgroundState or DFT_ground_state. The first variant still
526doens't look very good because one of the words is captalized (State) and one (ground) - is not. So we pick
527the second variant: DFT_ground_state (by the way, this is close to the Bjarne Stroustrup's naiming convention,
528where he uses first capital letter and underscores, for example class Io_obj).
529
530Some other examples:
531 - class Ground_state (composed of two words)
532 - class FFT_interface (composed of an abbreviation and a word)
533 - class Interface_XC (composed of a word and abbreviation)
534 - class Spline (single word)
535
536Exceptions are allowed if it makes sense. For example, low level utility classes like 'mdarray' (multi-dimensional
537array) or 'pstdout' (parallel standard output) are named with small letters.
538*/
539
540/**
541\page fderiv Functional derivatives
542
543Definition:
544\f[
545\frac{dF[f+\epsilon \eta ]}{d \epsilon}\Bigg\rvert_{\epsilon = 0} := \int \frac{\delta F[f]}{\delta f(x')} \eta(x') dx'
546\f]
547Alternative definition is:
548\f[
549\frac{\delta F[f(x)]}{\delta f(x')} = \lim_{\epsilon \to 0} \frac{F[f(x) + \epsilon \delta(x-x')] - F[f(x)]}{\epsilon}
550\f]
551
552*/
namespace for Niels Lohmann
static void initialize(int required__)
MPI initialization.
static void finalize()
MPI shut down.
Contains definition and implementation of cmd_args class.
Interface to CUDA eigen-solver library.
Contains definition and partial implementation of sirius::DFT_ground_state class.
Contains definition and implementation of various eigenvalue solver interfaces.
Contains definition and implementation of sirius::Gaunt class.
Contains definition and implementation of sirius::HDF5_tree class.
Interface to nlohmann::json library and helper functions.
Interface to SPLA library.
Declaration of sirius::Local_operator class.
void create_streams(int num_streams__)
Create CUDA streams.
Definition: acc.hpp:215
int num_devices()
Get the number of devices.
Definition: acc.cpp:32
void reset()
Reset device.
Definition: acc.hpp:240
void set_device_id(int id__)
Set the GPU id.
Definition: acc.hpp:183
void destroy_streams()
Destroy CUDA streams.
Definition: acc.hpp:226
int get_device_id(int num_devices__)
Get GPU device id associated with the current rank.
int num_ranks_per_node()
Get number of ranks per node.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
void initialize(bool call_mpi_init__=true)
Initialize the library.
Definition: sirius.hpp:82
static bool & is_initialized()
Return the status of the library (initialized or not).
Definition: sirius.hpp:61
void finalize(bool call_mpi_fin__=true, bool reset_device__=true, bool fftw_cleanup__=true)
Shut down the library.
Definition: sirius.hpp:143
Add or substitute OMP functions.
Read power counters on Cray.
A time-based profiler.
Contains declaration and partial implementation of sirius::Radial_solver class.
Contains declaration and particular implementation of sirius::SHT class.
Contains definition and implementation of Simulation_context class.
Get version number and related quantities.