Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91860610
sna.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 15, 05:50
Size
53 KB
Mime Type
text/x-c
Expires
Sun, Nov 17, 05:50 (2 d)
Engine
blob
Format
Raw Data
Handle
22337971
Attached To
rLAMMPS lammps
sna.cpp
View Options
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Aidan Thompson, Christian Trott, SNL
------------------------------------------------------------------------- */
#include "sna.h"
#include "math.h"
#include "math_const.h"
#include "math_extra.h"
#include "string.h"
#include "stdlib.h"
#include "openmp_snap.h"
#include "memory.h"
#include "error.h"
#include "comm.h"
#include "atom.h"
using
namespace
std
;
using
namespace
LAMMPS_NS
;
using
namespace
MathConst
;
/* ----------------------------------------------------------------------
this implementation is based on the method outlined
in Bartok[1], using formulae from VMK[2].
for the Clebsch-Gordan coefficients, we
convert the VMK half-integral labels
a, b, c, alpha, beta, gamma
to array offsets j1, j2, j, m1, m2, m
using the following relations:
j1 = 2*a
j2 = 2*b
j = 2*c
m1 = alpha+a 2*alpha = 2*m1 - j1
m2 = beta+b or 2*beta = 2*m2 - j2
m = gamma+c 2*gamma = 2*m - j
in this way:
-a <= alpha <= a
-b <= beta <= b
-c <= gamma <= c
becomes:
0 <= m1 <= j1
0 <= m2 <= j2
0 <= m <= j
and the requirement that
a+b+c be integral implies that
j1+j2+j must be even.
The requirement that:
gamma = alpha+beta
becomes:
2*m - j = 2*m1 - j1 + 2*m2 - j2
Similarly, for the Wigner U-functions U(J,m,m') we
convert the half-integral labels J,m,m' to
array offsets j,ma,mb:
j = 2*J
ma = J+m
mb = J+m'
so that:
0 <= j <= 2*Jmax
0 <= ma, mb <= j.
For the bispectrum components B(J1,J2,J) we convert to:
j1 = 2*J1
j2 = 2*J2
j = 2*J
and the requirement:
|J1-J2| <= J <= J1+J2, for j1+j2+j integral
becomes:
|j1-j2| <= j <= j1+j2, for j1+j2+j even integer
or
j = |j1-j2|, |j1-j2|+2,...,j1+j2-2,j1+j2
[1] Albert Bartok-Partay, "Gaussian Approximation..."
Doctoral Thesis, Cambrindge University, (2009)
[2] D. A. Varshalovich, A. N. Moskalev, and V. K. Khersonskii,
"Quantum Theory of Angular Momentum," World Scientific (1988)
------------------------------------------------------------------------- */
SNA
::
SNA
(
LAMMPS
*
lmp
,
double
rfac0_in
,
int
twojmax_in
,
int
diagonalstyle_in
,
int
use_shared_arrays_in
,
double
rmin0_in
,
int
switch_flag_in
)
:
Pointers
(
lmp
)
{
wself
=
1.0
;
use_shared_arrays
=
use_shared_arrays_in
;
rfac0
=
rfac0_in
;
rmin0
=
rmin0_in
;
switch_flag
=
switch_flag_in
;
twojmax
=
twojmax_in
;
diagonalstyle
=
diagonalstyle_in
;
ncoeff
=
compute_ncoeff
();
create_twojmax_arrays
();
bvec
=
NULL
;
dbvec
=
NULL
;
memory
->
create
(
bvec
,
ncoeff
,
"pair:bvec"
);
memory
->
create
(
dbvec
,
ncoeff
,
3
,
"pair:dbvec"
);
rij
=
NULL
;
inside
=
NULL
;
wj
=
NULL
;
rcutij
=
NULL
;
nmax
=
0
;
idxj
=
NULL
;
#ifdef TIMING_INFO
timers
=
new
double
[
20
];
for
(
int
i
=
0
;
i
<
20
;
i
++
)
timers
[
i
]
=
0
;
print
=
0
;
counter
=
0
;
#endif
build_indexlist
();
}
/* ---------------------------------------------------------------------- */
SNA
::~
SNA
()
{
if
(
!
use_shared_arrays
)
{
destroy_twojmax_arrays
();
memory
->
destroy
(
rij
);
memory
->
destroy
(
inside
);
memory
->
destroy
(
wj
);
memory
->
destroy
(
rcutij
);
memory
->
destroy
(
bvec
);
memory
->
destroy
(
dbvec
);
}
delete
[]
idxj
;
}
void
SNA
::
build_indexlist
()
{
if
(
diagonalstyle
==
0
)
{
int
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
idxj_count
++
;
// indexList can be changed here
idxj
=
new
SNA_LOOPINDICES
[
idxj_count
];
idxj_max
=
idxj_count
;
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
idxj
[
idxj_count
].
j1
=
j1
;
idxj
[
idxj_count
].
j2
=
j2
;
idxj
[
idxj_count
].
j
=
j
;
idxj_count
++
;
}
}
if
(
diagonalstyle
==
1
)
{
int
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j
=
0
;
j
<=
MIN
(
twojmax
,
2
*
j1
);
j
+=
2
)
{
idxj_count
++
;
}
// indexList can be changed here
idxj
=
new
SNA_LOOPINDICES
[
idxj_count
];
idxj_max
=
idxj_count
;
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j
=
0
;
j
<=
MIN
(
twojmax
,
2
*
j1
);
j
+=
2
)
{
idxj
[
idxj_count
].
j1
=
j1
;
idxj
[
idxj_count
].
j2
=
j1
;
idxj
[
idxj_count
].
j
=
j
;
idxj_count
++
;
}
}
if
(
diagonalstyle
==
2
)
{
int
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
{
idxj_count
++
;
}
// indexList can be changed here
idxj
=
new
SNA_LOOPINDICES
[
idxj_count
];
idxj_max
=
idxj_count
;
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
{
idxj
[
idxj_count
].
j1
=
j1
;
idxj
[
idxj_count
].
j2
=
j1
;
idxj
[
idxj_count
].
j
=
j1
;
idxj_count
++
;
}
}
if
(
diagonalstyle
==
3
)
{
int
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
if
(
j
>=
j1
)
idxj_count
++
;
// indexList can be changed here
idxj
=
new
SNA_LOOPINDICES
[
idxj_count
];
idxj_max
=
idxj_count
;
idxj_count
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
if
(
j
>=
j1
)
{
idxj
[
idxj_count
].
j1
=
j1
;
idxj
[
idxj_count
].
j2
=
j2
;
idxj
[
idxj_count
].
j
=
j
;
idxj_count
++
;
}
}
}
/* ---------------------------------------------------------------------- */
void
SNA
::
init
()
{
init_clebsch_gordan
();
init_rootpqarray
();
}
void
SNA
::
grow_rij
(
int
newnmax
)
{
if
(
newnmax
<=
nmax
)
return
;
nmax
=
newnmax
;
if
(
!
use_shared_arrays
)
{
memory
->
destroy
(
rij
);
memory
->
destroy
(
inside
);
memory
->
destroy
(
wj
);
memory
->
destroy
(
rcutij
);
memory
->
create
(
rij
,
nmax
,
3
,
"pair:rij"
);
memory
->
create
(
inside
,
nmax
,
"pair:inside"
);
memory
->
create
(
wj
,
nmax
,
"pair:wj"
);
memory
->
create
(
rcutij
,
nmax
,
"pair:rcutij"
);
}
}
/* ----------------------------------------------------------------------
compute Ui by summing over neighbors j
------------------------------------------------------------------------- */
void
SNA
::
compute_ui
(
int
jnum
)
{
double
rsq
,
r
,
x
,
y
,
z
,
z0
,
theta0
;
// utot(j,ma,mb) = 0 for all j,ma,ma
// utot(j,ma,ma) = 1 for all j,ma
// for j in neighbors of i:
// compute r0 = (x,y,z,z0)
// utot(j,ma,mb) += u(r0;j,ma,mb) for all j,ma,mb
zero_uarraytot
();
addself_uarraytot
(
wself
);
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
for
(
int
j
=
0
;
j
<
jnum
;
j
++
)
{
x
=
rij
[
j
][
0
];
y
=
rij
[
j
][
1
];
z
=
rij
[
j
][
2
];
rsq
=
x
*
x
+
y
*
y
+
z
*
z
;
r
=
sqrt
(
rsq
);
theta0
=
(
r
-
rmin0
)
*
rfac0
*
MY_PI
/
(
rcutij
[
j
]
-
rmin0
);
// theta0 = (r - rmin0) * rscale0;
z0
=
r
/
tan
(
theta0
);
compute_uarray
(
x
,
y
,
z
,
z0
,
r
);
add_uarraytot
(
r
,
wj
[
j
],
rcutij
[
j
]);
}
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
0
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
void
SNA
::
compute_ui_omp
(
int
jnum
,
int
sub_threads
)
{
double
rsq
,
r
,
x
,
y
,
z
,
z0
,
theta0
;
// utot(j,ma,mb) = 0 for all j,ma,ma
// utot(j,ma,ma) = 1 for all j,ma
// for j in neighbors of i:
// compute r0 = (x,y,z,z0)
// utot(j,ma,mb) += u(r0;j,ma,mb) for all j,ma,mb
zero_uarraytot
();
addself_uarraytot
(
wself
);
for
(
int
j
=
0
;
j
<
jnum
;
j
++
)
{
x
=
rij
[
j
][
0
];
y
=
rij
[
j
][
1
];
z
=
rij
[
j
][
2
];
rsq
=
x
*
x
+
y
*
y
+
z
*
z
;
r
=
sqrt
(
rsq
);
theta0
=
(
r
-
rmin0
)
*
rfac0
*
MY_PI
/
(
rcutij
[
j
]
-
rmin0
);
// theta0 = (r - rmin0) * rscale0;
z0
=
r
/
tan
(
theta0
);
omp_set_num_threads
(
sub_threads
);
#if defined(_OPENMP)
#pragma omp parallel shared(x,y,z,z0,r,sub_threads) default(none)
#endif
{
compute_uarray_omp
(
x
,
y
,
z
,
z0
,
r
,
sub_threads
);
}
add_uarraytot
(
r
,
wj
[
j
],
rcutij
[
j
]);
}
}
/* ----------------------------------------------------------------------
compute Zi by summing over products of Ui
------------------------------------------------------------------------- */
void
SNA
::
compute_zi
()
{
// for j1 = 0,...,twojmax
// for j2 = 0,twojmax
// for j = |j1-j2|,Min(twojmax,j1+j2),2
// for ma = 0,...,j
// for mb = 0,...,jmid
// z(j1,j2,j,ma,mb) = 0
// for ma1 = Max(0,ma+(j1-j2-j)/2),Min(j1,ma+(j1+j2-j)/2)
// sumb1 = 0
// ma2 = ma-ma1+(j1+j2-j)/2;
// for mb1 = Max(0,mb+(j1-j2-j)/2),Min(j1,mb+(j1+j2-j)/2)
// mb2 = mb-mb1+(j1+j2-j)/2;
// sumb1 += cg(j1,mb1,j2,mb2,j) *
// u(j1,ma1,mb1) * u(j2,ma2,mb2)
// z(j1,j2,j,ma,mb) += sumb1*cg(j1,ma1,j2,ma2,j)
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
// compute_dbidrj() requires full j1/j2/j chunk of z elements
// use zarray j1/j2 symmetry
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
{
for
(
int
j
=
j1
-
j2
;
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
double
sumb1_r
,
sumb1_i
;
int
ma2
,
mb2
;
for
(
int
mb
=
0
;
2
*
mb
<=
j
;
mb
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
=
0.0
;
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
]
=
0.0
;
for
(
int
ma1
=
MAX
(
0
,
(
2
*
ma
-
j
-
j2
+
j1
)
/
2
);
ma1
<=
MIN
(
j1
,
(
2
*
ma
-
j
+
j2
+
j1
)
/
2
);
ma1
++
)
{
sumb1_r
=
0.0
;
sumb1_i
=
0.0
;
ma2
=
(
2
*
ma
-
j
-
(
2
*
ma1
-
j1
)
+
j2
)
/
2
;
for
(
int
mb1
=
MAX
(
0
,
(
2
*
mb
-
j
-
j2
+
j1
)
/
2
);
mb1
<=
MIN
(
j1
,
(
2
*
mb
-
j
+
j2
+
j1
)
/
2
);
mb1
++
)
{
mb2
=
(
2
*
mb
-
j
-
(
2
*
mb1
-
j1
)
+
j2
)
/
2
;
sumb1_r
+=
cgarray
[
j1
][
j2
][
j
][
mb1
][
mb2
]
*
(
uarraytot_r
[
j1
][
ma1
][
mb1
]
*
uarraytot_r
[
j2
][
ma2
][
mb2
]
-
uarraytot_i
[
j1
][
ma1
][
mb1
]
*
uarraytot_i
[
j2
][
ma2
][
mb2
]);
sumb1_i
+=
cgarray
[
j1
][
j2
][
j
][
mb1
][
mb2
]
*
(
uarraytot_r
[
j1
][
ma1
][
mb1
]
*
uarraytot_i
[
j2
][
ma2
][
mb2
]
+
uarraytot_i
[
j1
][
ma1
][
mb1
]
*
uarraytot_r
[
j2
][
ma2
][
mb2
]);
}
// end loop over mb1
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+=
sumb1_r
*
cgarray
[
j1
][
j2
][
j
][
ma1
][
ma2
];
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
]
+=
sumb1_i
*
cgarray
[
j1
][
j2
][
j
][
ma1
][
ma2
];
}
// end loop over ma1
}
// end loop over ma, mb
}
// end loop over j
}
// end loop over j1, j2
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
1
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
void
SNA
::
compute_zi_omp
(
int
sub_threads
)
{
// for j1 = 0,...,twojmax
// for j2 = 0,twojmax
// for j = |j1-j2|,Min(twojmax,j1+j2),2
// for ma = 0,...,j
// for mb = 0,...,j
// z(j1,j2,j,ma,mb) = 0
// for ma1 = Max(0,ma+(j1-j2-j)/2),Min(j1,ma+(j1+j2-j)/2)
// sumb1 = 0
// ma2 = ma-ma1+(j1+j2-j)/2;
// for mb1 = Max(0,mb+(j1-j2-j)/2),Min(j1,mb+(j1+j2-j)/2)
// mb2 = mb-mb1+(j1+j2-j)/2;
// sumb1 += cg(j1,mb1,j2,mb2,j) *
// u(j1,ma1,mb1) * u(j2,ma2,mb2)
// z(j1,j2,j,ma,mb) += sumb1*cg(j1,ma1,j2,ma2,j)
if
(
omp_in_parallel
())
omp_set_num_threads
(
sub_threads
);
// compute_dbidrj() requires full j1/j2/j chunk of z elements
// use zarray j1/j2 symmetry
#if defined(_OPENMP)
#pragma omp parallel for schedule(auto) default(none)
#endif
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
double
sumb1_r
,
sumb1_i
;
int
ma2
,
mb2
;
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
=
0.0
;
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
]
=
0.0
;
for
(
int
ma1
=
MAX
(
0
,
(
2
*
ma
-
j
-
j2
+
j1
)
/
2
);
ma1
<=
MIN
(
j1
,
(
2
*
ma
-
j
+
j2
+
j1
)
/
2
);
ma1
++
)
{
sumb1_r
=
0.0
;
sumb1_i
=
0.0
;
ma2
=
(
2
*
ma
-
j
-
(
2
*
ma1
-
j1
)
+
j2
)
/
2
;
for
(
int
mb1
=
MAX
(
0
,
(
2
*
mb
-
j
-
j2
+
j1
)
/
2
);
mb1
<=
MIN
(
j1
,
(
2
*
mb
-
j
+
j2
+
j1
)
/
2
);
mb1
++
)
{
mb2
=
(
2
*
mb
-
j
-
(
2
*
mb1
-
j1
)
+
j2
)
/
2
;
sumb1_r
+=
cgarray
[
j1
][
j2
][
j
][
mb1
][
mb2
]
*
(
uarraytot_r
[
j1
][
ma1
][
mb1
]
*
uarraytot_r
[
j2
][
ma2
][
mb2
]
-
uarraytot_i
[
j1
][
ma1
][
mb1
]
*
uarraytot_i
[
j2
][
ma2
][
mb2
]);
sumb1_i
+=
cgarray
[
j1
][
j2
][
j
][
mb1
][
mb2
]
*
(
uarraytot_r
[
j1
][
ma1
][
mb1
]
*
uarraytot_i
[
j2
][
ma2
][
mb2
]
+
uarraytot_i
[
j1
][
ma1
][
mb1
]
*
uarraytot_r
[
j2
][
ma2
][
mb2
]);
}
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+=
sumb1_r
*
cgarray
[
j1
][
j2
][
j
][
ma1
][
ma2
];
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
]
+=
sumb1_i
*
cgarray
[
j1
][
j2
][
j
][
ma1
][
ma2
];
}
}
}
}
/* ----------------------------------------------------------------------
compute Bi by summing conj(Ui)*Zi
------------------------------------------------------------------------- */
void
SNA
::
compute_bi
()
{
// for j1 = 0,...,twojmax
// for j2 = 0,twojmax
// for j = |j1-j2|,Min(twojmax,j1+j2),2
// b(j1,j2,j) = 0
// for mb = 0,...,jmid
// for ma = 0,...,j
// b(j1,j2,j) +=
// 2*Conj(u(j,ma,mb))*z(j1,j2,j,ma,mb)
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
{
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
barray
[
j1
][
j2
][
j
]
=
0.0
;
for
(
int
mb
=
0
;
2
*
mb
<
j
;
mb
++
)
{
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
barray
[
j1
][
j2
][
j
]
+=
uarraytot_r
[
j
][
ma
][
mb
]
*
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+
uarraytot_i
[
j
][
ma
][
mb
]
*
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
];
}
}
// For j even, special treatment for middle column
if
(
j
%
2
==
0
)
{
int
mb
=
j
/
2
;
for
(
int
ma
=
0
;
ma
<
mb
;
ma
++
)
barray
[
j1
][
j2
][
j
]
+=
uarraytot_r
[
j
][
ma
][
mb
]
*
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+
uarraytot_i
[
j
][
ma
][
mb
]
*
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
];
int
ma
=
mb
;
barray
[
j1
][
j2
][
j
]
+=
(
uarraytot_r
[
j
][
ma
][
mb
]
*
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+
uarraytot_i
[
j
][
ma
][
mb
]
*
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
])
*
0.5
;
}
barray
[
j1
][
j2
][
j
]
*=
2.0
;
}
}
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
2
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
/* ----------------------------------------------------------------------
copy Bi array to a vector
------------------------------------------------------------------------- */
void
SNA
::
copy_bi2bvec
()
{
int
ncount
,
j1
,
j2
,
j
;
ncount
=
0
;
for
(
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
if
(
diagonalstyle
==
0
)
{
for
(
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
bvec
[
ncount
]
=
barray
[
j1
][
j2
][
j
];
ncount
++
;
}
}
else
if
(
diagonalstyle
==
1
)
{
j2
=
j1
;
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
bvec
[
ncount
]
=
barray
[
j1
][
j2
][
j
];
ncount
++
;
}
}
else
if
(
diagonalstyle
==
2
)
{
j
=
j2
=
j1
;
bvec
[
ncount
]
=
barray
[
j1
][
j2
][
j
];
ncount
++
;
}
else
if
(
diagonalstyle
==
3
)
{
for
(
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
if
(
j
>=
j1
)
{
bvec
[
ncount
]
=
barray
[
j1
][
j2
][
j
];
ncount
++
;
}
}
}
/* ----------------------------------------------------------------------
calculate derivative of Ui w.r.t. atom j
------------------------------------------------------------------------- */
void
SNA
::
compute_duidrj
(
double
*
rij
,
double
wj
,
double
rcut
)
{
double
rsq
,
r
,
x
,
y
,
z
,
z0
,
theta0
,
cs
,
sn
;
double
dz0dr
;
x
=
rij
[
0
];
y
=
rij
[
1
];
z
=
rij
[
2
];
rsq
=
x
*
x
+
y
*
y
+
z
*
z
;
r
=
sqrt
(
rsq
);
double
rscale0
=
rfac0
*
MY_PI
/
(
rcut
-
rmin0
);
theta0
=
(
r
-
rmin0
)
*
rscale0
;
cs
=
cos
(
theta0
);
sn
=
sin
(
theta0
);
z0
=
r
*
cs
/
sn
;
dz0dr
=
z0
/
r
-
(
r
*
rscale0
)
*
(
rsq
+
z0
*
z0
)
/
rsq
;
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
compute_duarray
(
x
,
y
,
z
,
z0
,
r
,
dz0dr
,
wj
,
rcut
);
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
3
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
/* ----------------------------------------------------------------------
calculate derivative of Bi w.r.t. atom j
variant using indexlist for j1,j2,j
variant not using symmetry relation
------------------------------------------------------------------------- */
void
SNA
::
compute_dbidrj_nonsymm
()
{
// for j1 = 0,...,twojmax
// for j2 = 0,twojmax
// for j = |j1-j2|,Min(twojmax,j1+j2),2
// dbdr(j1,j2,j) = 0
// for ma = 0,...,j
// for mb = 0,...,j
// dzdr = 0
// for ma1 = Max(0,ma+(j1-j2-j)/2),Min(j1,ma+(j1+j2-j)/2)
// sumb1 = 0
// ma2 = ma-ma1+(j1+j2-j)/2;
// for mb1 = Max(0,mb+(j1-j2-j)/2),Min(j1,mb+(j1+j2-j)/2)
// mb2 = mb-mb1+(j1+j2-j)/2;
// sumb1 += cg(j1,mb1,j2,mb2,j) *
// (dudr(j1,ma1,mb1) * u(j2,ma2,mb2) +
// u(j1,ma1,mb1) * dudr(j2,ma2,mb2))
// dzdr += sumb1*cg(j1,ma1,j2,ma2,j)
// dbdr(j1,j2,j) +=
// Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb) +
// Conj(u(j,ma,mb))*dzdr
double
*
dbdr
;
double
*
dudr_r
,
*
dudr_i
;
double
sumb1_r
[
3
],
sumb1_i
[
3
],
dzdr_r
[
3
],
dzdr_i
[
3
];
int
ma2
;
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
for
(
int
JJ
=
0
;
JJ
<
idxj_max
;
JJ
++
)
{
const
int
j1
=
idxj
[
JJ
].
j1
;
const
int
j2
=
idxj
[
JJ
].
j2
;
const
int
j
=
idxj
[
JJ
].
j
;
dbdr
=
dbarray
[
j1
][
j2
][
j
];
dbdr
[
0
]
=
0.0
;
dbdr
[
1
]
=
0.0
;
dbdr
[
2
]
=
0.0
;
double
**
*
j1duarray_r
=
duarray_r
[
j1
];
double
**
*
j2duarray_r
=
duarray_r
[
j2
];
double
**
*
j1duarray_i
=
duarray_i
[
j1
];
double
**
*
j2duarray_i
=
duarray_i
[
j2
];
double
**
j1uarraytot_r
=
uarraytot_r
[
j1
];
double
**
j2uarraytot_r
=
uarraytot_r
[
j2
];
double
**
j1uarraytot_i
=
uarraytot_i
[
j1
];
double
**
j2uarraytot_i
=
uarraytot_i
[
j2
];
double
**
j1j2jcgarray
=
cgarray
[
j1
][
j2
][
j
];
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
dzdr_r
[
0
]
=
0.0
;
dzdr_r
[
1
]
=
0.0
;
dzdr_r
[
2
]
=
0.0
;
dzdr_i
[
0
]
=
0.0
;
dzdr_i
[
1
]
=
0.0
;
dzdr_i
[
2
]
=
0.0
;
const
int
max_mb1
=
MIN
(
j1
,
(
2
*
mb
-
j
+
j2
+
j1
)
/
2
)
+
1
;
const
int
max_ma1
=
MIN
(
j1
,
(
2
*
ma
-
j
+
j2
+
j1
)
/
2
)
+
1
;
for
(
int
ma1
=
MAX
(
0
,
(
2
*
ma
-
j
-
j2
+
j1
)
/
2
);
ma1
<
max_ma1
;
ma1
++
)
{
ma2
=
(
2
*
ma
-
j
-
(
2
*
ma1
-
j1
)
+
j2
)
/
2
;
sumb1_r
[
0
]
=
0.0
;
sumb1_r
[
1
]
=
0.0
;
sumb1_r
[
2
]
=
0.0
;
sumb1_i
[
0
]
=
0.0
;
sumb1_i
[
1
]
=
0.0
;
sumb1_i
[
2
]
=
0.0
;
//inside loop 54 operations (mul and add)
for
(
int
mb1
=
MAX
(
0
,
(
2
*
mb
-
j
-
j2
+
j1
)
/
2
),
mb2
=
mb
+
(
j1
+
j2
-
j
)
/
2
-
mb1
;
mb1
<
max_mb1
;
mb1
++
,
mb2
--
)
{
double
*
dudr1_r
,
*
dudr1_i
,
*
dudr2_r
,
*
dudr2_i
;
dudr1_r
=
j1duarray_r
[
ma1
][
mb1
];
dudr2_r
=
j2duarray_r
[
ma2
][
mb2
];
dudr1_i
=
j1duarray_i
[
ma1
][
mb1
];
dudr2_i
=
j2duarray_i
[
ma2
][
mb2
];
const
double
cga_mb1mb2
=
j1j2jcgarray
[
mb1
][
mb2
];
const
double
uat_r_ma2mb2
=
cga_mb1mb2
*
j2uarraytot_r
[
ma2
][
mb2
];
const
double
uat_r_ma1mb1
=
cga_mb1mb2
*
j1uarraytot_r
[
ma1
][
mb1
];
const
double
uat_i_ma2mb2
=
cga_mb1mb2
*
j2uarraytot_i
[
ma2
][
mb2
];
const
double
uat_i_ma1mb1
=
cga_mb1mb2
*
j1uarraytot_i
[
ma1
][
mb1
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
sumb1_r
[
k
]
+=
dudr1_r
[
k
]
*
uat_r_ma2mb2
;
sumb1_r
[
k
]
-=
dudr1_i
[
k
]
*
uat_i_ma2mb2
;
sumb1_i
[
k
]
+=
dudr1_r
[
k
]
*
uat_i_ma2mb2
;
sumb1_i
[
k
]
+=
dudr1_i
[
k
]
*
uat_r_ma2mb2
;
sumb1_r
[
k
]
+=
dudr2_r
[
k
]
*
uat_r_ma1mb1
;
sumb1_r
[
k
]
-=
dudr2_i
[
k
]
*
uat_i_ma1mb1
;
sumb1_i
[
k
]
+=
dudr2_r
[
k
]
*
uat_i_ma1mb1
;
sumb1_i
[
k
]
+=
dudr2_i
[
k
]
*
uat_r_ma1mb1
;
}
}
// end loop over mb1,mb2
// dzdr += sumb1*cg(j1,ma1,j2,ma2,j)
dzdr_r
[
0
]
+=
sumb1_r
[
0
]
*
j1j2jcgarray
[
ma1
][
ma2
];
dzdr_r
[
1
]
+=
sumb1_r
[
1
]
*
j1j2jcgarray
[
ma1
][
ma2
];
dzdr_r
[
2
]
+=
sumb1_r
[
2
]
*
j1j2jcgarray
[
ma1
][
ma2
];
dzdr_i
[
0
]
+=
sumb1_i
[
0
]
*
j1j2jcgarray
[
ma1
][
ma2
];
dzdr_i
[
1
]
+=
sumb1_i
[
1
]
*
j1j2jcgarray
[
ma1
][
ma2
];
dzdr_i
[
2
]
+=
sumb1_i
[
2
]
*
j1j2jcgarray
[
ma1
][
ma2
];
}
// end loop over ma1,ma2
// dbdr(j1,j2,j) +=
// Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb) +
// Conj(u(j,ma,mb))*dzdr
dudr_r
=
duarray_r
[
j
][
ma
][
mb
];
dudr_i
=
duarray_i
[
j
][
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
dbdr
[
k
]
+=
(
dudr_r
[
k
]
*
zarray_r
[
j1
][
j2
][
j
][
ma
][
mb
]
+
dudr_i
[
k
]
*
zarray_i
[
j1
][
j2
][
j
][
ma
][
mb
])
+
(
uarraytot_r
[
j
][
ma
][
mb
]
*
dzdr_r
[
k
]
+
uarraytot_i
[
j
][
ma
][
mb
]
*
dzdr_i
[
k
]);
}
//end loop over ma mb
}
//end loop over j1 j2 j
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
4
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
/* ----------------------------------------------------------------------
calculate derivative of Bi w.r.t. atom j
variant using indexlist for j1,j2,j
variant using symmetry relation
------------------------------------------------------------------------- */
void
SNA
::
compute_dbidrj
()
{
// for j1 = 0,...,twojmax
// for j2 = 0,twojmax
// for j = |j1-j2|,Min(twojmax,j1+j2),2
// zdb = 0
// for mb = 0,...,jmid
// for ma = 0,...,j
// zdb +=
// Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb)
// dbdr(j1,j2,j) += 2*zdb
// zdb = 0
// for mb1 = 0,...,j1mid
// for ma1 = 0,...,j1
// zdb +=
// Conj(dudr(j1,ma1,mb1))*z(j1,j2,j,ma1,mb1)
// dbdr(j1,j2,j) += 2*zdb*(j+1)/(j1+1)
// zdb = 0
// for mb2 = 0,...,j2mid
// for ma2 = 0,...,j2
// zdb +=
// Conj(dudr(j2,ma2,mb2))*z(j1,j,j2,ma2,mb2)
// dbdr(j1,j2,j) += 2*zdb*(j+1)/(j2+1)
double
*
dbdr
;
double
*
dudr_r
,
*
dudr_i
;
double
sumzdu_r
[
3
];
double
**
jjjzarray_r
;
double
**
jjjzarray_i
;
double
jjjmambzarray_r
;
double
jjjmambzarray_i
;
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
starttime
);
#endif
for
(
int
JJ
=
0
;
JJ
<
idxj_max
;
JJ
++
)
{
const
int
j1
=
idxj
[
JJ
].
j1
;
const
int
j2
=
idxj
[
JJ
].
j2
;
const
int
j
=
idxj
[
JJ
].
j
;
dbdr
=
dbarray
[
j1
][
j2
][
j
];
dbdr
[
0
]
=
0.0
;
dbdr
[
1
]
=
0.0
;
dbdr
[
2
]
=
0.0
;
// Sum terms Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb)
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
=
0.0
;
// use zarray j1/j2 symmetry (optional)
if
(
j1
>=
j2
)
{
jjjzarray_r
=
zarray_r
[
j1
][
j2
][
j
];
jjjzarray_i
=
zarray_i
[
j1
][
j2
][
j
];
}
else
{
jjjzarray_r
=
zarray_r
[
j2
][
j1
][
j
];
jjjzarray_i
=
zarray_i
[
j2
][
j1
][
j
];
}
for
(
int
mb
=
0
;
2
*
mb
<
j
;
mb
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
dudr_r
=
duarray_r
[
j
][
ma
][
mb
];
dudr_i
=
duarray_i
[
j
][
ma
][
mb
];
jjjmambzarray_r
=
jjjzarray_r
[
ma
][
mb
];
jjjmambzarray_i
=
jjjzarray_i
[
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
//end loop over ma mb
// For j even, handle middle column
if
(
j
%
2
==
0
)
{
int
mb
=
j
/
2
;
for
(
int
ma
=
0
;
ma
<
mb
;
ma
++
)
{
dudr_r
=
duarray_r
[
j
][
ma
][
mb
];
dudr_i
=
duarray_i
[
j
][
ma
][
mb
];
jjjmambzarray_r
=
jjjzarray_r
[
ma
][
mb
];
jjjmambzarray_i
=
jjjzarray_i
[
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
int
ma
=
mb
;
dudr_r
=
duarray_r
[
j
][
ma
][
mb
];
dudr_i
=
duarray_i
[
j
][
ma
][
mb
];
jjjmambzarray_r
=
jjjzarray_r
[
ma
][
mb
];
jjjmambzarray_i
=
jjjzarray_i
[
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
(
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
)
*
0.5
;
}
// end if jeven
for
(
int
k
=
0
;
k
<
3
;
k
++
)
dbdr
[
k
]
+=
2.0
*
sumzdu_r
[
k
];
// Sum over Conj(dudr(j1,ma1,mb1))*z(j,j2,j1,ma1,mb1)
double
j1fac
=
(
j
+
1
)
/
(
j1
+
1.0
);
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
=
0.0
;
// use zarray j1/j2 symmetry (optional)
if
(
j
>=
j2
)
{
jjjzarray_r
=
zarray_r
[
j
][
j2
][
j1
];
jjjzarray_i
=
zarray_i
[
j
][
j2
][
j1
];
}
else
{
jjjzarray_r
=
zarray_r
[
j2
][
j
][
j1
];
jjjzarray_i
=
zarray_i
[
j2
][
j
][
j1
];
}
for
(
int
mb1
=
0
;
2
*
mb1
<
j1
;
mb1
++
)
for
(
int
ma1
=
0
;
ma1
<=
j1
;
ma1
++
)
{
dudr_r
=
duarray_r
[
j1
][
ma1
][
mb1
];
dudr_i
=
duarray_i
[
j1
][
ma1
][
mb1
];
jjjmambzarray_r
=
jjjzarray_r
[
ma1
][
mb1
];
jjjmambzarray_i
=
jjjzarray_i
[
ma1
][
mb1
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
//end loop over ma1 mb1
// For j1 even, handle middle column
if
(
j1
%
2
==
0
)
{
int
mb1
=
j1
/
2
;
for
(
int
ma1
=
0
;
ma1
<
mb1
;
ma1
++
)
{
dudr_r
=
duarray_r
[
j1
][
ma1
][
mb1
];
dudr_i
=
duarray_i
[
j1
][
ma1
][
mb1
];
jjjmambzarray_r
=
jjjzarray_r
[
ma1
][
mb1
];
jjjmambzarray_i
=
jjjzarray_i
[
ma1
][
mb1
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
int
ma1
=
mb1
;
dudr_r
=
duarray_r
[
j1
][
ma1
][
mb1
];
dudr_i
=
duarray_i
[
j1
][
ma1
][
mb1
];
jjjmambzarray_r
=
jjjzarray_r
[
ma1
][
mb1
];
jjjmambzarray_i
=
jjjzarray_i
[
ma1
][
mb1
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
(
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
)
*
0.5
;
}
// end if j1even
for
(
int
k
=
0
;
k
<
3
;
k
++
)
dbdr
[
k
]
+=
2.0
*
sumzdu_r
[
k
]
*
j1fac
;
// Sum over Conj(dudr(j2,ma2,mb2))*z(j1,j,j2,ma2,mb2)
double
j2fac
=
(
j
+
1
)
/
(
j2
+
1.0
);
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
=
0.0
;
// use zarray j1/j2 symmetry (optional)
if
(
j1
>=
j
)
{
jjjzarray_r
=
zarray_r
[
j1
][
j
][
j2
];
jjjzarray_i
=
zarray_i
[
j1
][
j
][
j2
];
}
else
{
jjjzarray_r
=
zarray_r
[
j
][
j1
][
j2
];
jjjzarray_i
=
zarray_i
[
j
][
j1
][
j2
];
}
for
(
int
mb2
=
0
;
2
*
mb2
<
j2
;
mb2
++
)
for
(
int
ma2
=
0
;
ma2
<=
j2
;
ma2
++
)
{
dudr_r
=
duarray_r
[
j2
][
ma2
][
mb2
];
dudr_i
=
duarray_i
[
j2
][
ma2
][
mb2
];
jjjmambzarray_r
=
jjjzarray_r
[
ma2
][
mb2
];
jjjmambzarray_i
=
jjjzarray_i
[
ma2
][
mb2
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
//end loop over ma2 mb2
// For j2 even, handle middle column
if
(
j2
%
2
==
0
)
{
int
mb2
=
j2
/
2
;
for
(
int
ma2
=
0
;
ma2
<
mb2
;
ma2
++
)
{
dudr_r
=
duarray_r
[
j2
][
ma2
][
mb2
];
dudr_i
=
duarray_i
[
j2
][
ma2
][
mb2
];
jjjmambzarray_r
=
jjjzarray_r
[
ma2
][
mb2
];
jjjmambzarray_i
=
jjjzarray_i
[
ma2
][
mb2
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
;
}
int
ma2
=
mb2
;
dudr_r
=
duarray_r
[
j2
][
ma2
][
mb2
];
dudr_i
=
duarray_i
[
j2
][
ma2
][
mb2
];
jjjmambzarray_r
=
jjjzarray_r
[
ma2
][
mb2
];
jjjmambzarray_i
=
jjjzarray_i
[
ma2
][
mb2
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
sumzdu_r
[
k
]
+=
(
dudr_r
[
k
]
*
jjjmambzarray_r
+
dudr_i
[
k
]
*
jjjmambzarray_i
)
*
0.5
;
}
// end if j2even
for
(
int
k
=
0
;
k
<
3
;
k
++
)
dbdr
[
k
]
+=
2.0
*
sumzdu_r
[
k
]
*
j2fac
;
}
//end loop over j1 j2 j
#ifdef TIMING_INFO
clock_gettime
(
CLOCK_REALTIME
,
&
endtime
);
timers
[
4
]
+=
(
endtime
.
tv_sec
-
starttime
.
tv_sec
+
1.0
*
(
endtime
.
tv_nsec
-
starttime
.
tv_nsec
)
/
1000000000
);
#endif
}
/* ----------------------------------------------------------------------
copy Bi derivatives into a vector
------------------------------------------------------------------------- */
void
SNA
::
copy_dbi2dbvec
()
{
int
ncount
,
j1
,
j2
,
j
;
ncount
=
0
;
for
(
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
{
if
(
diagonalstyle
==
0
)
{
for
(
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
dbvec
[
ncount
][
0
]
=
dbarray
[
j1
][
j2
][
j
][
0
];
dbvec
[
ncount
][
1
]
=
dbarray
[
j1
][
j2
][
j
][
1
];
dbvec
[
ncount
][
2
]
=
dbarray
[
j1
][
j2
][
j
][
2
];
ncount
++
;
}
}
else
if
(
diagonalstyle
==
1
)
{
j2
=
j1
;
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
dbvec
[
ncount
][
0
]
=
dbarray
[
j1
][
j2
][
j
][
0
];
dbvec
[
ncount
][
1
]
=
dbarray
[
j1
][
j2
][
j
][
1
];
dbvec
[
ncount
][
2
]
=
dbarray
[
j1
][
j2
][
j
][
2
];
ncount
++
;
}
}
else
if
(
diagonalstyle
==
2
)
{
j
=
j2
=
j1
;
dbvec
[
ncount
][
0
]
=
dbarray
[
j1
][
j2
][
j
][
0
];
dbvec
[
ncount
][
1
]
=
dbarray
[
j1
][
j2
][
j
][
1
];
dbvec
[
ncount
][
2
]
=
dbarray
[
j1
][
j2
][
j
][
2
];
ncount
++
;
}
else
if
(
diagonalstyle
==
3
)
{
for
(
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
if
(
j
>=
j1
)
{
dbvec
[
ncount
][
0
]
=
dbarray
[
j1
][
j2
][
j
][
0
];
dbvec
[
ncount
][
1
]
=
dbarray
[
j1
][
j2
][
j
][
1
];
dbvec
[
ncount
][
2
]
=
dbarray
[
j1
][
j2
][
j
][
2
];
ncount
++
;
}
}
}
}
/* ---------------------------------------------------------------------- */
void
SNA
::
zero_uarraytot
()
{
for
(
int
j
=
0
;
j
<=
twojmax
;
j
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
uarraytot_r
[
j
][
ma
][
mb
]
=
0.0
;
uarraytot_i
[
j
][
ma
][
mb
]
=
0.0
;
}
}
/* ---------------------------------------------------------------------- */
void
SNA
::
addself_uarraytot
(
double
wself_in
)
{
for
(
int
j
=
0
;
j
<=
twojmax
;
j
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
uarraytot_r
[
j
][
ma
][
ma
]
=
wself_in
;
uarraytot_i
[
j
][
ma
][
ma
]
=
0.0
;
}
}
/* ----------------------------------------------------------------------
add Wigner U-functions for one neighbor to the total
------------------------------------------------------------------------- */
void
SNA
::
add_uarraytot
(
double
r
,
double
wj
,
double
rcut
)
{
double
sfac
;
sfac
=
compute_sfac
(
r
,
rcut
);
sfac
*=
wj
;
for
(
int
j
=
0
;
j
<=
twojmax
;
j
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
uarraytot_r
[
j
][
ma
][
mb
]
+=
sfac
*
uarray_r
[
j
][
ma
][
mb
];
uarraytot_i
[
j
][
ma
][
mb
]
+=
sfac
*
uarray_i
[
j
][
ma
][
mb
];
}
}
void
SNA
::
add_uarraytot_omp
(
double
r
,
double
wj
,
double
rcut
)
{
double
sfac
;
sfac
=
compute_sfac
(
r
,
rcut
);
sfac
*=
wj
;
#if defined(_OPENMP)
#pragma omp for
#endif
for
(
int
j
=
0
;
j
<=
twojmax
;
j
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
uarraytot_r
[
j
][
ma
][
mb
]
+=
sfac
*
uarray_r
[
j
][
ma
][
mb
];
uarraytot_i
[
j
][
ma
][
mb
]
+=
sfac
*
uarray_i
[
j
][
ma
][
mb
];
}
}
/* ----------------------------------------------------------------------
compute Wigner U-functions for one neighbor
------------------------------------------------------------------------- */
void
SNA
::
compute_uarray
(
double
x
,
double
y
,
double
z
,
double
z0
,
double
r
)
{
double
r0inv
;
double
a_r
,
b_r
,
a_i
,
b_i
;
double
rootpq
;
// compute Cayley-Klein parameters for unit quaternion
r0inv
=
1.0
/
sqrt
(
r
*
r
+
z0
*
z0
);
a_r
=
r0inv
*
z0
;
a_i
=
-
r0inv
*
z
;
b_r
=
r0inv
*
y
;
b_i
=
-
r0inv
*
x
;
// VMK Section 4.8.2
uarray_r
[
0
][
0
][
0
]
=
1.0
;
uarray_i
[
0
][
0
][
0
]
=
0.0
;
for
(
int
j
=
1
;
j
<=
twojmax
;
j
++
)
{
// fill in left side of matrix layer from previous layer
for
(
int
mb
=
0
;
2
*
mb
<=
j
;
mb
++
)
{
uarray_r
[
j
][
0
][
mb
]
=
0.0
;
uarray_i
[
j
][
0
][
mb
]
=
0.0
;
for
(
int
ma
=
0
;
ma
<
j
;
ma
++
)
{
rootpq
=
rootpqarray
[
j
-
ma
][
j
-
mb
];
uarray_r
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
a_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
a_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
rootpq
=
rootpqarray
[
ma
+
1
][
j
-
mb
];
uarray_r
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
b_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
b_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
}
}
// copy left side to right side with inversion symmetry VMK 4.4(2)
// u[ma-j][mb-j] = (-1)^(ma-mb)*Conj([u[ma][mb])
int
mbpar
=
-
1
;
for
(
int
mb
=
0
;
2
*
mb
<=
j
;
mb
++
)
{
mbpar
=
-
mbpar
;
int
mapar
=
-
mbpar
;
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
mapar
=
-
mapar
;
if
(
mapar
==
1
)
{
uarray_r
[
j
][
j
-
ma
][
j
-
mb
]
=
uarray_r
[
j
][
ma
][
mb
];
uarray_i
[
j
][
j
-
ma
][
j
-
mb
]
=
-
uarray_i
[
j
][
ma
][
mb
];
}
else
{
uarray_r
[
j
][
j
-
ma
][
j
-
mb
]
=
-
uarray_r
[
j
][
ma
][
mb
];
uarray_i
[
j
][
j
-
ma
][
j
-
mb
]
=
uarray_i
[
j
][
ma
][
mb
];
}
}
}
}
}
void
SNA
::
compute_uarray_omp
(
double
x
,
double
y
,
double
z
,
double
z0
,
double
r
,
int
sub_threads
)
{
double
r0inv
;
double
a_r
,
b_r
,
a_i
,
b_i
;
double
rootpq
;
// compute Cayley-Klein parameters for unit quaternion
r0inv
=
1.0
/
sqrt
(
r
*
r
+
z0
*
z0
);
a_r
=
r0inv
*
z0
;
a_i
=
-
r0inv
*
z
;
b_r
=
r0inv
*
y
;
b_i
=
-
r0inv
*
x
;
// VMK Section 4.8.2
uarray_r
[
0
][
0
][
0
]
=
1.0
;
uarray_i
[
0
][
0
][
0
]
=
0.0
;
for
(
int
j
=
1
;
j
<=
twojmax
;
j
++
)
{
#if defined(_OPENMP)
#pragma omp for
#endif
for
(
int
mb
=
0
;
mb
<
j
;
mb
++
)
{
uarray_r
[
j
][
0
][
mb
]
=
0.0
;
uarray_i
[
j
][
0
][
mb
]
=
0.0
;
for
(
int
ma
=
0
;
ma
<
j
;
ma
++
)
{
rootpq
=
rootpqarray
[
j
-
ma
][
j
-
mb
];
uarray_r
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
a_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
a_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
rootpq
=
rootpqarray
[
ma
+
1
][
j
-
mb
];
uarray_r
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
b_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
b_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
}
}
int
mb
=
j
;
uarray_r
[
j
][
0
][
mb
]
=
0.0
;
uarray_i
[
j
][
0
][
mb
]
=
0.0
;
#if defined(_OPENMP)
#pragma omp for
#endif
for
(
int
ma
=
0
;
ma
<
j
;
ma
++
)
{
rootpq
=
rootpqarray
[
j
-
ma
][
mb
];
uarray_r
[
j
][
ma
][
mb
]
+=
rootpq
*
(
b_r
*
uarray_r
[
j
-
1
][
ma
][
mb
-
1
]
-
b_i
*
uarray_i
[
j
-
1
][
ma
][
mb
-
1
]);
uarray_i
[
j
][
ma
][
mb
]
+=
rootpq
*
(
b_r
*
uarray_i
[
j
-
1
][
ma
][
mb
-
1
]
+
b_i
*
uarray_r
[
j
-
1
][
ma
][
mb
-
1
]);
rootpq
=
rootpqarray
[
ma
+
1
][
mb
];
uarray_r
[
j
][
ma
+
1
][
mb
]
=
rootpq
*
(
a_r
*
uarray_r
[
j
-
1
][
ma
][
mb
-
1
]
-
a_i
*
uarray_i
[
j
-
1
][
ma
][
mb
-
1
]);
uarray_i
[
j
][
ma
+
1
][
mb
]
=
rootpq
*
(
a_r
*
uarray_i
[
j
-
1
][
ma
][
mb
-
1
]
+
a_i
*
uarray_r
[
j
-
1
][
ma
][
mb
-
1
]);
}
}
}
/* ----------------------------------------------------------------------
compute derivatives of Wigner U-functions for one neighbor
see comments in compute_uarray()
------------------------------------------------------------------------- */
void
SNA
::
compute_duarray
(
double
x
,
double
y
,
double
z
,
double
z0
,
double
r
,
double
dz0dr
,
double
wj
,
double
rcut
)
{
double
r0inv
;
double
a_r
,
a_i
,
b_r
,
b_i
;
double
da_r
[
3
],
da_i
[
3
],
db_r
[
3
],
db_i
[
3
];
double
dz0
[
3
],
dr0inv
[
3
],
dr0invdr
;
double
rootpq
;
double
rinv
=
1.0
/
r
;
double
ux
=
x
*
rinv
;
double
uy
=
y
*
rinv
;
double
uz
=
z
*
rinv
;
r0inv
=
1.0
/
sqrt
(
r
*
r
+
z0
*
z0
);
a_r
=
z0
*
r0inv
;
a_i
=
-
z
*
r0inv
;
b_r
=
y
*
r0inv
;
b_i
=
-
x
*
r0inv
;
dr0invdr
=
-
pow
(
r0inv
,
3.0
)
*
(
r
+
z0
*
dz0dr
);
dr0inv
[
0
]
=
dr0invdr
*
ux
;
dr0inv
[
1
]
=
dr0invdr
*
uy
;
dr0inv
[
2
]
=
dr0invdr
*
uz
;
dz0
[
0
]
=
dz0dr
*
ux
;
dz0
[
1
]
=
dz0dr
*
uy
;
dz0
[
2
]
=
dz0dr
*
uz
;
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
da_r
[
k
]
=
dz0
[
k
]
*
r0inv
+
z0
*
dr0inv
[
k
];
da_i
[
k
]
=
-
z
*
dr0inv
[
k
];
}
da_i
[
2
]
+=
-
r0inv
;
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
db_r
[
k
]
=
y
*
dr0inv
[
k
];
db_i
[
k
]
=
-
x
*
dr0inv
[
k
];
}
db_i
[
0
]
+=
-
r0inv
;
db_r
[
1
]
+=
r0inv
;
uarray_r
[
0
][
0
][
0
]
=
1.0
;
duarray_r
[
0
][
0
][
0
][
0
]
=
0.0
;
duarray_r
[
0
][
0
][
0
][
1
]
=
0.0
;
duarray_r
[
0
][
0
][
0
][
2
]
=
0.0
;
uarray_i
[
0
][
0
][
0
]
=
0.0
;
duarray_i
[
0
][
0
][
0
][
0
]
=
0.0
;
duarray_i
[
0
][
0
][
0
][
1
]
=
0.0
;
duarray_i
[
0
][
0
][
0
][
2
]
=
0.0
;
for
(
int
j
=
1
;
j
<=
twojmax
;
j
++
)
{
for
(
int
mb
=
0
;
2
*
mb
<=
j
;
mb
++
)
{
uarray_r
[
j
][
0
][
mb
]
=
0.0
;
duarray_r
[
j
][
0
][
mb
][
0
]
=
0.0
;
duarray_r
[
j
][
0
][
mb
][
1
]
=
0.0
;
duarray_r
[
j
][
0
][
mb
][
2
]
=
0.0
;
uarray_i
[
j
][
0
][
mb
]
=
0.0
;
duarray_i
[
j
][
0
][
mb
][
0
]
=
0.0
;
duarray_i
[
j
][
0
][
mb
][
1
]
=
0.0
;
duarray_i
[
j
][
0
][
mb
][
2
]
=
0.0
;
for
(
int
ma
=
0
;
ma
<
j
;
ma
++
)
{
rootpq
=
rootpqarray
[
j
-
ma
][
j
-
mb
];
uarray_r
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
a_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
][
mb
]
+=
rootpq
*
(
a_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
a_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
duarray_r
[
j
][
ma
][
mb
][
k
]
+=
rootpq
*
(
da_r
[
k
]
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
da_i
[
k
]
*
uarray_i
[
j
-
1
][
ma
][
mb
]
+
a_r
*
duarray_r
[
j
-
1
][
ma
][
mb
][
k
]
+
a_i
*
duarray_i
[
j
-
1
][
ma
][
mb
][
k
]);
duarray_i
[
j
][
ma
][
mb
][
k
]
+=
rootpq
*
(
da_r
[
k
]
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
da_i
[
k
]
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
a_r
*
duarray_i
[
j
-
1
][
ma
][
mb
][
k
]
-
a_i
*
duarray_r
[
j
-
1
][
ma
][
mb
][
k
]);
}
rootpq
=
rootpqarray
[
ma
+
1
][
j
-
mb
];
uarray_r
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
b_i
*
uarray_i
[
j
-
1
][
ma
][
mb
]);
uarray_i
[
j
][
ma
+
1
][
mb
]
=
-
rootpq
*
(
b_r
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
b_i
*
uarray_r
[
j
-
1
][
ma
][
mb
]);
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
duarray_r
[
j
][
ma
+
1
][
mb
][
k
]
=
-
rootpq
*
(
db_r
[
k
]
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
db_i
[
k
]
*
uarray_i
[
j
-
1
][
ma
][
mb
]
+
b_r
*
duarray_r
[
j
-
1
][
ma
][
mb
][
k
]
+
b_i
*
duarray_i
[
j
-
1
][
ma
][
mb
][
k
]);
duarray_i
[
j
][
ma
+
1
][
mb
][
k
]
=
-
rootpq
*
(
db_r
[
k
]
*
uarray_i
[
j
-
1
][
ma
][
mb
]
-
db_i
[
k
]
*
uarray_r
[
j
-
1
][
ma
][
mb
]
+
b_r
*
duarray_i
[
j
-
1
][
ma
][
mb
][
k
]
-
b_i
*
duarray_r
[
j
-
1
][
ma
][
mb
][
k
]);
}
}
}
int
mbpar
=
-
1
;
for
(
int
mb
=
0
;
2
*
mb
<=
j
;
mb
++
)
{
mbpar
=
-
mbpar
;
int
mapar
=
-
mbpar
;
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
{
mapar
=
-
mapar
;
if
(
mapar
==
1
)
{
uarray_r
[
j
][
j
-
ma
][
j
-
mb
]
=
uarray_r
[
j
][
ma
][
mb
];
uarray_i
[
j
][
j
-
ma
][
j
-
mb
]
=
-
uarray_i
[
j
][
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
duarray_r
[
j
][
j
-
ma
][
j
-
mb
][
k
]
=
duarray_r
[
j
][
ma
][
mb
][
k
];
duarray_i
[
j
][
j
-
ma
][
j
-
mb
][
k
]
=
-
duarray_i
[
j
][
ma
][
mb
][
k
];
}
}
else
{
uarray_r
[
j
][
j
-
ma
][
j
-
mb
]
=
-
uarray_r
[
j
][
ma
][
mb
];
uarray_i
[
j
][
j
-
ma
][
j
-
mb
]
=
uarray_i
[
j
][
ma
][
mb
];
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
duarray_r
[
j
][
j
-
ma
][
j
-
mb
][
k
]
=
-
duarray_r
[
j
][
ma
][
mb
][
k
];
duarray_i
[
j
][
j
-
ma
][
j
-
mb
][
k
]
=
duarray_i
[
j
][
ma
][
mb
][
k
];
}
}
}
}
}
double
sfac
=
compute_sfac
(
r
,
rcut
);
double
dsfac
=
compute_dsfac
(
r
,
rcut
);
sfac
*=
wj
;
dsfac
*=
wj
;
for
(
int
j
=
0
;
j
<=
twojmax
;
j
++
)
for
(
int
ma
=
0
;
ma
<=
j
;
ma
++
)
for
(
int
mb
=
0
;
mb
<=
j
;
mb
++
)
{
duarray_r
[
j
][
ma
][
mb
][
0
]
=
dsfac
*
uarray_r
[
j
][
ma
][
mb
]
*
ux
+
sfac
*
duarray_r
[
j
][
ma
][
mb
][
0
];
duarray_i
[
j
][
ma
][
mb
][
0
]
=
dsfac
*
uarray_i
[
j
][
ma
][
mb
]
*
ux
+
sfac
*
duarray_i
[
j
][
ma
][
mb
][
0
];
duarray_r
[
j
][
ma
][
mb
][
1
]
=
dsfac
*
uarray_r
[
j
][
ma
][
mb
]
*
uy
+
sfac
*
duarray_r
[
j
][
ma
][
mb
][
1
];
duarray_i
[
j
][
ma
][
mb
][
1
]
=
dsfac
*
uarray_i
[
j
][
ma
][
mb
]
*
uy
+
sfac
*
duarray_i
[
j
][
ma
][
mb
][
1
];
duarray_r
[
j
][
ma
][
mb
][
2
]
=
dsfac
*
uarray_r
[
j
][
ma
][
mb
]
*
uz
+
sfac
*
duarray_r
[
j
][
ma
][
mb
][
2
];
duarray_i
[
j
][
ma
][
mb
][
2
]
=
dsfac
*
uarray_i
[
j
][
ma
][
mb
]
*
uz
+
sfac
*
duarray_i
[
j
][
ma
][
mb
][
2
];
}
}
/* ----------------------------------------------------------------------
memory usage of arrays
------------------------------------------------------------------------- */
double
SNA
::
memory_usage
()
{
int
jdim
=
twojmax
+
1
;
double
bytes
;
bytes
=
jdim
*
jdim
*
jdim
*
jdim
*
jdim
*
sizeof
(
double
);
bytes
+=
2
*
jdim
*
jdim
*
jdim
*
sizeof
(
complex
<
double
>
);
bytes
+=
2
*
jdim
*
jdim
*
jdim
*
sizeof
(
double
);
bytes
+=
jdim
*
jdim
*
jdim
*
3
*
sizeof
(
complex
<
double
>
);
bytes
+=
jdim
*
jdim
*
jdim
*
3
*
sizeof
(
double
);
bytes
+=
ncoeff
*
sizeof
(
double
);
bytes
+=
jdim
*
jdim
*
jdim
*
jdim
*
jdim
*
sizeof
(
complex
<
double
>
);
return
bytes
;
}
/* ---------------------------------------------------------------------- */
void
SNA
::
create_twojmax_arrays
()
{
int
jdim
=
twojmax
+
1
;
memory
->
create
(
cgarray
,
jdim
,
jdim
,
jdim
,
jdim
,
jdim
,
"sna:cgarray"
);
memory
->
create
(
rootpqarray
,
jdim
+
1
,
jdim
+
1
,
"sna:rootpqarray"
);
memory
->
create
(
barray
,
jdim
,
jdim
,
jdim
,
"sna:barray"
);
memory
->
create
(
dbarray
,
jdim
,
jdim
,
jdim
,
3
,
"sna:dbarray"
);
memory
->
create
(
duarray_r
,
jdim
,
jdim
,
jdim
,
3
,
"sna:duarray"
);
memory
->
create
(
duarray_i
,
jdim
,
jdim
,
jdim
,
3
,
"sna:duarray"
);
memory
->
create
(
uarray_r
,
jdim
,
jdim
,
jdim
,
"sna:uarray"
);
memory
->
create
(
uarray_i
,
jdim
,
jdim
,
jdim
,
"sna:uarray"
);
if
(
!
use_shared_arrays
)
{
memory
->
create
(
uarraytot_r
,
jdim
,
jdim
,
jdim
,
"sna:uarraytot"
);
memory
->
create
(
zarray_r
,
jdim
,
jdim
,
jdim
,
jdim
,
jdim
,
"sna:zarray"
);
memory
->
create
(
uarraytot_i
,
jdim
,
jdim
,
jdim
,
"sna:uarraytot"
);
memory
->
create
(
zarray_i
,
jdim
,
jdim
,
jdim
,
jdim
,
jdim
,
"sna:zarray"
);
}
}
/* ---------------------------------------------------------------------- */
void
SNA
::
destroy_twojmax_arrays
()
{
memory
->
destroy
(
cgarray
);
memory
->
destroy
(
rootpqarray
);
memory
->
destroy
(
barray
);
memory
->
destroy
(
dbarray
);
memory
->
destroy
(
duarray_r
);
memory
->
destroy
(
duarray_i
);
memory
->
destroy
(
uarray_r
);
memory
->
destroy
(
uarray_i
);
if
(
!
use_shared_arrays
)
{
memory
->
destroy
(
uarraytot_r
);
memory
->
destroy
(
zarray_r
);
memory
->
destroy
(
uarraytot_i
);
memory
->
destroy
(
zarray_i
);
}
}
/* ----------------------------------------------------------------------
store n! and return it as needed
------------------------------------------------------------------------- */
double
SNA
::
factorial
(
int
n
)
{
const
int
nmax
=
167
;
// Largest n supported
double
nfac_table
[
nmax
+
1
]
=
{
1
,
1
,
2
,
6
,
24
,
120
,
720
,
5040
,
40320
,
362880
,
3628800
,
39916800
,
479001600
,
6227020800
,
87178291200
,
1307674368000
,
20922789888000
,
355687428096000
,
6.402373705728e+15
,
1.21645100408832e+17
,
2.43290200817664e+18
,
5.10909421717094e+19
,
1.12400072777761e+21
,
2.5852016738885e+22
,
6.20448401733239e+23
,
1.5511210043331e+25
,
4.03291461126606e+26
,
1.08888694504184e+28
,
3.04888344611714e+29
,
8.8417619937397e+30
,
2.65252859812191e+32
,
8.22283865417792e+33
,
2.63130836933694e+35
,
8.68331761881189e+36
,
2.95232799039604e+38
,
1.03331479663861e+40
,
3.71993326789901e+41
,
1.37637530912263e+43
,
5.23022617466601e+44
,
2.03978820811974e+46
,
8.15915283247898e+47
,
3.34525266131638e+49
,
1.40500611775288e+51
,
6.04152630633738e+52
,
2.65827157478845e+54
,
1.1962222086548e+56
,
5.50262215981209e+57
,
2.58623241511168e+59
,
1.24139155925361e+61
,
6.08281864034268e+62
,
3.04140932017134e+64
,
1.55111875328738e+66
,
8.06581751709439e+67
,
4.27488328406003e+69
,
2.30843697339241e+71
,
1.26964033536583e+73
,
7.10998587804863e+74
,
4.05269195048772e+76
,
2.35056133128288e+78
,
1.3868311854569e+80
,
8.32098711274139e+81
,
5.07580213877225e+83
,
3.14699732603879e+85
,
1.98260831540444e+87
,
1.26886932185884e+89
,
8.24765059208247e+90
,
5.44344939077443e+92
,
3.64711109181887e+94
,
2.48003554243683e+96
,
1.71122452428141e+98
,
1.19785716699699e+100
,
8.50478588567862e+101
,
6.12344583768861e+103
,
4.47011546151268e+105
,
3.30788544151939e+107
,
2.48091408113954e+109
,
1.88549470166605e+111
,
1.45183092028286e+113
,
1.13242811782063e+115
,
8.94618213078297e+116
,
7.15694570462638e+118
,
5.79712602074737e+120
,
4.75364333701284e+122
,
3.94552396972066e+124
,
3.31424013456535e+126
,
2.81710411438055e+128
,
2.42270953836727e+130
,
2.10775729837953e+132
,
1.85482642257398e+134
,
1.65079551609085e+136
,
1.48571596448176e+138
,
1.3520015276784e+140
,
1.24384140546413e+142
,
1.15677250708164e+144
,
1.08736615665674e+146
,
1.03299784882391e+148
,
9.91677934870949e+149
,
9.61927596824821e+151
,
9.42689044888324e+153
,
9.33262154439441e+155
,
9.33262154439441e+157
,
9.42594775983835e+159
,
9.61446671503512e+161
,
9.90290071648618e+163
,
1.02990167451456e+166
,
1.08139675824029e+168
,
1.14628056373471e+170
,
1.22652020319614e+172
,
1.32464181945183e+174
,
1.44385958320249e+176
,
1.58824554152274e+178
,
1.76295255109024e+180
,
1.97450685722107e+182
,
2.23119274865981e+184
,
2.54355973347219e+186
,
2.92509369349301e+188
,
3.3931086844519e+190
,
3.96993716080872e+192
,
4.68452584975429e+194
,
5.5745857612076e+196
,
6.68950291344912e+198
,
8.09429852527344e+200
,
9.8750442008336e+202
,
1.21463043670253e+205
,
1.50614174151114e+207
,
1.88267717688893e+209
,
2.37217324288005e+211
,
3.01266001845766e+213
,
3.8562048236258e+215
,
4.97450422247729e+217
,
6.46685548922047e+219
,
8.47158069087882e+221
,
1.118248651196e+224
,
1.48727070609069e+226
,
1.99294274616152e+228
,
2.69047270731805e+230
,
3.65904288195255e+232
,
5.01288874827499e+234
,
6.91778647261949e+236
,
9.61572319694109e+238
,
1.34620124757175e+241
,
1.89814375907617e+243
,
2.69536413788816e+245
,
3.85437071718007e+247
,
5.5502938327393e+249
,
8.04792605747199e+251
,
1.17499720439091e+254
,
1.72724589045464e+256
,
2.55632391787286e+258
,
3.80892263763057e+260
,
5.71338395644585e+262
,
8.62720977423323e+264
,
1.31133588568345e+267
,
2.00634390509568e+269
,
3.08976961384735e+271
,
4.78914290146339e+273
,
7.47106292628289e+275
,
1.17295687942641e+278
,
1.85327186949373e+280
,
2.94670227249504e+282
,
4.71472363599206e+284
,
7.59070505394721e+286
,
1.22969421873945e+289
,
2.0044015765453e+291
,
3.28721858553429e+293
,
5.42391066613159e+295
,
9.00369170577843e+297
,
1.503616514865e+300
,
};
if
(
n
<
0
||
n
>
nmax
)
{
char
str
[
128
];
sprintf
(
str
,
"Invalid argument to factorial %d"
,
n
);
error
->
all
(
FLERR
,
str
);
}
return
nfac_table
[
n
];
}
/* ----------------------------------------------------------------------
the function delta given by VMK Eq. 8.2(1)
------------------------------------------------------------------------- */
double
SNA
::
deltacg
(
int
j1
,
int
j2
,
int
j
)
{
double
sfaccg
=
factorial
((
j1
+
j2
+
j
)
/
2
+
1
);
return
sqrt
(
factorial
((
j1
+
j2
-
j
)
/
2
)
*
factorial
((
j1
-
j2
+
j
)
/
2
)
*
factorial
((
-
j1
+
j2
+
j
)
/
2
)
/
sfaccg
);
}
/* ----------------------------------------------------------------------
assign Clebsch-Gordan coefficients using
the quasi-binomial formula VMK 8.2.1(3)
------------------------------------------------------------------------- */
void
SNA
::
init_clebsch_gordan
()
{
double
sum
,
dcg
,
sfaccg
;
int
m
,
aa2
,
bb2
,
cc2
;
int
ifac
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
for
(
int
j2
=
0
;
j2
<=
twojmax
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
for
(
int
m1
=
0
;
m1
<=
j1
;
m1
+=
1
)
{
aa2
=
2
*
m1
-
j1
;
for
(
int
m2
=
0
;
m2
<=
j2
;
m2
+=
1
)
{
// -c <= cc <= c
bb2
=
2
*
m2
-
j2
;
m
=
(
aa2
+
bb2
+
j
)
/
2
;
if
(
m
<
0
||
m
>
j
)
continue
;
sum
=
0.0
;
for
(
int
z
=
MAX
(
0
,
MAX
(
-
(
j
-
j2
+
aa2
)
/
2
,
-
(
j
-
j1
-
bb2
)
/
2
));
z
<=
MIN
((
j1
+
j2
-
j
)
/
2
,
MIN
((
j1
-
aa2
)
/
2
,
(
j2
+
bb2
)
/
2
));
z
++
)
{
ifac
=
z
%
2
?
-
1
:
1
;
sum
+=
ifac
/
(
factorial
(
z
)
*
factorial
((
j1
+
j2
-
j
)
/
2
-
z
)
*
factorial
((
j1
-
aa2
)
/
2
-
z
)
*
factorial
((
j2
+
bb2
)
/
2
-
z
)
*
factorial
((
j
-
j2
+
aa2
)
/
2
+
z
)
*
factorial
((
j
-
j1
-
bb2
)
/
2
+
z
));
}
cc2
=
2
*
m
-
j
;
dcg
=
deltacg
(
j1
,
j2
,
j
);
sfaccg
=
sqrt
(
factorial
((
j1
+
aa2
)
/
2
)
*
factorial
((
j1
-
aa2
)
/
2
)
*
factorial
((
j2
+
bb2
)
/
2
)
*
factorial
((
j2
-
bb2
)
/
2
)
*
factorial
((
j
+
cc2
)
/
2
)
*
factorial
((
j
-
cc2
)
/
2
)
*
(
j
+
1
));
cgarray
[
j1
][
j2
][
j
][
m1
][
m2
]
=
sum
*
dcg
*
sfaccg
;
}
}
}
/* ----------------------------------------------------------------------
pre-compute table of sqrt[p/m2], p, q = 1,twojmax
the p = 0, q = 0 entries are allocated and skipped for convenience.
------------------------------------------------------------------------- */
void
SNA
::
init_rootpqarray
()
{
for
(
int
p
=
1
;
p
<=
twojmax
;
p
++
)
for
(
int
q
=
1
;
q
<=
twojmax
;
q
++
)
rootpqarray
[
p
][
q
]
=
sqrt
(
static_cast
<
double
>
(
p
)
/
q
);
}
/* ----------------------------------------------------------------------
a = j/2
------------------------------------------------------------------------- */
void
SNA
::
jtostr
(
char
*
str
,
int
j
)
{
if
(
j
%
2
==
0
)
sprintf
(
str
,
"%d"
,
j
/
2
);
else
sprintf
(
str
,
"%d/2"
,
j
);
}
/* ----------------------------------------------------------------------
aa = m - j/2
------------------------------------------------------------------------- */
void
SNA
::
mtostr
(
char
*
str
,
int
j
,
int
m
)
{
if
(
j
%
2
==
0
)
sprintf
(
str
,
"%d"
,
m
-
j
/
2
);
else
sprintf
(
str
,
"%d/2"
,
2
*
m
-
j
);
}
/* ----------------------------------------------------------------------
list values of Clebsch-Gordan coefficients
using notation of VMK Table 8.11
------------------------------------------------------------------------- */
void
SNA
::
print_clebsch_gordan
(
FILE
*
file
)
{
char
stra
[
20
],
strb
[
20
],
strc
[
20
],
straa
[
20
],
strbb
[
20
],
strcc
[
20
];
int
m
,
aa2
,
bb2
;
fprintf
(
file
,
"a, aa, b, bb, c, cc, c(a,aa,b,bb,c,cc)
\n
"
);
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
{
jtostr
(
stra
,
j1
);
for
(
int
j2
=
0
;
j2
<=
twojmax
;
j2
++
)
{
jtostr
(
strb
,
j2
);
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
{
jtostr
(
strc
,
j
);
for
(
int
m1
=
0
;
m1
<=
j1
;
m1
+=
1
)
{
mtostr
(
straa
,
j1
,
m1
);
aa2
=
2
*
m1
-
j1
;
for
(
int
m2
=
0
;
m2
<=
j2
;
m2
+=
1
)
{
bb2
=
2
*
m2
-
j2
;
m
=
(
aa2
+
bb2
+
j
)
/
2
;
if
(
m
<
0
||
m
>
j
)
continue
;
mtostr
(
strbb
,
j2
,
m2
);
mtostr
(
strcc
,
j
,
m
);
fprintf
(
file
,
"%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%g
\n
"
,
stra
,
straa
,
strb
,
strbb
,
strc
,
strcc
,
cgarray
[
j1
][
j2
][
j
][
m1
][
m2
]);
}
}
}
}
}
}
/* ---------------------------------------------------------------------- */
int
SNA
::
compute_ncoeff
()
{
int
ncount
;
ncount
=
0
;
for
(
int
j1
=
0
;
j1
<=
twojmax
;
j1
++
)
if
(
diagonalstyle
==
0
)
{
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
ncount
++
;
}
else
if
(
diagonalstyle
==
1
)
{
int
j2
=
j1
;
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
ncount
++
;
}
else
if
(
diagonalstyle
==
2
)
{
ncount
++
;
}
else
if
(
diagonalstyle
==
3
)
{
for
(
int
j2
=
0
;
j2
<=
j1
;
j2
++
)
for
(
int
j
=
abs
(
j1
-
j2
);
j
<=
MIN
(
twojmax
,
j1
+
j2
);
j
+=
2
)
if
(
j
>=
j1
)
ncount
++
;
}
return
ncount
;
}
/* ---------------------------------------------------------------------- */
double
SNA
::
compute_sfac
(
double
r
,
double
rcut
)
{
if
(
switch_flag
==
0
)
return
1.0
;
if
(
switch_flag
==
1
)
{
if
(
r
<=
rmin0
)
return
1.0
;
else
if
(
r
>
rcut
)
return
0.0
;
else
{
double
rcutfac
=
MY_PI
/
(
rcut
-
rmin0
);
return
0.5
*
(
cos
((
r
-
rmin0
)
*
rcutfac
)
+
1.0
);
}
}
return
0.0
;
}
/* ---------------------------------------------------------------------- */
double
SNA
::
compute_dsfac
(
double
r
,
double
rcut
)
{
if
(
switch_flag
==
0
)
return
0.0
;
if
(
switch_flag
==
1
)
{
if
(
r
<=
rmin0
)
return
0.0
;
else
if
(
r
>
rcut
)
return
0.0
;
else
{
double
rcutfac
=
MY_PI
/
(
rcut
-
rmin0
);
return
-
0.5
*
sin
((
r
-
rmin0
)
*
rcutfac
)
*
rcutfac
;
}
}
return
0.0
;
}
Event Timeline
Log In to Comment