10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-11-15 02:23:39 +01:00
QCaml/MOBasis/MOBasis.ml

201 lines
5.7 KiB
OCaml
Raw Normal View History

2018-07-20 16:09:06 +02:00
open Lacaml.D
open Util
2018-08-05 00:31:48 +02:00
open Constants
2018-07-20 16:09:06 +02:00
(** One-electron orthogonal basis set, corresponding to Molecular Orbitals. *)
module HF = HartreeFock_type
module Si = Simulation
type mo_type =
2019-02-20 18:15:15 +01:00
| RHF | ROHF | CASSCF
| Natural of string
| Localized of string
2018-07-20 16:09:06 +02:00
type t =
2019-02-20 18:15:15 +01:00
{
simulation : Simulation.t; (* Simulation which produced the MOs *)
mo_type : mo_type; (* Kind of MOs (RHF, CASSCF, Localized...) *)
mo_occupation : Vec.t; (* Occupation numbers *)
mo_coef : Mat.t; (* Matrix of the MO coefficients in the AO basis *)
eN_ints : NucInt.t lazy_t; (* Electron-nucleus potential integrals *)
ee_ints : ERI.t lazy_t; (* Electron-electron potential integrals *)
kin_ints : KinInt.t lazy_t; (* Kinetic energy integrals *)
}
2018-07-20 16:09:06 +02:00
2019-02-19 17:36:07 +01:00
let size t =
Mat.dim2 t.mo_coef
2019-02-20 18:15:15 +01:00
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
2018-07-20 16:09:06 +02:00
let mo_matrix_of_ao_matrix ~mo_coef ao_matrix =
2018-08-05 00:31:48 +02:00
xt_o_x ~x:mo_coef ~o:ao_matrix
2018-07-20 16:09:06 +02:00
let ao_matrix_of_mo_matrix ~mo_coef ~ao_overlap mo_matrix =
let sc = gemm ao_overlap mo_coef in
gemm sc @@
gemm ~transb:`T mo_matrix sc
let four_index_transform ~mo_coef eri_ao =
let ao_num = Mat.dim1 mo_coef in
let mo_num = Mat.dim2 mo_coef in
let eri_mo = ERI.create ~size:mo_num `Dense in
let mo_num_2 = mo_num * mo_num in
let ao_num_2 = ao_num * ao_num in
let ao_mo_num = ao_num * mo_num in
2019-02-20 18:15:15 +01:00
let range_mo = list_range 1 mo_num in
let range_ao = list_range 1 ao_num in
2018-07-20 16:09:06 +02:00
2018-08-05 00:31:48 +02:00
let u = Mat.create mo_num_2 mo_num
and o = Mat.create ao_num ao_num_2
and p = Mat.create ao_num_2 mo_num
and q = Mat.create ao_mo_num mo_num
2018-07-20 16:09:06 +02:00
in
Printf.eprintf "Transforming %d integrals : %!" mo_num;
List.iter (fun delta ->
Printf.eprintf "%d %!" delta;
Mat.fill u 0.;
List.iter (fun l ->
2018-08-05 00:31:48 +02:00
if abs_float mo_coef.{l,delta} > epsilon then
2019-02-20 18:15:15 +01:00
begin
let jk = ref 0 in
List.iter (fun k ->
List.iter (fun j ->
incr jk;
ERI.get_chem_all_i eri_ao ~j ~k ~l
|> Array.iteri (fun i x -> o.{i+1,!jk} <- x)
) range_ao
) range_ao;
(* o_i_jk *)
let p =
gemm ~transa:`T ~c:p o mo_coef
(* p_jk_alpha = \sum_i o_i_jk c_i_alpha *)
in
let p' =
Bigarray.reshape_2 (Bigarray.genarray_of_array2 p) ao_num ao_mo_num
(* p_j_kalpha *)
in
let q =
gemm ~transa:`T ~c:q p' mo_coef
(* q_kalpha_beta = \sum_j p_j_kalpha c_j_beta *)
in
let q' =
Bigarray.reshape_2 (Bigarray.genarray_of_array2 q) ao_num mo_num_2
(* q_k_alphabeta = \sum_j p_j_kalpha c_j_beta *)
in
ignore @@
2018-08-05 00:31:48 +02:00
gemm ~transa:`T ~beta:1. ~alpha:mo_coef.{l,delta} ~c:u q' mo_coef ;
(* u_alphabeta_gamma = \sum_k q_k_alphabeta c_k_gamma *)
2019-02-20 18:15:15 +01:00
end
) range_ao;
2018-07-20 16:09:06 +02:00
let u =
Bigarray.reshape
(Bigarray.genarray_of_array2 u)
[| mo_num ; mo_num ; mo_num |]
|> Bigarray.array3_of_genarray
in
List.iter (fun gamma ->
List.iter (fun beta ->
List.iter (fun alpha ->
2019-02-20 18:15:15 +01:00
let x = u.{alpha,beta,gamma} in
if x <> 0. then
2018-07-20 19:02:56 +02:00
ERI.set_chem eri_mo alpha beta gamma delta x
2019-02-20 18:15:15 +01:00
) (list_range 1 beta)
) range_mo
) (list_range 1 delta)
) range_mo;
2018-07-20 16:09:06 +02:00
Printf.eprintf "\n%!";
eri_mo
2019-02-20 18:15:15 +01:00
let make ~simulation ~mo_type ~mo_occupation ~mo_coef () =
let ao_basis =
Si.ao_basis simulation
in
2018-07-20 16:09:06 +02:00
let eN_ints = lazy (
2019-02-20 18:24:44 +01:00
AOBasis.eN_ints ao_basis
2018-07-20 16:09:06 +02:00
|> NucInt.matrix
|> mo_matrix_of_ao_matrix ~mo_coef
|> NucInt.of_matrix
)
and kin_ints = lazy (
2019-02-20 18:24:44 +01:00
AOBasis.kin_ints ao_basis
2018-07-20 16:09:06 +02:00
|> KinInt.matrix
|> mo_matrix_of_ao_matrix ~mo_coef
|> KinInt.of_matrix
)
and ee_ints = lazy (
2019-02-20 18:24:44 +01:00
AOBasis.ee_ints ao_basis
2018-07-20 16:09:06 +02:00
|> four_index_transform ~mo_coef
)
in
2019-02-20 18:15:15 +01:00
{ simulation ; mo_type ; mo_occupation ; mo_coef ;
2018-07-20 16:09:06 +02:00
eN_ints ; ee_ints ; kin_ints }
2019-02-20 18:15:15 +01:00
let of_rhf hf =
let mo_num = Vec.dim hf.HF.eigenvalues in
let mo_coef = hf.HF.eigenvectors in
let simulation = hf.HF.simulation in
let mo_type = RHF in
let nocc = hf.HF.nocc in
2018-07-20 16:09:06 +02:00
let mo_occupation =
2019-02-20 18:15:15 +01:00
Array.init mo_num (fun i ->
2018-07-20 16:09:06 +02:00
if i < nocc then 2. else 0.)
2019-02-20 18:15:15 +01:00
|> Vec.of_array
2018-07-20 16:09:06 +02:00
in
2018-08-05 00:31:48 +02:00
let result =
2019-02-20 18:15:15 +01:00
make ~simulation ~mo_type ~mo_occupation ~mo_coef ()
2018-08-05 00:31:48 +02:00
in
let () =
let e = ref 0. in
let t = KinInt.matrix (Lazy.force result.kin_ints) in
let v = NucInt.matrix (Lazy.force result.eN_ints) in
let g = Lazy.force result.ee_ints in
for i = 1 to 5 do
e := !e +. 2. *. (t.{i,i} +. v.{i,i})
done;
2019-02-20 18:27:58 +01:00
Printf.printf "Energy one-e = %20.15f\n" !e;
2018-08-05 00:31:48 +02:00
let e2 = ref 0. in
for i = 1 to 5 do
for j = i+1 to 5 do
e2 := !e2 +. 2. *. (ERI.get_phys g i j i j -.
ERI.get_phys g i j j i)
done;
done;
for i = 1 to 5 do
for j = 1 to 5 do
e2 := !e2 +. ERI.get_phys g i j i j
done;
done;
2019-02-20 18:27:58 +01:00
Printf.printf "Energy two-e = %20.15f\n" !e2;
Printf.printf "Energy = %20.15f\n" (Si.nuclear_repulsion simulation +. !e +. !e2)
2018-08-05 00:31:48 +02:00
in
result
2018-07-20 16:09:06 +02:00
2019-02-20 18:15:15 +01:00
let of_hartree_fock = function
| HF.RHF hf -> of_rhf hf
| _ -> assert false
2018-07-20 16:09:06 +02:00
2019-02-19 17:36:07 +01:00