(** Data structures for storing the determinant space. If the space is built as the outer product of all {% $\alpha$ %} and {% $\beta$ %} determinants, the storage is of type [Spin]. It is sufficient to have the arrays of {% $\alpha$ %} and {% $\beta$ %} spindeterminants. Otherwise, the space is of type [Arbitrary]. *) type arbitrary_space = { det : int array array ; det_alfa : Spindeterminant.t array ; det_beta : Spindeterminant.t array ; index_start : int array; } type determinant_storage = | Arbitrary of arbitrary_space | Spin of (Spindeterminant.t array * Spindeterminant.t array) type t = { n_alfa : int ; n_beta : int ; mo_class : MOClass.t ; mo_basis : MOBasis.t ; determinants : determinant_storage; } module Ss = SpindeterminantSpace let n_alfa t = t.n_alfa let n_beta t = t.n_beta let mo_class t = t.mo_class let mo_basis t = t.mo_basis let active_mos t = mo_class t |> MOClass.active_mos let inactive_mos t = mo_class t |> MOClass.inactive_mos let virtual_mos t = mo_class t |> MOClass.inactive_mos let mo_class_array t = mo_class t |> MOClass.mo_class_array let size t = match t.determinants with | Spin (a,b) -> (Array.length a) * (Array.length b) | Arbitrary a -> let ndet_a = Array.length a.det_alfa in a.index_start.(ndet_a) let determinant_stream t = match t.determinants with | Arbitrary a -> let det_beta = a.det_beta and det_alfa = a.det_alfa and det = a.det in let n_alfa = Array.length det_alfa in let alfa = ref det_alfa.(0) and det_i_alfa = ref det.(0) in let i_alfa = ref 0 and k_beta = ref 0 in Stream.from (fun _ -> if !i_alfa = n_alfa then None else begin let i_beta = (!det_i_alfa).(!k_beta) in let beta = det_beta.(i_beta) in let result = Some (Determinant.of_spindeterminants (!alfa) beta) in incr k_beta; if !k_beta = Array.length !det_i_alfa then begin k_beta := 0; incr i_alfa; if !i_alfa < n_alfa then begin alfa := det_alfa.(!i_alfa); det_i_alfa := det.(!i_alfa) end end; result end ) | Spin (a,b) -> let na = Array.length a and nb = Array.length b in let i = ref 0 and j = ref 0 in Stream.from (fun k -> if !j < nb then let result = Determinant.of_spindeterminants a.(!i) b.(!j) in incr i; if !i = na then (i := 0 ; incr j); Some result else None) let determinants t = t.determinants let determinants_array t = let s = determinant_stream t in Array.init (size t) (fun _ -> Stream.next s) let determinant t i = let alfa, beta = match t.determinants with | Arbitrary a -> let i_alfa = let index_start = a.index_start in let rec loop i_alfa = if index_start.(i_alfa) <= i then (loop [@tailcall]) (i_alfa+1) else i_alfa in loop 0 in let i_beta = i - a.index_start.(i_alfa) in let alfa = a.det_alfa.(i_alfa) in let beta = a.det_beta.(i_beta) in alfa, beta | Spin (a,b) -> let nb = Array.length b in let k = i / nb in let j = i - k * nb in a.(j), b.(k) in Determinant.of_spindeterminants alfa beta let fock_diag det_space det = let alfa_list = Determinant.alfa det |> Spindeterminant.to_list in let beta_list = Determinant.beta det |> Spindeterminant.to_list in let mo_basis = mo_basis det_space in let mo_num = MOBasis.size mo_basis in let one_e_ints = MOBasis.one_e_ints mo_basis and two_e_ints = MOBasis.two_e_ints mo_basis in let two_e i j k l = ERI.get_phys two_e_ints i j k l in let build_array list1 list2 = let result = Array.make (mo_num+1) 0. in (* Occupied *) List.iter (fun i -> let x = one_e_ints.{i,i} in result.(i) <- result.(i) +. x; result.(0) <- result.(0) +. x; List.iter (fun j -> if j <> i then begin let x = two_e i j i j -. two_e i j j i in result.(i) <- result.(i) +. x; result.(0) <- result.(0) +. 0.5 *. x; end ) list1; List.iter (fun j -> begin let x = two_e i j i j in result.(i) <- result.(i) +. x; result.(0) <- result.(0) +. 0.5 *. x; end ) list2; ) list1; (* Virtuals*) List.iter (fun i -> if result.(i) = 0. then begin let x = one_e_ints.{i,i} in result.(i) <- result.(i) +. x; List.iter (fun j -> let x = two_e i j i j -. two_e i j j i in result.(i) <- result.(i) +. x; ) list1; List.iter (fun j -> begin let x = two_e i j i j in result.(i) <- result.(i) +. x; end ) list2; end ) (Util.list_range 1 mo_num); result in let alfa, beta = build_array alfa_list beta_list, build_array beta_list alfa_list in let e = alfa.(0) +. beta.(0) in alfa.(0) <- e; beta.(0) <- e; alfa, beta let spin_of_mo_basis mo_basis f = let s = MOBasis.simulation mo_basis in let e = Simulation.electrons s in let n_alfa = Electrons.n_alfa e and n_beta = Electrons.n_beta e in let det_a = f n_alfa and det_b = f n_beta in let mo_class = Ss.mo_class det_a in let determinants = let det_alfa = Ss.spin_determinants det_a and det_beta = Ss.spin_determinants det_b in let n_det_beta = Array.length det_beta in let n_det_alfa = Array.length det_alfa in let ndet = n_det_alfa * n_det_beta in if Parallel.master then Format.printf "Number of determinants : %d %d %d\n%!" n_det_alfa n_det_beta ndet; Spin (det_alfa, det_beta) in { n_alfa ; n_beta ; mo_class ; mo_basis ; determinants } let arbitrary_of_mo_basis mo_basis f = let s = MOBasis.simulation mo_basis in let e = Simulation.electrons s in let n_alfa = Electrons.n_alfa e and n_beta = Electrons.n_beta e in let det_a = f n_alfa and det_b = f n_beta in let mo_class = Ss.mo_class det_a in let determinants = let det_alfa = Ss.spin_determinants det_a and det_beta = Ss.spin_determinants det_b in let n_det_beta = Array.length det_beta in let n_det_alfa = Array.length det_alfa in let det = Array.make n_det_alfa (Array.init n_det_beta (fun i -> i)) in let index_start = Array.init (n_det_alfa+1) (fun i -> i*n_det_beta) in let ndet = (index_start.(n_det_alfa)) in if Parallel.master then Format.printf "Number of determinants : %d %d %d\n%!" n_det_alfa n_det_beta ndet; Arbitrary { det_alfa ; det_beta ; det ; index_start } in { n_alfa ; n_beta ; mo_class ; mo_basis ; determinants } let cas_of_mo_basis mo_basis ~frozen_core n m = let f n_alfa = Ss.cas_of_mo_basis mo_basis ~frozen_core n_alfa n m in spin_of_mo_basis mo_basis f let fci_of_mo_basis mo_basis ~frozen_core = let f n_alfa = Ss.fci_of_mo_basis mo_basis ~frozen_core n_alfa in spin_of_mo_basis mo_basis f let fci_f12_of_mo_basis mo_basis ~frozen_core mo_num = let s = MOBasis.simulation mo_basis in let e = Simulation.electrons s in let n_alfa = Electrons.n_alfa e and n_beta = Electrons.n_beta e in let n_core = if frozen_core then (Nuclei.small_core @@ Simulation.nuclei @@ MOBasis.simulation mo_basis) / 2 else 0 in let n, m = (n_alfa + n_beta - n_core), (mo_num - n_core) in let f n_alfa = Ss.cas_of_mo_basis mo_basis ~frozen_core n_alfa n m in let r = spin_of_mo_basis mo_basis f in { r with mo_class = MOClass.to_list r.mo_class |> List.rev_map (fun i -> match i with | MOClass.Virtual i when i > mo_num -> MOClass.Auxiliary i | i -> i) |> List.rev |> MOClass.of_list } let cas_f12_of_mo_basis mo_basis ~frozen_core n m mo_num = let f n_alfa = Ss.cas_of_mo_basis mo_basis ~frozen_core n_alfa n m in let r = spin_of_mo_basis mo_basis f in { r with mo_class = MOClass.to_list r.mo_class |> List.rev_map (fun i -> match i with | MOClass.Virtual i when i > mo_num -> MOClass.Auxiliary i | i -> i) |> List.rev |> MOClass.of_list } let pp ppf t = Format.fprintf ppf "@[[ "; let i = ref 0 in determinant_stream t |> Stream.iter (fun d -> Format.fprintf ppf "@[@[%8d@]@;@[%a@]@]@;" !i (Determinant.pp (MOBasis.size (mo_basis t))) d; incr i) ; Format.fprintf ppf "]@]"