Program Listing for File angular.cpp¶
↰ Return to documentation for file (/Users/robertshaw/devfiles/libecpint/src/lib/angular.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 "angular.hpp"
#include "bessel.hpp"
#include "mathutil.hpp"
#include <cmath>
namespace libecpint {
double AngularIntegral::calcG(const int l, const int m) const {
double value = 0.0;
double value1 = FAST_POW[l](2.0) * FAC[l];
value1 = 1.0 / value1;
double value2 = (2.0 * l + 1) * FAC[l - m] / (2.0 * M_PI * FAC[l + m]);
value2 = std::sqrt(value2);
value = value1 * value2;
return value;
}
double AngularIntegral::calcH1(
const int i, const int j, const int l, const int m) const {
double value = 0.0;
value = FAC[l]/(FAC[j]*FAC[l - i]*FAC[i-j]);
value *= (1 - 2*(i%2)) * FAC[2*(l - i)] / (FAC[l - m - 2*i]);
return value;
}
double AngularIntegral::calcH2(
const int i, const int j, const int k, const int m) const {
double value = 0.0;
int ki2 = k - 2*i;
if ( m >= ki2 && ki2 >= 0 ) {
value = FAC[j]*FAC[m]/(FAC[i] * FAC[j-i] * FAC[ki2] * FAC[m-ki2]);
int p = (m - k + 2*i)/2;
value *= (1.0 - 2.0*(p%2));
}
return value;
}
ThreeIndex<double> AngularIntegral::uklm(
const int lam, const int mu) const {
ThreeIndex<double> values(lam+1, lam+1, 2);
double or2 = 1.0/std::sqrt(2.0);
double u = 0.0;
double um = 0.0;
double g = calcG(lam, mu);
double u1, h1, h2;
int j;
for (int k = 0; k <= lam; k++) {
for (int l = 0; l <= lam - k; l++) {
u = um = 0.0;
j = k + l - mu;
if (j % 2 == 0 && j > -1) {
u1 = 0.0;
j/=2;
for (int i = j; i <= (lam - mu)/2; i++) u1 += calcH1(i, j, lam, mu);
u = g * u1;
u1 = 0;
for (int i = 0; i <= j; i++) u1 += calcH2(i, j, k, mu);
u *= u1;
um = u;
j = l % 2;
u *= (1 - j);
um *= j;
if (mu == 0) {
u *= or2;
um = u;
}
}
values(k, l, 0) = u;
values(k, l, 1) = um;
}
}
return values;
}
ThreeIndex<double> AngularIntegral::Pijk(const int maxI) const {
int dim = maxI+1;
ThreeIndex<double> values(dim, dim, dim);
double pi4 = 4.0*M_PI;
values(0, 0, 0) = pi4;
for (int i = 1; i <= maxI; i++) {
values(i, 0, 0) = pi4 / ((double) (2*i+1));
for (int j = 1; j <= i; j++) {
values(i, j, 0) = values(i, j-1, 0) * (2.0*j - 1.0) / (2.0 * ((double)(i + j)) + 1.0);
for (int k = 1; k <= j; k++)
values(i, j, k) = values(i, j, k-1) * (2.0*k - 1.0) / (2.0 * ((double)(i + j + k)) + 1.0);
}
}
return values;
}
FiveIndex<double> AngularIntegral::makeU() const {
int dim = maxL + 1;
FiveIndex<double> values(dim, dim, dim, dim, 2);
for (int lam = 0; lam <= maxL; lam++) {
for (int mu = 0; mu <= lam; mu++) {
ThreeIndex<double> Uij = uklm(lam, mu);
for (int i = 0; i <= lam; i++) {
for (int j = 0; j <= lam - i; j++){
values(lam, mu, i, j, 0) = Uij(i, j, 0);
values(lam, mu, i, j, 1) = Uij(i, j, 1);
}
}
}
}
return values;
}
void AngularIntegral::makeW(const FiveIndex<double> &U) {
int LB2 = 2*LB;
int dim = wDim;
int maxI = (maxL + dim)/2;
int maxLam = maxL;
FiveIndex<double> values{dim+1, dim+1, dim+1, maxLam+1, 2*(maxLam + 1)};
ThreeIndex<double> pijk = Pijk(maxI);
int plam, pmu;
double smu, w;
std::vector<int> ix(3);
for (int k = 0; k <= dim; k++) {
for (int l = 0; l <= dim; l++) {
for(int m = 0; m <= dim; m++) {
plam = (k + l + m)%2;
int limit = maxLam > k+l+m ? k+l+m : maxLam;
for(int lam = plam; lam <= limit; lam += 2){
smu = 1 - 2*(l%2);
pmu = (k+l) % 2;
for (int mu = pmu; mu <= lam; mu+=2) {
w = 0.0;
for (int i = 0; i <= lam; i++) {
for (int j = 0; j <= lam - i; j++) {
ix[0] = k+i;
ix[1] = l+j;
ix[2] = m + lam - i - j;
if (ix[0]%2 + ix[1]%2 + ix[2]%2 == 0){
std::sort(ix.begin(), ix.end());
w += U(lam, mu, i, j, (1 - (int)(smu))/2)*pijk(ix[2]/2, ix[1]/2, ix[0]/2);
}
}
}
values(k, l, m, lam, lam+(int)(smu*mu)) = w;
}
}
}
}
}
W = values;
}
void AngularIntegral::makeOmega(const FiveIndex<double> &U) {
int lamDim = LE + LB;
int muDim = 2*lamDim + 1;
SevenIndex<double> values{LB+1, LB+1, LB+1, lamDim+1, muDim+1, lamDim+1, muDim+1};
double om_plus=0.0, om_minus=0.0;
double wval;
for (int k = 0; k <= LB; k++) {
for (int l = 0; l <= LB; l++) {
for (int m = 0; m <= LB; m++) {
for (int rho = 0; rho <= lamDim; rho++ ) {
for (int sigma = -rho; sigma <= rho; sigma++) {
for (int lam = 0; lam <= rho; lam++) {
for (int mu = 0; mu <= lam; mu++) {
om_plus = om_minus = 0.0;
for (int i = 0; i<= lam; i++ ) {
for (int j = 0; j <= lam - i; j++) {
wval = W(k+i, l+j, m+lam-i-j, rho, rho+sigma);
om_plus += U(lam, mu, i, j, 0) * wval;
om_minus += U(lam, mu, i, j, 1) * wval;
}
}
if (mu == 0) om_minus = om_plus;
values(k, l, m, rho, sigma+rho, lam, lam+mu) = om_plus;
values(k, l, m, lam, lam+mu, rho, sigma+rho) = om_plus;
values(k, l, m, rho, sigma+rho, lam, lam-mu) = om_minus;
values(k, l, m, lam, lam-mu, rho, sigma+rho) = om_minus;
}
}
}
}
}
}
}
omega = values;
}
AngularIntegral::AngularIntegral() { init(0, 0); }
AngularIntegral::AngularIntegral(const int _LB, const int _LE) { init(_LB, _LE); }
void AngularIntegral::init(const int _LB, const int _LE ) {
LB = _LB;
LE = _LE;
wDim = 4*LB > 3*LB + LE ? 4*LB : 3*LB + LE;
maxL = 2*LB > LB + LE ? 2*LB : LB+LE;
}
void AngularIntegral::compute() {
FiveIndex<double> U = makeU();
makeW(U);
makeOmega(U);
}
void AngularIntegral::clear() {}
double AngularIntegral::getIntegral(
const int k, const int l, const int m, const int lam, const int mu) const {
return W(k, l, m, lam, lam+mu);
}
double AngularIntegral::getIntegral(
const int k, const int l, const int m, const int lam, const int mu, const int rho, const int sigma) const {
return omega(k, l, m, lam, lam+mu, rho, rho+sigma);
}
bool AngularIntegral::isZero(
const int k, const int l, const int m, const int lam, const int mu, const double tolerance) const {
if (wDim > 0) return std::fabs(W(k, l, m, lam, lam+mu)) < tolerance;
else return true;
}
bool AngularIntegral::isZero(
const int k, const int l, const int m, const int lam, const int mu, const int rho, const int sigma, const double tolerance) const {
if (wDim > 0) return std::fabs(omega(k, l, m, lam, lam+mu, rho, rho+sigma)) < tolerance;
else return true;
}
}