2020-10-09 09:47:57 +02:00
|
|
|
open Common
|
2020-09-26 12:02:53 +02:00
|
|
|
|
2018-02-09 19:41:22 +01:00
|
|
|
type t =
|
|
|
|
{
|
2020-09-26 12:02:53 +02:00
|
|
|
coefs_and_shell_pairs : (float * Primitive_shell_pair.t) list;
|
|
|
|
shell_a : Contracted_shell.t;
|
|
|
|
shell_b : Contracted_shell.t;
|
2018-02-09 19:41:22 +01:00
|
|
|
}
|
2018-01-17 18:19:38 +01:00
|
|
|
|
|
|
|
|
2020-09-26 12:02:53 +02:00
|
|
|
module Am = Angular_momentum
|
2018-03-15 15:25:49 +01:00
|
|
|
module Co = Coordinate
|
2020-09-26 12:02:53 +02:00
|
|
|
module Cs = Contracted_shell
|
|
|
|
module Ps = Primitive_shell
|
|
|
|
module Psp = Primitive_shell_pair
|
2018-02-23 15:49:27 +01:00
|
|
|
|
2020-09-26 12:02:53 +02:00
|
|
|
(** Creates an contracted shell pair : a list of pairs of primitive shells.
|
2018-02-07 17:07:05 +01:00
|
|
|
A contracted shell with N functions combined with a contracted
|
|
|
|
shell with M functions generates a NxM array of shell pairs.
|
|
|
|
*)
|
2018-03-21 18:54:56 +01:00
|
|
|
let make ?(cutoff=Constants.epsilon) s_a s_b =
|
2018-03-15 15:25:49 +01:00
|
|
|
|
2018-03-20 14:11:31 +01:00
|
|
|
let make = Psp.create_make_of (Cs.primitives s_a).(0) (Cs.primitives s_b).(0) in
|
2018-03-15 15:25:49 +01:00
|
|
|
|
2018-03-20 19:02:58 +01:00
|
|
|
let coefs_and_shell_pairs =
|
2018-03-15 16:03:43 +01:00
|
|
|
Array.mapi (fun i p_a ->
|
2018-03-20 14:11:31 +01:00
|
|
|
let c_a = (Cs.coefficients s_a).(i) in
|
2018-03-15 19:11:59 +01:00
|
|
|
let make = make p_a in
|
2018-03-15 16:03:43 +01:00
|
|
|
Array.mapi (fun j p_b ->
|
2018-03-20 14:11:31 +01:00
|
|
|
let c_b = (Cs.coefficients s_b).(j) in
|
2018-03-15 16:03:43 +01:00
|
|
|
let coef = c_a *. c_b in
|
|
|
|
assert (coef <> 0.);
|
|
|
|
let cutoff = cutoff /. abs_float coef in
|
2018-03-20 14:11:31 +01:00
|
|
|
coef, make p_b cutoff) (Cs.primitives s_b)) (Cs.primitives s_a)
|
2018-02-09 19:41:22 +01:00
|
|
|
|> Array.to_list
|
|
|
|
|> Array.concat
|
|
|
|
|> Array.to_list
|
2018-03-15 16:03:43 +01:00
|
|
|
|> List.filter (function (_, Some _) -> true | _ -> false)
|
2018-03-20 19:02:58 +01:00
|
|
|
|> List.map (function (c, Some x) -> (c *. Psp.normalization x, x) | _ -> assert false)
|
2018-02-09 19:41:22 +01:00
|
|
|
in
|
2018-03-15 16:03:43 +01:00
|
|
|
|
2018-03-20 19:02:58 +01:00
|
|
|
match coefs_and_shell_pairs with
|
2018-03-20 18:20:40 +01:00
|
|
|
| [] -> None
|
2018-03-20 19:02:58 +01:00
|
|
|
| coefs_and_shell_pairs -> Some { shell_a = s_a ; shell_b = s_b ; coefs_and_shell_pairs }
|
|
|
|
|
|
|
|
|
2018-03-21 15:01:39 +01:00
|
|
|
|
2018-03-20 19:02:58 +01:00
|
|
|
let shell_a x = x.shell_a
|
|
|
|
let shell_b x = x.shell_b
|
|
|
|
let coefs_and_shell_pairs x = x.coefs_and_shell_pairs
|
|
|
|
|
|
|
|
let shell_pairs x =
|
|
|
|
List.map snd x.coefs_and_shell_pairs
|
|
|
|
|> Array.of_list
|
|
|
|
|
|
|
|
let coefficients x =
|
|
|
|
List.map fst x.coefs_and_shell_pairs
|
|
|
|
|> Array.of_list
|
|
|
|
|
|
|
|
let exponents_inv x =
|
|
|
|
List.map (fun (_,sp) -> Psp.exponent_inv sp) x.coefs_and_shell_pairs
|
|
|
|
|> Array.of_list
|
|
|
|
|
2018-03-21 15:01:39 +01:00
|
|
|
let a_minus_b x =
|
2018-03-20 19:02:58 +01:00
|
|
|
match x.coefs_and_shell_pairs with
|
|
|
|
| [] -> assert false
|
|
|
|
| (_,sp)::_ -> Psp.a_minus_b sp
|
|
|
|
|
2018-03-21 15:01:39 +01:00
|
|
|
let a_minus_b_sq x =
|
2018-03-20 19:02:58 +01:00
|
|
|
match x.coefs_and_shell_pairs with
|
|
|
|
| [] -> assert false
|
|
|
|
| (_,sp)::_ -> Psp.a_minus_b_sq sp
|
|
|
|
|
2018-03-21 15:01:39 +01:00
|
|
|
let ang_mom x =
|
2018-03-20 19:02:58 +01:00
|
|
|
match x.coefs_and_shell_pairs with
|
|
|
|
| [] -> assert false
|
2018-03-21 15:01:39 +01:00
|
|
|
| (_,sp)::_ -> Psp.ang_mom sp
|
2018-03-20 19:02:58 +01:00
|
|
|
|
|
|
|
let norm_scales x =
|
|
|
|
match x.coefs_and_shell_pairs with
|
|
|
|
| [] -> assert false
|
|
|
|
| (_,sp)::_ -> Psp.norm_scales sp
|
|
|
|
|
|
|
|
let monocentric x =
|
|
|
|
match x.coefs_and_shell_pairs with
|
|
|
|
| [] -> assert false
|
|
|
|
| (_,sp)::_ -> Psp.monocentric sp
|
|
|
|
|
2018-03-14 14:39:22 +01:00
|
|
|
|
2018-03-21 15:01:39 +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 =
|
2020-09-26 12:02:53 +02:00
|
|
|
List.rev_map Hashtbl.hash a
|
|
|
|
|> Array.of_list
|
2018-02-07 17:07:05 +01:00
|
|
|
|
|
|
|
(** Comparison function, used for sorting *)
|
2020-09-26 12:02:53 +02:00
|
|
|
let compare t t' =
|
|
|
|
let a = hash t.coefs_and_shell_pairs in
|
|
|
|
let b = hash t'.coefs_and_shell_pairs in
|
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.
|
|
|
|
*)
|
2018-03-21 18:54:56 +01:00
|
|
|
let of_contracted_shell_array ?(cutoff=Constants.epsilon) basis =
|
2018-03-22 00:29:14 +01:00
|
|
|
let rec loop accu = function
|
2018-03-22 00:51:34 +01:00
|
|
|
| [] -> accu
|
2018-03-22 00:29:14 +01:00
|
|
|
| (s_a :: rest) as l ->
|
|
|
|
let new_accu =
|
|
|
|
(List.map (fun s_b -> make ~cutoff s_a s_b) l) :: accu
|
2019-09-10 18:39:14 +02:00
|
|
|
in (loop [@tailcall]) new_accu rest
|
2018-03-22 00:29:14 +01:00
|
|
|
in
|
2018-03-22 00:51:34 +01:00
|
|
|
loop [] (List.rev (Array.to_list basis))
|
2018-03-22 00:29:14 +01:00
|
|
|
|> List.concat
|
2020-09-26 12:02:53 +02:00
|
|
|
|> Util.list_some
|
2018-03-22 00:29:14 +01:00
|
|
|
|
2018-02-07 13:33:25 +01:00
|
|
|
|
2020-09-26 12:02:53 +02:00
|
|
|
(*
|
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-03-15 16:03:43 +01:00
|
|
|
let rec eqv = function
|
|
|
|
| 0 -> true
|
|
|
|
| k -> if Psp.equivalent x.(k) y.(k) then
|
2019-09-10 18:39:14 +02:00
|
|
|
(eqv [@tailcall]) (k-1)
|
2018-03-15 16:03:43 +01:00
|
|
|
else false
|
|
|
|
in eqv (Array.length x - 1)
|
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 ->
|
2019-09-10 18:39:14 +02:00
|
|
|
let newaccu =
|
|
|
|
try
|
|
|
|
ignore @@ List.find (fun y -> equivalent x y) accu;
|
|
|
|
accu
|
|
|
|
with Not_found -> (x::accu)
|
|
|
|
in
|
|
|
|
(aux [@tailcall]) newaccu rest
|
2018-02-08 01:00:54 +01:00
|
|
|
in
|
|
|
|
aux [] sp
|
2020-09-26 12:02:53 +02:00
|
|
|
*)
|
2018-02-07 13:33:25 +01:00
|
|
|
|
|
|
|
|
2018-03-21 15:01:39 +01:00
|
|
|
let zkey_array x =
|
|
|
|
Am.zkey_array (Am.Doublet
|
|
|
|
Cs.(ang_mom x.shell_a, ang_mom x.shell_b)
|
|
|
|
)
|
2018-02-07 17:07:05 +01:00
|
|
|
|
2018-01-22 23:19:24 +01:00
|
|
|
|