-
Notifications
You must be signed in to change notification settings - Fork 18
Code Overview: LibxcProxy
In this section we'll explain how to modify the source code of Lio to use the Libxc functionalities.
In g2g/libxc
you'll find the class LibxcProxy.h, the objective of this class is to provide a simple interface to perform the communication between Lio and Libxc. The idea is that all the calls to Libxc go through this class.
The component (or class) that carries out the communication between Lio and Libxc is called LibxcProxy, and through him we will make the calls to the Libxc's functionals. The LibxcProxy component supports the use of templates to be compatible with any scalar data type of the C language (floats
, double
).
Now, we'll explain how to use the LibxcProxy component from Lio.
The code that uses the LibxcProxy component within Lio must be enclosed using some compiler directives. This is because the LibxcProxy component only works when Lio is compiled with support for Libxc (see).
The compiler directives are group in two categories
- CPU directives
- GPU directives
If we want the code of the component LibxcProxy to be executed only when Lio is compiled for CPU, we have to enclose the code in,
#if USE_LIBXC
#if LIBXC_CPU
// The code used by the LibxcProxy component goes here
...
#endif
#endif
#if USE LIBXC
// The code used by the LibxcProxy component goes here
#endif
Note that the only difference with CPU directives is that in the GPU version we don't use the #if LIBXC_CPU
directive.
Before being able to make the calls to the functionals, we must instantiate and initialize the LibxcProxy component indicating the ids
of the functional we want to use.
One thing to keep in mind is that from Libxc the exchange and correlation calculations are made in separate functions, therefore when we initialize the LibxcProxy component we must set the identifiers (ids) of the exchange and correlation functionals.
Suppose we want to use the LibxcProxy component somewhere in the source code of Lio, then we have to add the following code to create and initialize the component,
#if USE_LIBXC
#if LIBXC_CPU
// Define the configuration parameters
int nspin = 1; // 1 - closed shell | 2 - open shell.
int functionalExchange = 101; // Libxc exchange identifier.
int functionalCorrelation = 130; // Libxc correlation identifier.
LibxcProxy<float,3> libxcProxy (functionalExchange, functionalCorrelation, nspin);
#endif
#endif
In this case we are creating (or instantiating) the LibxcProxy component in the libxcProxy
variable and we are also telling that the datatypes that we are going to run the simulation are floats
.
In case you want to use the LibxcProxy with doubles, you simply change float
by double
in the initialization,
#if USE_LIBXC
#if LIBXC_CPU
// Define the configuration parameters
int nspin = 1; // 1 - closed shell | 2 - open shell.
int functionalExchange = 101; // Libxc exchange identifier.
int functionalCorrelation = 130; // Libxc correlation identifier.
// We instantiate and initialize the proxy with doubles as a datatype.
LibxcProxy<double,3> libxcProxy (functionalExchange, functionalCorrelation, nspin);
#endif
#endif
The initialization of the GPU version of the LibxcProxy component is similar to the CPU version,
#if USE_LIBXC
int nspin = 1; // 1 - closed shell | 2 - open shell.
int functionalExchange = 1101; // Libxc exchange identifier.
int functionalCorrelation = 1130; // Libxc correlation identifier.
LibxcProxy<double,4> libxcProxy (functionalExchange, functionalCorrelation, nspin);
#endif
In this case, the identifiers of the functionals are different. You can also create the component with floats
or doubles
as needed.
Let's see now how we should use the component LibxcProxy when we want to make calls to the functions that perform the functional calculation when we want to run simulations in CPU.
#if USE_LIBXC
#if LIBXC_CPU
// Proxy parameters.
int nspin = 1;
int functionalExchange = 101;
int functionalCorrelation = 130;
// Instantiate the proxy.
LibxcProxy<float,3> libxcProxy(functionalExchange, functionalCorrelation, nspin);
// Create some test data.
float exc = 0, corr = 0, y2a = 0;
const G2G::vec_type <float, 3> dxyz(0,0,0.447213595);
const G2G::vec_type <float, 3> dd1(0,0,0);
const G2G::vec_type <float, 3> dd2(0,0,0);
float densidad = 0.1;
// We use the function that performs the
// calculation of functional GGA family.
libxcProxy.doGGA (densidad, dxyz, dd1, dd2, exc, corr, y2a);
// Show the results.
fprintf (stdout, "Density '%lf' \n", densidad);
fprintf (stdout, "Exchange '%lf' \n", exc);
fprintf (stdout, "Correlation '%lf' \n", corr);
fprintf (stdout, "Y2A '%lf' \n", y2a);
#endif
#endif
In the example we can see how to make a call to calculate the exchange and correlation coefficients in a single point. The results are found in the variables exc
, corr
and y2a
.