10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-11-07 06:33:39 +01:00
QCaml/perturbation/mp2.org

181 lines
4.8 KiB
Org Mode

#+begin_src elisp tangle: no :results none :exports none
(setq pwd (file-name-directory buffer-file-name))
(setq name (file-name-nondirectory (substring buffer-file-name 0 -4)))
(setq lib (concat pwd "lib/"))
(setq testdir (concat pwd "test/"))
(setq mli (concat lib name ".mli"))
(setq ml (concat lib name ".ml"))
(setq test-ml (concat testdir name ".ml"))
(org-babel-tangle)
#+end_src
* MP2
:PROPERTIES:
:header-args: :noweb yes :comments both
:END:
** Type
#+begin_src ocaml :tangle (eval mli)
type t
#+end_src
#+begin_src ocaml :tangle (eval ml) :exports none
type t = {
energy : float ;
mo_basis : Mo.Basis.t ;
frozen_core : Mo.Frozen_core.t ;
}
#+end_src
** Creation
#+begin_src ocaml :tangle (eval mli)
val make : frozen_core:Mo.Frozen_core.t -> Mo.Basis.t -> t
#+end_src
| ~make~ | Creates an MP2 data structure |
#+begin_example
let mp2 =
Perturbation.Mp2.make ~frozen_core:(Mo.Frozen_core.(make Small nuclei)) mo_basis
;;
val mp2 : Perturbation.Mp2.t = E(MP2)=-0.185523
#+end_example
#+begin_src ocaml :tangle (eval ml) :exports none
open Linear_algebra
let make_rmp2 mo_basis mo_class =
let epsilon = Mo.Basis.mo_energies mo_basis in
let eri = Mo.Basis.ee_ints mo_basis in
let inactives =
List.filter (fun i ->
match i with Mo.Class.Inactive _ -> true | _ -> false) mo_class
and virtuals =
List.filter (fun i ->
match i with Mo.Class.Virtual _ -> true | _ -> false) mo_class
in
List.fold_left (fun accu b ->
match b with Mo.Class.Virtual b ->
let eps = -. (epsilon%.(b)) in
accu +.
List.fold_left (fun accu a ->
match a with Mo.Class.Virtual a ->
let eps = eps -. (epsilon%.(a)) in
accu +.
List.fold_left (fun accu j ->
match j with Mo.Class.Inactive j ->
let eps = eps +. epsilon%.(j) in
accu +.
List.fold_left (fun accu i ->
match i with Mo.Class.Inactive i ->
let eps = eps +. epsilon%.(i) in
let ijab = Four_idx_storage.get_phys eri i j a b
and abji = Four_idx_storage.get_phys eri a b j i in
let abij = ijab in
accu +. ijab *. ( abij +. abij -. abji) /. eps
| _ -> accu
) 0. inactives
| _ -> accu
) 0. inactives
| _ -> accu
) 0. virtuals
| _ -> accu
) 0. virtuals
let make ~frozen_core mo_basis =
let mo_class =
Mo.Class.cas_sd mo_basis ~frozen_core 0 0
|> Mo.Class.to_list
in
let energy =
match Mo.Basis.mo_type mo_basis with
| RHF -> make_rmp2 mo_basis mo_class
| ROHF -> Common.Util.not_implemented "ROHF MP2"
| UHF -> Common.Util.not_implemented "UHF MP2"
| _ -> invalid_arg "MP2 needs RHF or ROHF MOs"
in
{ energy ; mo_basis ; frozen_core }
#+end_src
** Access
#+begin_src ocaml :tangle (eval mli)
val energy : t -> float
val mo_basis : t -> Mo.Basis.t
val frozen_core : t -> Mo.Frozen_core.t
#+end_src
| ~energy~ | Returns the MP2 energy |
| ~mo_basis~ | Returns the MO basis on which the MP2 energy was computed |
| ~frozen_core~ | Returns the frozen_core scheme used to compute the MP2 energy |
#+begin_example
#+end_example
#+begin_src ocaml :tangle (eval ml) :exports none
let energy t = t.energy
let mo_basis t = t.mo_basis
let frozen_core t = t.frozen_core
#+end_src
** Printers
#+begin_src ocaml :tangle (eval mli)
val pp : Format.formatter -> t -> unit
#+end_src
#+begin_src ocaml :tangle (eval ml) :exports none
let pp ppf t =
Format.fprintf ppf "@[E(MP2)=%f@]" t.energy
#+end_src
** Tests
#+begin_src ocaml :tangle (eval test-ml) :exports none
open Alcotest
open Particles
let wd = Common.Qcaml.root ^ Filename.dir_sep ^ "test"
let tests =
[ "HF Water", `Quick, fun () ->
let nuclei =
wd ^ Filename.dir_sep ^ "water.xyz"
|> Nuclei.of_xyz_file
in
let basis_filename =
wd ^ Filename.dir_sep ^ "cc-pvdz"
in
let ao_basis =
Ao.Basis.of_nuclei_and_basis_filename ~kind:`Gaussian
~cartesian:false ~nuclei basis_filename
in
let simulation = Simulation.make ~nuclei ao_basis in
let hf = Mo.Hartree_fock.make ~guess:`Huckel simulation in
Format.printf "%a" (Mo.Hartree_fock.pp) hf;
check (float 2.e-10) "Energy" (-76.0267987005) (Mo.Hartree_fock.energy hf);
let mo_basis = Mo.Basis.of_hartree_fock hf in
let frozen_core = Mo.Frozen_core.(make Small nuclei) in
let mp2 = Perturbation.Mp2.make ~frozen_core mo_basis in
let e_mp2 = Perturbation.Mp2.energy mp2 in
check (float 1.e-9) "MP2" (-0.2016211415) (e_mp2)
]
#+end_src