QCaml/SCF/HartreeFock_type.ml

129 lines
4.6 KiB
OCaml

open Lacaml.D
open Util
type s =
{
simulation : Simulation.t;
guess : Guess.t;
eigenvectors : Mat.t ;
eigenvalues : Vec.t ;
occupation : Vec.t ;
iterations : (float * float * float) array;
energy : float ;
nuclear_repulsion : float ;
kin_energy : float ;
eN_energy : float ;
coulomb_energy : float ;
exchange_energy : float ;
nocc : int;
}
type t =
| RHF of s (** Restricted Hartree-Fock *)
| ROHF of s (** Restricted Open-shell Hartree-Fock *)
| UHF of s (** Unrestricted Hartree-Fock *)
let iterations_to_string hf_calc =
" # HF energy Convergence HOMO-LUMO
---------------------------------------------------" ::
Array.to_list (Array.mapi (fun i (e, c, g) ->
Printf.sprintf " %5d %13.8f %11.4e %11.4f " (i+1) e c g) hf_calc.iterations)
@ [ " -----------------------------------------------------" ]
|> String.concat "\n"
let summary hf_calc =
let ha_to_ev = Constants.ha_to_ev in
String.concat "\n" [
" =====================================================";
Printf.sprintf " One-electron energy %16.10f" (hf_calc.kin_energy +. hf_calc.eN_energy) ;
Printf.sprintf " Kinetic energy %16.10f" hf_calc.kin_energy ;
Printf.sprintf " Potential energy %16.10f" hf_calc.eN_energy ;
" ---------------------------------------------------";
Printf.sprintf " Two-electron energy %16.10f" (hf_calc.coulomb_energy +. hf_calc.exchange_energy) ;
Printf.sprintf " Coulomb energy %16.10f" hf_calc.coulomb_energy ;
Printf.sprintf " Exchange energy %16.10f" hf_calc.exchange_energy ;
" ---------------------------------------------------";
Printf.sprintf " Electronic energy %16.10f" (hf_calc.energy -. hf_calc.nuclear_repulsion);
Printf.sprintf " Nuclear repulsion %16.10f" hf_calc.coulomb_energy ;
Printf.sprintf " Hartree-Fock energy %16.10f" hf_calc.energy ;
" ---------------------------------------------------";
Printf.sprintf " HF HOMO energy %16.10f eV" (ha_to_ev *. hf_calc.eigenvalues.{hf_calc.nocc} );
Printf.sprintf " HF LUMO energy %16.10f eV" (ha_to_ev *. hf_calc.eigenvalues.{hf_calc.nocc+1} );
Printf.sprintf " HF HOMO-LUMO gap %16.10f eV"
(ha_to_ev *.(hf_calc.eigenvalues.{hf_calc.nocc+1} -. hf_calc.eigenvalues.{hf_calc.nocc}));
" =====================================================" ]
let mos_to_string hf_calc =
let open Lacaml.Io in
let rows = Mat.dim1 hf_calc.eigenvectors
and cols = Mat.dim2 hf_calc.eigenvectors
in
let rec aux accu first last =
if (first > last) then String.concat "\n" (List.rev accu)
else
let nw =
"\n Eigenvalues : " ^ (
Array.mapi (fun i x ->
if (i+1 >= first) && (i+1 <= first+4 ) then
Some (Printf.sprintf " %f " x)
else None
)
(Vec.to_array hf_calc.eigenvalues)
|> Array.to_list
|> list_some
|> String.concat " "
)^
Format.asprintf "\n\n %a\n" (Lacaml.Io.pp_lfmat
~row_labels:
(Array.init rows (fun i -> Printf.sprintf "%d " (i + 1)))
~col_labels:
(Array.init (min 5 (cols-first+1)) (fun i -> Printf.sprintf "-- %d --" (i + first) ))
~print_right:false
~print_foot:false
() ) (lacpy ~ac:first ~n:(min 5 (cols-first+1)) hf_calc.eigenvectors)
in
aux (nw :: accu) (first+5) last
in
String.concat "\n" [ "
=========================================================================
Molecular Orbitals
=========================================================================
Occupied
-----------------------------------------------------------------------
" ;
aux [] 1 hf_calc.nocc ;
"
Virtual
-----------------------------------------------------------------------
" ;
aux [] (hf_calc.nocc+1) (Mat.dim2 hf_calc.eigenvectors) ;
"
=========================================================================
" ]
let to_string hf =
let aux hf_calc r =
String.concat "\n" [ Printf.sprintf "
=====================================================
%s Hartree-Fock
=====================================================" r ; "" ;
iterations_to_string hf_calc ; "" ;
summary hf_calc ; "" ;
mos_to_string hf_calc ; "" ;
]
in
match hf with
| RHF hf_calc -> aux hf_calc "Restricted"
| UHF hf_calc -> aux hf_calc "Unrestricted"
| ROHF hf_calc -> aux hf_calc "Restricted Open-shell"