%
% The LIBINT Programmer's Manual
%

\documentclass[10pt]{article}

\usepackage{amsmath}
\usepackage{listings}
\lstloadlanguages{[ISO]C++}
\usepackage{courier}
\usepackage{color}
\usepackage{xcolor}
\usepackage[top=1in,left=1in,right=1in,bottom=1in]{geometry}

\usepackage{float}
\usepackage{wrapfig}
\usepackage[font=footnotesize,labelfont=footnotesize]{caption}
\captionsetup[wrapfigure]{name=Figure,font=footnotesize,labelfont=footnotesize,labelfont+=bf}
\captionsetup[wrapprogram]{name=Program,font=footnotesize,labelfont=footnotesize,labelfont+=bf}

\usepackage{algorithm}
\usepackage{algorithmic}
\usepackage{appendix}
\usepackage{graphicx}
\usepackage{epsfig}
\usepackage{amsfonts}
\IfFileExists{braket.sty}{
  \usepackage{braket}
}{}
\providecommand{\braket}[1]{\ensuremath{\langle #1 \rangle}}
\usepackage{dcolumn}
\usepackage{url}
\usepackage{textcomp}
\usepackage{mathcomp}
\usepackage{listings}
\usepackage{latexsym}
\usepackage{color}
\usepackage{verbatim}
\usepackage{subfigure}
\usepackage{setspace}
\usepackage{hyperref}
\usepackage{framed}

\usepackage{paralist}
\usepackage{footmisc}
\usepackage[sort&compress,super,comma]{natbib}
\renewcommand{\thefootnote}{\fnsymbol{footnote}}
\renewcommand{\familydefault}{\sfdefault}
\IfFileExists{sfmath.sty}{
  \usepackage[cm]{sfmath}
}{}
\IfFileExists{bbding.sty}{
  \usepackage{bbding}
}{}


\lstset{
         basicstyle=\footnotesize\ttfamily, % Standardschrift
         %numbers=left,               % Ort der Zeilennummern
         numberstyle=\tiny,          % Stil der Zeilennummern
         %stepnumber=2,               % Abstand zwischen den Zeilennummern
         numbersep=5pt,              % Abstand der Nummern zum Text
         tabsize=2,                  % Groesse von Tabs
         extendedchars=true,         %
         breaklines=true,            % Zeilen werden Umgebrochen
         keywordstyle=\color{red},
         frame=b,         
         stringstyle=\color{white}\ttfamily, % Farbe der String
         showspaces=false,           % Leerzeichen anzeigen ?
         showtabs=false,             % Tabs anzeigen ?
         xleftmargin=17pt,
         framexleftmargin=17pt,
         framexrightmargin=5pt,
         framexbottommargin=4pt,
         %backgroundcolor=\color{lightgray},
         showstringspaces=false      % Leerzeichen in Strings anzeigen ?        
 }
\usepackage{caption}
\DeclareCaptionFont{white}{\color{white}}
\DeclareCaptionFormat{listing}{\colorbox{gray}{\parbox{\textwidth}{#1#2#3}}}
\captionsetup[lstlisting]{format=listing,labelfont=white,textfont=white}

\begin{document}
\input{macros}

\begin{center}
{\bf {\Large The \LIBINT\ Programmer's Manual}} \\
~\\
Edward F.\ Valeev \\
~\\
{\em Department of Chemistry, Virginia Tech, Blacksburg, Virginia 24061 USA}\\
~\\
\LIBINTv \\
Created on: \today \\
\vspace{30\baselineskip}
\includegraphics[width=0.3\textwidth]{Libint_Logo3_alt}

\end{center}

\thispagestyle{empty}

\newpage
\section{Introduction}
\LIBINT\ library contains functions to compute many-body integrals over Gaussian
functions which appear in electronic and molecular structure theories.
\LIBINTv \cite{Libint1}\ can currently compute several different types of integrals:

\begin{itemize}

\item Two-body Coulomb (electron repulsion) integrals (ERIs). This is by
far the most common type of integrals in molecular structure theory. Two-,
three-, and four-center integrals, and their geometrical derivatives, are
supported.

\item Two-body integrals which appear in explicitly correlated R12/F12 methods
with Gaussian correlation factors.\cite{Kutzelnigg85,Kutzelnigg91,Persson96} All R12 methods, such as
MP2-R12, contain terms in the wave function that depend on the interelectronic distances
$r_{ij}$ (hence the name). Appearance of several types of {\em two}-body integrals
is due to the use of the approximate resolution of the identity to reduce three- and four-body
integrals to products of simpler integrals.

\end{itemize}

A somewhat unusual feature of \LIBINT\ library is that its source code is
generated by a computer program, i.e., a {\em compiler}. The purpose of the
\LIBINT\ compiler is twofold:
\begin{itemize}
\item First, the compiler eliminates need for tedious writing,
debugging, and optimizing the integrals code.
Instead, a programmer provides high-level specification of
operators and recurrence relations,
and heuristics of how to apply the recurrence relations and the compiler takes care of the rest.
This currently requires some high-level programming, in a domain-specific
mini-language taylored for expressing recurrence relations. For example, the
following Obara-Saika recurrence relation,\cite{Obara86}
\begin{eqnarray}
\label{eq:osvrrA}
({\bf a}+1_i\ {\bf b}| {\bf c} {\bf d})^{(m)} & = &
({\bf PA})_i ({\bf a} {\bf b}| {\bf c} {\bf d})^{(m)} +
({\bf WP})_i ({\bf a} {\bf b}| {\bf c} {\bf d})^{(m+1)} \nonumber \\
& & +
\frac{a_i}{2 \zeta} \Bigl[
({\bf a}-1_i\ {\bf b}| {\bf c} {\bf d})^{(m)} - \frac{\rho}{\zeta}
({\bf a}-1_i\ {\bf b}| {\bf c} {\bf d})^{(m+1)} \Bigr] \nonumber \\
& & +
\frac{b_i}{2 \zeta} \Bigl[
({\bf a}\ {\bf b}-1_i| {\bf c} {\bf d})^{(m)} - \frac{\rho}{\zeta}
({\bf a}\ {\bf b}-1_i| {\bf c} {\bf d})^{(m+1)} \Bigr] \nonumber \\
& & +
\frac{c_i}{2 (\zeta+\eta)}
({\bf a} {\bf b}| {\bf c}-1_i\ {\bf d})^{(m+1)} \nonumber \\
& & +
\frac{d_i}{2 (\zeta+\eta)}
({\bf a} {\bf b}| {\bf c}\ {\bf d}-1_i)^{(m+1)}
\end{eqnarray}
is specified in a high-level form in C++ as shown in Listing \ref{lst:osrrcode}.
\item Second, the goal of the compiler is to make possible optimizing the code
for existing and future computer hardware. For example, the ongoing trend in
processors is to support single instruction multiple data (SIMD)
parallelism. To effectively take advantage of the SIMD units
The \LIBINT\ compiler can generate vectorized code at user's request.
As the hardware evolves, manual code reengineering can be avoided --
only the compiler needs to be modified.
\end{itemize}


\begin{lstlisting}[label=lst:osrrcode,caption=Example specification of an
Obara-Saika recurrence relation in \LIBINT\ compiler (see {\tt
src/bin/libint2/vrr\_11\_twoprep\_11.h}).
The corresponding mathematical expression is shown in Eq. \eqref{eq:osvrrA}]{}
  auto ABCD_m = factory.make_child(a,b,c,d,m);
  auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
  expr_ = Vector("PA")[dir] * ABCD_m + Vector("WP")[dir] * ABCD_mp1;
  
  auto am1 = a - _1;
  if (exists(am1)) {
    auto Am1BCD_m = factory.make_child(am1,b,c,d,m);
    auto Am1BCD_mp1 = factory.make_child(am1,b,c,d,m+1);
    expr_ += Scalar(a[dir]) * Scalar("oo2z") * (Am1BCD_m - Scalar("roz") * Am1BCD_mp1);
  }

  auto bm1 = b - _1;
  if (exists(bm1)) {
    auto ABm1CD_m = factory.make_child(a,bm1,c,d,m);
    auto ABm1CD_mp1 = factory.make_child(a,bm1,c,d,m+1);
    expr_ += Scalar(b[dir]) * Scalar("oo2z") * (ABm1CD_m - Scalar("roz") * ABm1CD_mp1);
  }

  auto cm1 = c - _1;
  if (exists(cm1)) {
    auto ABCm1D_mp1 = factory.make_child(a,b,cm1,d,m+1);
    expr_ += Scalar(c[dir]) * Scalar("oo2ze") * ABCm1D_mp1;
  }

  auto dm1 = d - _1;
  if (exists(dm1)) {
    auto ABCDm1_mp1 = factory.make_child(a,b,c,dm1,m+1);
    expr_ += Scalar(d[dir]) * Scalar("oo2ze") * ABCDm1_mp1;
  }
\end{lstlisting}

There are also drawbacks to the compiler-based \LIBINT\ approach. First, the
generated code can be fairly large and thus take a long time to compile.
It is a relatively benign problem in practice.
Also, the \LIBINT\ compiler is a fairly complicated program; this
limits the extent to which an average programmer can modify it.

\LIBINT\ currently implements recursive schemes based on the Obara-Saika method,\cite{Obara86, Obara88}
and Head-Gordon-Pople\cite{Head-Gordon88} and Hamilton-Lindh variations thereof.\cite{Hamilton91,Lindh91}
Other recurrence relations can be easily implemented as needed.

Unlike version 1, which came as three separate interdependent libraries, version
2 of \LIBINT\ comes as a single library configured at code-generation time.
The following features of the library can be configured:
\begin{itemize}
\item support for four-center ERI, including optional support for two- and
three-center ERIs,
\item derivative level for ERI,
\item support for some special two-body integrals for explicitly-correlated
integrals, e.g. of $[\hat{T}_1,\exp(- \alpha r_{12}^2)]$,
\item optimization features (whether shell-sets of integrals can be unrolled,
whether to perform Common Subexpression Elimination, etc.),
\item vectorization features,
\item algorithmic features (evaluation strategy),
\item API features (name prefix, FLOP counter, whether to accumulate target integrals, floating-point type,
shell ordering of Cartesian basis functions),
\item shared library support.
\end{itemize}
Depending on its configuration, the library may not lack some capabilities.

\section{Overview of \LIBINT 's API}

({\bf Note}: Depending on configuration, \LIBINT\ may support computation of several types of integrals. This section describes
the parts of the interface that deal with theevaluatiin of four-center two-body Coulomb integrals.
Additional notes on computing other types of integrals are provided in later sections.)

\LIBINT\ library is a low-level C++ code. C linking convention is adopted to enable interoperability with other languages, such as C and FORTRAN.
For notes on how to use \LIBINT\ library from FORTRAN code, see subsection
\ref{ssec:fort}.

\LIBINT\ API consists of 3 major components: type definitions, function and variable prototypes, and C preprocessor macros.
The API is described in the following header files:
\begin{itemize}
\item \libinth\ -- main header file, it includes most other headers (not generated).
\item \libintinttypesh\ -- architecture-specific definitions for long integer types (not generated).
\item \libinttypesh\ -- definitions for the integral evaluator types (generated).
\item \libintparamsh\ -- C preprocessor macros for library features (generated).
\item \libintifaceh\ -- prototypes for functions and data as well as some misc macros (generated).
\item \boysh\ -- engines for computation of the Boys function and related quantities (not generated).
\end{itemize}
\libinth\ (and, optionally, \boysh) is the only header that must be included explicitly in the user code.

The preprocessor macros provided by \libinth\ are necessary so that the user code can
access the library configuration parameters. For example, the library can be configured at the code generation time
to support any finite angular momentum (quantum numbers) of the basis functions. The user code must still
test whether the maximum angular momentum present in the basis set exceeds the library limit.

The preprocessor value macros provided by \libinth\ are listed in Listing
\ref{lst:valmacros}
The most important macro, {\tt LIBINT2\_REALTYPE}, specifies the floating-point type
used by the library for all computations (usually, {\tt double}).
The next macro, {\tt LIBINT2\_MAX\_VECLEN} specifies the maximum vector length supported by the library. For the scalar code
this macro will be set to 1, whereas for the vectorized library this will have a value greater than
1.
The next macro, {\tt LIBINT2\_API\_PREFIX}, is used by the {\tt LIBINT2\_PREFIXED\_NAME} function macro and should not be
used explicitly (I list it here for completeness).
The last three macros describe whether the library supports computation of the electron repulsion integrals,
the maximum angular momentum of the basis functions supported for the ERI code (value of 3 corresponds to support
of up to $f$ functions, etc.), and the maximum order of the
ERI derivatives which can be computed.

\begin{lstlisting}[label=lst:valmacros,caption=C preprocessor value macros
provided by \libinth . The angled brackets describe valid macro values.]{}
#define LIBINT2_REALTYPE <C++ floating-point type>
#define LIBINT2_MAX_VECLEN <positive integer>
#define LIBINT2_API_PREFIX <string>

/* ERI-specific macros */
#define LIBINT2_SUPPORT_ERI <0 or 1>
#define LIBINT2_MAX_AM_eri <nonnegative integer>
#define LIBINT2_DERIV_ERI_ORDER <nonnegative integer>
\end{lstlisting}

\LIBINT\ API also specifies several functions and variables whose decralations
are listed in Listing \ref{lst:api}.

The first two functions perform static initialization and cleanup of the library.
Thus {\tt libint2\_static\_init} must be called before \LIBINT\ is used and
{\tt libint2\_static\_cleanup} must be called after \LIBINT\ is no longer needed (only one thread needs to call these functions).

The next two functions are used to initialize and cleanup the key data
structure ({\em integral evaluator}) involved in the computation of the electron repulsion integrals.
To initialize the integral evaluator, {\tt libint2\_init\_eri} should be called with three arguments:
1) the pointer to the evaluator to be initialized (or to the first evaluator of an array of evaluators -- see the notes on handling contracted Gaussians below); 2) the maximum angular momentum
of basis functions this object will support ({\tt max\_am} will affect the memory requirements
for the computation and therefore should be always set to the actual maximum value needed,
not the maximum value supported by the library); 3) optional pointer to the scratch buffer
which will be used to hold intermediate results. If the third argument is 0, then
the call will dynamically allocate the needed space. If the user code needs to control
memory allocation/deallocation, the scratch buffer needs to be allocated prior to the call.
{\tt libint2\_need\_memory\_eri} can be used to compute the required size of
the scratch buffer in units of {\tt LIBINT2\_REALTYPE}. Lastly, {\tt libint2\_build\_eri} is a 4-dimensional
array of pointers to functions that evaluate ERIs, e.g., {\tt libint2\_build\_eri[1][0][2][0](\&erieval)}
will compute the $(ps|ds)$ set using evaluator {\tt erieval} ({\tt erieval} must have been initialized
with {\tt libint2\_init\_eri}).

\begin{lstlisting}[label=lst:api,caption=\LIBINT\ API  functions and data.
{\tt N = LIBINT2\_MAX\_AM\_ERI + 1}.]{}
void libint2_static_init();
void libint2_static_cleanup();

/* ERI-specific API */
void libint2_init_eri(Libint_eri_t* libint, int max_am, LIBINT2_REALTYPE* buf);
void libint2_cleanup_eri(Libint_eri_t* libint);
size_t libint2_need_memory_eri(int max_am);
void (*libint2_build_eri[N][N][N][N])(Libint_eri_t *);
\end{lstlisting}

\LIBINT\ API described so far is very simple. However, as you may have noticed, there has been no mention of
where the basis set data is stored. This is because \LIBINT\ does not maintain the basis set information.
As part of \LIBINT 's philosophy to provide the leanest possible code, the user code
is in charge of precomputing basis set data and Boys function values and then feeding it to the evaluator object
of type {\tt Libint\_eri\_t}. (Note that since currently all integral evaluations in \LIBINT\ use the same
evaluator object type, they are all just typedefs to the common type {\tt Libint\_t}, henceforth
we will use both interchangeably).

\begin{lstlisting}[label=lst:libintt,caption=Definition of the \LIBINT\ integral evaluator type.]{}
typedef struct {
  _aB_s__0__s__1___TwoERep_s__0__s__1___Ab__up_0[VECLEN];
  _aB_s__0__s__1___TwoERep_s__0__s__1___Ab__up_1[VECLEN];
  _aB_s__0__s__1___TwoERep_s__0__s__1___Ab__up_2[VECLEN];
  _aB_s__0__s__1___TwoERep_s__0__s__1___Ab__up_3[VECLEN];
  _aB_s__0__s__1___TwoERep_s__0__s__1___Ab__up_4[VECLEN];
  /* and so on until 4 * LIBINT2_MAX_AM_ERI */

  LIBINT2_REALTYPE WP_x[VECLEN], WP_y[VECLEN], WP_z[VECLEN];
  LIBINT2_REALTYPE WQ_x[VECLEN], WQ_y[VECLEN], WQ_z[VECLEN];
  LIBINT2_REALTYPE PA_x[VECLEN], PA_y[VECLEN], PA_z[VECLEN];
  LIBINT2_REALTYPE QC_x[VECLEN], QC_y[VECLEN], QC_z[VECLEN];
  LIBINT2_REALTYPE AB_x[VECLEN], AB_y[VECLEN], AB_z[VECLEN];
  LIBINT2_REALTYPE CD_x[VECLEN], CD_y[VECLEN], CD_z[VECLEN];

  LIBINT2_REALTYPE oo2z[VECLEN];
  LIBINT2_REALTYPE oo2e[VECLEN];
  LIBINT2_REALTYPE oo2ze[VECLEN];
  LIBINT2_REALTYPE roz[VECLEN];
  LIBINT2_REALTYPE roe[VECLEN];
  
  LIBINT2_REALTYPE* stack;   /* used internally */
  LIBINT2_REALTYPE* vstack;  /* used internally */
  LIBINT2_REALTYPE* targets[LIBINT2_MAX_NTARGETS_eri];
  int veclen;

  LIBINT2_UINT_LEAST64* nflops;
  int zero_out_targets;
} Libint_eri_t;
\end{lstlisting}

The definition of {\tt Libint\_eri\_t} is shown in Listing \ref{lst:libintt}.
{\tt Libint\_eri\_t} is a C structure, i.e., its members can be manipulated directly.
This is done to allow direct manipulation of {\tt Libint\_eri\_t} from
Fortran and other languages.
Note that only ERI-specific parts of the actual definition {\tt Libint\_eri\_t}
are shown in Listing \ref{lst:libintt}. Currently, the same data structure is
used for all types of evaluators (i.e. for ERI evaluators and Gaussian geminal type evaluators), i.e. {\tt Libint\_eri\_t} contains also members which are only used
for evaluation of Gaussian geminal integrals also. In the future the evaluator types will be generated
automatically and will be specific to each type of computation.

Let's look in detail at the members of {\tt Libint\_eri\_t} which must be precomputed before
calling the relevant {\tt libint2\_build\_eri} function:
\begin{itemize}
\item {\tt \_aB\_s\_\_0\_\_s\_\_1\_\_\_TwoERep\_s\_\_0\_\_s\_\_1\_\_\_Ab\_\_up\_m} --
values of auxiliary primitive integrals $({\bf 00}|{\bf 00})^{(m)}$ (Eq.
\eqref{eq:0000m}) for $0 \leq m \leq \lambda({\bf a}) + \lambda({\bf b}) +
\lambda({\bf c}) + \lambda({\bf d}) + C$, where $C = 0$ when computing ERIs, $C=1$ when computing first derivative ERIs, etc.
\item {\tt AB\_i}, {\tt CD\_i} -- cartesian components of vectors ${\bf AB} \equiv {\bf A} - {\bf B}$
and ${\bf CD} \equiv {\bf C} - {\bf D}$.
\item {\tt PA\_i}, {\tt QC\_i} -- cartesian components of vectors ${\bf PA} \equiv {\bf P} - {\bf A}$
and ${\bf QC} \equiv {\bf Q} - {\bf C}$.
\item {\tt WP\_i}, {\tt WQ\_i} -- cartesian components of vectors ${\bf WP} \equiv {\bf W} - {\bf P}$
and ${\bf WQ} \equiv {\bf W} - {\bf Q}$.
\item {\tt oo2z} -- $\frac{1}{2\zeta}$
\item {\tt oo2n} -- $\frac{1}{2\eta}$
\item {\tt oo2zn} -- $\frac{1}{2(\zeta+\eta)}$
\item {\tt roz} -- $\frac{\rho}{\zeta}$
\item {\tt ron} -- $\frac{\rho}{\eta}$
\end{itemize}
Most of these quantities are simple to evaluate. Evaluation of the Boys function needed to compute
the auxiliary integrals $({\bf 00}|{\bf 00})^{(m)}$ can be fairly complicated.\cite{Gill91}
\LIBINT\ includes C++ classes that can evaluate Boys and related functions relatively
efficiently (see \boysh\ header). An example of how to use \LIBINT\ to compute Boys function
is shown in Listing \ref{lst:boys}.
\begin{lstlisting}[label=lst:boys,caption=Computation of Boys function using \LIBINT.]{}
#include <libint2/boys.h>

// initialize Boys function engine to support m values up to mmax
// not thread-safe, should be constructed by main thread
libint2::FmEval_Chebyshev7 fmeval(mmax);

// double* Fm initialized somewhere else
// on return Fm[m], m=0..M, contains Fm(T)
// thread-safe provided each thread uses its own Fm
fmeval.eval(Fm, T, M);
\end{lstlisting}

Note that the evaluator object contains data that is depends on the Gaussian exponents.
Hence for a shell set over contracted Gaussian functions data for each combination of primitive Gaussians
will be kept in its own evaluator object, resulting in an array of evaluator objects necessary to evaluate contracted integrals.
This is best illustrated by an example shown in Listing \ref{lst:contrloops}.
This is perhaps the most significant change relative to the version 1 of the library, where the single evaluator object kept the data for all primitive combinations contributing to the given shell set. 
\begin{lstlisting}[label=lst:contrloops,caption=Initialization and use of \LIBINT\ with contracted basis functions.]{}
libint2_static_init(); // static initialization (once per program)
std::vector<Libint_t> inteval(contrdepth4); // array of contrdepth4 evaluators
                                            // contrdepth4 = contrdepth^4, where contrdepth is the max contraction
                                            // depth of Gaussians in the basis set

// initialize the array of evaluators .. this allocates the scratch array
// use libint2_need_memory_eri() to figure out how much memory is needed
libint2_init_eri(&inteval[0], // ptr to the first evaluator in the array
                 lmax,        // maximum angular momentum
                 0);          

// loop over (contracted) Gaussian shells
for(int s0=0; s0<nshell; ++s0) {
  for(int s1=0; s1<nshell; ++s1) {
    for(int s2=0; s2<nshell; ++s2) {
      for(int s3=0; s3<nshell; ++s3) {
        
        // decide whether to evaluate the integral (uniqueness, magnitude, etc.)
        // ..

        // loop over each primitive combination for this shell set
        int p0123 = 0;
        for(int p0=0; p0<nprim[s0]; ++p0) {
          for(int p1=0; p1<nprim[s0]; ++p1) {
            for(int p2=0; p2<nprim[s0]; ++p2) {
              for(int p3=0; p3<nprim[s0]; ++p3) {

                // optionally screen out primitive combinations
                
                // compute primitive data and put into inteval[p0123]
                // ...

                ++p0123;
              }
            }
          }
        }
        // report the number of primitive combinations to libint
        inteval[0].contrdepth = p0123;
        
        // evaluate the contracted integral shell set
        libint2_build_eri[am[s0]][am[s1]][am[s2]][am[s3]](&inteval[0]);
        
        // grab the resulting shell set in inteval[0].targets[0][...]
      }
    }
  }
}

libint2_cleanup_eri(&inteval[0]);
libint2_static_cleanup();
\end{lstlisting}

After the integrals have been built, they are placed somewhere in the scratch buffer.
To recover their location, the array of pointers {\tt targets} is provided, e.g.,
the computed ERI shell-set is located at {\tt target[0]}.
ERI evaluation produces only one shell-set of integrals, but other types of computations
may produce several shell-sets of integrals at a time, e.g., usually all 12 derivative
ERI integrals are computed at the same time. That's why {\tt target} is an array of pointers, not a pointer.

Shell-sets of integrals contain integrals in ``row major'' order.\cite{KnuthACP} For example, if
the number of functions in each shell is $n_a$, $n_b$, $n_c$, and $n_d$, respectively,
then the integral $(ab|cd)$ is found at position $abcd = ( (a n_b + b) n_c + c) n_d + d$.

The rest of {\tt Libint\_eri\_t} is used to control various aspects of its behavior:
\begin{itemize}
\item {\tt veclength} is used in vectorized computation of integrals.
\item {\tt nflops} is used to count the total number of FLOPs (the library must have been \
configured with {\tt --enable-flop-counter}).
\item {\tt zero\_out\_targets} is used to zero out the target integral buffers. This is only useful
  if \LIBINT\ was configured with {\tt --enable-accum-ints}.
\end{itemize}

{\bf Note} that currently the \LIBINT\ compiler minimizes the amount of code it
generates by taking advantage of the permutational symmetry of the integrals.
This means that only certain combinations of the angular momenta can be handled.
In standard configuration \LIBINT\ can evaluate a shell quartet $({\bf ab}|{\bf cd})$ if $\lambda({\bf a}) \geq \lambda({\bf b})$, $\lambda({\bf c}) \geq \lambda({\bf d})$, and $\lambda({\bf c}) + \lambda({\bf d}) \geq \lambda({\bf a}) + \lambda({\bf b})$.
(There is also the ordering used by {\tt ORCA} program for which \LIBINT\ can be
configured --- it will not be discussed here). If one needs to compute a quartet that doesn't conform the rule,
e.g. of type $(pf|sd)$, permutational symmetry of integrals can be utilized to compute such quartet:
\begin{eqnarray}
(pq|rs) = (pq|sr) = (qp|rs) = (qp|sr) = (rs|pq) = (rs|qp)= (sr|pq) = (sr|qp)
\end{eqnarray}
In the case of $(pf|sd)$ shell quartet, one computes quartet $(ds|fp)$ instead, and then
permutes function indices back to obtain the desired $(pf|sd)$.

The final integrals that \LIBINT\ computes are not normalized. The best way to include the normalization
is to scale the auxiliary integrals $({\bf 00}|{\bf 00})^{(m)}$ by the normalization factors.
However, Gaussians in a shell of angular momentum $>1$ have different normalization factors.
Usually the convention is to unit-normalize only the functions which have all
quanta along one Cartesian direction, e.g., $d_{xx}, f_{xxx}$, etc. Some
programs (e.g., GAMESS) require all functions to be unit-normalized;
this can be achieved by scaling the final integrals.

\section{Using \LIBINT\ to compute non-Coulomb integrals}

As elegantly shown by Ahlrichs,\cite{Ahlrichs:2006} Obara-Saika and related schemes can also be used to compute many two-body integrals with spherically-symmetric kernels $f(r_{12})$. Such integrals appear in, for example, explicitly correlated R12/F12 methods or in range-separated form of Kohn-Sham density functional theory. To compute such integrals, instead of the Coulomb-kernel $({\bf 00}|{\bf 00})^{(m)}$ integrals related to the Boys function by Eq. \ref{eq:0000m_scaled} \LIBINT\ needs to be fed the corresponding kernel-specific $({\bf 00}|{\bf 00})^{(m)}$ integrals related to the
the kernel-specific $G_{m}(\rho,T)$ function of Ahlrichs. Explicit expressions for $G_{m}$ for several important kernels are given
in Section 5 of Ref. \cite{Ahlrichs:2006}. For example, for the Coulomb kernel $G_{m}(\rho,T)$ are related to the Boys function as (Eq. (39) of Ahrlichs paper):
\begin{align}
G_{0}(\rho, T) = & \frac{2 \pi}{\rho} F_{m}(T).
\end{align}
Hence Eq. \eqref{eq:0000m_scaled} changes to
\begin{eqnarray} \label{eq:0000m_scaled_Gm}
({\bf 00}|{\bf 00})^{(m)} & = &  G_m(\rho, \rho |{\bf PQ}|^2) \sqrt{\frac{\rho^{3}}{\pi^{3}}}S_{12}S_{34}
C_1 C_2 C_3 C_4 .
\end{eqnarray}
where the overlaps $S_{12}$ and $S_{34}$ are defined in Eqs. \eqref{eq:S12} and \eqref{eq:S34}, {\bf not} the overlaps from Ahlrichs' paper.

\LIBINT\ supports computation of the $G_{m}$ function for the important case of a contracted Gaussian kernel that appears in
explicitly correlated methods:
\begin{align}
f_{k}(r_{12}) = & r_{12}^{k} \sum_{i=1}^{n} c_{i} \exp(- \alpha_{i} r_{12}^{2}) , \quad k=-1,0,2.
\end{align}
Example code is shown in Listing \ref{lst:GmGaussian}.

\begin{lstlisting}[label=lst:GmGaussian,caption=Computation of the $G_{m}$ function for the contracted Gaussian kernel using \LIBINT.]{}
#include <libint2/boys.h>

// initialize Gaussian Gm function engine to support m values up to mmax
// k specifies the exponent of r_{12} in the kernel (0, -1, and 2 supported)
libint2::GaussianGmEval<double, k> gmeval(mmax, 1e-15);  // 1e-15 is the desired precision

// vector of {exponent,coefficient} pairs = contracted Gaussian kernel
std::vector<std::pair<double,double> > gauss;

// double* Gm initialized somewhere else
// on return Gm[m], m=0..M, contains Gm(rho,T)
gmeval.eval(Gm, rho, T, M, gauss);
\end{lstlisting}

\section{Using \LIBINT\ to compute geometrical derivatives of integrals.}
\LIBINT\ can also evaluate geometrical derivatives of two-body integrals with respect to basis function positions.
One shell set of four-center two-body integrals $({\bf ab}|{\bf cd})$ has total of 12 first-order geometrical derivatives:
\begin{eqnarray}
& & \frac{\partial ({\bf ab}|{\bf cd})}{\partial A_i}, \frac{\partial ({\bf ab}|{\bf cd})}{\partial B_i},
\frac{\partial ({\bf ab}|{\bf cd})}{\partial C_i},
\frac{\partial ({\bf ab}|{\bf cd})}{\partial D_i} :\quad i \in \{x,y,z\} \nonumber
\end{eqnarray}
and $12\times12=144$ second-order derivatives, although only $\frac{12 (12+1)}{2}=78$ of those are unique because of
permutation symmetry with respect to the order of taking the derivative:
\begin{eqnarray}
& & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial A_j}, \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial B_j},
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial C_i \partial C_j}, \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial D_i \partial D_j} :\quad
i \leq j \in \{x,y,z\} \nonumber \\
& & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial B_j}, \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial C_j},
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial D_j}, \nonumber \\
& & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial C_j}, \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial D_j},
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial C_i \partial D_j} : \quad i,j \in \{x,y,z\} \nonumber
\end{eqnarray}
The translational invariance of the integral can be used to eliminate derivatives involving one of the centers (as a matter of convention, \LIBINT\ skips the third center, {\bf C}). This allows to eliminate 3 of the 12 first-order derivatives.
\begin{eqnarray} \label{eqn:TId1eri}
\frac{\partial ({\bf ab}|{\bf cd})}{\partial C_i} & = & - \frac{\partial ({\bf ab}|{\bf cd})}{\partial A_i} -
\frac{\partial ({\bf ab}|{\bf cd})}{\partial B_i} - \frac{\partial ({\bf ab}|{\bf cd})}{\partial D_i} \quad i \in \{x,y,z\}
\end{eqnarray}
and
33 of the 78 second-order derivatives
\begin{eqnarray} \label{eqn:TId2eri_AC}
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial C_j} & = & - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial A_j} -
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial B_j} - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial D_j} \quad i,j \in \{x,y,z\} \\
\label{eqn:TId2eri_CC}
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial C_i \partial C_j} & = & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial A_j} +
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial C_j} + \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial D_j} \nonumber \\
& & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_j \partial B_i} +
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial C_j} + \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial D_j} \nonumber \\
& & \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_j \partial D_i} +
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_j \partial D_i} + \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial D_i \partial D_j} \quad i \leq j \in \{x,y,z\} \\
\label{eqn:TId2eri_BC}
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial C_j} & = & - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_j \partial B_i} -
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial B_j} - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial D_j} \quad i,j \in \{x,y,z\} \\
\label{eqn:TId2eri_CD}
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial C_i \partial D_j} & = & - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial A_i \partial D_j} -
\frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial B_i \partial D_j} - \frac{\partial^2 ({\bf ab}|{\bf cd})}{\partial D_i \partial D_j} \quad i,j \in \{x,y,z\} \\
\end{eqnarray}
Here's an easy way to understand how many derivatives are permutationally and translationally invariant:
translational invariance allows to omit one center from consideration, hence we are left with 4-1=3 centers and $3\times3 = 9$
first-order geometrical derivatives; for the $k$th-order derivatives the order of differentiation does not matter, hence
we are left with $(9+k)!/9!k!$ unique derivatives, i.e. $9 \times 10/2 = 45$ second-order derivatives.

To minimize the operation count, \LIBINT\ evaluates a complete set of unique shell-set derivatives at once.
On return, {\tt Libint\_t::target[i]} will contain the {\tt i}-th set of derivative integrals. For the first-order derivatives
sets $i=0..2$ corresponds to the derivative with respect to $A_{x} .. A_{z}$, respectively, $i=3..5$ --- $B_{x} .. B_{z}$,
and $i=6..8$ --- $D_{x} .. D_{z}$; derivatives with respect to coordinates $C_{x}..C_{z}$ can be recovered using Eq. \eqref{eqn:TId1eri}.
Similarly, for the second-order derivatives {\tt Libint\_t::target[ij]} will contain {\tt ij}-th set of derivative integrals,
where $ij$ is the composite ``upper-triangle'' index: $ij = i\times(19-i)/2 + (j-i), 0\leq i \leq j<9$.
For example, {\tt Libint\_t::target[29]} thus contains the $\partial^{2}/\partial B_{x} \partial D_{z}$ derivative set ($ij=29 \to i=3, j=8$).

The additional types of ``compute'' functions specific to the geometric derivatives are:
\begin{verbatim}
extern void (*libint2_build_eri1[5][5][5][5])(Libint_t *);
extern void (*libint2_build_eri2[4][4][4][4])(Libint_t *);
\end{verbatim}
The former refers to functions which compute first derivative ERIs, and the second
refers to functions which compute second derivative ERIs.
The dimensions of each array are determined by the following 2 configure-time macros defined in \libintparamsh:
\begin{verbatim}
#define LIBINT2_MAX_AM_ERI1 5
#define LIBINT2_MAX_AM_ERI2 4
\end{verbatim}
(the actual values ail depend on how the library was configured).

Each derivative shell set is identical in structure to a nondifferentiated
shell set, i.e. individual integrals are arranged in a row major order. Normalization convention
for the derivative integrals is the same as for the regular ERIs.

\section{Using \LIBINT\ to compute three- and two-center integrals}

No notes yet --- see {\tt tests/eri/test\_eri.cc} for a working example of how to compute 2- and 3-center integrals and their geometrical derivatives.

\section{Example: using \libint\ to compute four-center two-body Coulomb integrals}

A C++ function that uses \LIBINT\ to evaluate four-center two-body Coulomb
integrals over {\em primitive} (non-contracted) Gaussians is shown in Listing
\ref{lst:usecpp}.

\lstinputlisting[label=lst:usecpp,caption=Using \LIBINT\ from
C++.]{lstusecpp.cc}

To see how to use \LIBINT\ for efficient computation of integrals over
{\em contracted} basis functions refer to the sample code found in
{\tt tests/eri} directory.

\section{Notes on using \LIBINT\ from Fortran \label{ssec:fort} }

\subsection{Modern Fortran}

Codes that compile with Fortran standard 2003 or later can easily access \LIBINT\ via its Fortran bindings.
The Fortran API is located in the fortran subdirectory of \LIBINT\ and is organised as follows:
\begin{itemize}
    \item {\tt libint2\_types\_f.h} -- definitions for the integral evaluator types (generated)
    \item {\tt libint\_f.F90} -- prototypes for functions and data (not generated)
    \item {\tt fortran\_example.F90} -- Fortran example: four-center two-body Coulomb integrals over primitive Gaussians and derivatives (not generated)
\end{itemize}

The Fortran API currently has support for two-, three- and four-center Coulomb integrals and its derivatives.
Some parts of \LIBINT\ C++ API that do not provide a C interface are missing - most notably the Boys function engine.
For {\tt LIBINT2\_REALTYPE} only {\tt float} and {\tt double} ({\tt c\_float} and {\tt c\_double} in Fortran) are currently supported.
If specific functions of Libint are missing (integrals other than Coulomb), it is easy to contribute them to \LIBINT\ ({\tt libint\_f.F90}),
or to write Fortran bindings for these in your own code.

The provided Fortran bindings are an exact translation of the C API.
The definition of the Fortran derived type {\tt Libint\_t} is shown in Listing \ref{lst:libinttf}.
The only notable difference to the corresponding C struct (Listing \ref{lst:libintt}) is that variable names starting with an underscore in C are prefixed with a letter {\tt f} in Fortran.
Refer to Listing \ref{lst:apif} for Fortran prototypes of procedures and data.
Note that the index order of multidimensional arrays is reverse in fortran
compared to C due to row-major vs. column-major order such that e.g. {\tt
libint2\_build\_eri[am1][am2][am3][am4]} in C corresponds to {\tt
libint2\_build\_eri(am4, am3, am2, am1)} in Fortran.

\begin{lstlisting}[label=lst:libinttf,caption=Fortran definition of the \LIBINT\ integral evaluator type.]{}
type, bind(c) :: Libint_t
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: f_aB_s___0___ElecPot_s___0___Ab__up_0
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: f_aB_s___0___ElecPot_s___0___Ab__up_1
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: f_aB_s___0___ElecPot_s___0___Ab__up_2
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: f_aB_s___0___ElecPot_s___0___Ab__up_3
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: f_aB_s___0___ElecPot_s___0___Ab__up_4
   ! and so on until 4 * LIBINT2_MAX_AM_eri

   real(LIBINT2_REALTYPE), dimension(VECLEN) :: WP_x, WP_y, WP_z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: WQ_x, WQ_y, WQ_z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: PA_x, PA_y, PA_z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: QC_x, QC_y, QC_z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: AB_x, AB_y, AB_z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: CD_x, CD_y, CD_z

   real(LIBINT2_REALTYPE), dimension(VECLEN) :: oo2z
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: oo2e
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: oo2ze
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: roz
   real(LIBINT2_REALTYPE), dimension(VECLEN) :: roe

   type(c_ptr)                                      :: stack
   type(c_ptr)                                      :: vstack
   type(c_ptr), dimension(LIBINT2_MAX_NTARGETS_eri) :: targets
   integer(c_int)                                   :: veclen

   type(c_ptr)    :: nflops
   integer(c_int) :: zero_out_targets
end type
\end{lstlisting}

\begin{lstlisting}[label=lst:apif,caption=\LIBINT\ Fortran API procedures and data.]{}
subroutine libint2_static_init() bind(C)
end subroutine

subroutine libint2_static_cleanup() bind(C)
end subroutine


! ERI-specific API

subroutine libint2_init_eri(libint, max_am, buf) bind(C)
   type(libint_t), dimension(*) :: libint
   integer(kind=c_int), value   :: max_am
   type(c_ptr), value           :: buf
end subroutine

subroutine libint2_cleanup_eri(libint) bind(C)
   type(libint_t), dimension(*) :: libint
end subroutine

function libint2_need_memory_eri(max_am) bind(C)
   integer(kind=c_int), value :: max_am
   integer(kind=c_size_t)     :: libint2_need_memory_eri
end function

type(c_funptr), &
   dimension(0:LIBINT2_MAX_AM_eri, 0:LIBINT2_MAX_AM_eri, &
             0:LIBINT2_MAX_AM_eri, 0:LIBINT2_MAX_AM_eri), &
   bind(c) :: libint2_build_eri
\end{lstlisting}

Using \LIBINT\ from Fortran requires the Fortran builtin {\tt iso\_c\_binding} module in order to ensure compatibility between Fortran and C data types.
Fortran pointers are not directly interoperable with C pointers, therefore special datatypes for C pointers ({\tt c\_ptr} and {\tt c\_funptr}) and methods
from {\tt iso\_c\_binding} to convert to Fortran pointers ({\tt c\_f\_pointer} and {\tt c\_f\_procpointer}) are needed.
If your code should be compatible with different configurations of libint compiler, you need to use conditional compilation based on the macros provided
in {\tt libint2/config.h} and {\tt libint2/libint2\_params.h} such as the
macros {\tt LIBINT2\_MAX\_AM\_eri} and {\tt LIBINT\_CONTRACTED\_INTS} (for
their use see listings \ref{lst:libinttf} and \ref{lst:usefortran}).

An example subroutine that demonstrates how to actually calculate integrals using \LIBINT\ is provided in Listing \ref{lst:usefortran}.
This example is a translation of Listing \ref{lst:usecpp} to Fortran and evaluates four-center two-body Coulomb integrals over primitive Gaussians.
See {\tt fortran\_example.F90} for an example of how to deal with contracted Gaussians and derivatives.

\begin{lstlisting}[label=lst:usefortran, caption=Using \LIBINT\ from Fortran.]{}
! include libint configuration-specific macros (may not be needed)
#include <libint2/config.h>
#include <libint2/libint2_params.h>

module libint_f_example

   USE iso_c_binding  ! C interoperability
   USE libint_f       ! libint fortran bindings

   implicit none

contains

   ! This subroutine evaluates ERI over 4 primitive Gaussian shells.
   ! See compute_eri_f in fortran/libint_f.F90 for an example of how
   ! to deal with contracted Gaussians.
   subroutine compute_eri(am1, alpha1, A, &
                          am2, alpha2, B, &
                          am3, alpha3, C, &
                          am4, alpha4, D)

      integer, parameter :: dp = c_double ! C interoperable double type
      integer, parameter :: i = c_int     ! C interoperable int type

      integer(kind=i), intent(in) :: am1, am2, am3, am4
      real(kind=dp), intent(in) :: alpha1, alpha2, alpha3, alpha4
      real(kind=dp), intent(in), dimension(3) :: A, B, C, D

      real(kind=dp) :: gammap, AB2, CD2, PQ2, gammaq, gammapq, K1, K2, pfac
      real(kind=dp), allocatable, dimension(:) :: F
      real(kind=dp), dimension(:), pointer :: eri_shell_set
      real(kind=dp), dimension(3) :: P, Q, QC, QD, PQ, PA, PB, W
      real(kind=dp), parameter :: pi = 4*atan(1.0_dp)
      integer(kind=i) :: n1, n2, n3, n4, na, nb, nc, nd, ishell, max_am, am

      type(libint_t), dimension(1) :: erieval

      procedure(libint2_build), pointer :: build_eri

      ! I will assume that libint2_static_init() has been called elsewhere!

      !
      ! initialize (usually outside this function)
      !

      max_am = maxval([am1, am2, am3, am4])
      call libint2_init_eri(erieval, max_am, C_NULL_PTR)

#if LIBINT_CONTRACTED_INTS
      ! if have support for contracted integrals, set the contraction length to 1
      erieval(1)%contrdepth = 1
#endif

      !
      ! Compute requisite data
      !

      gammap = alpha1 + alpha2
      P = (alpha1*A + alpha2*B)/gammap
      PA = P - A
      PB = P - B
      AB2 = sum((A - B)*(A - B))

      erieval(1)%PA_x(1) = PA(1)
      erieval(1)%PA_y(1) = PA(2)
      erieval(1)%PA_z(1) = PA(3)
      erieval(1)%AB_x(1) = A(1) - B(1)
      erieval(1)%AB_y(1) = A(2) - B(2)
      erieval(1)%AB_z(1) = A(3) - B(3)
      erieval(1)%oo2z(1) = 0.5_dp/gammap

      gammaq = alpha3 + alpha4
      gammapq = gammap*gammaq/(gammap + gammaq)
      Q = (alpha3*C + alpha4*D)/gammaq
      QC = Q - C
      QD = Q - D
      CD2 = sum((C - D)*(C - D))

      erieval(1)%QC_x(1) = QC(1)
      erieval(1)%QC_y(1) = QC(2)
      erieval(1)%QC_z(1) = QC(3)
      erieval(1)%CD_x(1) = C(1) - D(1)
      erieval(1)%CD_y(1) = C(2) - D(2)
      erieval(1)%CD_z(1) = C(3) - D(3)
      erieval(1)%oo2e(1) = 0.5_dp/gammaq

      PQ = P - Q
      PQ2 = sum(PQ*PQ)
      W = (gammap*P + gammaq*Q)/(gammap + gammaq)

      erieval(1)%WP_x(1) = W(1) - P(1)
      erieval(1)%WP_y(1) = W(2) - P(2)
      erieval(1)%WP_z(1) = W(3) - P(3)
      erieval(1)%WQ_x(1) = W(1) - Q(1)
      erieval(1)%WQ_y(1) = W(2) - Q(2)
      erieval(1)%WQ_z(1) = W(3) - Q(3)
      erieval(1)%oo2ze(1) = 0.5_dp/(gammap + gammaq)

      erieval(1)%roz(1) = gammapq/gammap
      erieval(1)%roe(1) = gammapq/gammaq

      K1 = exp(-alpha1*alpha2*AB2/gammap)
      K2 = exp(-alpha3*alpha4*CD2/gammaq)
      pfac = 2*pi**2.5_dp*K1*K2/(gammap*gammaq*sqrt(gammap + gammaq))

      am = am1 + am2 + am3 + am4

      !
      ! evaluate Boys function F_m for all m in [0, am]
      !

      ! here we omit the evaluation of Boys function values F(m+1)
      ! these would be calculated externally since libint Boys function engine is not
      ! accessible from Fortran
      allocate F(am + 1)
      F(1) = ...
      F(2) = ...
      ...
      F(am + 1) = ...

      if (am >= 0) &
         erieval(1)%f_aB_s___0__s___1___TwoPRep_s___0__s___1___Ab__up_0(1) = pfac*F(1)
      if (am >= 1) &
         erieval(1)%f_aB_s___0__s___1___TwoPRep_s___0__s___1___Ab__up_1(1) = pfac*F(2)
      if (am >= 2) &
         erieval(1)%f_aB_s___0__s___1___TwoPRep_s___0__s___1___Ab__up_2(1) = pfac*F(3)
      if (am >= 3) &
         erieval(1)%f_aB_s___0__s___1___TwoPRep_s___0__s___1___Ab__up_3(1) = pfac*F(4)
      if (am >= 4) &
         erieval(1)%f_aB_s___0__s___1___TwoPRep_s___0__s___1___Ab__up_4(1) = pfac*F(5)
      ! etc.

      !
      ! compute ERIs
      !

      ! convert C function pointer libint2_build_eri(am4, am3, am2, am1) to
      ! Fortran procedure pointer build_eri
      call c_f_procpointer(libint2_build_eri(am4, am3, am2, am1), build_eri)

      ! call function to compute ERIs
      call build_eri(erieval)

      !
      ! Print out the integrals
      !

      n1 = (am1 + 1)*(am1 + 2)/2
      n2 = (am2 + 1)*(am2 + 2)/2
      n3 = (am3 + 1)*(am3 + 2)/2
      n4 = (am4 + 1)*(am4 + 2)/2

      ! get C pointer to targets and convert to Fortran pointer eri_shell_set
      call c_f_pointer(erieval(1)%targets(1), eri_shell_set, shape=[n1*n2*n3*n4])

      ishell = 0
      do na = 1, n1
         do nb = 1, n2
            do nc = 1, n3
               do nd = 1, n4
                  ishell = ishell + 1
                  print *, "a = ", na, &
                     "b = ", nb, &
                     "c = ", nc, &
                     "d = ", nd, &
                     "(ab|cd) = ", eri_shell_set(ishell)
               enddo
            enddo
         enddo
      enddo

      !
      ! cleanup (usually outside this function)
      !

      call libint2_cleanup_eri(erieval)
   end subroutine

end module
\end{lstlisting}

\subsection{Fortran 77}
Codes written in Fortran 77 can not use the Fortran bindings included in {\tt LIBINT}.
In general, C functions can be easily called from Fortran 77 programs, but sharing data structures
is not straightforward. Thus the main culprit is how to modify  {\tt Libint\_eri\_t} objects
from Fortran. Older Fortran standards can access C data structures indirectly, via
common blocks. An (non-working) example of how a Fortran subroutine can manipulate {\tt Libint\_eri\_t}
is shown in Listing \ref{lst:usefort}. The
common block {\tt erieval} referened in that Listing is created by declaring
in C++ a global variable as follows:
\begin{verbatim}
extern Libint_eri_t erieval;
\end{verbatim}

\begin{lstlisting}[label=lst:usefort,caption=Accesing {\tt Libint\_eri\_t}
structure from a Fortran code.]{}
       c assuming that LIBINT2_REALTYPE is 8-bytes long
       real(8) F0(1)
       real(8) F1(1)
       real(8) F2(1)
       real(8) F3(1)
       real(8) F4(1)
       etc.
       real(8) WP_x(1), WP_y(1), WP_z(1)
       real(8) WQ_x(1), WQ_y(1), WQ_z(1)
       real(8) PA_x(1), PA_y(1), PA_z(1)
       real(8) QC_x(1), QC_y(1), QC_z(1)
       real(8) AB_x(1), AB_y(1), AB_z(1)
       real(8) CD_x(1), CD_y(1), CD_z(1)
       real(8) oo2z(1), oo2e(1), oo2ze(1), roz(1), roe(1)
       c in 64-bit environment pointers are 8-bytes long
       c assuming LIBINT2_MAX_NTARGETS is 10
       integer(8) targets(10)
       integer(4) veclength
       integer(8) nflops
       integer(4) zero_out_targets
       c common erieval represents the C object erieval
       common/erieval/ F0, F1, ... , WP_x, WP_y, etc.

       c now can access elements of erieval
       AB_x[0] = Ax[0] - Bx[0]
       etc.
\end{lstlisting}

The caveat of accessing C data structures from Fortran programs is that the members of the data structure must be
declared in the common block in the exact order in which they appear in the definition of {\tt Libint\_eri\_t}.
The actual definition of {\tt Libint\_eri\_t} in \libinttypesh\ must always be consulted.

Calling \LIBINT\ functions from Fortran should be straightforward. Using the function pointer array {\tt libint2\_build\_eri} may
not be feasible in older Fortran standards. Actual function names must be used instead, i.e.,
a C++ expression
\begin{verbatim}
libint2_build_eri[1][0][2][0](&erival);
\end{verbatim}
will be replaced with a Fortran expression (I'm not sure how to pass pointer to erieval to the function from Fortran!)
\begin{verbatim}
_aB_p__0__d__1___TwoERep_s__0__s__1___Ab__up_0()
\end{verbatim}
where {\tt
\_aB\_p\_\_0\_\_d\_\_1\_\_\_TwoERep\_s\_\_0\_\_s\_\_1\_\_\_Ab\_\_up\_0} is the
name of the function to which \\
{\tt libint2\_build\_eri[1][0][2][0]} points.

\appendix
\appendixpage
\section{\label{sec:notation} Notation}

Following Obara and Saika,\cite{Obara86}
we write an {\em unnormalized primitive Cartesian} Gaussian function centered at {\bf A}\ as
\begin{eqnarray}
\phi ({\bf r}; \zeta, \n, {\bf A}) & = & (x - A_x)^{n_x} (y - A_y)^{n_y} (z - A_z)^{n_z} \nonumber \\
& & \times \exp [-\zeta({\bf r}-{\bf A})^2]\ ,
\end{eqnarray}
where {\bf r}\ is the coordinate vector of the electron, $\zeta$ is the orbital exponent, and
\n\ is a set of non-negative integers. The sum of $n_x$, $n_y$, and $n_z$ will be denoted $\lambda(\n)$
and be referred to as the angular momentum or orbital quantum number of the Gaussian function.
Hereafter \n\ will be termed the angular momentum index.
Henceforth, $n_i$ will refer to the $i$-th component of \n, where $i \in \{x, y, z\}$.
Basic vector addition rules will apply to these vector-like triads of numbers, e.g.
$\n + {\bf 1}_x \equiv \{ n_x+1, n_y, n_z\}$.

A set of $(\lambda(\n) + 1)(\lambda(\n) + 2)/2$ functions with the same $\lambda(\n)$, $\zeta$, and centered
at the common center
but with different \n\ form a {\em Cartesian shell},
or just a {\em shell}. For example, an $s$ shell ($\lambda=0$) has one function, a $p$ shell ($\lambda=1$) --
3 functions, etc.
There is no unique choice for the order of functions in shells.
The standard \LIBINT\ ordering is:
\begin{eqnarray}
p & : & p_x, p_y, p_z \nonumber \\
d & : & d_{xx}, d_{xy}, d_{xz}, d_{yy}, d_{yz}, d_{zz} \nonumber \\
f & : & f_{xxx}, f_{xxy}, f_{xxz}, f_{xyy}, f_{xyz}, f_{xzz}, f_{yyy}, f_{yyz}, f_{yzz}, f_{zzz} \nonumber \\
{\rm etc.} \nonumber
\end{eqnarray}
In general, the following loop structure can be used to generate angular momentum indices in the canonical \LIBINT\ order for all
members of a shell of angular momentum {\tt am}:
\begin{verbatim}
for(int i=0; i<=am; i++) {
  int nx = am - i;  /* exponent of x */
  for(int j=0; j<=i; j++) {
    int ny = i-j;   /* exponent of y */
    int nz = j;     /* exponent of z */
  }
}
\end{verbatim}
Other shell orderings are supported as well, e.g., those employed by the {\tt
intv3} engine in the {\tt MPQC} program, the ordering used in the {\tt GAMESS}
program, or that in the {\tt ORCA} program. These can be specified when the
library is generated (see the {\tt --with-cartgauss-ordering} configure flag).
Support of a new ordering is trivial to implement.
If your program relies on an ordering different from the above, please contact the author of \LIBINT .

The normalization constant for a primitive Gaussian $\phi ({\bf r}; \zeta, \n, {\bf A})$
\begin{eqnarray}
N(\zeta,\n) & = & \left[ \left(\frac{2}{\pi}\right)^{3/4}\frac{2^{(\lambda(\n))}\zeta^{(2\lambda(\n)+3)/4}}
                {[(2n_x-1)!!(2n_y-1)!!(2n_z-1)!!]^{1/2}} \right]
\end{eqnarray}

A contracted Gaussian function is just a linear combination of primitive Gaussians (also termed {\em primitives})
centered at the same center {\bf A} and with the same momentum indices {\bf n}
but with different exponents $\zeta_i$:
\begin{eqnarray}
\phi ({\bf r}; \bmath{\zeta}, {\bf C}, \n, {\bf A}) & = & (x - A_x)^{n_x} (y - A_y)^{n_y} (z - A_z)^{n_z} \nonumber \\
& & \times \sum_{i=1}^M C_i \exp [-\zeta_i ({\bf r}-{\bf A})^2]\ ,
\end{eqnarray}
Contracted Gaussians form shells the same way as primitives.
The contraction coefficients {\bf C} already include normalization constants so that the resulting combination
is properly normalized. Published contraction coefficients {\bf c} are linear coefficients for normalized primitives,
hence the normalization-including contraction coefficients {\bf C} have to be computed from them as
\begin{eqnarray} \label{eq:C1}
C_i & = & c_i N(\zeta_i,\n)
\end{eqnarray}
and scaled further so that the self-overlap of the contracted function is 1:
\begin{eqnarray} \label{eq:C2}
\frac{\pi^{3/2} (2n_x-1)!!(2n_y-1)!!(2n_z-1)!!}{2^{\lambda(\n)}}
\sum_{i=1}^M \sum_{j=1}^M \frac{C_i C_j }{(\zeta_i+\zeta_j)^{\lambda(\n)+3/2}} & = & 1
\end{eqnarray}

If sets of orbital exponents are used to form contracted Gaussians of one angular momentum only
then this is called a {\em segmented} contraction scheme. If there is a set of exponents that forms
contracted Gaussians of several angular momenta then such scheme is called {\em general} contraction.
Examples of basis sets that include general contractions include Atomic Natural Orbitals (ANO) sets.
\LIBINT\ was not designed to handle general contractions very well. You should use either split general contractions
into segments for each angular momentum (it's done for correlation consistent basis sets)
or use basis sets with segmented contractions only.

An integral of a two-body operator $\hat{O}({\bf r}_1, {\bf r}_2)$ over unnormalized
primitive Cartesian Gaussians is written as
\begin{eqnarray}
\int \phi({\bf r}_1; \zeta_a, {\bf a}, {\bf A}) \phi ({\bf r}_2; \zeta_c, {\bf c}, \C) \hat{O}({\bf r}_1, {\bf r}_2)
\phi({\bf r}_1; \zeta_b, {\bf b}, \B) \phi({\bf r}_2; \zeta_d, {\bf d}, \D)
d{\bf r}_1 d{\bf r}_2 \equiv ({\bf ab} |\hat{O}|{\bf cd}) \equiv \braket{ {\bf
ac} | \hat{O} | {\bf bd} }
\end{eqnarray}
A set of integrals $\{ ({\bf a} {\bf b}|\hat{O}({\bf r}_1, {\bf r}_2)|{\bf c} {\bf d}) \}$
over all possible combinations of functions ${\bf a} \in {\rm Shell A}$, ${\bf b} \in {\rm Shell B}$, etc.
will be termed a {\em shell-set}, or simply a {\em set}, of integrals. For example, a $(ps|sd)$ set consists of
$3 \times 1 \times 1 \times 6 = 18$ integrals.

The following definitions have been used throughout this work:
\begin{eqnarray}
\zeta & = & \zeta_a + \zeta_b \\
\eta  & = & \zeta_c + \zeta_d \\
\rho  & = & \frac{\zeta\eta}{\zeta+\eta} \\
{\bf P}& = & \frac{\zeta_a {\bf A} + \zeta_b \B}{\zeta} \\
{\bf Q}& = & \frac{\zeta_c \C + \zeta_d \D}{\eta} \\
{\bf W}& = & \frac{\zeta {\bf P} + \eta {\bf Q}}{\zeta+\eta}
\end{eqnarray}
The Boys function is defined as
\begin{eqnarray}
F_m(T) & = & \int_0^{1} dt\ t^{2m}\ \exp (-Tt^2)
\end{eqnarray}

Evaluation of integrals over functions of non-zero angular momentum starts with the
{\em auxiliary} integrals over primitive $s$-functions
defined as
\begin{eqnarray}
\label{eq:0000m}
({\bf 00}|{\bf 00})^{(m)} & = & 2 F_m(\rho |{\bf PQ}|^2) \sqrt{\frac{\rho}{\pi}}S_{12}S_{34}
\end{eqnarray}
where ${\bf PQ} = {\bf P} - {\bf Q}$ and primitive overlaps $S_{12}$ and $S_{34}$
are computed as
\begin{eqnarray} \label{eq:S12}
S_{12} & = & \Bigl( \frac{\pi}{\zeta} \Bigr)^{3/2}
\exp \Bigl(-\frac{\zeta_a\zeta_b}{\zeta} |{\bf AB}|^2 \Bigr) \\
\label{eq:S34}
S_{34} & = & \Bigl( \frac{\pi}{\eta} \Bigr)^{3/2}
\exp \Bigl(-\frac{\zeta_c\zeta_d}{\eta} |{\bf CD}|^2 \Bigr)
\end{eqnarray}
In the evaluation of integrals over contracted functions it is convenient to
use auxiliary integrals over primitives which include contraction and normalization factors of the
target quartet $({\bf ab}|{\bf cd})$:
\begin{eqnarray} \label{eq:0000m_scaled}
({\bf 00}|{\bf 00})^{(m)} & = &  2 F_m(\rho |{\bf PQ}|^2) \sqrt{\frac{\rho}{\pi}}S_{12}S_{34}
C_1 C_2 C_3 C_4
\end{eqnarray}
where the coefficients $C_a$, $C_b$, $C_c$, and $C_d$ are
normalization-including contraction coefficients (Eqs. (\ref{eq:C1})
and (\ref{eq:C2})) for the first basis function out of each respective shell
in the target shell of integrals.

\bibliographystyle{unsrt}
\bibliography{refs}

\end{document}
