10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-12-21 11:53:31 +01:00

Cleaned simulation

This commit is contained in:
Anthony Scemama 2019-02-20 18:15:15 +01:00
parent b858e8a4b8
commit 8454863e91
18 changed files with 408 additions and 147 deletions

View File

@ -2,17 +2,45 @@ type t =
{
elec_num : int;
mo_basis : MOBasis.t;
mo_class : MOClass.t;
spindets : Spindeterminant.t array;
}
let fci_of_mo_basis mo_basis elec_num =
let fci_of_mo_basis ?(frozen_core=true) mo_basis elec_num =
let mo_num = MOBasis.size mo_basis in
let ncore = (Nuclei.small_core @@ Simulation.nuclei @@ MOBasis.simulation mo_basis) / 2 in
let mo_class =
MOClass.of_list @@
if frozen_core then
List.concat [
Util.list_range 1 ncore
|> List.map (fun i -> MOClass.Core i) ;
Util.list_range (ncore+1) mo_num
|> List.map (fun i -> MOClass.Active i)
]
else
Util.list_range 1 mo_num
|> List.map (fun i -> MOClass.Active i)
in
let m l =
List.fold_left (fun accu i -> let j = i-1 in Z.(logor accu (shift_left one j))
) Z.zero l
in
let occ_mask = m (MOClass.core_mos mo_class)
and active_mask = m (MOClass.active_mos mo_class)
in
let neg_active_mask = Z.neg active_mask in
Format.printf "%a\n" Util.pp_bitstring occ_mask;
Format.printf "%a\n" Util.pp_bitstring active_mask;
Format.printf "%a\n" Util.pp_bitstring neg_active_mask;
let spindets =
Util.bit_permtutations elec_num mo_num
|> List.filter (fun b -> Z.logand neg_active_mask b = occ_mask)
|> List.map (fun b -> Spindeterminant.of_bitstring b)
|> Array.of_list
in
{ elec_num ; mo_basis ; spindets }
{ elec_num ; mo_basis ; mo_class ; spindets }
let pp_spindet_space ppf t =
@ -23,4 +51,3 @@ let pp_spindet_space ppf t =

View File

@ -0,0 +1,23 @@
type t =
{
elec_num : int ; (** Number of electrons *)
mo_basis : MOBasis.t ; (** MO basis on which the space is built *)
mo_class : MOClass.t ; (** CI Classes of the MOs *)
spindets : Spindeterminant.t array ; (** Spin-determinants belonging to the space *)
}
val fci_of_mo_basis : ?frozen_core:bool -> MOBasis.t -> int -> t
(** Create a space of all possible ways to put [n_elec] electrons in the [Active] MOs.
All other MOs are untouched.
*)
(** {2 Printing} *)
val pp_spindet_space : Format.formatter -> t -> unit

View File

@ -7,34 +7,34 @@ open Constants
module HF = HartreeFock_type
module Si = Simulation
type mo_class =
| Core of int
| Inactive of int
| Active of int
| Virtual of int
| Deleted of int
type mo_type =
| RHF | ROHF | CASSCF
| Natural of string
| Localized of string
| RHF | ROHF | CASSCF
| Natural of string
| Localized of string
type t =
{
ao_basis : AOBasis.t; (* Atomic basis set on which the MOs are built. *)
mo_type : mo_type; (* Kind of MOs (RHF, CASSCF, Localized... *)
mo_class : mo_class array; (* CI-Class of the MOs *)
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 *)
}
{
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 *)
}
let size t =
Mat.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 mo_matrix_of_ao_matrix ~mo_coef ao_matrix =
xt_o_x ~x:mo_coef ~o:ao_matrix
@ -56,8 +56,8 @@ let four_index_transform ~mo_coef eri_ao =
let ao_num_2 = ao_num * ao_num in
let ao_mo_num = ao_num * mo_num in
let range_mo = list_range ~start:1 mo_num in
let range_ao = list_range ~start:1 ao_num in
let range_mo = list_range 1 mo_num in
let range_ao = list_range 1 ao_num in
let u = Mat.create mo_num_2 mo_num
and o = Mat.create ao_num ao_num_2
@ -71,40 +71,40 @@ let four_index_transform ~mo_coef eri_ao =
List.iter (fun l ->
if abs_float mo_coef.{l,delta} > epsilon then
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 *)
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 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
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 @@
ignore @@
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 *)
end
) range_ao;
end
) range_ao;
let u =
Bigarray.reshape
(Bigarray.genarray_of_array2 u)
@ -114,19 +114,21 @@ let four_index_transform ~mo_coef eri_ao =
List.iter (fun gamma ->
List.iter (fun beta ->
List.iter (fun alpha ->
let x = u.{alpha,beta,gamma} in
if x <> 0. then
let x = u.{alpha,beta,gamma} in
if x <> 0. then
ERI.set_chem eri_mo alpha beta gamma delta x
) (list_range ~start:1 beta)
) range_mo
) (list_range ~start:1 delta)
) range_mo;
) (list_range 1 beta)
) range_mo
) (list_range 1 delta)
) range_mo;
Printf.eprintf "\n%!";
eri_mo
let make ~ao_basis ~mo_type ~mo_class ~mo_occupation ~mo_coef () =
let make ~simulation ~mo_type ~mo_occupation ~mo_coef () =
let ao_basis =
Si.ao_basis simulation
in
let eN_ints = lazy (
Lazy.force ao_basis.AOBasis.eN_ints
|> NucInt.matrix
@ -144,36 +146,23 @@ let make ~ao_basis ~mo_type ~mo_class ~mo_occupation ~mo_coef () =
|> four_index_transform ~mo_coef
)
in
{ ao_basis ; mo_type ; mo_class ; mo_occupation ; mo_coef ;
{ simulation ; mo_type ; mo_occupation ; mo_coef ;
eN_ints ; ee_ints ; kin_ints }
let of_rhf ~frozen_core hf =
let simulation = hf.HF.simulation in
let nocc = hf.HF.nocc in
let ncore =
if frozen_core then Nuclei.small_core simulation.Si.nuclei
else 0
in
let mo_num = Vec.dim hf.HF.eigenvalues in
let ao_basis = simulation.Si.ao_basis in
let mo_type = RHF in
let mo_class =
Array.init mo_num (fun i ->
if (i < ncore) then Core i
else
if (i < nocc ) then Inactive i
else Virtual i)
in
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
let mo_occupation =
Array.init mo_num (fun i ->
Array.init mo_num (fun i ->
if i < nocc then 2. else 0.)
|> Vec.of_array
|> Vec.of_array
in
let mo_coef = hf.HF.eigenvectors in
let result =
make ~ao_basis ~mo_type ~mo_class ~mo_occupation ~mo_coef ()
make ~simulation ~mo_type ~mo_occupation ~mo_coef ()
in
let () =
@ -198,13 +187,14 @@ let of_rhf ~frozen_core hf =
done;
done;
Printf.printf "Energy bi = %20.15f\n" !e2;
Printf.printf "Energy = %20.15f\n" (simulation.Si.nuclear_repulsion +. !e +. !e2)
Printf.printf "Energy = %20.15f\n" (Si.nuclear_repulsion simulation +. !e +. !e2)
in
result
let of_hartree_fock ~frozen_core = function
| HF.RHF hf -> of_rhf ~frozen_core hf
| _ -> assert false
let of_hartree_fock = function
| HF.RHF hf -> of_rhf hf
| _ -> assert false

View File

@ -1,45 +1,58 @@
(** Data structure to represent the molecular orbitals. *)
(** Data structure to represent the molecular orbitals.
The MO indices start from 1.
*)
open Lacaml.D
type mo_class =
| Core of int
| Inactive of int
| Active of int
| Virtual of int
| Deleted of int
type mo_type =
| RHF | ROHF | CASSCF
| Natural of string
| Localized of string
| RHF | ROHF | CASSCF
| Natural of string
| Localized of string
type t = private
{
ao_basis : AOBasis.t; (* Atomic basis set on which the MOs are built. *)
mo_type : mo_type; (* Kind of MOs (RHF, CASSCF, Localized... *)
mo_class : mo_class array; (* CI-Class of the MOs *)
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 *)
}
type t
(** {1 Accessors} *)
val make : ao_basis:AOBasis.t ->
mo_type:mo_type ->
mo_class:mo_class array ->
mo_occupation:Vec.t ->
mo_coef:Mat.t ->
unit -> t
(** Function to build a data structure representing the molecular orbitals. *)
val simulation : t -> Simulation.t
(** Simulation which produced the MOs *)
val of_hartree_fock : frozen_core:bool -> HartreeFock_type.t -> t
(** Build MOs from a Restricted Hartree-Fock calculation. *)
val mo_type : t -> mo_type
(** Kind of MOs (RHF, CASSCF, Localized...) *)
val ao_basis : t -> AOBasis.t
(** Matrix of the MO coefficients in the AO basis *)
val mo_occupation : t -> Vec.t
(** Occupation numbers *)
val mo_coef : t -> Mat.t
(** Molecular orbitcal coefficients *)
val eN_ints : t -> NucInt.t
(** Electron-nucleus potential integrals *)
val ee_ints : t -> ERI.t
(** Electron-electron repulsion integrals *)
val kin_ints : t -> KinInt.t
(** Kinetic energy integrals *)
val size : t -> int
(** Number of molecular orbitals in the basis *)
(** {1 Creators} *)
val make : simulation:Simulation.t ->
mo_type:mo_type ->
mo_occupation:Vec.t ->
mo_coef:Mat.t ->
unit -> t
(** Function to build a data structure representing the molecular orbitals. *)
val of_hartree_fock : HartreeFock_type.t -> t
(** Build MOs from a Restricted Hartree-Fock calculation. *)

57
MOBasis/MOClass.ml Normal file
View File

@ -0,0 +1,57 @@
type mo_class =
| Core of int (* Always doubly occupied *)
| Inactive of int (* With 0,1 or 2 holes *)
| Active of int (* With 0,1 or 2 holes or particles *)
| Virtual of int (* With 0,1 or 2 particles *)
| Deleted of int (* Always unoccupied *)
type t = mo_class list
let pp_mo_occ ppf = function
| Core i -> Format.fprintf ppf "@[Core %d@]" i
| Inactive i -> Format.fprintf ppf "@[Inactive %d@]" i
| Active i -> Format.fprintf ppf "@[Active %d@]" i
| Virtual i -> Format.fprintf ppf "@[Virtual %d@]" i
| Deleted i -> Format.fprintf ppf "@[Deleted %d@]" i
let of_list t = t
let core_mos t =
List.map (fun x ->
match x with
| Core i -> Some i
| _ -> None) t
|> Util.list_some
let inactive_mos t =
List.map (fun x ->
match x with
| Inactive i -> Some i
| _ -> None ) t
|> Util.list_some
let active_mos t =
List.map (fun x ->
match x with
| Active i -> Some i
| _ -> None ) t
|> Util.list_some
let virtual_mos t =
List.map (fun x ->
match x with
| Virtual i -> Some i
| _ -> None ) t
|> Util.list_some
let deleted_mos t =
List.map (fun x ->
match x with
| Deleted i -> Some i
| _ -> None ) t
|> Util.list_some

35
MOBasis/MOClass.mli Normal file
View File

@ -0,0 +1,35 @@
(** CI Classes of MOs : active, inactive, etc *)
type mo_class =
| Core of int (* Always doubly occupied *)
| Inactive of int (* With 0,1 or 2 holes *)
| Active of int (* With 0,1 or 2 holes or particles *)
| Virtual of int (* With 0,1 or 2 particles *)
| Deleted of int (* Always unoccupied *)
type t
(** Creation *)
val of_list : mo_class list -> t
val core_mos : t -> int list
(** Returns a list containing the indices of the core MOs. *)
val active_mos : t -> int list
(** Returns a list containing the indices of the active MOs. *)
val virtual_mos : t -> int list
(** Returns a list containing the indices of the virtual MOs. *)
val inactive_mos : t -> int list
(** Returns a list containing the indices of the inactive MOs. *)
val deleted_mos : t -> int list
(** Returns a list containing the indices of the deleted MOs. *)
(** {2 Printers} *)
val pp_mo_occ : Format.formatter -> mo_class -> unit

View File

@ -5,10 +5,10 @@ LIBS=
PKGS=
OCAMLBUILD=ocamlbuild -j 0 -cflags $(ocamlcflags) -lflags $(ocamllflags) $(ocamldocflags) -Is $(INCLUDE_DIRS) -ocamlopt $(ocamloptflags) $(mpi)
MLLFILES=$(wildcard */*.mll) $(wildcard *.mll) Utils/math_functions.c
MLYFILES=$(wildcard */*.mly) $(wildcard *.mly)
MLFILES= $(filter-out $(wildcard Parallel_*/*), $(wildcard */*.ml) $(wildcard *.ml) )
MLIFILES=$(filter-out $(wildcard Parallel_*/*), $(wildcard */*.mli) $(wildcard *.mli) )
MLLFILES=$(filter-out $(wildcard _build/*), $(wildcard */*.mll) $(wildcard *.mll)) Utils/math_functions.c
MLYFILES=$(filter-out $(wildcard _build/*), $(wildcard */*.mly) $(wildcard *.mly))
MLFILES= $(filter-out $(wildcard Parallel_*/*) $(wildcard _build/*), $(wildcard */*.ml) $(wildcard *.ml) )
MLIFILES=$(filter-out $(wildcard Parallel_*/*) $(wildcard _build/*), $(wildcard */*.mli) $(wildcard *.mli) )
ALL_NATIVE=$(patsubst %.ml,%.native,$(wildcard run_*.ml))
ALL_BYTE=$(patsubst %.ml,%.byte,$(wildcard run_*.ml))
@ -16,6 +16,7 @@ ALL_EXE=$(ALL_BYTE) $(ALL_NATIVE)
.PHONY: default doc
default: $(ALL_EXE) doc
tests: run_tests.native

View File

@ -1,8 +1,7 @@
open Util
open Simulation
let make ?guess simulation =
if simulation.electrons.Electrons.multiplicity = 1 then
if (Simulation.electrons simulation).Electrons.multiplicity = 1 then
RHF.make ?guess simulation
else
invalid_arg "UHF or ROHF not implemented"

View File

@ -12,15 +12,15 @@ let make ?guess:(guess=`Huckel) ?max_scf:(max_scf=64) ?level_shift:(level_shift=
(* Number of occupied MOs *)
let nocc =
simulation.Si.electrons.El.n_alpha
(Si.electrons simulation).El.n_alpha
in
let nuclear_repulsion =
simulation.Si.nuclear_repulsion
Si.nuclear_repulsion simulation
in
let ao_basis =
simulation.Si.ao_basis
Si.ao_basis simulation
in
(* Initial guess *)

View File

@ -7,6 +7,13 @@ type t = {
nuclear_repulsion : float;
}
let nuclei t = t.nuclei
let charge t = t.charge
let electrons t = t.electrons
let basis t = t.basis
let ao_basis t = t.ao_basis
let nuclear_repulsion t = t.nuclear_repulsion
let make ?cartesian:(cartesian=false)
?multiplicity:(multiplicity=1)
?charge:(charge=0)

29
Simulation.mli Normal file
View File

@ -0,0 +1,29 @@
type t
val nuclei : t -> Nuclei.t
(** Nuclear coordinates used in the smiulation *)
val charge : t -> Charge.t
(** Total charge (electrons + nuclei) *)
val electrons : t -> Electrons.t
(** Electrons used in the simulation *)
val basis : t -> Basis.t
(** Basis set used to build the AOs *)
val ao_basis : t -> AOBasis.t
(** Atomic basis set *)
val nuclear_repulsion : t -> float
(** Nuclear repulsion energy *)
(** {1 Creation} *)
val make :
?cartesian:bool ->
?multiplicity:int -> ?charge:int -> nuclei:Nuclei.t -> Basis.t -> t
val of_filenames :
?cartesian:bool ->
?multiplicity:int -> ?charge:int -> nuclei:string -> string -> t

46
Utils/Range.ml Normal file
View File

@ -0,0 +1,46 @@
type t = int list
let to_int_list r = r
let expand_range r =
match String.split_on_char '-' r with
| s :: f :: [] ->
begin
let start = int_of_string s
and finish = int_of_string f
in
assert (start <= finish) ;
let rec do_work = function
| i when i=finish -> [ i ]
| i -> i::(do_work (i+1))
in do_work start
end
| r :: [] -> int_of_string r
| [] -> []
| _ -> invalid_arg "Only one range expected"
let of_string s =
match s.[0] with
| '0' .. '9' -> [ int_of_string s ]
| _ ->
assert (s.[0] = '[') ;
assert (s.[(String.length s)-1] = ']') ;
let s = String.sub s 1 ((String.length s) - 2) in
let l = String_ext.split ~on:',' s in
let l = List.map expand_range l in
List.concat l
|> List.sort_uniq compare
let to_string l =
"[" ^
(List.map string_of_int l
|> String.concat ",") ^
"]"
let pp_range ppf t =
Format.fprintf "@[%s@]" ppf (to_string t)

30
Utils/Range.mli Normal file
View File

@ -0,0 +1,30 @@
(** A range is a sorted list of integers in an interval.
{[ "[36-53,72-107,126-131]" ]}
represents the list of integers
{[ [ 37 ; 37 ; 38 ; ... ; 52 ; 53 ; 72 ; 73 ; ... ; 106 ; 107 ; 126 ; 127 ; ...
; 130 ; 131 ] ]}
*)
type t
val of_string : string -> t
(** Create from a string:
- "[a-b]" : range between a and b (included)
- "[a]" : the list with only one integer a
- "a" : equivalent to "[a]"
*)
val to_string : t -> string
(** String representation. *)
val to_int_list : t -> int list
(** Transform into a list of ints. *)
(** {2 Printers} *)
val pp_range : Format.formatter -> t -> unit

View File

@ -180,17 +180,21 @@ let list_some l =
(** {2 Stream functions} *)
let stream_range ?(start=0) n =
let stream_range first last =
Stream.from (fun i ->
let result = i+start in
if result <= n then
let result = i+first in
if result <= last then
Some result
else None
)
let list_range ?(start=0) n =
Array.init n (fun i -> start+i) |> Array.to_list
let list_range first last =
let rec aux accu = function
| 0 -> first :: accu
| i -> aux ( (first+i)::accu ) (i-1)
in
aux [] (last-first)

View File

@ -66,12 +66,12 @@ val list_some : 'a option list -> 'a list
(** Filters out all [None] elements of the list, and returns the elements without
the [Some]. *)
val list_range : ?start:int -> int -> int list
(** Returns a list [start ; start+1 ; ... ; start+n]. Default is [start=0]. *)
val list_range : int -> int -> int list
(** [list_range first last] returns a list [first; first+1 ; ... ; last-1 ; last ]. *)
(** {2 Useful streams} *)
val stream_range : ?start:int -> int -> int Stream.t
(** Returns a stream <start ; start+1 ; ... ; start+n>. Default is [start=0]. *)
val stream_range : int -> int -> int Stream.t
(** [stream_range first last] returns a stream <first ; first+1 ; ... ; last-1 ; last>. *)
(** {2 Linear algebra } *)

View File

@ -41,9 +41,9 @@ let run ~out =
let hf = HartreeFock.make s in
let mos =
MOBasis.of_hartree_fock ~frozen_core:true hf
MOBasis.of_hartree_fock hf
in
let ee_ints = Lazy.force mos.MOBasis.ee_ints in
let ee_ints = MOBasis.ee_ints mos in
ERI.to_file ~filename:("mo.eri") ee_ints
let () =

View File

@ -31,12 +31,12 @@ let run ~out =
Simulation.of_filenames ~nuclei:nuclei_file basis_file
in
print_endline @@ Nuclei.to_string s.Simulation.nuclei;
print_endline @@ Nuclei.to_string @@ Simulation.nuclei s;
print_endline "Nuclear repulsion : ";
print_float s.Simulation.nuclear_repulsion; print_newline ();
print_endline @@ Basis.to_string s.Simulation.basis;
print_float @@ Simulation.nuclear_repulsion s; print_newline ();
print_endline @@ Basis.to_string @@ Simulation.basis s;
let ao_basis = s.Simulation.ao_basis in
let ao_basis = Simulation.ao_basis s in
let overlap = Lazy.force ao_basis.AOBasis.overlap in
let eN_ints = Lazy.force ao_basis.AOBasis.eN_ints in
let kin_ints = Lazy.force ao_basis.AOBasis.kin_ints in

View File

@ -10,7 +10,7 @@ let test_water_dz () =
in
let ao_basis =
simulation_closed_shell.Simulation.ao_basis
Simulation.ao_basis simulation_closed_shell
in
Alcotest.run "Water, cc-pVDZ" [
"AO_Basis", AOBasis.test_case ao_basis;