2020-10-17 19:02:37 +02:00
|
|
|
open Linear_algebra
|
|
|
|
|
|
|
|
(** One-electron orthogonal basis set, corresponding to Molecular Orbitals. *)
|
|
|
|
|
2020-10-18 01:58:22 +02:00
|
|
|
module HF = Hartree_fock
|
2020-10-17 19:02:37 +02:00
|
|
|
module Si = Simulation
|
|
|
|
|
2020-10-18 01:58:22 +02:00
|
|
|
type ao = Ao.Ao_dim.t
|
|
|
|
type mo = Mo_dim.t
|
|
|
|
|
2020-10-17 19:02:37 +02:00
|
|
|
type mo_type =
|
|
|
|
| RHF | ROHF | UHF | CASSCF | Projected
|
|
|
|
| Natural of string
|
|
|
|
| Localized of string
|
|
|
|
|
|
|
|
type t =
|
|
|
|
{
|
|
|
|
simulation : Simulation.t; (* Simulation which produced the MOs *)
|
|
|
|
mo_type : mo_type; (* Kind of MOs (RHF, CASSCF, Localized...) *)
|
2020-10-18 01:58:22 +02:00
|
|
|
mo_occupation : mo Vector.t; (* Occupation numbers *)
|
|
|
|
mo_coef : (ao,mo) Matrix.t; (* Matrix of the MO coefficients in the AO basis *)
|
|
|
|
eN_ints : (mo,mo) Matrix.t lazy_t; (* Electron-nucleus potential integrals *)
|
|
|
|
ee_ints : mo Four_idx_storage.t lazy_t; (* Electron-electron potential integrals *)
|
|
|
|
kin_ints : (mo,mo) Matrix.t lazy_t; (* Kinetic energy integrals *)
|
|
|
|
one_e_ints : (mo,mo) Matrix.t lazy_t; (* One-electron integrals *)
|
2020-10-17 19:02:37 +02:00
|
|
|
(* TODO
|
|
|
|
f12_ints : F12.t lazy_t; (* F12 integrals *)
|
|
|
|
*)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let size t =
|
|
|
|
Matrix.dim2 t.mo_coef
|
|
|
|
|
|
|
|
let simulation t = t.simulation
|
|
|
|
let mo_type t = t.mo_type
|
|
|
|
let ao_basis t = Si.ao_basis t.simulation
|
|
|
|
let mo_occupation t = t.mo_occupation
|
|
|
|
let mo_coef t = t.mo_coef
|
|
|
|
let eN_ints t = Lazy.force t.eN_ints
|
|
|
|
let ee_ints t = Lazy.force t.ee_ints
|
|
|
|
let kin_ints t = Lazy.force t.kin_ints
|
|
|
|
let two_e_ints t = Lazy.force t.ee_ints
|
|
|
|
(* TODO
|
|
|
|
let f12_ints t = Lazy.force t.f12_ints
|
|
|
|
*)
|
|
|
|
let one_e_ints t = Lazy.force t.one_e_ints
|
|
|
|
|
|
|
|
|
|
|
|
let mo_energies t =
|
|
|
|
let m_C = mo_coef t in
|
|
|
|
let f =
|
|
|
|
let m_N = Matrix.of_diag @@ mo_occupation t in
|
2020-10-18 01:58:22 +02:00
|
|
|
let m_P = Matrix.x_o_xt ~o:m_N ~x:m_C in
|
2020-10-17 19:02:37 +02:00
|
|
|
match t.mo_type with
|
|
|
|
| RHF -> Fock.make_rhf ~density:m_P (ao_basis t)
|
|
|
|
| Projected
|
2020-10-18 01:58:22 +02:00
|
|
|
| ROHF -> (Matrix.scale_inplace 0.5 m_P;
|
2020-10-17 19:02:37 +02:00
|
|
|
Fock.make_uhf ~density_same:m_P ~density_other:m_P (ao_basis t))
|
|
|
|
| _ -> failwith "Not implemented"
|
|
|
|
in
|
|
|
|
let m_F0 = Fock.fock f in
|
2020-10-18 01:58:22 +02:00
|
|
|
Matrix.xt_o_x ~o:m_F0 ~x:m_C
|
2020-10-17 19:02:37 +02:00
|
|
|
|> Matrix.diag
|
|
|
|
|
|
|
|
|
|
|
|
let mo_matrix_of_ao_matrix ~mo_coef ao_matrix =
|
|
|
|
Matrix.xt_o_x ~x:mo_coef ~o:ao_matrix
|
|
|
|
|
|
|
|
|
|
|
|
let ao_matrix_of_mo_matrix ~mo_coef ~ao_overlap mo_matrix =
|
|
|
|
let sc = Matrix.gemm ao_overlap mo_coef in
|
|
|
|
Matrix.x_o_xt ~x:sc ~o:mo_matrix
|
|
|
|
|
|
|
|
|
|
|
|
let make ~simulation ~mo_type ~mo_occupation ~mo_coef () =
|
|
|
|
let ao_basis =
|
|
|
|
Si.ao_basis simulation
|
|
|
|
in
|
|
|
|
let eN_ints = lazy (
|
|
|
|
Ao.Basis.eN_ints ao_basis
|
|
|
|
|> mo_matrix_of_ao_matrix ~mo_coef
|
|
|
|
)
|
|
|
|
and kin_ints = lazy (
|
|
|
|
Ao.Basis.kin_ints ao_basis
|
|
|
|
|> mo_matrix_of_ao_matrix ~mo_coef
|
|
|
|
)
|
|
|
|
and ee_ints = lazy (
|
|
|
|
Ao.Basis.ee_ints ao_basis
|
2020-10-18 01:58:22 +02:00
|
|
|
|> Four_idx_storage.four_index_transform mo_coef
|
2020-10-17 19:02:37 +02:00
|
|
|
)
|
|
|
|
(*
|
|
|
|
and f12_ints = lazy (
|
|
|
|
Ao.Basis.f12_ints ao_basis
|
|
|
|
|> F12.four_index_transform mo_coef
|
|
|
|
)
|
|
|
|
*)
|
|
|
|
in
|
|
|
|
let one_e_ints = lazy (
|
|
|
|
Matrix.add (Lazy.force eN_ints) (Lazy.force kin_ints) )
|
|
|
|
in
|
|
|
|
{ simulation ; mo_type ; mo_occupation ; mo_coef ;
|
|
|
|
eN_ints ; ee_ints ; kin_ints ; one_e_ints ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let values t point =
|
|
|
|
let c = mo_coef t in
|
|
|
|
let a = Ao.Basis.values (Simulation.ao_basis t.simulation) point in
|
2020-10-18 01:58:22 +02:00
|
|
|
Matrix.gemv_t c a
|
2020-10-17 19:02:37 +02:00
|
|
|
|
2020-12-17 12:55:11 +01:00
|
|
|
|
2020-10-17 19:02:37 +02:00
|
|
|
let of_hartree_fock hf =
|
|
|
|
let mo_coef = HF.eigenvectors hf in
|
|
|
|
let simulation = HF.simulation hf in
|
|
|
|
let mo_occupation = HF.occupation hf in
|
|
|
|
let mo_type =
|
|
|
|
match HF.kind hf with
|
2020-10-18 01:58:22 +02:00
|
|
|
| HF.RHF -> RHF
|
|
|
|
| HF.ROHF -> ROHF
|
|
|
|
| HF.UHF -> UHF
|
2020-10-17 19:02:37 +02:00
|
|
|
in
|
|
|
|
make ~simulation ~mo_type ~mo_occupation ~mo_coef ()
|
|
|
|
|
2020-10-18 01:58:22 +02:00
|
|
|
(*
|
2020-10-17 19:02:37 +02:00
|
|
|
let of_mo_basis simulation other =
|
|
|
|
|
|
|
|
let mo_coef =
|
|
|
|
let basis = Simulation.ao_basis simulation in
|
|
|
|
let basis_other = ao_basis other in
|
|
|
|
let m_S =
|
2020-10-18 01:58:22 +02:00
|
|
|
Ao.Overlap.(of_basis_pair
|
|
|
|
(Ao.Basis.ao_basis basis)
|
|
|
|
(Ao.Basis.ao_basis basis_other) )
|
2020-10-17 19:02:37 +02:00
|
|
|
in
|
2020-10-18 01:58:22 +02:00
|
|
|
let m_X = Ao.Basis.ortho basis in
|
2020-10-17 19:02:37 +02:00
|
|
|
(* Project other vectors in the current basis *)
|
|
|
|
let m_C =
|
|
|
|
gemm m_S @@ mo_coef other
|
|
|
|
in
|
|
|
|
(* Append dummy vectors to the input vectors *)
|
|
|
|
let result =
|
|
|
|
let vecs = Mat.to_col_vecs m_X in
|
|
|
|
Array.iteri (fun i v -> if (i < Array.length vecs) then vecs.(i) <- v)
|
|
|
|
(Mat.to_col_vecs m_C) ;
|
|
|
|
Mat.of_col_vecs vecs
|
|
|
|
in
|
|
|
|
(* Gram-Schmidt Orthonormalization *)
|
|
|
|
gemm m_X @@ (Util.qr_ortho @@ gemm ~transa:`T m_X result)
|
|
|
|
|> Util.remove_epsilons
|
|
|
|
|> Conventions.rephase
|
|
|
|
in
|
|
|
|
|
|
|
|
let mo_occupation =
|
|
|
|
let occ = mo_occupation other in
|
|
|
|
Vec.init (Mat.dim2 mo_coef) (fun i ->
|
|
|
|
if (i <= Vec.dim occ) then occ.{i}
|
|
|
|
else 0.)
|
|
|
|
in
|
|
|
|
make ~simulation ~mo_type:Projected ~mo_occupation ~mo_coef ()
|
2020-10-18 01:58:22 +02:00
|
|
|
*)
|
2020-10-17 19:02:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let pp ?(start=1) ?(finish=0) ppf t =
|
2020-10-18 01:58:22 +02:00
|
|
|
let rows = Matrix.dim1 t.mo_coef
|
|
|
|
and cols = Matrix.dim2 t.mo_coef
|
2020-10-17 19:02:37 +02:00
|
|
|
in
|
|
|
|
let finish =
|
|
|
|
match finish with
|
|
|
|
| 0 -> cols
|
|
|
|
| x -> x
|
|
|
|
in
|
|
|
|
|
|
|
|
let rec aux first =
|
|
|
|
|
|
|
|
if (first > finish) then ()
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
Format.fprintf ppf "@[<v>@[<v4>@[<h>%s@;" "Eigenvalues:";
|
|
|
|
|
|
|
|
Array.iteri (fun i x ->
|
|
|
|
if (i+1 >= first) && (i+1 <= first+4 ) then
|
|
|
|
Format.fprintf ppf "%12f@ " x)
|
2020-10-18 01:58:22 +02:00
|
|
|
(Vector.to_array @@ mo_energies t);
|
2020-10-17 19:02:37 +02:00
|
|
|
|
|
|
|
Format.fprintf ppf "@]@;";
|
|
|
|
Format.fprintf ppf "@[%a@]"
|
|
|
|
(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
|
2020-10-18 01:58:22 +02:00
|
|
|
() ) (Matrix.to_bigarray_inplace t.mo_coef
|
|
|
|
|> Lacaml.D.lacpy ~ac:first ~n:(min 5 (cols-first+1)) ) ;
|
2020-10-17 19:02:37 +02:00
|
|
|
Format.fprintf ppf "@]@;@;@]";
|
|
|
|
(aux [@tailcall]) (first+5)
|
|
|
|
end
|
|
|
|
in
|
|
|
|
aux start
|