46 KiB
Test of F12 matrix elements¶
Initialization¶
#cd "/home/scemama/QCaml";;
#use "topfind";;
#require "jupyter.notebook";;
let png_image name =
Jupyter_notebook.display_file ~base64:true "image/png" ("Notebooks/images/"^name)
;;
#require "lacaml.top";;
#require "alcotest";;
#require "str";;
#require "bigarray";;
#require "zarith";;
#require "getopt";;
#directory "_build";;
#directory "_build/Basis";;
#directory "_build/CI";;
#directory "_build/MOBasis";;
#directory "_build/Nuclei";;
#directory "_build/Parallel";;
#directory "_build/Perturbation";;
#directory "_build/SCF";;
#directory "_build/Utils";;
Modules to load¶
#load "Constants.cmo";;
#load_rec "Util.cma";;
#load_rec "Matrix.cmo";;
#load_rec "Simulation.cmo";;
#load_rec "Spindeterminant.cmo";;
#load_rec "Determinant.cmo";;
#load_rec "HartreeFock.cmo";;
#load_rec "MOBasis.cmo";;
#load_rec "F12CI.cmo";;
open Lacaml.D;;
Printers¶
#install_printer AngularMomentum.pp_string ;;
#install_printer Basis.pp ;;
#install_printer Charge.pp ;;
#install_printer Coordinate.pp ;;
#install_printer Vector.pp;;
#install_printer Matrix.pp;;
#install_printer Util.pp_float_2darray;;
#install_printer Util.pp_float_array;;
#install_printer Util.pp_matrix;;
#install_printer HartreeFock.pp ;;
#install_printer Fock.pp ;;
#install_printer MOClass.pp ;;
let pp_mo ppf t = MOBasis.pp ~start:1 ~finish:0 ppf t ;;
#install_printer pp_mo;;
#install_printer DeterminantSpace.pp;;
#install_printer SpindeterminantSpace.pp;;
#install_printer Bitstring.pp;;
Run¶
Simulation¶
let basis_filename = "/home/scemama/qp2/data/basis/6-31g"
let aux_basis_filename = "/home/scemama/qp2/data/basis/cc-pvdz"
let nuclei = Nuclei.of_zmt_string "be"
let frozen_core = false
let multiplicity = 1
let state = 1
let basis = Basis.of_nuclei_and_basis_filenames ~nuclei [basis_filename]
let aux_basis = Basis.of_nuclei_and_basis_filenames ~nuclei (basis_filename :: aux_basis_filename :: [])
let f12 = F12factor.gaussian_geminal 1.0
let charge = 0
let simulation =
Simulation.make
~f12 ~charge ~multiplicity ~nuclei
~cartesian:true
basis
Hartree-Fock¶
let hf = HartreeFock.make ~guess:`Hcore simulation ;;
let mo_basis = MOBasis.of_hartree_fock hf
FCI-F12¶
Notations:
- $\langle ij || kl \rangle = \int \phi_i(r_1) \phi_j(r_2) \frac{1}{r_{12}} \phi_k(r1) \phi_l(r2) $
- $\left[ ij || kl \right] = \int \phi_i(r_1) \phi_j(r_2) f_{12} \phi_k(r1) \phi_l(r2) $
Common functions¶
let f12 = Util.of_some @@ Simulation.f12 simulation
let mo_num = MOBasis.size mo_basis
let pp_spindet = Spindeterminant.pp mo_num
let pp_det = Determinant.pp mo_num
;;
#install_printer pp_spindet ;;
#install_printer pp_det ;;
let simulation_aux =
let charge = Charge.to_int @@ Simulation.charge simulation
and multiplicity = Electrons.multiplicity @@ Simulation.electrons simulation
and nuclei = Simulation.nuclei simulation
in
let general_basis =
Basis.general_basis @@ Simulation.basis simulation
in
GeneralBasis.combine [
general_basis ; GeneralBasis.read aux_basis_filename
]
|> Basis.of_nuclei_and_general_basis nuclei
|> Simulation.make ~f12 ~charge ~multiplicity ~nuclei
let aux_basis =
MOBasis.of_mo_basis simulation_aux mo_basis
let aux_num =
MOBasis.size aux_basis
let () = ignore @@ MOBasis.f12_ints aux_basis
let () = ignore @@ MOBasis.two_e_ints aux_basis
Integral-based functions¶
let cancel_singles = false
let mos_cabs =
Util.list_range (mo_num+1) aux_num
let mos_abs =
Util.list_range 1 aux_num
let mos_in =
Util.list_range 1 mo_num
let mos_a k =
Determinant.alfa k
|> Spindeterminant.to_list
let mos_b k =
Determinant.beta k
|> Spindeterminant.to_list
H integrals¶
let h_one =
let h =
MOBasis.one_e_ints aux_basis
in fun i j _ -> h.{i,j}
let h_two =
let two_e_ints = MOBasis.two_e_ints aux_basis in
let h2 i j k l (s:Spin.t) (s':Spin.t) =
if s' <> s then
ERI.get_phys two_e_ints i j k l
else
(ERI.get_phys two_e_ints i j k l) -.
(ERI.get_phys two_e_ints i j l k)
in
h2
F12 integrals¶
let f_two =
let two_e_ints = MOBasis.f12_ints aux_basis in
let f2 i j k l (s:Spin.t) (s':Spin.t) =
if s' <> s then
0.5 *. F12.get_phys two_e_ints i j k l
else
0.5 *. (
(F12.get_phys two_e_ints i j k l) -.
(F12.get_phys two_e_ints i j l k) )
in
let f3 i j k l (s:Spin.t) (s':Spin.t) =
if (i=k && j<>l) || (j=l && i<>k) then
0.
else
f2 i j k l s s'
in
if cancel_singles then f3 else f2
let f_one = fun _ _ _ -> 0.
(*
let f_two = h_two
let f_one = h_one
*)
Determinant-based functions¶
Integrals¶
let f12_integrals mo_basis =
( f_one, f_two, None )
let h_ij mo_basis ki kj =
let integrals =
List.map (fun f -> f mo_basis)
[ CI.h_integrals ]
in
CIMatrixElement.make integrals ki kj
|> List.hd
let f_ij mo_basis ki kj =
let integrals =
List.map (fun f -> f mo_basis)
[ f12_integrals ]
in
CIMatrixElement.make integrals ki kj
|> List.hd
let hf_ij mo_basis ki kj =
let integrals =
List.map (fun f -> f mo_basis)
[ CI.h_integrals ; f12_integrals ]
in
CIMatrixElement.make integrals ki kj
Determinant space¶
let is_a_double det_space =
let mo_class = DeterminantSpace.mo_class det_space in
let mo_num = Array.length @@ MOClass.mo_class_array mo_class in
let m l =
List.fold_left (fun accu i ->
let j = i-1 in Bitstring.logor accu (Bitstring.shift_left_one mo_num j)
) (Bitstring.zero mo_num) l
in
let aux_mask = m (MOClass.auxiliary_mos mo_class) in
fun k ->
let alfa =
Determinant.alfa k
|> Spindeterminant.bitstring
in
let beta =
Determinant.beta k
|> Spindeterminant.bitstring
in
let a = Bitstring.logand aux_mask alfa
and b = Bitstring.logand aux_mask beta
in
match Bitstring.popcount a + Bitstring.popcount b with
| 2 | 1 -> true
| 0 | _ -> false
let in_space =
DeterminantSpace.fci_f12_of_mo_basis aux_basis ~frozen_core mo_num
let aux_space =
DeterminantSpace.fci_of_mo_basis aux_basis ~frozen_core
let det_space_in () =
DeterminantSpace.determinant_stream in_space
let det_space_out () =
let s =
DeterminantSpace.determinant_stream aux_space
in
Stream.from (fun _ ->
try
let is_a_double = is_a_double in_space in
let rec result () =
let ki = Stream.next s in
if is_a_double ki then
Some (ki,ki)
else
result ()
in
result ()
with Stream.Failure -> None
)
let ci = CI.make ~n_states:state in_space
let ci_coef, ci_energy = Lazy.force ci.eigensystem
let _ = print_newline ()
Permutation operator $p_{12}$ that generates a new determinant with electrons 1 and 2 swapped.
let p12 det_space = let mo_class = DeterminantSpace.mo_class det_space in let mo_num = Array.length @@ MOClass.mo_class_array mo_class in let m l = List.fold_left (fun accu i -> let j = i-1 in Bitstring.logor accu (Bitstring.shift_left_one mo_num j) ) (Bitstring.zero mo_num) l in let aux_mask = m (MOClass.auxiliary_mos mo_class) in let not_aux_mask = Bitstring.(shift_left_one mo_num (mo_num-1) |> minus_one |> logxor aux_mask) in fun k -> let alfa = Determinant.alfa k |> Spindeterminant.bitstring in let beta = Determinant.beta k |> Spindeterminant.bitstring in let a = Bitstring.logand aux_mask alfa and b = Bitstring.logand aux_mask beta in match Bitstring.popcount a, Bitstring.popcount b with | 2, 0 | 0, 2 -> Some (Determinant.negate_phase k) | 1, 1 -> Some (Determinant.of_spindeterminants (Spindeterminant.of_bitstring @@ Bitstring.(logor b (logand not_aux_mask alfa)) ) (Spindeterminant.of_bitstring @@ Bitstring.(logor a (logand not_aux_mask beta)) ) ) | 1, 0 | 0, 1 -> Some k | _ -> None
Matrices $\langle I | H | \alpha \rangle$ and $\langle I | F | \alpha \rangle$¶
let out_list =
Util.stream_to_list (det_space_out ())
let in_list =
Util.stream_to_list (det_space_in ())
let det_a = Array.of_list out_list
|> Array.map (fun (i,_) -> i)
let det_I = Array.of_list in_list
let m_H_aux, m_F_aux = let rec col_vecs_list accu_H accu_F = function | [] -> List.rev accu_H, List.rev accu_F | (ki, ki') :: rest when ki = ki' -> begin let h, f = List.map (fun kj -> match hf_ij aux_basis kj ki with | [ a ; b ] -> a, b | _ -> assert false ) in_list |> List.split in let h = Vec.of_list h in let f = Vec.of_list f in scal 0.5 f; (* Specific to He singlet *) col_vecs_list (h::accu_H) (f::accu_F) rest end | (ki, ki') :: rest -> begin assert false; end in let h, f = col_vecs_list [] [] out_list in Mat.of_col_vecs_list h, Mat.of_col_vecs_list f
Function to generate all intermediate external determinants $|\alpha \rangle$ between $|I\rangle$ and $|J\rangle$, with a positive phase factor.
exc
is the degree of excitation between $|I\rangle$ and $|J\rangle$cabs
is the number of electrons in the CABSl
is the degree of excitation between $|I\rangle$ and $|\alpha \rangle$r
is the degree of excitation between $|\alpha \rangle$ and $|J\rangle$
let generate_alphas ki kj exc cabs l r =
(* Check input excitation degree *)
let d = Determinant.degree ki kj in
if d <> exc then
Printf.sprintf "Invalid excitation degree. Expected %d and found %d." exc d
|> failwith;
(* Generate single excitations *)
let all_singles ki =
let mos_a, mos_b = Determinant.to_lists ki in
[ List.map (fun hole ->
List.map (fun particle ->
Determinant.single_excitation Spin.Alfa hole particle ki
) mos_abs
) mos_a
;
List.map (fun hole ->
List.map (fun particle ->
Determinant.single_excitation Spin.Beta hole particle ki
) mos_abs
) mos_b
]
|> List.concat
|> List.concat
|> List.filter (fun x -> Determinant.is_none x = false)
|> List.map (fun x -> Determinant.set_phase Phase.Pos x)
in
(* Generate double excitations *)
let all_doubles ki =
let mos_a, mos_b = Determinant.to_lists ki in
[ List.map (fun hole -> (* Alpha-Alpha *)
List.map (fun particle ->
List.map (fun hole' ->
List.map (fun particle' ->
if hole' > hole && particle' < particle then
Some (Determinant.double_excitation Spin.Alfa hole particle Spin.Alfa hole' particle' ki)
else None
) mos_abs
) mos_a
) mos_abs
) mos_a
;
List.map (fun hole -> (* Beta-Beta *)
List.map (fun particle ->
List.map (fun hole' ->
List.map (fun particle' ->
if hole' > hole && particle' < particle then
Some (Determinant.double_excitation Spin.Beta hole particle Spin.Beta hole' particle' ki)
else None
) mos_abs
) mos_b
) mos_abs
) mos_b
;
List.map (fun hole -> (* Alpha-Beta *)
List.map (fun particle ->
List.map (fun hole' ->
List.map (fun particle' ->
Some (Determinant.double_excitation Spin.Alfa hole particle Spin.Beta hole' particle' ki)
) mos_abs
) mos_b
) mos_abs
) mos_a
]
|> List.concat
|> List.concat
|> List.concat
|> List.concat
|> Util.list_some
|> List.filter (fun x -> Determinant.is_none x = false)
|> List.map (fun x -> Determinant.set_phase Phase.Pos x)
in
(* Generate left and right excitations *)
let al =
match l with
| 1 -> all_singles ki
| 2 -> all_doubles ki
| _ -> assert false
in
let ar =
match r with
| 1 -> all_singles kj
| 2 -> all_doubles kj
| _ -> assert false
in
let mo_class = DeterminantSpace.mo_class in_space in
let m l =
List.fold_left (fun accu i ->
let j = i-1 in Bitstring.logor accu (Bitstring.shift_left_one mo_num j)
) (Bitstring.zero mo_num) l
in
let aux_mask = m (MOClass.auxiliary_mos mo_class) in
let good_cabs k =
let alfa =
Determinant.alfa k
|> Spindeterminant.bitstring
in
let beta =
Determinant.beta k
|> Spindeterminant.bitstring
in
let a = Bitstring.logand aux_mask alfa
and b = Bitstring.logand aux_mask beta
in
Bitstring.popcount a + Bitstring.popcount b = cabs
in
let good_lr k =
Determinant.degree ki k = l &&
Determinant.degree k kj = r
in
(* Merge lists in a set of unique determinants *)
List.concat [ al; ar ]
|> List.sort_uniq compare
(* Filter out all determinants with incorrect numbers of electrons in the CABS *)
|> List.filter good_cabs
(* Filter out all determinants with incorrect excitation numbers *)
|> List.filter good_lr
let compute_HaaF ki alphas kj =
List.fold_left (fun accu alpha -> accu
+. h_ij aux_basis ki alpha
*. f_ij aux_basis alpha kj
) 0. alphas
let check n integral_value exc cabs lexc rexc =
let det_list =
match n with
| 0 -> det_I
| n -> Array.sub det_I 0 n
in
let result =
Printf.printf "Checking ... \n%!";
let percent = ref 0 in
Array.mapi (fun i ki ->
let p = (10 * (i+1))/(Array.length det_list) in
if p <> !percent then
( percent := p ; Printf.printf " - %3d %%\n%!" (p*10) );
Array.mapi (fun j kj ->
if i > j then (0,0,0.,0.) else
if Determinant.degree ki kj <> exc then (0,0,0.,0.) else
let alphas = generate_alphas ki kj exc cabs lexc rexc in
let det_value =
compute_HaaF ki alphas kj
in
let int_value =
integral_value ki kj
in
(i,j,det_value,int_value)
) det_list
) det_list
|> Array.to_list
|> Array.concat
in
let i,j,d,v =
let rec aux k imax jmax emax dmax vmax =
if k = -1 then
imax, jmax, dmax, vmax
else
let i, j, d, v = result.(k) in
let e = abs_float (d -. v) in
if e > emax then
aux (k-1) i j e d v
else
aux (k-1) imax jmax emax dmax vmax
in
aux (n-1) 0 0 0. 0. 0.
in
let error = abs_float (d -. v) in
if error < epsilon_float then
Printf.printf "OK: %e\n%!" error
else
Printf.printf "Failed: (%d, %d) | %e %e | %e\n%!" i j d v error
1. 0 1 11¶
png_image "0_1_11.png"
$i,j$ : orbital indices of MOs occupied in $|I\rangle$.
\begin{align} \sum_{a} \left( \sum_{i} \sum_{j} \left(h_{ia} + \langle i j || a j \rangle \right) \left(f_{ai} + \left[ a j || i j \right] \right) + \sum_{i} \sum_{\bar{j}} \left(h_{ia} + \langle i \bar{j} | a \bar{j} \rangle \right) \left(f_{ai} + \left[ a \bar{j} | i \bar{j} \right] \right) \right) + \\ \sum_{\bar{a}} \left( \sum_{\bar{i}} \sum_{\bar{j}} \left(h_{\bar{i}\bar{a}} + \langle \bar{i} \bar{j} || \bar{a} \bar{j} \rangle \right) \left(f_{\bar{a}\bar{i}} + \left[ \bar{a} \bar{j} || \bar{i} \bar{j} \right] \right) + \sum_{\bar{i}} \sum_{j} \left(h_{\bar{i}\bar{a}} + \langle \bar{i} j | \bar{a} j \rangle \right) \left(f_{\bar{a}\bar{i}} + \left[ \bar{a} j | \bar{i} j \right] \right) \right) \end{align}let integral_value ki kj =
(* Alpha-Beta *)
let s, s' = Spin.(Alfa, Beta) in
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
List.fold_left (fun accu a ->
accu +.( (h_one i a s +. h_two i j a j s s') *.
(f_one a i s +. f_two a j i j s s') )
+.( (h_one j a s' +. h_two i j i a s s') *.
(f_one a j s' +. f_two i a i j s s') )
) 0. mos_cabs
) 0. (mos_a ki)
) 0. (mos_b ki)
+.
(* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu (mos,s) ->
let s' = s in accu +.
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
List.fold_left (fun accu a ->
accu +.( (h_one i a s +. h_two i j a j s s') *.
(f_one a i s +. f_two a j i j s s') )
) 0. mos_cabs
) 0. mos
) 0. mos
) 0. [ (mos_a ki,Spin.Alfa) ; (mos_b ki,Spin.Beta)]
let _ =
check 0 integral_value 0 1 1 1
2. 0 1 22¶
png_image "0_1_22.png"
$i,j$ : orbital indices of MOs occupied in $|I\rangle$.
$k$ : orbital indices of MOs unoccupied in $|I\rangle$.
\begin{align} \sum_{a} \sum_{k} \sum_{i} \sum_{j<i} \langle i j || a k \rangle \left[ a k || i j \right] + \sum_{a} \sum_{\bar{k}} \sum_{i} \sum_{\bar{j}} \langle i \bar{j} | a \bar{k} \rangle \left[ a \bar{k} | i \bar{j} \right] + \\ \sum_{\bar{a}} \sum_{k} \sum_{\bar{i}} \sum_{j} \langle \bar{i} j | \bar{a} k \rangle \left[ \bar{a} k | \bar{i} j \right] + \sum_{\bar{a}} \sum_{\bar{k}} \sum_{\bar{i}} \sum_{\bar{j}<\bar{i}} \langle \bar{i} \bar{j} || \bar{a} \bar{k} \rangle \left[ \bar{a} \bar{k} || \bar{i} \bar{j} \right] \end{align}let integral_value ki kj =
(* mos unoccupied in both I and J *)
let mos_virt_a, mos_virt_b =
Array.init mo_num (fun i -> Some (i+1)) ,
Array.init mo_num (fun i -> Some (i+1))
in
List.iter (fun i -> mos_virt_a.(i-1) <- None) (mos_a ki);
List.iter (fun i -> mos_virt_a.(i-1) <- None) (mos_a kj);
List.iter (fun i -> mos_virt_b.(i-1) <- None) (mos_b ki);
List.iter (fun i -> mos_virt_b.(i-1) <- None) (mos_b kj);
let mos_virt_a, mos_virt_b =
Array.to_list mos_virt_a |> Util.list_some,
Array.to_list mos_virt_b |> Util.list_some
in
(* Alpha-Beta *)
let s, s' = Spin.(Alfa, Beta) in
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
List.fold_left (fun accu k -> accu +.
List.fold_left (fun accu a ->
accu +. h_two i j a k s s' *. f_two a k i j s s'
) 0. mos_cabs
) 0. mos_virt_b
) 0. (mos_a ki)
) 0. (mos_b ki)
+.
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
List.fold_left (fun accu k -> accu +.
List.fold_left (fun accu a ->
accu +. h_two i j a k s s' *. f_two a k i j s s'
) 0. mos_cabs
) 0. mos_virt_a
) 0. (mos_b ki)
) 0. (mos_a ki)
+.
(* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu (mos_virt,mos,s) ->
let s' = s in accu +.
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
if i < j then accu else
List.fold_left (fun accu k -> accu +.
List.fold_left (fun accu a ->
accu +. h_two i j a k s s' *. f_two a k i j s s'
) 0. mos_cabs
) 0. mos_virt
) 0. mos
) 0. mos
) 0. [ (mos_virt_a,mos_a ki,Spin.Alfa) ; (mos_virt_b,mos_b ki,Spin.Beta)]
let _ =
check 0 integral_value 0 1 2 2
3. 0 2 22¶
png_image "0_2_22.png"
$i,j$ : orbital indices of MOs occupied in $|I\rangle$.
\begin{align} \sum_{a} \sum_{b>a} \sum_{i} \sum_{j<i} \langle i j || a b \rangle \left[ a b || i j \right] + \sum_{a} \sum_{\bar{b}} \sum_{i} \sum_{\bar{j}} \langle i \bar{j} | a \bar{b} \rangle \left[ a \bar{b} | i \bar{j} \right] + \\ \sum_{\bar{a}} \sum_{b} \sum_{\bar{i}} \sum_{j} \langle \bar{i} j | \bar{a} b \rangle \left[ \bar{a} b | \bar{i} j \right] + \sum_{\bar{a}} \sum_{\bar{b}>\bar{a}} \sum_{\bar{i}} \sum_{\bar{j}<\bar{i}} \langle \bar{i} \bar{j} || \bar{a} \bar{b} \rangle \left[ \bar{a} \bar{b} || \bar{i} \bar{j} \right] \end{align}let integral_value ki kj =
(* Alpha-Beta *)
let s, s' = Spin.(Alfa, Beta) in
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
List.fold_left (fun accu b -> accu +.
List.fold_left (fun accu a ->
accu +. h_two i j a b s s' *. f_two a b i j s s'
) 0. mos_cabs
) 0. mos_cabs
) 0. (mos_a ki)
) 0. (mos_b ki)
+.
(* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu (mos,s) ->
let s' = s in accu +.
List.fold_left (fun accu j -> accu +.
List.fold_left (fun accu i -> accu +.
if i < j then accu else
List.fold_left (fun accu b -> accu +.
List.fold_left (fun accu a ->
if b > a then accu else
accu +. h_two i j a b s s' *. f_two a b i j s s'
) 0. mos_cabs
) 0. mos_cabs
) 0. mos
) 0. mos
) 0. [ (mos_a ki,Spin.Alfa) ; (mos_b ki,Spin.Beta)]
let _ =
check 100 integral_value 0 2 2 2
4. 1 1 11¶
png_image "1_1_11.png"
$|J\rangle = \hat{T}_{i}^{k}|I\rangle$
$j$ : orbital indices of MOs occupied both in $|I\rangle$ and $|J\rangle$.
\begin{align} \sum_{a} \sum_{j} \left( h_{ia} + \langle i j || a j \rangle \right) \left( f_{ak} + \left[ a j || k j \right] \right) + \sum_{\bar{j}} \left( h_{ia} + \langle i \bar{j} | a \bar{j} \rangle \right) \left( f_{ak} + \left[ a \bar{j} | k \bar{j} \right] \right) \end{align}let integral_value ki kj =
let i, k, s, phase =
match Excitation.of_det ki kj with
| Excitation.(Single (phase, { hole ; particle ; spin })) ->
hole, particle, spin, phase
| _ -> assert false
in
let mos, mos' =
match s with
| Spin.Alfa -> mos_a ki, mos_b ki
| Spin.Beta -> mos_b ki, mos_a ki
in
let result =
(* Alpha-Beta *)
List.fold_left (fun accu j ->
let s' = Spin.other s in
accu +. List.fold_left (fun accu a ->
accu +. (h_one i a s +. h_two i j a j s s')
*. (f_one a k s +. f_two a j k j s s')
) 0. mos_cabs
) 0. mos'
+.
(* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu j ->
if j = i then accu else
let s' = s in
accu +. List.fold_left (fun accu a ->
accu +. (h_one i a s +. h_two i j a j s s')
*. (f_one a k s +. f_two a j k j s s')
) 0. mos_cabs
) 0. mos
in
match phase with
| Phase.Pos -> result
| Phase.Neg -> -. result
let _ = check 50 integral_value 1 1 1 1
let ki = det_I.(0)
let kj = det_I.(0)
let _ =
let alphas =
generate_alphas ki kj 0 1 2 2
in
compute_HaaF ki alphas kj
let _ = integral_value ki kj
5. 1 1 12¶
png_image "1_1_12.png"
6. 1 1 21¶
png_image "1_1_21.png"
7. 1 1 22¶
png_image "1_1_22.png"
8. 1 2 22¶
png_image "1_2_22.png"
$|J\rangle = \hat{T}_{i}^{k}|I\rangle$
$j$ : orbital indices of MOs occupied both in $|I\rangle$ and $|J\rangle$.
$$ \sum_{j} \sum_{b}\sum_{a<b} \langle i j || a b \rangle \left[ ab || kj \right] $$let integral_value ki kj =
let h, p, s, phase =
match Excitation.of_det ki kj with
| Excitation.(Single (phase, { hole ; particle ; spin })) ->
hole, particle, spin, phase
| _ -> assert false
in
let mos, mos' =
match s with
| Spin.Alfa -> mos_a ki, mos_b ki
| Spin.Beta -> mos_b ki, mos_a ki
in
let result =
(* Alpha-Beta *)
List.fold_left (fun accu j ->
let s' = Spin.other s in
accu +. List.fold_left (fun accu b ->
accu +. List.fold_left (fun accu a ->
accu +. h_two h j a b s s' *. f_two a b p j s s'
) 0. mos_cabs
) 0. mos_cabs
) 0. mos'
+.
(* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu j ->
let s' = s in
accu +. List.fold_left (fun accu b ->
accu +. List.fold_left (fun accu a ->
if b > a then accu else
accu +. h_two h j a b s s' *. f_two a b p j s s'
) 0. mos_cabs
) 0. mos_cabs
) 0. mos
in
match phase with
| Phase.Pos -> result
| Phase.Neg -> -. result
let _ = check 50 integral_value 1 2 2 2
9. 2 1 12¶
png_image "2_1_12.png"
10. 2 1 21¶
png_image "2_1_21.png"
11. 2 1 22¶
png_image "2_1_22.png"
12. 2 2 22¶
png_image "2_2_22.png"
$|J\rangle = \hat{T}_{ij}^{kl}|I\rangle$
$$ \sum_{b}\sum_{a<b} \langle i j || a b \rangle \left[ ab || kj \right] $$let integral_value ki kj =
let h, h', p, p', s, s', phase =
match Excitation.of_det ki kj with
| Excitation.(Double (phase,
{ hole=h ; particle=p ; spin=s },
{ hole=h'; particle=p'; spin=s'}) ) -> h, h', p, p', s, s', phase
| _ -> assert false
in
let result =
if s <> s' then (* Alpha-Beta *)
List.fold_left (fun accu b ->
accu +. List.fold_left (fun accu a ->
accu +. h_two h h' a b s s' *. f_two a b p p' s s'
) 0. mos_cabs
) 0. mos_cabs
else (* Alpha-Alpha / Beta-Beta *)
List.fold_left (fun accu b ->
accu +. List.fold_left (fun accu a ->
if b > a then accu else
accu +. h_two h h' a b s s' *. f_two a b p p' s s'
) 0. mos_cabs
) 0. mos_cabs
in
match phase with
| Phase.Pos -> result
| Phase.Neg -> -. result
let _ = check 100 integral_value 2 2 2 2
13. 3 1 2 2¶
png_image "3_1_22.png"
$|J\rangle = \hat{T}_{ijm}^{kln}|I\rangle$
$$ \sum_{a} \langle i j || k a \rangle \left[ m a || n l \right] $$let integral_value ki kj =
let h1, h2, h3, p1, p2, p3, s1, s2, s3, phase =
match Excitation.of_det ki kj with
| Excitation.(Triple (phase,
{ hole=h1 ; particle=p1 ; spin=s1 },
{ hole=h2 ; particle=p2 ; spin=s2 },
{ hole=h3 ; particle=p3 ; spin=s3 }) ) -> h1, h2, h3, p1, p2, p3, s1, s2, s3, phase
| _ -> assert false
in
(*
123
213
231
321
312
132
*)
let result =
List.fold_left (fun accu a -> accu +.
h_two h1 h2 p1 a s1 s2 *. f_two h3 a p3 p2 s3 s2 -.
h_two h2 h1 p2 a s2 s1 *. f_two h3 a p3 p1 s3 s1 +.
h_two h2 h3 p2 a s2 s3 *. f_two h1 a p1 p3 s1 s3 -.
h_two h3 h2 p3 a s3 s2 *. f_two h1 a p1 p2 s1 s2 +.
h_two h3 h1 p3 a s3 s1 *. f_two h2 a p2 p1 s2 s1 -.
h_two h1 h3 p1 a s1 s3 *. f_two h2 a p2 p3 s2 s3
) 0. mos_cabs
in
match phase with
| Phase.Pos -> result
| Phase.Neg -> -. result
let _ = check 100 integral_value 3 1 2 2