QCaml/Basis/F12RR.ml

290 lines
9.2 KiB
OCaml

open Util
open Constants
module Am = AngularMomentum
module Asp = AtomicShellPair
module Aspc = AtomicShellPairCouple
module Co = Coordinate
module Cs = ContractedShell
module Csp = ContractedShellPair
module Cspc = ContractedShellPairCouple
module Po = Powers
module Psp = PrimitiveShellPair
module Pspc = PrimitiveShellPairCouple
module Ps = PrimitiveShell
let cutoff = Constants.integrals_cutoff
let cutoff2 = cutoff *. cutoff
exception NullQuartet
type four_idx_intermediates =
{
zero : float array array;
gp : float array;
gg : float array;
gq : float array;
coef_g : float array ;
center_ra : Co.t array ;
center_rc : Co.t array ;
center_ab : Co.t ;
center_cd : Co.t ;
}
(** Horizontal and Vertical Recurrence Relations (HVRR) *)
let rec hvrr angMom_a angMom_b angMom_c angMom_d
abcd map_x map_y map_z =
let gp = abcd.gp in
let gg = abcd.gg in
let gq = abcd.gq in
let coef_g = abcd.coef_g in
let run xyz map =
let zero =
match xyz with
| Co.X -> abcd.zero.(0)
| Co.Y -> abcd.zero.(1)
| Co.Z -> abcd.zero.(2)
in
let angMom_a = Po.get xyz angMom_a in
let angMom_b = Po.get xyz angMom_b in
let angMom_c = Po.get xyz angMom_c in
let angMom_d = Po.get xyz angMom_d in
let center_ab = Co.get xyz abcd.center_ab in
let center_cd = Co.get xyz abcd.center_cd in
let center_ra = Array.map (fun x -> Co.get xyz x) abcd.center_ra in
let center_rc = Array.map (fun x -> Co.get xyz x) abcd.center_rc in
let rec vrr angMom_a angMom_c =
match angMom_a, angMom_c with
| 0, -1
| -1, 0 -> assert false
| 0, 0 -> zero
| 1, 0 ->
let v1 = zero in
Array.mapi (fun i v1i -> center_ra.(i) *. v1i ) v1
| 0, 1 ->
let v1 = zero in
Array.mapi (fun i v1i -> center_rc.(i) *. v1i ) v1
| 1, 1 ->
let v1 = vrr 1 0 in
let v2 = zero in
Array.mapi (fun i v1i -> center_rc.(i) *. v1i +.
gg.(i) *. v2.(i) ) v1
| 2, 0 ->
let v1 = vrr 1 0 in
let v2 = zero in
Array.mapi (fun i v1i -> center_ra.(i) *. v1i +. gp.(i) *. v2.(i)) v1
| _, 0 ->
let v1 =
vrr (angMom_a-1) 0
in
let a = float_of_int_fast (angMom_a-1) in
let v2 =
vrr (angMom_a-2) 0
in
Array.mapi (fun i v1i -> center_ra.(i) *. v1i +. a *. gp.(i) *. v2.(i)) v1
| _, 1 ->
let v1 =
vrr angMom_a 0
in
let a = float_of_int_fast angMom_a in
let v2 =
vrr (angMom_a-1) 0
in
Array.mapi (fun i v1i -> center_rc.(i) *. v1i +.
a *. gg.(i) *. v2.(i) ) v1
| 0, _ ->
let v1 =
vrr 0 (angMom_c-1)
in
let b = float_of_int_fast (angMom_c-1) in
let v3 =
vrr 0 (angMom_c-2)
in
Array.mapi (fun i v1i -> center_rc.(i) *. v1i +.
b *. gq.(i) *. v3.(i)) v1
| _ ->
let v1 =
vrr angMom_a (angMom_c-1)
in
let a = float_of_int_fast angMom_a in
let b = float_of_int_fast (angMom_c-1) in
let v2 =
vrr (angMom_a-1) (angMom_c-1)
in
let v3 =
vrr angMom_a (angMom_c-2)
in
Array.mapi (fun i v1i -> center_rc.(i) *. v1i +.
a *. gg.(i) *. v2.(i) +. b *. gq.(i) *. v3.(i)) v1
in
let rec hrr angMom_a angMom_b angMom_c angMom_d =
let key = Zkey.of_int_four angMom_a angMom_b angMom_c angMom_d in
try Zmap.find map key with
| Not_found ->
let result =
match angMom_b, angMom_d with
| -1, 0
| 0, -1 -> assert false
| 0, 0 ->
vrr angMom_a angMom_c
| _, 0 ->
let h1 =
hrr (angMom_a+1) (angMom_b-1) angMom_c angMom_d
in
if center_ab = 0. then
h1
else
let h2 =
hrr angMom_a (angMom_b-1) angMom_c angMom_d
in
Array.mapi (fun i h1i -> h1i +. center_ab *. h2.(i)) h1
| _ ->
let h1 =
hrr angMom_a angMom_b (angMom_c+1) (angMom_d-1)
in
if center_cd = 0. then
h1
else
let h2 =
hrr angMom_a angMom_b angMom_c (angMom_d-1)
in
Array.mapi (fun i h1i -> h1i +. center_cd *. h2.(i)) h1
in (Zmap.add map key result; result)
in
hrr angMom_a angMom_b angMom_c angMom_d
in
let x, y, z =
(run Co.X map_x), (run Co.Y map_y), (run Co.Z map_z)
in
let rec aux accu = function
| 0 -> accu +. coef_g.(0) *. x.(0) *. y.(0) *. z.(0)
| i -> (aux [@tailcall]) (accu +. coef_g.(i) *. x.(i) *. y.(i) *. z.(i)) (i-1)
in
aux 0. (Array.length x - 1)
let contracted_class_shell_pair_couple ~basis expo_g_inv coef_g shell_pair_couple : float Zmap.t =
(* Pre-computation of integral class indices *)
let class_indices = Cspc.zkey_array shell_pair_couple 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 *)
let shell_p = Cspc.shell_pair_p shell_pair_couple
and shell_q = Cspc.shell_pair_q shell_pair_couple
in
let center_ab = Csp.a_minus_b shell_p
and center_cd = Csp.a_minus_b shell_q
in
let norm_scales = Cspc.norm_scales shell_pair_couple in
List.iter (fun (coef_prod, spc) ->
let sp_ab = Pspc.shell_pair_p spc
and sp_cd = Pspc.shell_pair_q spc
in
let expo_p_inv = Psp.exponent_inv sp_ab in
let expo_q_inv = Psp.exponent_inv sp_cd in
let expo_pgq = Array.map (fun e ->
1. /. (expo_p_inv +. expo_q_inv +. e)
) expo_g_inv
in
let fp = Array.map (fun e -> expo_p_inv *. e) expo_pgq in
let fq = Array.map (fun e -> expo_q_inv *. e) expo_pgq in
let gp =
let x = 0.5 *. expo_p_inv in
Array.map (fun f -> (1. -. f) *. x) fp
in
let gq =
let x = 0.5 *. expo_q_inv in
Array.map (fun f -> (1. -. f) *. x) fq
in
let gg =
let x = 0.5 *. expo_q_inv in
Array.map (fun f -> f *. x) fp
in
let center_pq = Co.(Psp.center sp_ab |- Psp.center sp_cd) in
let center_qc = Psp.center_minus_a sp_cd in
let center_pa = Psp.center_minus_a sp_ab in
let center_ra = Array.map (fun f -> Co.(center_pa |- (f |. center_pq))) fp in
let center_rc = Array.map (fun f -> Co.(center_qc |+ (f |. center_pq))) fq in
(* zero_m is defined here *)
let zero = Array.map (fun xyz ->
let x = Co.get xyz center_pq in
Array.mapi (fun i ei ->
let fg = expo_g_inv.(i) *. ei in
(sqrt fg) *. exp (-. x *. x *. ei )) expo_pgq
) Co.[| X ; Y ; Z |]
in
begin
match Cspc.ang_mom shell_pair_couple with
(*
| Am.S ->
let integral =
zero.(0) *. zero.(1) *. zero.(2)
in
contracted_class.(0) <- contracted_class.(0) +. coef_prod *. integral
*)
| _ ->
let map_x, map_y, map_z =
Zmap.create (Array.length class_indices),
Zmap.create (Array.length class_indices),
Zmap.create (Array.length class_indices)
in
(* Compute the integral class from the primitive shell quartet *)
class_indices
|> Array.iteri (fun i key ->
let (angMom_a,angMom_b,angMom_c,angMom_d) =
match Zkey.to_powers key with
| Zkey.Twelve x -> x
| _ -> assert false
in
let norm = norm_scales.(i) in
let coef_prod = coef_prod *. norm in
let abcd = {
zero ; gp ; gg ; gq ;
center_ab ; center_cd ;
center_ra ; center_rc ;
coef_g ;
} in
let integral =
hvrr
angMom_a angMom_b angMom_c angMom_d
abcd map_x map_y map_z
in
contracted_class.(i) <- contracted_class.(i) +. coef_prod *. integral
)
end
) (Cspc.coefs_and_shell_pair_couples shell_pair_couple);
let result =
Zmap.create (Array.length contracted_class)
in
Array.iteri (fun i key -> Zmap.add result key contracted_class.(i)) class_indices;
result