10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-11-19 04:22:21 +01:00
QCaml/Basis/ContractedShellPair.ml

202 lines
5.4 KiB
OCaml
Raw Normal View History

2018-01-17 18:19:38 +01:00
open Util
2018-02-02 01:25:10 +01:00
open Constants
2018-01-17 18:19:38 +01:00
2018-02-08 01:00:54 +01:00
exception Null_contribution
2018-02-09 19:41:22 +01:00
type t =
{
2018-02-23 18:41:30 +01:00
shell_a : ContractedShell.t;
shell_b : ContractedShell.t;
2018-02-09 19:41:22 +01:00
shell_pairs : ShellPair.t array;
coef : float array;
expo_inv : float array;
center_ab : Coordinate.t; (* A-B *)
norm_sq : float; (* |A-B|^2 *)
norm_coef_scale : float array; (* norm_coef.(i) / norm_coef.(0) *)
2018-02-11 23:41:18 +01:00
totAngMomInt : int; (* Total angular Momentum *)
monocentric : bool;
2018-02-09 19:41:22 +01:00
}
2018-01-17 18:19:38 +01:00
2018-02-23 18:41:30 +01:00
module Am = AngularMomentum
2018-02-23 15:49:27 +01:00
module Co = Coordinate
2018-02-23 18:41:30 +01:00
module Cs = ContractedShell
2018-02-23 15:49:27 +01:00
module Sp = ShellPair
2018-02-07 17:07:05 +01:00
(** Creates an contracted shell pair : an array of pairs of primitive shells.
A contracted shell with N functions combined with a contracted
shell with M functions generates a NxM array of shell pairs.
*)
let create ?cutoff p_a p_b =
let cutoff, log_cutoff =
match cutoff with
| None -> -1., max_float
| Some cutoff -> cutoff, -. (log cutoff)
2018-01-17 18:19:38 +01:00
in
2018-02-23 15:49:27 +01:00
let center_ab = Co.( p_a.Cs.center |- p_b.Cs.center )
2018-01-17 18:19:38 +01:00
in
2018-01-17 19:09:57 +01:00
let norm_sq =
2018-02-23 15:49:27 +01:00
Co.dot center_ab center_ab
2018-01-17 19:09:57 +01:00
in
2018-02-01 16:09:04 +01:00
let norm_coef_scale_a =
2018-02-23 15:49:27 +01:00
p_a.norm_coef_scale
2018-02-01 16:09:04 +01:00
and norm_coef_scale_b =
2018-02-23 15:49:27 +01:00
p_b.norm_coef_scale
2018-02-01 16:09:04 +01:00
in
2018-02-01 17:13:47 +01:00
let norm_coef_scale =
Array.map (fun v1 ->
Array.map (fun v2 -> v1 *. v2) norm_coef_scale_b
) norm_coef_scale_a
|> Array.to_list
|> Array.concat
2018-02-01 16:09:04 +01:00
in
2018-02-09 19:41:22 +01:00
let shell_pairs =
2018-02-23 15:49:27 +01:00
Array.init p_a.size (fun i ->
let p_a_expo_center = Co.(p_a.Cs.expo.(i) |. p_a.Cs.center) in
let norm_coef_a = p_a.norm_coef.(i) in
Array.init p_b.size (fun j ->
2018-02-09 19:41:22 +01:00
try
2018-02-23 15:49:27 +01:00
let norm_coef_b = p_b.norm_coef.(j) in
let norm_coef = norm_coef_a *. norm_coef_b
2018-02-09 19:41:22 +01:00
in
2018-02-23 15:49:27 +01:00
if norm_coef < cutoff then
2018-02-09 19:41:22 +01:00
raise Null_contribution;
2018-02-23 15:49:27 +01:00
let p_b_expo_center = Co.(p_b.expo.(j) |. p_b.center) in
let expo = p_a.expo.(i) +. p_b.expo.(j) in
2018-02-09 19:41:22 +01:00
let expo_inv = 1. /. expo in
2018-02-23 15:49:27 +01:00
let center = Co.(expo_inv |. (p_a_expo_center |+ p_b_expo_center ) )
2018-02-09 19:41:22 +01:00
in
let argexpo =
2018-02-23 15:49:27 +01:00
p_a.Cs.expo.(i) *. p_b.Cs.expo.(j) *. norm_sq *. expo_inv
2018-02-09 19:41:22 +01:00
in
if (argexpo > log_cutoff) then
raise Null_contribution;
let g =
2018-02-23 15:49:27 +01:00
(pi *. expo_inv)**(1.5) *. exp (-. argexpo)
2018-02-09 19:41:22 +01:00
in
let coef =
2018-02-23 15:49:27 +01:00
norm_coef *. p_a.coef.(i) *. p_b.coef.(j) *. g
2018-02-09 19:41:22 +01:00
in
2018-02-23 15:49:27 +01:00
if abs_float coef < cutoff then
2018-02-09 19:41:22 +01:00
raise Null_contribution;
let center_a =
2018-02-23 15:49:27 +01:00
Co.(center |- p_a.center)
2018-02-09 19:41:22 +01:00
in
let monocentric =
2018-02-23 15:49:27 +01:00
p_a.center = p_b.center
2018-02-09 19:41:22 +01:00
in
2018-02-10 03:37:00 +01:00
let totAngMomInt =
2018-02-23 15:49:27 +01:00
Am.to_int p_a.totAngMom +
Am.to_int p_b.totAngMom
2018-02-10 03:37:00 +01:00
in
2018-02-23 15:49:27 +01:00
Some {
Sp.i ; j ;
shell_a=p_a ; shell_b=p_b ;
norm_coef ; coef ;
expo ; expo_inv ;
center ; center_a ; center_ab ;
norm_sq ; monocentric ; totAngMomInt
}
2018-02-09 19:41:22 +01:00
with
| Null_contribution -> None
)
)
|> Array.to_list
|> Array.concat
|> Array.to_list
|> List.filter (function Some _ -> true | None -> false)
|> List.map (function Some x -> x | None -> assert false)
|> Array.of_list
in
2018-02-23 15:49:27 +01:00
let coef = Array.map (fun x -> (fun y -> y.Sp.coef) x) shell_pairs
and expo_inv = Array.map (fun x -> (fun y -> y.Sp.expo_inv) x) shell_pairs
2018-02-09 19:41:22 +01:00
in
{
shell_a = p_a ; shell_b = p_b ; coef ; expo_inv ;
shell_pairs ; center_ab=shell_pairs.(0).center_ab;
2018-02-10 03:37:00 +01:00
norm_coef_scale ; norm_sq=shell_pairs.(0).norm_sq;
2018-02-23 15:49:27 +01:00
totAngMomInt = shell_pairs.(0).Sp.totAngMomInt;
monocentric = shell_pairs.(0).Sp.monocentric;
2018-02-09 19:41:22 +01:00
}
2018-01-17 18:19:38 +01:00
2018-02-07 13:33:25 +01:00
2018-02-07 17:07:05 +01:00
(** Returns an integer characteristic of a contracted shell pair *)
2018-02-07 13:33:25 +01:00
let hash a =
2018-02-08 01:00:54 +01:00
Array.map Hashtbl.hash a
2018-02-07 13:33:25 +01:00
2018-02-07 17:07:05 +01:00
(** Comparison function, used for sorting *)
2018-02-07 13:33:25 +01:00
let cmp a b =
2018-02-08 01:00:54 +01:00
if a = b then 0
else if (Array.length a < Array.length b) then -1
else if (Array.length a > Array.length b) then 1
else
let out = ref 0 in
begin
try
for k=0 to (Array.length a - 1) do
if a.(k) < b.(k) then
(out := (-1); raise Not_found)
else if a.(k) > b.(k) then
(out := 1; raise Not_found);
done
with Not_found -> ();
end;
!out
(** The array of all shell pairs with their correspondance in the list
of contracted shells.
*)
let shell_pairs basis =
Array.mapi (fun i shell_a ->
Array.mapi (fun j shell_b ->
create shell_a shell_b)
(Array.sub basis 0 (i+1))
) basis
2018-02-07 13:33:25 +01:00
2018-02-08 01:00:54 +01:00
let equivalent x y =
(Array.length x = Array.length y) &&
2018-02-23 15:49:27 +01:00
(Array.init (Array.length x) (fun k -> Sp.equivalent x.(k) y.(k))
2018-02-08 01:00:54 +01:00
|> Array.fold_left (fun accu x -> x && accu) true)
2018-02-07 17:07:05 +01:00
(** A list of unique shell pairs *)
2018-02-08 01:00:54 +01:00
let unique sp =
let sp =
Array.to_list sp
|> Array.concat
|> Array.to_list
in
let rec aux accu = function
| [] -> accu
| x::rest ->
try ignore @@ List.find (fun y -> equivalent x y) accu; aux accu rest
with Not_found -> aux (x::accu) rest
in
aux [] sp
2018-02-07 13:33:25 +01:00
2018-02-08 01:00:54 +01:00
(** A map from a shell pair hash to the list of indices in the array
of shell pairs.
*)
let indices sp =
2018-02-07 17:07:05 +01:00
let map =
2018-02-07 13:33:25 +01:00
Hashtbl.create 129
in
2018-02-07 17:07:05 +01:00
Array.iteri (fun i s ->
Array.iteri (fun j shell_p ->
let key =
hash shell_p
in
2018-02-08 01:00:54 +01:00
Hashtbl.add map key (i,j); ) s
) sp;
2018-02-07 13:33:25 +01:00
map
2018-02-07 17:07:05 +01:00
2018-01-22 23:19:24 +01:00