# Add OpenRSP to a quantum chemistry program¶

If you want to add OpenRSP to a quantum chemistry program, then you are free to do so provided that you do not violate OpenRSP’s LGPL v2.1 software license as described on OpenRSP’s GitHub repository.

In order to enable OpenRSP to work as intended, you must provide routines that connect to the OpenRSP application programming interface (API) to give OpenRSP access to contributions such as perturbed one- and two electron integrals, exchange-correlation contributions if calculations at the density-functional theory (DFT) level is desired, or solution routines for response equations.

Please note that OpenRSP is a program library that manages the calculation of response properties, and it cannot carry out actual such calculations without getting contributions like the ones mentioned here from program routines that are external to OpenRSP.

## Compile OpenRP¶

Before compiling OpenRSP, you need to make sure the following programs are installed on your computer:

1. Git,
2. CMake ($$\ge2.8$$),
3. C, C++ (if C++ APIs built) and/or Fortran 2003 (if Fortran APIs built) compilers,
4. HDF 5 ($$\ge1.8$$) if it is enabled in QcMatrix library,
5. BLAS and LAPACK libraries, and
6. QcMatrix library.

For the time being, only CMake can be used to compile OpenRSP. In general, OpenRSP should be compiled together with the host programs. See for example the LSDalton program.

You can also compile OpenRSP alone to be familiar with how it works. But no real calculations will be performed, all the callback functions in the OpenRSP unit testing only return pre-defined data or read data from file. Let us assume that you want to compile the library in directory build, you could invoke the following commands:

mkdir build
cd build
ccmake ..
make


During the step ccmake, you need to set some parameters appropriately for the compilation. For instance, if you enable OPENRSP_TEST_EXECUTABLE, some executables for the test suite will be built and can run after compilation. So that you are able to check if OpenRSP has been successfully compiled. A detailed list of the parameters controlling the compilation is given in the following table:

OpenRSP CMake parameters
CMake parameters Description Default
OPENRSP_BUILD_WEB Build OpenRSP from WEB files (only useful for developers) OFF
OPENRSP_FORTRAN_API Build Fortran 2003 API OFF
OPENRSP_PERT_LABEL_BIT Number of bits for a perturbation label (used for perturbation free scheme) 10
OPENRSP_TEST_EXECUTABLE Build test suite as excutables (otherwise, as functions in the library) ON
OPENRSP_USER_CONTEXT Enable user context in callback functions OFF
OPENRSP_ZERO_BASED Zero-based numbering ON
QCMATRIX_HEADER_DIR Directory of header files of QcMatrix library None
QCMATRIX_LIB Name of QcMatrix library with absolute path None
QCMATRIX_MODULE_DIR Directory of Fortran modules of QcMatrix library None

## OpenRSP Notations and Conventions¶

The following notations and conventions will be used through the OpenRSP program and the documentation:

Perturbation
is described by a label, a complex frequency and its order. Any two perturbations are different if they have different labels, and/or frequencies, and/or orders.
Perturbation label
An integer distinguishing one perturbation from others; all different perturbation labels involved in the calculations should be given by calling the application programming interface (API) OpenRSPSetPerturbations(); OpenRSP will stop if there is any unspecified perturbation label given afterwards when calling the APIs OpenRSPGetRSPFun() or OpenRSPGetResidue().
Perturbation order
Each perturbation can acting on molecules once or many times, that is the order of the perturbation.
Perturbation components and their ranks

Each perturbation may have different numbers of components for their different orders, the position of each component is called its rank.

For instance, there will usually be $$x,y,z$$ components for the electric dipole perturbation, and their ranks are {0,1,2} in zero-based numbering, or {1,2,3} in one-based numbering.

The numbers of different components of perturbations and their ranks are totally decided by the host program. OpenRSP will get such information from callback functions, that is OpenRSP itself is a perturbation free library.

NOTE: the above perturbtion free scheme is however not implemented for the current release so that OpenRSP will use its own internal representations for different perturbations.

Perturbation tuple

An ordered list of perturbation labels, and in which we further require that identical perturbation labels should be consecutive. That means the tuple $$(a,b,b,c)$$ is allowed, but $$(a,b,c,b)$$ is illegal because the identical labels $$b$$ are not consecutive.

As a tuple:

1. Multiple instances of the same labels are allowed so that $$(a,b,b,c)\ne(a,b,c)$$, and
2. The perturbation labels are ordered so that $$(a,b,c)\ne(a,c,b)$$ (because their corresponding response functions or residues are in different shapes).

We will sometimes use an abbreviated form of perturbation tuple as, for instance $$abc\equiv(a,b,c)$$.

Obviously, a perturbation tuple $$+$$ its corresponding complex frequencies for each perturbation label can be viewed as a set of perturbations, in which the number of times a label (with the same frequency) appears is the order of the corresponding perturbation.

Category of perturbation frequencies

We use different integers for distinguishing different values of frequencies within a frequency configuration. The category arrary is determined by:

1. For each frequency configuration, we start at the first perturbation and let its frequency value be designated number 1, then
2. For the next perturbation,
1. If its frequency value corresponds to a frequency value encountered previously in this frequency, then use the same designation as for that previously encountered frequency value, or
2. If its frequency value has not been encountered before, then let that frequency value be designated with the first unused number;
3. Continue like this until the end of the perturbation tuple;
4. Start the numbering over again at the next frequency configuration.
Canonical order
1. In OpenRSP, all perturbation tuples are canonically orderd according to the argument pert_tuple in the API OpenRSPGetRSPFun() or OpenRSPGetResidue(). For instance, when a perturbation tuple $$(a,b,c)$$ given as pert_tuple in the API OpenRSPGetRSPFun(), OpenRSP will use such order ($$a>b>c$$) to arrange all perturbation tuples inside and sent to the callback functions.

2. Moreover, a collection of several perturbation tuples will also follow the canonical order. For instance, a collection of all possible perturbation tuples of labels $$a,b,c,d$$ are $$(0,a,b,ab,c,ac,bc,abc,d,ad,bd,abd,cd,acd,bcd,abcd)$$, where $$0$$ means unperturbed quantities that is always the first one in the collection.

The rules for generating the above collection are:

1. When taking a new perturbation into consideration, always do so in alphabetical order (and begin with the empty set);
2. When taking a new perturbation into consideration, the new subsets are created by making the union of all previous subsets (including the empty set) and the new perturbation (putting the new perturbation at the end).
Perturbation $$a$$
The first perturbation label in the tuple sent to OpenRSP APIs OpenRSPGetRSPFun() or OpenRSPGetResidue(), are the perturbation $$a$$ [Thorvaldsen2008].
1. The addressing of perturbation labels in a tuple is decided by (i) the argument pert_tuple sent to the API OpenRSPGetRSPFun() or OpenRSPGetResidue(), and (ii) the canonical order that OpenRSP uses.
2. The addressing of components per perturbation (several consecutive identical labels with the same complex frequency) are decided by the host program (NOTE: as mentioned above, the perturbtion free scheme is not implemented for the current release so that OpenRSP will use its own internal subroutines to compute the address of components per perturbation).
3. The addressing of a collection of perturbation tuples follows the canonical order as aforementioned.

Therefore, the shape of response functions or residues is mostly decided by the host program. Take $$\mathcal{E}^{abbc}$$ as an example, its shape is $$(N_{a},N_{bb},N_{c})$$, where $$N_{a}$$ and $$N_{c}$$ are respectively the numbers of components of the first order of the perturbations $$a$$ and $$c$$, and $$N_{bb}$$ is the number of components of the second order of the perturbation $$b$$, and

1. In OpenRSP, we will use notation [a][bb][c] for $$\mathcal{E}^{abbc}$$, where the leftmost index (a) runs slowest in memory and the rightmost index (c) runs fastest. However, one should be aware that the results are still in a one-dimensional array.
2. If there two different frequencies for the perturbation $$b$$, OpenRSP will return [a][b1][b2][c], where b1 and b2 stand for the components of the first order of the perturbation $$b$$.
3. The notation for a collection of perturbation tuples (still in a one-dimensional array) is {1,[a],[b],[a][b],[c],[a][c],[b][c],[a][b][c]} for $$(0,a,b,ab,c,ac,bc,abc)$$, where as aforementioned the first one is the unperturbed quantities.

## API Reference¶

In order to use OpenRSP, C users should first include the header file of OpenRSP in their codes:

#inclde "OpenRSP.h"


while Fortran users should use the OpenRSP module:

use OpenRSP_f


In this chapter, we will describe all the functions defined in OpenRSP API for users. These functions should be invoked as:

ierr = OpenRSP...(...)


where ierr contains the error information. Users should check if it equals to QSUCCESS (constant defined in QcMatrix library). If not, there was error happened in the invoked function, and the calculations should stop.

### Functions of OpenRSP API (C version)¶

QErrorCode OpenRSPCreate(open_rsp, num_atoms)

Creates the context of response theory calculations, should be called at first.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* (struct*) num_atoms (const QInt) – number of atoms (to be removed after perturbation free scheme implemented) QErrorCode (error information)
QErrorCode OpenRSPSetLinearRSPSolver(open_rsp, user_ctx, get_linear_rsp_solution)

Sets the context of linear response equation solver.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* user_ctx (void*) – user-defined callback function context get_linear_rsp_solution (const GetLinearRSPSolution (function pointer void (*)(...))) – user-specified callback function of linear response equation solver, see the callback function get_linear_rsp_solution() QErrorCode
QErrorCode OpenRSPSetPerturbations(open_rsp, num_pert_lab, pert_labels, pert_max_orders, pert_num_comps, user_ctx, get_pert_concatenation)

Sets all perturbations involved in response theory calculations.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels involved in calculations pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels pert_num_comps (const QInt*) – number of components of a perturbation described by exactly one of the above different labels, up to the allowed maximal order, size is therefore the sum of pert_max_orders user_ctx (void*) – user-defined callback function context get_pert_concatenation (const GetPertCat (function pointer void (*)(...))) – user specified function for getting the ranks of components of sub-perturbation tuples (with the same perturbation label) for given components of the corresponding concatenated perturbation tuple QErrorCode

NOTE: get_pert_concatenation() will not be invoked in the current release; OpenRSP will use it after the perturbation free scheme implmented.

QErrorCode OpenRSPSetOverlap(open_rsp, num_pert_lab, pert_labels, pert_max_orders, user_ctx, get_overlap_mat, get_overlap_exp)

Sets the overlap operator.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels that can act on the overlap operator pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels user_ctx (void*) – user-defined callback function context get_overlap_mat (const GetOverlapMat (function pointer void (*)(...))) – user-specified callback function to calculate integral matrices of overlap operator as well as its derivatives with respect to different perturbations, see the callback function get_overlap_mat() get_overlap_exp (const GetOverlapExp (function pointer void (*)(...))) – user-specified callback function to calculate expectation values of overlap operator as well as its derivatives with respect to different perturbations, see the callback function get_overlap_exp() QErrorCode
QErrorCode OpenRSPAddOneOper(open_rsp, num_pert_lab, pert_labels, pert_max_orders, user_ctx, get_one_oper_mat, get_one_oper_exp)

Adds a one-electron operator to the Hamiltonian.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels that can act on the one-electron operator pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels user_ctx (void*) – user-defined callback function context get_one_oper_mat (const GetOneOperMat (function pointer void (*)(...))) – user-specified callback function to calculate integral matrices of one-electron operator as well as its derivatives with respect to different perturbations, see the callback function get_one_oper_mat() get_one_oper_exp (const GetOneOperExp (function pointer void (*)(...))) – user-specified callback function to calculate expectation values of one-electron operator as well as its derivatives with respect to different perturbations, see the callback function get_one_oper_exp() QErrorCode
QErrorCode OpenRSPAddTwoOper(open_rsp, num_pert_lab, pert_labels, pert_max_orders, user_ctx, get_two_oper_mat, get_two_oper_exp)

Adds a two-electron operator to the Hamiltonian.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels that can act on the two-electron operator pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels user_ctx (void*) – user-defined callback function context get_two_oper_mat (const GetTwoOperMat (function pointer void (*)(...))) – user-specified callback function to calculate integral matrices of two-electron operator as well as its derivatives with respect to different perturbations, see the callback function get_two_oper_mat() get_two_oper_exp (const GetTwoOperExp (function pointer void (*)(...))) – user-specified callback function to calculate expectation values of two-electron operator as well as its derivatives with respect to different perturbations, see the callback function get_two_oper_exp() QErrorCode
QErrorCode OpenRSPAddXCFun(open_rsp, num_pert_lab, pert_labels, pert_max_orders, user_ctx, get_xc_fun_mat, get_xc_fun_exp)

Adds an exchange-correlation (XC) functional to the Hamiltonian.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels that can act on the XC functional pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels user_ctx (void*) – user-defined callback function context get_xc_fun_mat (const GetXCFunMat (function pointer void (*)(...))) – user-specified callback function to calculate integral matrices of XC functional as well as its derivatives with respect to different perturbations, see the callback function get_xc_fun_mat() get_xc_fun_exp (const GetXCFunExp (function pointer void (*)(...))) – user-specified callback function to calculate expectation values of XC functional as well as its derivatives with respect to different perturbations, see the callback function get_xc_fun_exp() QErrorCode
QErrorCode OpenRSPAddZeroOper(open_rsp, num_pert_lab, pert_labels, pert_max_orders, user_ctx, get_zero_oper_contrib)

Adds a zero-electron operator to the Hamiltonian.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* num_pert_lab (const QInt) – number of all different perturbation labels that can act on the zero-electron operator pert_labels (const QcPertInt*) – all the different perturbation labels involved pert_max_orders (const QInt*) – allowed maximal order of a perturbation described by exactly one of the above different labels user_ctx (void*) – user-defined callback function context get_zero_oper_contrib (const GetZeroOperContrib (function pointer void (*)(...))) – user-specified function to calculate contributions from the zero-electron operator, see the callback function get_zero_oper_contrib() QErrorCode
QErrorCode OpenRSPAssemble(open_rsp)

Assembles the context of response theory calculations and checks its validity, should be called before any function OpenRSPGet...(), otherwise the results might be incorrect.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* QErrorCode
QErrorCode OpenRSPWrite(open_rsp, fp_rsp)

Writes the context of response theory calculations.

Parameters: open_rsp (const OpenRSP*) – context of response theory calculations fp_rsp (FILE*) – file pointer QErrorCode
QErrorCode OpenRSPGetRSPFun(open_rsp, ref_ham, ref_state, ref_overlap, num_props, len_tuple, pert_tuple, num_freq_configs, pert_freqs, kn_rules, r_flag, write_threshold, size_rsp_funs, rsp_funs)

Gets the response functions for given perturbations.

Parameters: Var rsp_funs: open_rsp (OpenRSP*) – context of response theory calculations ref_ham (const QcMat*) – Hamiltonian of referenced state ref_state (const QcMat*) – electronic state of referenced state ref_overlap (const QcMat*) – overlap integral matrix of referenced state num_props (const QInt) – number of properties to calculate len_tuple (const QInt*) – length of perturbation tuple for each property, size is the number of properties (num_props) pert_tuple (const QcPertInt*) – ordered list of perturbation labels (perturbation tuple) for each property, size is sum(len_tuple), the first label of each property is the perturbation $$a$$ num_freq_configs (const QInt*) – number of different frequency configurations for each property, size is num_props pert_freqs (const QReal*) – complex frequencies of each perturbation label (except for the perturbation $$a$$) over all frequency configurations, size is 2 $$\times$$ (dot_product(len_tuple,num_freq_configs)-sum(num_freq_configs)), and arranged as [num_freq_configs[i]][len_tuple[i]-1][2] (i runs from 0 to num_props-1) and the real and imaginary parts of each frequency are consecutive in memory kn_rules (const QInt*) – number $$k$$ for the $$(k,n)$$ rule [1] for each property (OpenRSP will determine the number $$n$$), size is the number of properties (num_props) r_flag (const QInt) – flag to determine the restarting setup; 0 means “do not load/use any existing restarting data and do not save any new restarting data”, and 3 means “use any existing restarting data and extend existing restarting data with all new restarting data” write_threshold (const QReal) – tensor elements with absolute value below write_threshold will not be output by OpenRSP size_rsp_funs (const QInt) – size of the response functions, equals to the sum of the size of each property to calculate—which is the product of the size of added perturbations (specified by the perturbation tuple pert_tuple) and the number of frequency configurations num_freq_configs for each property the response functions, size is 2 $$\times$$ size_rsp_funs and arranged as [num_props][num_freq_configs][pert_tuple][2], where the real and imaginary parts of the response functions are consecutive in memory QReal* QErrorCode
 [1] The description of the $$(k,n)$$ rule can be found, for instance, in [Ringholm2014].
QErrorCode OpenRSPGetResidue(open_rsp, ref_ham, ref_state, ref_overlap, order_residue, num_excit, excit_energy, eigen_vector, num_props, len_tuple, pert_tuple, residue_num_pert, residue_idx_pert, num_freq_configs, pert_freqs, kn_rules, r_flag, write_threshold, size_residues, residues)

Gets the residues for given perturbations.

Parameters: Var residues: open_rsp (OpenRSP*) – context of response theory calculations ref_ham (const QcMat*) – Hamiltonian of referenced state ref_state (const QcMat*) – electronic state of referenced state ref_overlap (const QcMat*) – overlap integral matrix of referenced state order_residue (const QInt) – order of residues, that is also the length of each excitation tuple num_excit (const QInt) – number of excitation tuples that will be used for residue calculations excit_energy (const QReal*) – excitation energies of all tuples, size is order_residue $$\times$$ num_excit, and arranged as [num_excit][order_residue]; that is, there will be order_residue frequencies of perturbation labels (or sums of frequencies of perturbation labels) respectively equal to the order_residue excitation energies per tuple excit_energy[i][:] (i runs from 0 to num_excit-1) eigen_vector (QcMat*[]) – eigenvectors (obtained from the generalized eigenvalue problem) of all excitation tuples, size is order_residue $$\times$$ num_excit, and also arranged in memory as [num_excit][order_residue] so that each eigenvector has its corresponding excitation energy in excit_energy num_props (const QInt) – number of properties to calculate len_tuple (const QInt*) – length of perturbation tuple for each property, size is the number of properties (num_props) pert_tuple (const QcPertInt*) – ordered list of perturbation labels (perturbation tuple) for each property, size is sum(len_tuple), the first label of each property is the perturbation $$a$$ residue_num_pert (const QInt*) – for each property and each excitation energy in the tuple, the number of perturbation labels whose sum of frequencies equals to that excitation energy, size is order_residue $$\times$$ num_props, and arragned as [num_props][order_residue]; a negative residue_num_pert[i][j] (i runs from 0 to num_props-1) means that the sum of frequencies of perturbation labels equals to -excit_energy[:][j] residue_idx_pert (const QInt*) – for each property and each excitation energy in the tuple, the indices of perturbation labels whose sum of frequencies equals to that excitation energy, size is sum(residue_num_pert), and arranged as [residue_num_pert] num_freq_configs (const QInt*) – number of different frequency configurations for each property, size is num_props pert_freqs (const QReal*) – complex frequencies of each perturbation label (except for the perturbation $$a$$) over all frequency configurations and excitation tuples, size is 2 $$\times$$ (dot_product(len_tuple,num_freq_configs)-sum(num_freq_configs)) $$\times$$ num_excit, and arranged as [num_excit][num_freq_configs[i]][len_tuple[i]-1][2] (i runs from 0 to num_props-1) and the real and imaginary parts of each frequency are consecutive in memory; notice that the (sums of) frequencies of perturbation labels specified by residue_idx_pert should equal to the corresponding excitation energies for all frequency configurations and excitation tuples kn_rules (const QInt*) – number $$k$$ for the $$(k,n)$$ rule for each property (OpenRSP will determine the number $$n$$), size is the number of properties (num_props) r_flag (const QInt) – flag to determine the restarting setup; 0 means “do not load/use any existing restarting data and do not save any new restarting data”, and 3 means “use any existing restarting data and extend existing restarting data with all new restarting data” write_threshold (const QReal) – tensor elements with absolute value below write_threshold will not be output by OpenRSP size_residues (const QInt) – size of the residues, equals to the sum of the size of each property to calculate—which is the product of the size of added perturbations (specified by the perturbation tuple pert_tuple), the number of excitation tuples (num_excit) and the number of frequency configurations num_freq_configs for each property the residues, size is 2 $$\times$$ size_residues and arranged as [num_props][num_excit][num_freq_configs][pert_tuple][2], where the real and imaginary parts of the residues are consecutive in memory QReal* QErrorCode
QErrorCode OpenRSPDestroy(open_rsp)

Destroys the context of response theory calculations, should be called at the end.

Var open_rsp: Vartype open_rsp: context of response theory calculations OpenRSP* QErrorCode

### Functions of OpenRSP API (Fortran version)¶

Functions of OpenRSP API (Fortran) are similar to those of the C version, except that an extra _f should be appended to each function. Other differences are the (ii) argument types and (iii) callback functions (subroutines for Fortran). The latter will be described in Chapter Callback Function Scheme. The former relates to the convention of types in Fortran, please refer to the manual of QcMatrix library and the following table for the convention:

Type in OpenRSP Fortran
struct OpenRSP type(OpenRSP)
void* user_ctx type(C_PTR) user_ctx
callback functions external subroutines

We also want to mention that users can also pass their own defined Fortran type as the user-defined callback function context to OpenRSP, by encapsulated into the type(C_PTR) user_ctx.

## Callback Function Scheme¶

To use OpenRSP, users should also prepare different callback functions needed by OpenRSP. These callback functions will be invoked by OpenRSP during calculations to get integral matrices or expectation values of different one- and two-electron operators, exchange-correlation functionals and nuclear contributions, or to solve the linear response equation. The callback functions are slightly different for C and Fortran users, which will be described separately in this chapter.

It should be noted that the arguments in the following callback functions are over complete. For instance, from the knowledge of perturbations (oper_num_pert, oper_pert_labels and oper_pert_orders), the dimension of integral matrices num_int in the callback function get_one_oper_mat() can be computed.

Last but not least, users should be aware that:

1. OpenRSP always ask for complex expectation values for different one- and two-electron operators, exchange-correlation functionals and nuclear contributions, and these values are presented in memory that the real and imaginary parts of each value are consecutive. This affects:
2. In order to reduce the use of temporary matrices and values, OpenRSP requires that calculated integral matrices and expectation values should be added to the returned argument. OpenRSP will zero the entries of these matrices and expectation values at first. This requirement affects the callback functions of one- and two-electron operators, exchange-correlation functionals and nuclear contributions:

### OpenRSP Callback Functions (C version)¶

Examples of C callback functions can be found in these files tests/OpenRSP*Callback.c. The detailed information of these callback functions are given as follows.

void get_pert_concatenation(pert_label, first_cat_comp, num_cat_comps, num_sub_tuples, len_sub_tuples, user_ctx, rank_sub_comps)

User specified function for getting the ranks of components of sub-perturbation tuples (with the same perturbation label) for given components of the corresponding concatenated perturbation tuple, the last argument for the function OpenRSPSetPerturbations().

Parameters: Var rank_sub_comps: pert_label (const QcPertInt) – the perturbation label first_cat_comp (const QInt) – rank of the first component of the concatenated perturbation tuple num_cat_comps (const QInt) – number of components of the concatenated perturbation tuple num_sub_tuples (const QInt) – number of sub-perturbation tuples to construct the concatenated perturbation tuple len_sub_tuples (const QInt*) – length of each sub-perturbation tuple, size is num_sub_tuples; so that the length of the concatenated perturbation is sum(len_sub_tuples) user_ctx (void*) – user-defined callback function context ranks of components of sub-perturbation tuples for the corresponding component of the concatenated perturbation tuple, i.e. num_cat_comps components starting from the one with rank first_cat_comp, size is therefore num_sub_tuples $$\times$$ num_cat_comps, and arranged as [num_cat_comps][num_sub_tuples] QInt* void

NOTE: get_pert_concatenation() will not be invoked in the current release so that users can use a “faked” function for it.

void get_overlap_mat(bra_num_pert, bra_pert_labels, bra_pert_orders, ket_num_pert, ket_pert_labels, ket_pert_orders, oper_num_pert, oper_pert_labels, oper_pert_orders, user_ctx, num_int, val_int)

User-specified callback function to calculate integral matrices of overlap operator as well as its derivatives with respect to different perturbations, the second last argument for the function OpenRSPSetOverlap().

Parameters: Var val_int: bra_num_pert (const QInt) – number of perturbations on the bra center bra_pert_labels (const QcPertInt*) – labels of perturbations on the bra center, size is bra_num_pert bra_pert_orders (const QInt*) – orders of perturbations on the bra center, size is bra_num_pert ket_num_pert (const QInt) – number of perturbations on the ket center ket_pert_labels (const QcPertInt*) – labels of perturbations on the ket center, size is ket_num_pert ket_pert_orders (const QInt*) – orders of perturbations on the ket center, size is ket_num_pert oper_num_pert (const QInt) – number of perturbations on the overlap operator [2] oper_pert_labels (const QcPertInt*) – labels of perturbations on the overlap operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the overlap operator, size is oper_num_pert [3] user_ctx (void*) – user-defined callback function context num_int (const QInt) – number of the integral matrices, as the product of the sizes of perturbations on the bra, the ket and the overlap operator the integral matrices to be added, size is num_int, and arranged as [oper_pert][bra_pert][ket_pert] QcMat*[] void
 [2] Here perturbations on the overlap operator represent those acting on the whole integral of the overlap operator, i.e. they can act on either the bra center or the ket center by applying the rule of derivatives of a product.
 [3] Only overlap integrals perturbed on the bra and/or the ket, and those perturbed on the whole integral are needed in the calculations. It means that, OpenRSP will only ask for overlap integrals either with perturbations on the bra and/or ket (oper_num_pert=0), or with perturbations on the whole overlap integral (bra_num_pert=0 and ket_num_pert=0).
void get_overlap_exp(bra_num_pert, bra_pert_labels, bra_pert_orders, ket_num_pert, ket_pert_labels, ket_pert_orders, oper_num_pert, oper_pert_labels, oper_pert_orders, num_dmat, dens_mat, user_ctx, num_exp, val_exp)

User-specified function for calculating expectation values of the overlap operator and its derivatives, the last argument for the function OpenRSPSetOverlap().

Parameters: Var val_exp: bra_num_pert (const QInt) – number of perturbations on the bra center bra_pert_labels (const QcPertInt*) – labels of perturbations on the bra center, size is bra_num_pert bra_pert_orders (const QInt*) – orders of perturbations on the bra center, size is bra_num_pert ket_num_pert (const QInt) – number of perturbations on the ket center ket_pert_labels (const QcPertInt*) – labels of perturbations on the ket center, size is ket_num_pert ket_pert_orders (const QInt*) – orders of perturbations on the ket center, size is ket_num_pert oper_num_pert (const QInt) – number of perturbations on the overlap operator [4] oper_pert_labels (const QcPertInt*) – labels of perturbations on the overlap operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the overlap operator, size is oper_num_pert num_dmat (const QInt) – number of atomic orbital (AO) based density matrices dens_mat (QcMat*[]) – the AO based density matrices user_ctx (void*) – user-defined callback function context num_exp (const QInt) – number of the expectation values, as the product of sizes of perturbations on the bra, the ket, the overlap operator and the number of density matrices (num_dmat) the expectation values to be added, size is 2 $$\times$$ num_exp, and arranged as [num_dmat][oper_pert][bra_pert][ket_pert][2] QReal* void
 [4] Similar to the callback function get_overlap_mat(), OpenRSP will only ask for expectation values either with perturbations on the bra and/or ket (oper_num_pert=0), or with perturbations on the whole overlap integral (bra_num_pert=0 and ket_num_pert=0).
void get_one_oper_mat(oper_num_pert, oper_pert_labels, oper_pert_orders, user_ctx, num_int, val_int)

User-specified function for calculating integral matrices of the one-electron operator and its derivatives, the second last argument for the function OpenRSPAddOneOper().

Parameters: Var val_int: oper_num_pert (const QInt) – number of perturbations on the one-electron operator oper_pert_labels (const QcPertInt*) – labels of perturbations on the one-electron operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the one-electron operator, size is oper_num_pert user_ctx (void*) – user-defined callback function context num_int (const QInt) – number of the integral matrices, as the size of perturbations that are specified by oper_num_pert, oper_pert_labels and oper_pert_orders the integral matrices to be added, size is num_int QcMat*[] void
void get_one_oper_exp(oper_num_pert, oper_pert_labels, oper_pert_orders, num_dmat, dens_mat, user_ctx, num_exp, val_exp)

User-specified callback function to calculate expectation values of one-electron operator as well as its derivatives with respect to different perturbations, the last argument for the function OpenRSPAddOneOper().

Parameters: Var val_exp: oper_num_pert (const QInt) – number of perturbations on the one-electron operator oper_pert_labels (const QcPertInt*) – labels of perturbations on the one-electron operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the one-electron operator, size is oper_num_pert num_dmat (const QInt) – number of AO based density matrices dens_mat (QcMat*[]) – the AO based density matrices user_ctx (void*) – user-defined callback function context num_exp (const QInt) – number of expectation values, as the product of the size of perturbations on the one-electron operator (specified by oper_num_pert, oper_pert_labels and oper_pert_orders) and the number of density matrices (num_dmat) the expectation values to be added, size is 2 $$\times$$ num_exp, and arranged as [num_dmat][oper_pert][2] QReal* void
void get_two_oper_mat(oper_num_pert, oper_pert_labels, oper_pert_orders, num_dmat, dens_mat, user_ctx, num_int, val_int)

User-specified function for calculating integral matrices of the two-electron operator and its derivatives, the second last argument for the function OpenRSPAddTwoOper().

Parameters: Var val_int: oper_num_pert (const QInt) – number of perturbations on the two-electron operator oper_pert_labels (const QcPertInt*) – labels of perturbations on the two-electron operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the two-electron operator, size is oper_num_pert num_dmat (const QInt) – number of AO based density matrices dens_mat (QcMat*[]) – the AO based density matrices ($$\boldsymbol{D}$$) for calculating $$\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D})$$, where $$\texttt{perturbations}$$ are specified by oper_num_pert, oper_pert_labels and oper_pert_orders. user_ctx (void*) – user-defined callback function context num_int (const QInt) – number of the integral matrices, as the product of the size of perturbations on the two-electron operator (specified by oper_num_pert, oper_pert_labels and oper_pert_orders) and the number of AO based density matrices (num_dmat) the integral matrices to be added, size is num_int, and arranged as [num_dmat][oper_pert] QcMat*[] void
void get_two_oper_exp(oper_num_pert, oper_pert_labels, oper_pert_orders, dmat_len_tuple, num_LHS_dmat, LHS_dens_mat, num_RHS_dmat, RHS_dens_mat, user_ctx, num_exp, val_exp)

User-specified callback function to calculate expectation values of two-electron operator as well as its derivatives with respect to different perturbations, the last argument for the function OpenRSPAddTwoOper().

Parameters: Var val_exp: oper_num_pert (const QInt) – number of perturbations on the two-electron operator oper_pert_labels (const QcPertInt*) – labels of perturbations on the two-electron operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the two-electron operator, size is oper_num_pert dmat_len_tuple (const QInt) – length of different perturbation tuples of the left-hand-side (LHS) and right-hand-side (RHS) AO based density matrices passed; for instance, if the LHS density matrices passed are ($$\boldsymbol{D}$$, $$\boldsymbol{D}^{a}$$, $$\boldsymbol{D}^{b}$$, $$\boldsymbol{D}^{ab}$$), and the RHS density matrices passed are ($$\boldsymbol{D}^{b}$$, $$\boldsymbol{D}^{c}$$, $$\boldsymbol{D}^{bc}$$, $$\boldsymbol{D}^{d}$$), then dmat_len_tuple equals to 4, and that means we want to calculate $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D})\boldsymbol{D}^{b}]$$, $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D}^{a})\boldsymbol{D}^{c}]$$, $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D}^{b})\boldsymbol{D}^{bc}]$$, and $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D}^{ab})\boldsymbol{D}^{d}]$$, where $$\texttt{perturbations}$$ are specified by oper_num_pert, oper_pert_labels and oper_pert_orders. num_LHS_dmat (const QInt*) – number of LHS AO based density matrices passed for each LHS density matrix perturbation tuple, size is dmat_len_tuple; sticking with the above example, num_LHS_dmat will be {1, N_a, N_b, N_ab} where N_a, N_b and N_ab are respectively the numbers of density matrices for the density matrix perturbation tuples a, b and ab LHS_dens_mat (QcMat*[]) – the LHS AO based density matrices ($$\boldsymbol{D}_{\text{LHS}}$$) for calculating $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D}_{\text{LHS}})\boldsymbol{D}_{\text{RHS}}]$$, size is the sum of num_LHS_dmat num_RHS_dmat (const QInt*) – number of RHS AO based density matrices passed for each RHS density matrix perturbation tuple, size is dmat_len_tuple; sticking with the above example, num_RHS_dmat will be {N_b, N_c, N_bc, N_d} where N_b, N_c N_bc and N_d are respectively the numbers of density matrices for the density matrix perturbation tuples b, c, bc and d RHS_dens_mat (QcMat*[]) – the RHS AO based density matrices ($$\boldsymbol{D}_{\text{RHS}}$$) for calculating $$\mathrm{Tr}[\boldsymbol{G}^{\texttt{perturbations}}(\boldsymbol{D}_{\text{LHS}})\boldsymbol{D}_{\text{RHS}}]$$, size is the sum of num_RHS_dmat user_ctx (void*) – user-defined callback function context num_exp (const QInt) – number of expectation values, as the product of the size of perturbations on the two-electron operator (specified by oper_num_pert, oper_pert_labels and oper_pert_orders) and the number of pairs of LHS and RHS density matrices, and the number of pairs of LHS and RHS density matrices can be computed as the dot product of num_LHS_dmat and num_RHS_dmat the expectation values to be added, size is 2 $$\times$$ num_exp, and arranged as [dmat_len_tuple][num_LHS_dmat][num_RHS_dmat][oper_pert][2] QReal* void
void get_xc_fun_mat(xc_len_tuple, xc_pert_tuple, num_freq_configs, pert_freq_category, dmat_num_tuple, dmat_idx_tuple, num_dmat, dens_mat, user_ctx, num_int, val_int)

User-specified function for calculating integral matrices of the XC functional and its derivatives, the second last argument for the function OpenRSPAddXCFun().

Parameters: Var val_int: xc_len_tuple (const QInt) – length of the perturbation tuple on the XC functional xc_pert_tuple (const QcPertInt*) – perturbation tuple on the XC functional, size is xc_len_tuple num_freq_configs (const QInt) – the number of different frequency configurations to be considered for the perturbation tuple specified by xc_pert_tuple pert_freq_category (const QInt*) – category of perturbation frequencies, size is [num_freq_configs][xc_len_tuple]. Take $$\mathcal{E}^{gfff}$$ as an example, suppose we have four different frequency configurations: “0.0,0.0,0.0,0.0” ($$3N\times 10$$ unique elements), “0.0,-0.2,0.1,0.1” ($$3N\times 18$$ unique elements), “0.0,-0,3,0.1,0.2” ($$3N\times 27$$ unique elements) and “0.0,-0.1,0.1,0.0” ($$3N\times 27$$ unique elements), the pert_freq_category argument would then be (1,1,1,1, 1,2,3,3, 1,2,3,4, 1,2,3,1). dmat_num_tuple (const QInt) – the number of different perturbation tuples of the AO based density matrices passed; for instance, the complete density matrix perturbation tuples (canonically ordered) for a property $$\mathcal{E}^{abc}$$ (i.e. the perturbation tuple xc_pert_tuple is abc) are ($$\boldsymbol{D}$$, $$\boldsymbol{D}^{a}$$, $$\boldsymbol{D}^{b}$$, $$\boldsymbol{D}^{ab}$$, $$\boldsymbol{D}^{c}$$, $$\boldsymbol{D}^{ac}$$, $$\boldsymbol{D}^{bc}$$), and with the $$(0,2)$$ rule, the relevant density matrix perturbation tuples become ($$\boldsymbol{D}$$, $$\boldsymbol{D}^{b}$$, $$\boldsymbol{D}^{c}$$, $$\boldsymbol{D}^{bc}$$) that gives the dmat_num_tuple as 4 dmat_idx_tuple (const QInt*) – indices of the density matrix perturbation tuples passed (canonically ordered), size is dmat_num_tuple; sticking with the above example, the density matrix perturbation tuples passed are ($$\boldsymbol{D}$$, $$\boldsymbol{D}^{b}$$, $$\boldsymbol{D}^{c}$$, $$\boldsymbol{D}^{bc}$$) and their associated indices dmat_idx_tuple is {1, 3, 5, 7} because these numbers correspond to the positions of the “$$(k,n)$$-surviving” perturbation tuples in the canonically ordered complete density matrix perturbation tuples num_dmat (const QInt) – number of collected AO based density matrices for the passed density matrix perturbation tuples (specified by dmat_idx_tuple) and all frequency configurations, that is num_freq_configs $$\times\sum_{\text{i}}N_{\text{i}}$$, where $$N_{\text{i}}$$ is the number of density matrices for the density matrix perturbation tuple dmat_idx_tuple[i] for a frequency configuration dens_mat (QcMat*[]) – the collected AO based density matrices, size is num_dmat, and arranged as [num_freq_configs][dmat_idx_tuple] user_ctx (void*) – user-defined callback function context num_int (const QInt) – number of the integral matrices, equals to the product of the size of perturbations on the XC functional (specified by the perturbation tuple xc_pert_tuple) and the number of different frequency configurations num_freq_configs the integral matrices to be added, size is num_int, and arranged as [num_freq_configs][xc_pert_tuple] QcMat*[] void
void get_xc_fun_exp(xc_len_tuple, xc_pert_tuple, num_freq_configs, pert_freq_category, dmat_num_tuple, dmat_idx_tuple, num_dmat, dens_mat, user_ctx, num_exp, val_exp)

User-specified function for calculating expectation values of the XC functional and its derivatives, the last argument for the function OpenRSPAddXCFun().

Parameters: Var val_exp: xc_len_tuple (const QInt) – length of the perturbation tuple on the XC functional xc_pert_tuple (const QcPertInt*) – perturbation tuple on the XC functional, size is xc_len_tuple num_freq_configs (const QInt) – the number of different frequency configurations to be considered for the perturbation tuple specified by xc_pert_tuple pert_freq_category (const QInt*) – category of perturbation frequencies, size is [num_freq_configs][xc_len_tuple]. dmat_num_tuple (const QInt) – the number of different perturbation tuples of the AO based density matrices passed dmat_idx_tuple (const QInt*) – indices of the density matrix perturbation tuples passed (canonically ordered), size is dmat_num_tuple num_dmat (const QInt) – number of collected AO based density matrices for the passed density matrix perturbation tuples (specified by dmat_idx_tuple) and all frequency configurations, that is num_freq_configs $$\times\sum_{\text{i}}N_{\text{i}}$$, where $$N_{\text{i}}$$ is the number of density matrices for the density matrix perturbation tuple dmat_idx_tuple[i] for a frequency configuration dens_mat (QcMat*[]) – the collected AO based density matrices, size is num_dmat, and arranged as [num_freq_configs][dmat_idx_tuple] user_ctx (void*) – user-defined callback function context num_exp (const QInt) – number of the expectation values, equals to the product of the size of perturbations on the XC functional (specified by the perturbation tuple xc_pert_tuple) and the number of different frequency configurations num_freq_configs the expectation values to be added, size is 2 $$\times$$ num_exp, and arranged as [num_freq_configs][xc_pert_tuple][2] QReal* void
void get_zero_oper_contrib(oper_num_pert, oper_pert_labels, oper_pert_orders, user_ctx, size_pert, val_oper)

User-specified callback function to calculate contributions from the zero-electron operator, the last argument for the function OpenRSPAddZeroOper().

Parameters: Var val_oper: oper_num_pert (const QInt) – number of perturbations on the zero-electron operator oper_pert_labels (const QcPertInt*) – labels of perturbations on the zero-electron operator, size is oper_num_pert oper_pert_orders (const QInt*) – orders of perturbations on the zero-electron operator, size is oper_num_pert user_ctx (void*) – user-defined callback function context size_pert (const QInt) – size of the perturbations on the zero-electron operator contributions from the zero-electron operator to be added, arranged as [size_pert][2] QReal* void
void get_linear_rsp_solution(num_pert, num_comps, num_freq_sums, freq_sums, RHS_mat, user_ctx, rsp_param)

User-specified callback function of linear response equation solver, the last argument for the function OpenRSPSetLinearRSPSolver().

Parameters: Var rsp_param: num_pert (const QInt) – number of different perturbations on the right hand side of the linear response equation num_comps (const QInt*) – number of components of each perturbation, size is num_pert num_freq_sums (const QInt*) – for each perturbation, number of complex frequency sums on the left hand side of the linear response equation, size is num_pert freq_sums (const QReal*) – the complex frequency sums on the left hand side of the linear response equation, size is twice of the sum of num_freq_sums, the real and imaginary parts of each frequency sum are consecutive in memory RHS_mat (QcMat*[]) – RHS matrices, size is the dot product of num_comps and num_freq_sums, and index of num_freq_sums runs faster in memory user_ctx (void*) – user-defined callback function context solved response parameters, size is the dot product of num_comps and num_freq_sums, and index of num_freq_sums runs faster in memory QcMat*[] void

### OpenRSP Callback Subroutines (Fortran version)¶

The callback subroutines of Fortran codes take almost the exact arguments as the callback functions of C codes. One difference is the type convention between C and Fortran, which has been discussed in Secion Functions of OpenRSP API (Fortran version). Moreover, the pointers of basic types (integer and real numbers) in the C codes should be converted to corresponding array in Fortran. The array of QcMat pointers should be converted to an array of type(QcMat) in Fortran. Last, the user-defined callback function/subroutine context should be replaced by type(C_PTR).

We will develop Fortran unit testing in next release. For the time being, interested users can refer to LSDalton for examples of Fortran callback subroutines.

## Limitations or Known Problems¶

• “T matrix contributions” - i.e. contributions from the perturbed “half-time-differentiated” overlap matrix - are not yet supported. These contributions are only nonzero for perturbations that both a) affect the basis set and b) have frequencies other than zero. The most relevant such kind of perturbation is the magnetic dipole perturbations using London atomic orbitals. Properties consisting of only other kinds of perturbations - such as geometric displacement of the nuclei or electric dipole perturbations - are unaffected by the lack of T matrix contributions.

• Currently we use QcPertInt (defined as QInt type in include/RSPPerturbation.h, and src/fortran/RSPPertBasicTypes.F90 for Fortran APIs) to reprenset several perturbation labels (see OpenRSP Notations and Conventions), in which one label is described by OPENRSP_PERT_LABEL_BIT bits (that can be modified during the step ccmake, see Compile OpenRP).

For the time being, we do not suggest that users change the type of QcPertInt, because other integer types are not supported by OpenRSP yet.

• The current implementation for calculation of residues of response functions is significantly limited in generality. Currently, only electric dipole perturbations and single residues are possible; furthermore, there are significant limitations for the calculation setup. These limitations are described in further detail in the manual of LSDalton in its (at the time of writing unreleased) 2020 version.

## Unit Testing¶

After successfully building OpenRSP (see Compile OpenRP), we recommend users perform the unit testing of OpenRSP.

If OPENRSP_TEST_EXECUTABLE is enabled, you will have an executable openrsp_c_test after successfully building OpenRSP. Run this executable for unit testing.

If OPENRSP_TEST_EXECUTABLE is disabled, you will need to call the function

QErrorCode OpenRSPTest(FILE *fp_log)

to perform the unit testing.