open Util open Constants type t = { norm_scales : float array lazy_t; exponent : float; (* {% $\alpha + \beta$ %} *) exponent_inv : float; (* {% $1/(\alpha + \beta)$ %} *) a_minus_b_sq : float; (* {% $|A-B|^2$ %} *) normalization : float; (* [norm_coef_a * norm_coef_b * g], with {% $g = (\pi/(\alpha+\beta))^(3/2) \exp (-|A-B|^2 \alpha\beta/(\alpha+\beta))$ %} *) center : Coordinate.t; (* {% $P = (\alpha A + \beta B)/(\alpha+\beta)$ %} *) center_minus_a : Coordinate.t; (* {% $P - A$ %} *) a_minus_b : Coordinate.t; (* {% $A - B$ %} *) ang_mom : AngularMomentum.t; shell_a : PrimitiveShell.t; shell_b : PrimitiveShell.t; } exception Null_contribution module Am = AngularMomentum module Co = Coordinate module Ps = PrimitiveShell let hash a = Hashtbl.hash a let equivalent a b = a.exponent = b.exponent && a.ang_mom = b.ang_mom && a.normalization = b.normalization && a.center = b.center && a.center_minus_a = b.center_minus_a && a.a_minus_b = b.a_minus_b let cmp a b = hash a - hash b let create_make_of p_a p_b = let a_minus_b = Co.( Ps.center p_a |- Ps.center p_b ) in let a_minus_b_sq = Co.dot a_minus_b a_minus_b in let norm_scales = lazy ( Array.map (fun v1 -> Array.map (fun v2 -> v1 *. v2) (Ps.norm_scales p_b) ) (Ps.norm_scales p_a) |> Array.to_list |> Array.concat ) in let ang_mom = Am.( Ps.ang_mom p_a + Ps.ang_mom p_b ) in function p_a -> let norm_coef_a = Ps.normalization p_a in let alfa_a = Co.( Ps.exponent p_a |. Ps.center p_a ) in function p_b -> let normalization = norm_coef_a *. Ps.normalization p_b in let exponent = Ps.exponent p_a +. Ps.exponent p_b in let exponent_inv = 1. /. exponent in let normalization = let argexpo = Ps.exponent p_a *. Ps.exponent p_b *. a_minus_b_sq *. exponent_inv in normalization *. (pi *. exponent_inv)**1.5 *. exp (-. argexpo) in function cutoff -> if abs_float normalization > cutoff then ( let beta_b = Co.( Ps.exponent p_b |. Ps.center p_b ) in let center = Co.(exponent_inv |. (alfa_a |+ beta_b)) in let center_minus_a = Co.(center |- Ps.center p_a) in Some { ang_mom ; exponent ; exponent_inv ; center ; center_minus_a ; a_minus_b ; a_minus_b_sq ; normalization ; norm_scales ; shell_a = p_a; shell_b = p_b } ) else None let make p_a p_b = let f = create_make_of p_a p_b in match f p_a p_b 0. with | Some result -> result | None -> assert false let norm_scales x = Lazy.force x.norm_scales let exponent_inv x = x.exponent_inv let monocentric x = Ps.center x.shell_a = Ps.center x.shell_b let ang_mom x = x.ang_mom let a_minus_b x = x.a_minus_b let a_minus_b_sq x = x.a_minus_b_sq let center_minus_a x = x.center_minus_a let normalization x = x.normalization let exponent x = x.exponent let center x = x.center let shell_a x = x.shell_a let shell_b x = x.shell_b let zkey_array x = Am.zkey_array (Am.Doublet Ps.(ang_mom x.shell_a, ang_mom x.shell_b) )