Skip to content

Code Overview: LibxcProxy

Eduardo Andres Perez Leale edited this page Jun 17, 2018 · 6 revisions

In this section we'll explain how to modify the source code of Lio to use the Libxc functionalities.

Class LibxcProxy.h

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).

Use cases LibxcProxy

Now, we'll explain how to use the LibxcProxy component from Lio.

1. Compiler directives

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

1.1 CPU 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

1.2 GPU directives

#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.

2. LibxcProxy initialization

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.

2.1 CPU initialization

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

2.2 GPU initialization

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.

3. Functional's calculation

3.1 CPU version

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.