QCaml/Basis/KinInt.ml

163 lines
4.6 KiB
OCaml

open Util
open Constants
open Lacaml.D
type t = Mat.t
(** Computes all the kinetic integrals of the contracted shell pair *)
let contracted_class shell_a shell_b : float Zmap.t =
let shell_p =
ContractedShellPair.create shell_a shell_b
in
(* Pre-computation of integral class indices *)
let class_indices =
Angular_momentum.zkey_array (Angular_momentum.Doublet
Contracted_shell.(totAngMom shell_a, totAngMom shell_b))
in
let contracted_class =
Array.make (Array.length class_indices) 0.
in
(* Compute all integrals in the shell for each pair of significant shell pairs *)
for ab=0 to (Array.length shell_p - 1)
do
let coef_prod =
shell_p.(ab).ShellPair.coef
in
(** Screening on thr product of coefficients *)
if (abs_float coef_prod) > 1.e-4*.cutoff then
begin
let center_ab =
shell_p.(ab).ShellPair.center_ab
in
let center_pa =
shell_p.(ab).ShellPair.center_a
in
let expo_inv =
shell_p.(ab).ShellPair.expo_inv
in
let norm_coef_scale =
shell_p.(ab).ShellPair.norm_coef_scale
in
let i, j =
shell_p.(ab).ShellPair.i, shell_p.(ab).ShellPair.j
in
let expo_a =
Contracted_shell.expo shell_p.(ab).ShellPair.shell_a i
and expo_b =
Contracted_shell.expo shell_p.(ab).ShellPair.shell_b j
in
Array.iteri (fun i key ->
let (angMomA,angMomB) =
let a = Zkey.to_int_array Zkey.Kind_6 key in
( [| a.(0) ; a.(1) ; a.(2) |],
[| a.(3) ; a.(4) ; a.(5) |] )
in
let ov a b k =
Overlap_primitives.hvrr (a, b)
expo_inv
(Coordinate.coord center_ab k,
Coordinate.coord center_pa k)
in
let f k =
ov angMomA.(k) angMomB.(k) k
and g k =
let s1 = ov (angMomA.(k)-1) (angMomB.(k)-1) k
and s2 = ov (angMomA.(k)+1) (angMomB.(k)-1) k
and s3 = ov (angMomA.(k)-1) (angMomB.(k)+1) k
and s4 = ov (angMomA.(k)+1) (angMomB.(k)+1) k
and a = float_of_int angMomA.(k)
and b = float_of_int angMomB.(k)
in
0.5 *. a *. b *. s1 -. expo_a *. b *. s2 -. expo_b *. a *. s3 +.
2.0 *. expo_a *. expo_b *. s4
in
let s = Array.init 3 f
and k = Array.init 3 g
in
let norm = norm_coef_scale.(i) in
let integral = chop norm (fun () ->
k.(0)*.s.(1)*.s.(2) +.
s.(0)*.k.(1)*.s.(2) +.
s.(0)*.s.(1)*.k.(2)
) in
contracted_class.(i) <- contracted_class.(i) +. coef_prod *. integral
) class_indices
end
done;
let result =
Zmap.create (Array.length contracted_class)
in
Array.iteri (fun i key -> Zmap.add result key contracted_class.(i)) class_indices;
result
(** Create kinetic energy matrix *)
let of_basis basis =
let to_int_tuple x =
let open Zkey in
match to_int_tuple Kind_3 x with
| Three x -> x
| _ -> assert false
in
let n =
Basis.size basis
and shell =
Basis.contracted_shells basis
in
let result = Mat.create n n in
for j=0 to (Array.length shell) - 1 do
for i=0 to j do
(* Compute all the integrals of the class *)
let cls =
contracted_class shell.(i) shell.(j)
in
Array.iteri (fun j_c powers_j ->
let j_c = Contracted_shell.index shell.(j) + j_c + 1 in
let xj = to_int_tuple powers_j in
Array.iteri (fun i_c powers_i ->
let i_c = Contracted_shell.index shell.(i) + i_c + 1 in
let xi = to_int_tuple powers_i in
let key =
Zkey.of_int_tuple (Zkey.Six (xi,xj))
in
let value =
try Zmap.find cls key
with Not_found -> failwith "Bug in kinetic integrals"
in
result.{i_c,j_c} <- value
) (Contracted_shell.powers shell.(i));
) (Contracted_shell.powers shell.(j))
done;
done;
Mat.detri result;
result
(** Write all kinetic integrals to a file *)
let to_file ~filename kinetic =
let oc = open_out filename in
let n =
Mat.dim1 kinetic
in
for j=1 to n do
for i=1 to j do
if (abs_float kinetic.{i,j} > cutoff) then
Printf.fprintf oc "%4d %4d %20.12e\n" i j kinetic.{i,j}
done;
done;
close_out oc