Program Listing for File qgen.cpp

Return to documentation for file (/Users/robertshaw/devfiles/libecpint/src/lib/qgen.cpp)

/*
*      Copyright (c) 2020 Robert Shaw
*       This file is a part of Libecpint.
*
*      Permission is hereby granted, free of charge, to any person obtaining
*      a copy of this software and associated documentation files (the
*      "Software"), to deal in the Software without restriction, including
*      without limitation the rights to use, copy, modify, merge, publish,
*      distribute, sublicense, and/or sell copies of the Software, and to
*      permit persons to whom the Software is furnished to do so, subject to
*      the following conditions:
*
*      The above copyright notice and this permission notice shall be
*      included in all copies or substantial portions of the Software.
*
*      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*      NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
*      LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
*      OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*      WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include "qgen.hpp"
#include <cmath>
#include "mathutil.hpp"
#include <iostream>

namespace libecpint {
    namespace qgen {
        void rolled_up(const int lam, const int LA, const int LB, const ThreeIndex<double> &radials, const FiveIndex<double> &CA, const FiveIndex<double> &CB, const TwoIndex<double> &SA, const TwoIndex<double> &SB, const AngularIntegral &angint, ThreeIndex<double> &values)
        {
            double prefac = 16.0 * M_PI * M_PI;
            int L = LA + LB;

            int z1, z2, w_m, w_l, w_lm;
            int w_ax, w_ay, w_az, w_l1;
            int w_bx, w_by, w_bz, w_l2;
            double C, val;
      const int* mults = angint.getOmegaMults();
      const std::vector<double>& omega = angint.getOmegaData();
            int w_size = 2*lam+1;
            double w1_contr[w_size*(lam+LA+1)];
            double w2_contr[w_size*(lam+LB+1)];

            int w_lam = lam * mults[3];
            // Loop over cartesian shell functions in alpha order, e.g. {xx xy, xz, yy, yz, zz} for l=2
            int na = 0; // Rows are shellA
            for (int x1 = LA; x1 >= 0; x1--) {
                for (int r1 = LA-x1; r1 >= 0; r1--) {
                    z1 = LA - x1 - r1;

                    int nb = 0; // Cols are shellB
                    for (int x2 = LB; x2 >= 0; x2--) {
                        for (int y2 = LB - x2; y2 >= 0; y2--) {
                            z2 = LB - x2 - y2;

                            // Begin full ECP integral expansion
                            for (int alpha_x = 0; alpha_x <= x1; alpha_x++) {
                                w_ax = w_lam + alpha_x*mults[0];
                                for (int alpha_y = 0; alpha_y <= r1; alpha_y++) {
                                    w_ay = w_ax + alpha_y*mults[1];
                                    for (int alpha_z = 0; alpha_z <= z1; alpha_z++) {
                                        w_az = w_ay + alpha_z*mults[2];
                                        int alpha = alpha_x + alpha_y + alpha_z;

                                        for (int beta_x = 0; beta_x <= x2; beta_x++) {
                                            w_bx = w_lam + beta_x*mults[0];
                                            for (int beta_y = 0; beta_y <= y2; beta_y++) {
                                                w_by = w_bx + beta_y*mults[1];
                                                for (int beta_z = 0; beta_z <= z2; beta_z++) {
                                                    w_bz = w_by + beta_z*mults[2];
                                                    int beta = beta_x + beta_y + beta_z;
                                                    int N = alpha + beta;
                                                    C = CA(0, na, alpha_x, alpha_y, alpha_z) * CB(0, nb, beta_x, beta_y, beta_z);

                                                    if (std::abs(C) > 1e-15) {

                                                        for (int lam1 = 0; lam1 <= lam + alpha; lam1++) {
                                                            w_l = lam1*w_size+lam;
                                                            w_l1 = w_az + lam1*(1+mults[5]);
                                                            w_m = w_l1-mults[4];
                                                            for (int mu = -lam; mu <= lam; mu++) {
                                                                w_m += mults[4];
                                                                w_lm = lam1*SA.dims[1];
                                                                w1_contr[w_l+mu] = 0.0;
                                                                for (int mu1 = -lam1; mu1 <= lam1; mu1++)
                                                                    w1_contr[w_l+mu] += SA.data[w_lm++] * omega[w_m+mu1];
                                                            }
                                                        }

                                                        for (int lam2 = 0; lam2 <= lam+beta; lam2++) {
                                                            w_l  = lam2*w_size+lam;
                                                            w_l2 = w_bz + lam2*(1+mults[5]);
                                                            w_m = w_l2-mults[4];
                                                            for (int mu = -lam; mu <= lam; mu++) {
                                                                w_m += mults[4];
                                                                w_lm = lam2*SB.dims[1];
                                                                w2_contr[w_l+mu] = 0.0;
                                                                for (int mu2 = -lam2; mu2 <= lam2; mu2++)
                                                                    w2_contr[w_l+mu] += SB.data[w_lm++] * omega[w_m+mu2];
                                                            }
                                                        }

                                                        for (int lam1=0; lam1 <= lam+alpha; lam1++) {
                                                            w_l1 = lam1*w_size+lam;
                                                            int lam2start = (lam1 + N) % 2;
                                                            for (int lam2 = lam2start; lam2 <= lam + beta; lam2+=2) {
                                                                w_l2 = lam2*w_size+lam;

                                                                val = prefac * C * radials(N, lam1, lam2);
                                                                for (int mu = -lam; mu <= lam; mu++)
                                                                    values(na, nb, lam+mu) += val * w1_contr[w_l1+mu] * w2_contr[w_l2+mu];

                                                            }
                                                        }
                                                    }

                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            nb++;
                        }
                    }

                    na++;
                }
            }
        }

        void rolled_up_special(const int lam, const int LA, const int LB, const ThreeIndex<double>& radials, const FiveIndex<double>& CB, const TwoIndex<double>& SB, const AngularIntegral& angint, ThreeIndex<double>& values) {
            double prefac = 8.0 * M_PI * std::sqrt(M_PI);
            int L = LA + LB;

            int z1, z2;
            double C, val1, val2;

            int w_bx, w_by, w_bz, w_l2, w_m2, w1, w_m;
      const int* mults = angint.getOmegaMults();
      const std::vector<double>& omega = angint.getOmegaData();
            int w_lam = lam * mults[3];

            // Loop over cartesian shell functions in alpha order, e.g. {xx xy, xz, yy, yz, zz} for l=2
            int na = 0; // Rows are shellA
            for (int x1 = LA; x1 >= 0; x1--) {
                for (int r1 = LA-x1; r1 >= 0; r1--) {
                    z1 = LA - x1 - r1;
                    w1 = w_lam + x1*mults[0] + r1*mults[1] + z1*mults[2];

                    int nb = 0; // Cols are shellB
                    for (int x2 = LB; x2 >= 0; x2--) {
                        for (int y2 = LB - x2; y2 >= 0; y2--) {
                            z2 = LB - x2 - y2;

                            // Begin full ECP integral expansion
                            int alpha = x1 + r1 + z1;

                            for (int beta_x = 0; beta_x <= x2; beta_x++) {
                                w_bx = w_lam + beta_x*mults[0];
                                for (int beta_y = 0; beta_y <= y2; beta_y++) {
                                    w_by = w_bx + beta_y*mults[1];
                                    for (int beta_z = 0; beta_z <= z2; beta_z++) {
                                        w_bz = w_by + beta_z*mults[2];
                                        int beta = beta_x + beta_y + beta_z;
                                        int N = alpha + beta;
                                        C = CB(0, nb, beta_x, beta_y, beta_z);

                                        if (std::abs(C) > 1e-15) {

                                            int lam2start =  N % 2;
                                            for (int lam2 = lam2start; lam2 <= lam + beta; lam2+=2) {
                                                w_l2 = w_bz + lam2*(1+mults[5]);
                                                val1 = prefac * C * radials(N, 0, lam2);


                                                for (int mu2 = -lam2; mu2 <= lam2; mu2++) {
                                                    w_m2 = w_l2 + mu2;
                                                    val2 = val1 *  SB(lam2, lam2+mu2);
                                                    w_m = -mults[4];
                                                    for (int mu = -lam; mu <= lam; mu++) {
                                                        w_m += mults[4];
                                                        values(na, nb, lam+mu) += val2 * omega[w1+w_m] * omega[w_m2+w_m];
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            nb++;
                        }
                    }
                    na++;
                }
            }
        }
    }
}