mirror of
https://gitlab.com/scemama/QCaml.git
synced 2024-12-22 20:33:36 +01:00
Added CI
This commit is contained in:
parent
5c0b356b6c
commit
3694f8695c
116
ci/lib/determinant.ml
Normal file
116
ci/lib/determinant.ml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
open Common
|
||||||
|
|
||||||
|
type t =
|
||||||
|
{
|
||||||
|
alfa : Spindeterminant.t ;
|
||||||
|
beta : Spindeterminant.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type hole = int
|
||||||
|
type particle = int
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let alfa t = t.alfa
|
||||||
|
|
||||||
|
let beta t = t.beta
|
||||||
|
|
||||||
|
let vac n =
|
||||||
|
{
|
||||||
|
alfa = Spindeterminant.vac n;
|
||||||
|
beta = Spindeterminant.vac n;
|
||||||
|
}
|
||||||
|
|
||||||
|
let phase t =
|
||||||
|
match Spindeterminant.(phase t.alfa, phase t.beta) with
|
||||||
|
| Phase.Pos, Phase.Pos
|
||||||
|
| Phase.Neg, Phase.Neg -> Phase.Pos
|
||||||
|
| _ -> Phase.Neg
|
||||||
|
|
||||||
|
|
||||||
|
let of_spindeterminants a b =
|
||||||
|
{
|
||||||
|
alfa = a ;
|
||||||
|
beta = b
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let is_none t = Spindeterminant.(is_none t.alfa || is_none t.beta)
|
||||||
|
|
||||||
|
|
||||||
|
let negate_phase t =
|
||||||
|
{ t with alfa = Spindeterminant.negate_phase t.alfa }
|
||||||
|
|
||||||
|
let set_phase p t =
|
||||||
|
{ alfa = Spindeterminant.set_phase p t.alfa ;
|
||||||
|
beta = Spindeterminant.set_phase Phase.Pos t.beta
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let excitation_level_alfa t t' =
|
||||||
|
Spindeterminant.excitation_level t.alfa t'.alfa
|
||||||
|
|
||||||
|
let excitation_level_beta t t' =
|
||||||
|
Spindeterminant.excitation_level t.beta t'.beta
|
||||||
|
|
||||||
|
let excitation_levels t t' =
|
||||||
|
excitation_level_alfa t t', excitation_level_beta t t'
|
||||||
|
|
||||||
|
|
||||||
|
let excitation_level t t' =
|
||||||
|
(excitation_level_alfa t t') + (excitation_level_beta t t')
|
||||||
|
|
||||||
|
|
||||||
|
let of_lists n a b =
|
||||||
|
let alfa = Spindeterminant.of_list n a
|
||||||
|
and beta = Spindeterminant.of_list n b
|
||||||
|
in of_spindeterminants alfa beta
|
||||||
|
|
||||||
|
|
||||||
|
let to_lists t =
|
||||||
|
Spindeterminant.to_list t.alfa,
|
||||||
|
Spindeterminant.to_list t.beta
|
||||||
|
|
||||||
|
|
||||||
|
let creation spin p t =
|
||||||
|
match spin with
|
||||||
|
| Spin.Alfa -> { t with alfa = Spindeterminant.creation p t.alfa }
|
||||||
|
| Spin.Beta -> { t with beta = Spindeterminant.creation p t.beta }
|
||||||
|
|
||||||
|
|
||||||
|
let annihilation spin h t =
|
||||||
|
match spin with
|
||||||
|
| Spin.Alfa -> { t with alfa = Spindeterminant.annihilation h t.alfa }
|
||||||
|
| Spin.Beta -> { t with beta = Spindeterminant.annihilation h t.beta }
|
||||||
|
|
||||||
|
|
||||||
|
let single_excitation spin h p t =
|
||||||
|
assert (h <> p);
|
||||||
|
match spin with
|
||||||
|
| Spin.Alfa -> { t with alfa = Spindeterminant.single_excitation h p t.alfa }
|
||||||
|
| Spin.Beta -> { t with beta = Spindeterminant.single_excitation h p t.beta }
|
||||||
|
|
||||||
|
|
||||||
|
let double_excitation spin h p spin' h' p' t =
|
||||||
|
assert (h <> p);
|
||||||
|
assert (h' <> p');
|
||||||
|
match spin, spin' with
|
||||||
|
| Spin.(Alfa, Beta) -> { alfa = Spindeterminant.single_excitation h p t.alfa ;
|
||||||
|
beta = Spindeterminant.single_excitation h' p' t.beta }
|
||||||
|
| Spin.(Beta, Alfa) -> { beta = Spindeterminant.single_excitation h p t.beta ;
|
||||||
|
alfa = Spindeterminant.single_excitation h' p' t.alfa }
|
||||||
|
| Spin.(Alfa, Alfa) -> { t with alfa = Spindeterminant.double_excitation h p h' p' t.alfa }
|
||||||
|
| Spin.(Beta, Beta) -> { t with beta = Spindeterminant.double_excitation h p h' p' t.beta }
|
||||||
|
|
||||||
|
|
||||||
|
let compare = compare
|
||||||
|
|
||||||
|
|
||||||
|
let pp ppf t =
|
||||||
|
Format.fprintf ppf "@[<v>@[phase:%a@]@;@[a:%a@]@;@[b:%a@]@]@."
|
||||||
|
Phase.pp (phase t)
|
||||||
|
Spindeterminant.pp t.alfa
|
||||||
|
Spindeterminant.pp t.beta
|
||||||
|
|
||||||
|
|
90
ci/lib/determinant.mli
Normal file
90
ci/lib/determinant.mli
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
(** A Slater determinant is expressed as a Waller-Hartree double determinant:
|
||||||
|
{% $$
|
||||||
|
D(\mathbf{R}) = D_\alpha(\mathbf{R_\alpha}) \times D_\beta(\mathbf{R_\beta})
|
||||||
|
$$ %}
|
||||||
|
The {% $\alpha$ %} and {% $\beta$ %} determinants are of type [Spindeterminant.t].
|
||||||
|
*)
|
||||||
|
|
||||||
|
open Common
|
||||||
|
|
||||||
|
type t
|
||||||
|
type hole = int
|
||||||
|
type particle = int
|
||||||
|
|
||||||
|
(** {1 Accessors} *)
|
||||||
|
|
||||||
|
val alfa : t -> Spindeterminant.t
|
||||||
|
(** Get the {% $\alpha$ %} spin-determinant. *)
|
||||||
|
|
||||||
|
val beta : t -> Spindeterminant.t
|
||||||
|
(** Get the {% $\beta$ %} spin-determinant. *)
|
||||||
|
|
||||||
|
val phase : t -> Phase.t
|
||||||
|
(** Get the phase of the Slater determinant, the product of the phases of the
|
||||||
|
spin-determinants.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val is_none : t -> bool
|
||||||
|
(** Tests if a Determinant is [None]. *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Second quantization operators} *)
|
||||||
|
|
||||||
|
val vac : int -> t
|
||||||
|
(** Vacuum state, [vac = Some ]{% $|\rangle$ %}. The integer parameter is the size of the
|
||||||
|
MO basis set. *)
|
||||||
|
|
||||||
|
val creation : Spin.t -> particle -> t -> t
|
||||||
|
(** [creation spin p] is the creation operator {% $a^\dagger_p$ %}. *)
|
||||||
|
|
||||||
|
val annihilation : Spin.t -> hole -> t -> t
|
||||||
|
(** [annihilation spin h] is the annihilation operator {% $a_h$ %}. *)
|
||||||
|
|
||||||
|
val single_excitation : Spin.t -> hole -> particle -> t -> t
|
||||||
|
(** Single excitation operator {% $T_h^p = a^\dagger_p a_h$ %}. *)
|
||||||
|
|
||||||
|
val double_excitation : Spin.t -> hole -> particle -> Spin.t -> hole -> particle -> t -> t
|
||||||
|
(** Double excitation operator {% $T_{hh'}^{pp'} = a^\dagger_p a^\dagger_{p'} a_{h'} a_h$ %}. *)
|
||||||
|
|
||||||
|
val excitation_level_alfa : t -> t -> int
|
||||||
|
(** Returns the excitation level between two determinants in the {% $\alpha$ %} spin. *)
|
||||||
|
|
||||||
|
val excitation_level_beta : t -> t -> int
|
||||||
|
(** Returns the excitation level between two determinants in the {% $\beta$ %} spin. *)
|
||||||
|
|
||||||
|
val excitation_levels : t -> t -> int*int
|
||||||
|
(** Returns levels of excitation between two determinants in {% $\alpha$ %} and
|
||||||
|
{% $\beta$ %} spins as a pair. *)
|
||||||
|
|
||||||
|
val excitation_level : t -> t -> int
|
||||||
|
(** Returns excitation level between two determinants. *)
|
||||||
|
|
||||||
|
val to_lists : t -> int list * int list
|
||||||
|
(** Converts a Slater determinant to a pair of lists of orbital indices. *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Creators} *)
|
||||||
|
|
||||||
|
val of_spindeterminants : Spindeterminant.t -> Spindeterminant.t -> t
|
||||||
|
(** Creates a Slater determinant from an {% $\alpha$ %} and a {% $\beta$ %}
|
||||||
|
[Spindeterminant.t].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val of_lists : int -> int list -> int list -> t
|
||||||
|
(** Creates a Slater determinant from a two lists of orbital indices.
|
||||||
|
The integer parameter is the size of the MO basis set. *)
|
||||||
|
|
||||||
|
val negate_phase : t -> t
|
||||||
|
(** Returns the same determinant with the phase negated. *)
|
||||||
|
|
||||||
|
val set_phase : Phase.t -> t -> t
|
||||||
|
(** Returns the same determinant with the phase set to [p]. *)
|
||||||
|
|
||||||
|
val compare : t -> t -> int
|
||||||
|
(** Comparison function for sorting *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Printers} *)
|
||||||
|
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
|
|
13
ci/lib/dune
Normal file
13
ci/lib/dune
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
(library
|
||||||
|
(name ci)
|
||||||
|
(public_name qcaml.ci)
|
||||||
|
(synopsis "Configuration interaction")
|
||||||
|
(libraries
|
||||||
|
qcaml.common
|
||||||
|
qcaml.particles
|
||||||
|
qcaml.mo
|
||||||
|
)
|
||||||
|
(instrumentation (backend landmarks))
|
||||||
|
|
||||||
|
)
|
||||||
|
|
157
ci/lib/excitation.ml
Normal file
157
ci/lib/excitation.ml
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
open Common
|
||||||
|
|
||||||
|
type single_exc =
|
||||||
|
{
|
||||||
|
hole : int ;
|
||||||
|
particle : int ;
|
||||||
|
spin : Spin.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type t =
|
||||||
|
| Identity of Phase.t
|
||||||
|
| Single of Phase.t * single_exc
|
||||||
|
| Double of Phase.t * single_exc * single_exc
|
||||||
|
| Triple of Phase.t * single_exc * single_exc * single_exc
|
||||||
|
| Multiple of Phase.t * single_exc list
|
||||||
|
|
||||||
|
|
||||||
|
let single_of_spindet t t' =
|
||||||
|
assert (Spindeterminant.excitation_level t t' = 1);
|
||||||
|
let d = Spindeterminant.bitstring t
|
||||||
|
and d' = Spindeterminant.bitstring t'
|
||||||
|
in
|
||||||
|
let tmp = Bitstring.logxor d d' in
|
||||||
|
let shift_left_one = Bitstring.(shift_left_one (numbits tmp)) in
|
||||||
|
let hole_z = Bitstring.logand (Spindeterminant.bitstring t ) tmp
|
||||||
|
and particle_z = Bitstring.logand (Spindeterminant.bitstring t') tmp
|
||||||
|
in
|
||||||
|
let hole = 1 + Bitstring.trailing_zeros hole_z
|
||||||
|
and particle = 1 + Bitstring.trailing_zeros particle_z
|
||||||
|
in
|
||||||
|
(* Phase calculation *)
|
||||||
|
let low, high =
|
||||||
|
if particle > hole then hole, particle
|
||||||
|
else particle, hole
|
||||||
|
in
|
||||||
|
let mask =
|
||||||
|
let h = high-1 in
|
||||||
|
let l = low in
|
||||||
|
let mask_up = shift_left_one h |> Bitstring.minus_one
|
||||||
|
and mask_dn = Bitstring.plus_one @@ Bitstring.lognot (shift_left_one l)
|
||||||
|
in Bitstring.logand mask_up mask_dn
|
||||||
|
in
|
||||||
|
let phase =
|
||||||
|
Phase.multiply (Phase.multiply (Spindeterminant.phase t) (Spindeterminant.phase t'))
|
||||||
|
(Phase.of_nperm (Bitstring.popcount @@ Bitstring.logand d mask ))
|
||||||
|
in
|
||||||
|
(hole, particle, phase)
|
||||||
|
|
||||||
|
|
||||||
|
let single_of_det t t' =
|
||||||
|
assert Determinant.(beta t = beta t' || alfa t = alfa t');
|
||||||
|
if Determinant.(beta t = beta t') then
|
||||||
|
let hole, particle, phase =
|
||||||
|
single_of_spindet (Determinant.alfa t) (Determinant.alfa t')
|
||||||
|
in
|
||||||
|
Single (phase, { hole ; particle ; spin=Spin.Alfa })
|
||||||
|
else
|
||||||
|
let hole, particle, phase =
|
||||||
|
single_of_spindet (Determinant.beta t) (Determinant.beta t')
|
||||||
|
in
|
||||||
|
Single (phase, { hole ; particle ; spin=Spin.Beta })
|
||||||
|
|
||||||
|
|
||||||
|
let multiple_of_spindet t t' =
|
||||||
|
let holes = Spindeterminant.holes_of t t'
|
||||||
|
and particles = Spindeterminant.particles_of t t'
|
||||||
|
in
|
||||||
|
let t'' =
|
||||||
|
List.fold_left (fun accu h -> Spindeterminant.annihilation h accu) t holes
|
||||||
|
in
|
||||||
|
let t'' =
|
||||||
|
List.fold_left (fun accu p -> Spindeterminant.creation p accu) t'' particles
|
||||||
|
in
|
||||||
|
assert (t' = t'' || t' = Spindeterminant.negate_phase t'');
|
||||||
|
let phase =
|
||||||
|
if Spindeterminant.phase t' = Spindeterminant.phase t'' then
|
||||||
|
Phase.Pos
|
||||||
|
else
|
||||||
|
Phase.Neg
|
||||||
|
in
|
||||||
|
(phase, List.rev @@ List.rev_map2 (fun hole particle -> (hole, particle)) holes (List.rev particles) )
|
||||||
|
|
||||||
|
|
||||||
|
let double_of_spindet t t' =
|
||||||
|
match multiple_of_spindet t t' with
|
||||||
|
| (phase, (h1,p1)::(h2,p2)::[]) -> (h1, p1, h2, p2, phase)
|
||||||
|
| _ -> invalid_arg "t and t' are not doubly excited"
|
||||||
|
|
||||||
|
|
||||||
|
let triple_of_spindet t t' =
|
||||||
|
match multiple_of_spindet t t' with
|
||||||
|
| (phase, (h1,p1)::(h2,p2)::(h3,p3)::[]) -> (h1, p1, h2, p2, h3, p3, phase)
|
||||||
|
| _ -> invalid_arg "t and t' are not doubly excited"
|
||||||
|
|
||||||
|
|
||||||
|
let multiple_of_det t t' =
|
||||||
|
let pa, a =
|
||||||
|
multiple_of_spindet (Determinant.alfa t) (Determinant.alfa t')
|
||||||
|
and pb, b =
|
||||||
|
multiple_of_spindet (Determinant.beta t) (Determinant.beta t')
|
||||||
|
in
|
||||||
|
let phase = Phase.multiply pa pb in
|
||||||
|
Multiple (phase, List.concat [
|
||||||
|
List.rev @@ List.rev_map (fun (hole, particle) -> { hole ; particle ; spin=Spin.Alfa }) a ;
|
||||||
|
List.rev @@ List.rev_map (fun (hole, particle) -> { hole ; particle ; spin=Spin.Beta }) b ])
|
||||||
|
|
||||||
|
|
||||||
|
let double_of_det t t' =
|
||||||
|
match multiple_of_det t t' with
|
||||||
|
| Multiple (phase, [e1 ; e2]) -> Double (phase, e1, e2)
|
||||||
|
| _ -> assert false
|
||||||
|
|
||||||
|
|
||||||
|
let triple_of_det t t' =
|
||||||
|
match multiple_of_det t t' with
|
||||||
|
| Multiple (phase, [e1 ; e2 ; e3]) -> Triple (phase, e1, e2, e3)
|
||||||
|
| _ -> assert false
|
||||||
|
|
||||||
|
|
||||||
|
let of_det t t' =
|
||||||
|
match Determinant.excitation_level t t' with
|
||||||
|
| 0 -> if Determinant.phase t = Determinant.phase t' then
|
||||||
|
Identity Phase.Pos
|
||||||
|
else
|
||||||
|
Identity Phase.Neg
|
||||||
|
| 1 -> single_of_det t t'
|
||||||
|
| 2 -> double_of_det t t'
|
||||||
|
| 3 -> triple_of_det t t'
|
||||||
|
| _ -> multiple_of_det t t'
|
||||||
|
|
||||||
|
let pp_s_exc ppf t =
|
||||||
|
Format.fprintf ppf "@[T^{%s}_{%d->%d}@]"
|
||||||
|
(match t.spin with
|
||||||
|
| Spin.Alfa -> "\\alpha"
|
||||||
|
| Spin.Beta -> "\\beta " )
|
||||||
|
t.hole t.particle
|
||||||
|
|
||||||
|
let pp ppf t =
|
||||||
|
let phase, l =
|
||||||
|
match t with
|
||||||
|
| Identity p -> p, []
|
||||||
|
| Single (p,x) -> p, x::[]
|
||||||
|
| Double (p,x,y) -> p, x::y::[]
|
||||||
|
| Triple (p,x,y,z) -> p, x::y::z::[]
|
||||||
|
| Multiple (p,l) -> p, l
|
||||||
|
in
|
||||||
|
Format.fprintf ppf "@[%c"
|
||||||
|
(match phase with
|
||||||
|
| Phase.Pos -> '+'
|
||||||
|
| Phase.Neg -> '-' );
|
||||||
|
List.iter (fun x -> Format.fprintf ppf "@[T^{%s}_{%d->%d}@]"
|
||||||
|
(match x.spin with
|
||||||
|
| Spin.Alfa -> "\\alpha"
|
||||||
|
| Spin.Beta -> "\\beta " )
|
||||||
|
x.hole x.particle) l;
|
||||||
|
Format.fprintf ppf "@]"
|
||||||
|
|
31
ci/lib/phase.ml
Normal file
31
ci/lib/phase.ml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
type t =
|
||||||
|
| Pos
|
||||||
|
| Neg
|
||||||
|
|
||||||
|
let of_nperm nperm =
|
||||||
|
if (nperm land 1) = 1 then Neg
|
||||||
|
else Pos
|
||||||
|
|
||||||
|
let to_nperm = function
|
||||||
|
| Pos -> 0
|
||||||
|
| Neg -> 1
|
||||||
|
|
||||||
|
let multiply t t' =
|
||||||
|
match t, t' with
|
||||||
|
| Pos, Pos
|
||||||
|
| Neg, Neg -> Pos
|
||||||
|
| Pos, Neg
|
||||||
|
| Neg, Pos -> Neg
|
||||||
|
|
||||||
|
let neg = function
|
||||||
|
| Pos -> Neg
|
||||||
|
| Neg -> Pos
|
||||||
|
|
||||||
|
let add_nperm phase = function
|
||||||
|
| 0 -> phase
|
||||||
|
| nperm -> multiply phase (of_nperm nperm)
|
||||||
|
|
||||||
|
let pp ppf = function
|
||||||
|
| Pos -> Format.fprintf ppf "@[<h>+1@]"
|
||||||
|
| Neg -> Format.fprintf ppf "@[<h>-1@]"
|
||||||
|
|
23
ci/lib/phase.mli
Normal file
23
ci/lib/phase.mli
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
type t =
|
||||||
|
| Pos
|
||||||
|
| Neg
|
||||||
|
|
||||||
|
val of_nperm : int -> t
|
||||||
|
(** Returns the phase obtained by a given number of permuations. *)
|
||||||
|
|
||||||
|
val to_nperm : t -> int
|
||||||
|
(** Converts the phase to [1] or [0] permutations. *)
|
||||||
|
|
||||||
|
val multiply : t -> t -> t
|
||||||
|
(** Multiply an existing phase by another phase. *)
|
||||||
|
|
||||||
|
val add_nperm : t -> int -> t
|
||||||
|
(** Add to an existing phase a given number of permutations. *)
|
||||||
|
|
||||||
|
val neg : t -> t
|
||||||
|
(** Negate the phase. *)
|
||||||
|
|
||||||
|
(** {1 Printers} *)
|
||||||
|
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
|
|
144
ci/lib/spindeterminant.ml
Normal file
144
ci/lib/spindeterminant.ml
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
open Common
|
||||||
|
|
||||||
|
type s =
|
||||||
|
{
|
||||||
|
bitstring : Bitstring.t;
|
||||||
|
phase : Phase.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type t = s option
|
||||||
|
type hole = int
|
||||||
|
type particle = int
|
||||||
|
|
||||||
|
let phase = function
|
||||||
|
| Some s -> s.phase
|
||||||
|
| None -> Phase.Pos
|
||||||
|
|
||||||
|
|
||||||
|
let is_none = function
|
||||||
|
| None -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
|
||||||
|
let bitstring = function
|
||||||
|
| Some s -> s.bitstring
|
||||||
|
| None -> invalid_arg "Spindeterminant is None"
|
||||||
|
|
||||||
|
|
||||||
|
let vac n =
|
||||||
|
Some { bitstring = Bitstring.zero n;
|
||||||
|
phase = Phase.Pos; }
|
||||||
|
|
||||||
|
|
||||||
|
let creation p = function
|
||||||
|
| None -> None
|
||||||
|
| Some spindet ->
|
||||||
|
let i = pred p in
|
||||||
|
if Bitstring.testbit spindet.bitstring i then
|
||||||
|
None
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
let numbits = Bitstring.numbits spindet.bitstring in
|
||||||
|
let x = Bitstring.shift_left_one numbits i in
|
||||||
|
let bitstring = Bitstring.logor spindet.bitstring x in
|
||||||
|
let mask = Bitstring.minus_one x in
|
||||||
|
let r = Bitstring.logand bitstring mask in
|
||||||
|
let phase = Phase.add_nperm spindet.phase (Bitstring.popcount r) in
|
||||||
|
Some { bitstring ; phase }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
let annihilation h = function
|
||||||
|
| None -> None
|
||||||
|
| Some spindet ->
|
||||||
|
let i = pred h in
|
||||||
|
if not (Bitstring.testbit spindet.bitstring i) then
|
||||||
|
None
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
let numbits = Bitstring.numbits spindet.bitstring in
|
||||||
|
let x = Bitstring.shift_left_one numbits i in
|
||||||
|
let mask = Bitstring.minus_one x in
|
||||||
|
let r = Bitstring.logand spindet.bitstring mask in
|
||||||
|
let phase = Phase.add_nperm spindet.phase (Bitstring.popcount r) in
|
||||||
|
let bitstring = Bitstring.logand spindet.bitstring (Bitstring.lognot x) in
|
||||||
|
Some { bitstring ; phase }
|
||||||
|
end
|
||||||
|
|
||||||
|
let single_excitation_reference h p spindet =
|
||||||
|
creation p @@ annihilation h @@ spindet
|
||||||
|
|
||||||
|
let single_excitation h p =
|
||||||
|
single_excitation_reference h p
|
||||||
|
|
||||||
|
|
||||||
|
let double_excitation_reference h' p' h p spindet =
|
||||||
|
creation p' @@ creation p @@ annihilation h @@ annihilation h' @@ spindet
|
||||||
|
|
||||||
|
let double_excitation h' p' h p =
|
||||||
|
double_excitation_reference h' p' h p
|
||||||
|
|
||||||
|
|
||||||
|
let excitation_level t t' =
|
||||||
|
Bitstring.hamdist (bitstring t) (bitstring t') / 2
|
||||||
|
|
||||||
|
let holes_of t t' =
|
||||||
|
Bitstring.logand (bitstring t) (Bitstring.logxor (bitstring t) (bitstring t'))
|
||||||
|
|> Bitstring.to_list
|
||||||
|
|
||||||
|
let particles_of t t' =
|
||||||
|
Bitstring.logand (bitstring t') (Bitstring.logxor (bitstring t) (bitstring t'))
|
||||||
|
|> Bitstring.to_list
|
||||||
|
|
||||||
|
let holes_particles_of t t' =
|
||||||
|
let x = Bitstring.logxor (bitstring t) (bitstring t') in
|
||||||
|
let holes = Bitstring.logand (bitstring t) x |> Bitstring.to_list
|
||||||
|
and particles = Bitstring.logand (bitstring t') x |> Bitstring.to_list
|
||||||
|
in
|
||||||
|
List.rev_map2 (fun h p -> (h,p)) holes particles
|
||||||
|
|> List.rev
|
||||||
|
|
||||||
|
|
||||||
|
let set_phase p = function
|
||||||
|
| Some t -> Some { t with phase = p }
|
||||||
|
| None -> None
|
||||||
|
|
||||||
|
let negate_phase = function
|
||||||
|
| Some t -> Some { t with phase = Phase.neg t.phase }
|
||||||
|
| None -> None
|
||||||
|
|
||||||
|
|
||||||
|
let of_bitstring ?(phase=Phase.Pos) bitstring =
|
||||||
|
Some { bitstring ; phase }
|
||||||
|
|
||||||
|
let of_list n l =
|
||||||
|
List.rev l
|
||||||
|
|> List.fold_left (fun accu p -> creation p accu) (vac n)
|
||||||
|
|
||||||
|
|
||||||
|
let to_list = function
|
||||||
|
| None -> []
|
||||||
|
| Some spindet ->
|
||||||
|
let rec aux accu z =
|
||||||
|
if not (Bitstring.is_zero z) then
|
||||||
|
let element = ((Bitstring.trailing_zeros z)+1) in
|
||||||
|
(aux [@tailcall]) (element::accu) (Bitstring.logand z (Bitstring.minus_one z) )
|
||||||
|
else List.rev accu
|
||||||
|
in aux [] spindet.bitstring
|
||||||
|
|
||||||
|
let to_array t =
|
||||||
|
to_list t
|
||||||
|
|> Array.of_list
|
||||||
|
|
||||||
|
let n_electrons = function
|
||||||
|
| Some t -> Bitstring.popcount t.bitstring
|
||||||
|
| None -> 0
|
||||||
|
|
||||||
|
|
||||||
|
let pp ppf = function
|
||||||
|
| None -> Format.fprintf ppf "@[<h>None@]"
|
||||||
|
| Some s ->
|
||||||
|
Format.fprintf ppf "@[<h>%a %a@]" Phase.pp s.phase Bitstring.pp
|
||||||
|
s.bitstring
|
||||||
|
|
||||||
|
|
91
ci/lib/spindeterminant.mli
Normal file
91
ci/lib/spindeterminant.mli
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
(**
|
||||||
|
A spin-determinant is one of the two determinants in the Waller-Hartree
|
||||||
|
double determinant representation of a Slater determinant. It is represented
|
||||||
|
as a bit string and a phase factor.
|
||||||
|
*)
|
||||||
|
|
||||||
|
open Common
|
||||||
|
|
||||||
|
type t
|
||||||
|
type hole = int
|
||||||
|
type particle = int
|
||||||
|
|
||||||
|
(** {1 Accessors}. *)
|
||||||
|
|
||||||
|
val phase : t -> Phase.t
|
||||||
|
(** Phase factor.
|
||||||
|
@raise Invalid_argument if the spin-determinant is [None].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val set_phase : Phase.t -> t -> t
|
||||||
|
(** Returns a spin-determinant with the phase set to [p]. *)
|
||||||
|
|
||||||
|
|
||||||
|
val bitstring : t -> Bitstring.t
|
||||||
|
(** Bit string.
|
||||||
|
@raise Invalid_argument if the spin-determinant is [None].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val is_none : t -> bool
|
||||||
|
(** Tests if a spin-determinant is [None]. *)
|
||||||
|
|
||||||
|
val negate_phase : t -> t
|
||||||
|
(** Returns a spin-determinant with the phase reversed. *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Second quantization operators} *)
|
||||||
|
|
||||||
|
val vac : int -> t
|
||||||
|
(** Vacuum state, [vac = Some ]{% $|\rangle$ %}. The integer parameter contains the
|
||||||
|
number of orbitals in the basis set. *)
|
||||||
|
|
||||||
|
val creation : particle -> t -> t
|
||||||
|
(** [creation p] is the creation operator {% $a^\dagger_p$ %}. *)
|
||||||
|
|
||||||
|
val annihilation : hole -> t -> t
|
||||||
|
(** [annihilation h] is the annihilation operator {% $a_h$ %}. *)
|
||||||
|
|
||||||
|
val single_excitation : hole -> particle -> t -> t
|
||||||
|
(** Single excitation operator {% $T_h^p = a^\dagger_p a_h$ %}. *)
|
||||||
|
|
||||||
|
val double_excitation : hole -> particle -> hole -> particle -> t -> t
|
||||||
|
(** Double excitation operator {% $T_{hh'}^{pp'} = a^\dagger_p a^\dagger_{p'} a_{h'} a_h$ %}. *)
|
||||||
|
|
||||||
|
val excitation_level : t -> t -> int
|
||||||
|
(** Returns the excitation level between two spin-determinants. *)
|
||||||
|
|
||||||
|
val holes_of : t -> t -> int list
|
||||||
|
(** Returns the list of holes in the excitation from one determinant to another. *)
|
||||||
|
|
||||||
|
val particles_of : t -> t -> int list
|
||||||
|
(** Returns the list of particles in the excitation from one determinant to another. *)
|
||||||
|
|
||||||
|
val holes_particles_of : t -> t -> (int*int) list
|
||||||
|
(** Returns the list of pairs of holes/particles in the excitation from one determinant to
|
||||||
|
another. *)
|
||||||
|
|
||||||
|
val n_electrons : t -> int
|
||||||
|
(** Returns the number of electrons in the determinant. *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Creation} *)
|
||||||
|
|
||||||
|
val of_bitstring : ?phase:Phase.t -> Bitstring.t -> t
|
||||||
|
(** Creates from a bitstring and an optional phase.*)
|
||||||
|
|
||||||
|
val of_list : int -> int list -> t
|
||||||
|
(** Builds a spin-determinant from a list of orbital indices. If the creation of the
|
||||||
|
spin-determinant is not possible because of Pauli's exclusion principle, a [None]
|
||||||
|
spin-determinant is returned.
|
||||||
|
The first integer is the size of the MO basis set. *)
|
||||||
|
|
||||||
|
val to_list : t -> int list
|
||||||
|
(** Transforms a spin-determinant into a list of orbital indices. *)
|
||||||
|
|
||||||
|
val to_array : t -> int array
|
||||||
|
(** Transforms a spin-determinant into an array of orbital indices. *)
|
||||||
|
|
||||||
|
(** {1 Printers}. *)
|
||||||
|
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
|
|
75
ci/lib/spindeterminant_space.ml
Normal file
75
ci/lib/spindeterminant_space.ml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
open Common
|
||||||
|
|
||||||
|
type t =
|
||||||
|
{
|
||||||
|
elec_num : int;
|
||||||
|
mo_basis : Mo.Basis.t;
|
||||||
|
mo_class : Mo.Class.t;
|
||||||
|
spin_determinants : Spindeterminant.t array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let spin_determinants t = t.spin_determinants
|
||||||
|
let elec_num t = t.elec_num
|
||||||
|
let mo_basis t = t.mo_basis
|
||||||
|
let mo_class t = t.mo_class
|
||||||
|
let size t = Array.length t.spin_determinants
|
||||||
|
|
||||||
|
let fci_of_mo_basis ~frozen_core mo_basis elec_num =
|
||||||
|
let mo_num = Mo.Basis.size mo_basis in
|
||||||
|
let mo_class = Mo.Class.fci ~frozen_core mo_basis in
|
||||||
|
let m l =
|
||||||
|
List.fold_left (fun accu i -> let j = i-1 in
|
||||||
|
Bitstring.logor accu (Bitstring.shift_left_one mo_num j)
|
||||||
|
) (Bitstring.zero mo_num) l
|
||||||
|
in
|
||||||
|
let occ_mask = m (Mo.Class.core_mos mo_class)
|
||||||
|
and active_mask = m (Mo.Class.active_mos mo_class)
|
||||||
|
in
|
||||||
|
let neg_active_mask = Bitstring.lognot active_mask in
|
||||||
|
(* Here we generate the FCI space and filter out unwanted determinants
|
||||||
|
with excitations involving the core electrons. This should be improved. *)
|
||||||
|
let spin_determinants =
|
||||||
|
Bitstring.permutations elec_num mo_num
|
||||||
|
|> List.filter (fun b -> Bitstring.logand neg_active_mask b = occ_mask)
|
||||||
|
|> Array.of_list
|
||||||
|
|> Array.map (fun b -> Spindeterminant.of_bitstring b)
|
||||||
|
in
|
||||||
|
{ elec_num ; mo_basis ; mo_class ; spin_determinants }
|
||||||
|
|
||||||
|
|
||||||
|
let cas_of_mo_basis mo_basis ~frozen_core elec_num n m =
|
||||||
|
let mo_num = Mo.Basis.size mo_basis in
|
||||||
|
let mo_class = Mo.Class.cas_sd ~frozen_core mo_basis n m in
|
||||||
|
let m l =
|
||||||
|
List.fold_left (fun accu i -> let j = i-1 in
|
||||||
|
Bitstring.logor accu (Bitstring.shift_left_one mo_num j)
|
||||||
|
) (Bitstring.zero mo_num) l
|
||||||
|
in
|
||||||
|
let active_mask = m (Mo.Class.active_mos mo_class) in
|
||||||
|
let occ_mask = m (Mo.Class.core_mos mo_class) in
|
||||||
|
let inactive_mask = m (Mo.Class.inactive_mos mo_class) in
|
||||||
|
let occ_mask = Bitstring.logor occ_mask inactive_mask in
|
||||||
|
let neg_active_mask = Bitstring.lognot active_mask in
|
||||||
|
(* Here we generate the FCI space and filter out all the unwanted determinants.
|
||||||
|
This should be improved. *)
|
||||||
|
let spin_determinants =
|
||||||
|
Bitstring.permutations elec_num mo_num
|
||||||
|
|> List.filter (fun b -> Bitstring.logand neg_active_mask b = occ_mask)
|
||||||
|
|> Array.of_list
|
||||||
|
|> Array.map (fun b -> Spindeterminant.of_bitstring b)
|
||||||
|
in
|
||||||
|
{ elec_num ; mo_basis ; mo_class ; spin_determinants }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let pp ppf t =
|
||||||
|
Format.fprintf ppf "@[<v 2> [";
|
||||||
|
Array.iteri (fun i d ->
|
||||||
|
Format.fprintf ppf "@[<v>@[%8d@] @[%a@]@]@;" i Spindeterminant.pp d)
|
||||||
|
(spin_determinants t) ;
|
||||||
|
Format.fprintf ppf "]@]"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
46
ci/lib/spindeterminant_space.mli
Normal file
46
ci/lib/spindeterminant_space.mli
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
(**
|
||||||
|
The space built with determinants made with same-spin spinorbitals.
|
||||||
|
*)
|
||||||
|
|
||||||
|
type t
|
||||||
|
|
||||||
|
(** {1 Accessors} *)
|
||||||
|
|
||||||
|
val size : t -> int
|
||||||
|
(** Number of determinants in the space. *)
|
||||||
|
|
||||||
|
val spin_determinants : t -> Spindeterminant.t array
|
||||||
|
(** All the spin-determinants belonging to the space. *)
|
||||||
|
|
||||||
|
val elec_num : t -> int
|
||||||
|
(** Number of (same-spin) electrons occupying the MOs. *)
|
||||||
|
|
||||||
|
val mo_class : t -> Mo.Class.t
|
||||||
|
(** The MO classes used to generate the space. *)
|
||||||
|
|
||||||
|
val mo_basis : t -> Mo.Basis.t
|
||||||
|
(** The MO basis on which the determinants are expanded. *)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Creation} *)
|
||||||
|
|
||||||
|
val fci_of_mo_basis : frozen_core:Mo.Frozen_core.t -> Mo.Basis.t -> int -> t
|
||||||
|
(** Create a space of all possible ways to put [n_elec-ncore] electrons in the
|
||||||
|
[Active] MOs. All other MOs are untouched.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val cas_of_mo_basis : Mo.Basis.t -> frozen_core:Mo.Frozen_core.t-> int -> int -> int -> t
|
||||||
|
(** [cas_of_mo_basis mo_basis n_elec n m] creates a CAS(n,m) space of
|
||||||
|
[Active] MOs. The unoccupied MOs are [Virtual], and the occupied MOs
|
||||||
|
are [Core] and [Inactive].
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
(** {2 Printing} *)
|
||||||
|
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
111
ci/test/determinant.ml
Normal file
111
ci/test/determinant.ml
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
open Common
|
||||||
|
open Ci
|
||||||
|
|
||||||
|
let tests =
|
||||||
|
|
||||||
|
let test_creation () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ]
|
||||||
|
and l_b = [ 2 ; 3 ; 5 ; 65 ] in
|
||||||
|
let det = Determinant.of_lists 66 l_a l_b in
|
||||||
|
let z_a = Determinant.alfa det
|
||||||
|
and z_b = Determinant.beta det in
|
||||||
|
Alcotest.(check (list int )) "alfa" (Spindeterminant.to_list z_a) l_a;
|
||||||
|
Alcotest.(check (list int )) "beta" (Spindeterminant.to_list z_b) l_b;
|
||||||
|
Alcotest.(check bool) "phase" (Determinant.phase det = Phase.Pos) true;
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_phase () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 64 ; 5 ]
|
||||||
|
and l_b = [ 2 ; 3 ; 5 ; 65 ] in
|
||||||
|
let det = Determinant.of_lists 66 l_a l_b in
|
||||||
|
Alcotest.(check bool) "phase" (Determinant.phase det = Phase.Neg) true;
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 64 ; 5 ]
|
||||||
|
and l_b = [ 3 ; 2 ; 5 ; 65 ] in
|
||||||
|
let det = Determinant.of_lists 66 l_a l_b in
|
||||||
|
Alcotest.(check bool) "phase" (Determinant.phase det = Phase.Pos) true;
|
||||||
|
let l_a = [ 1 ; 3 ; 2 ; 64 ; 5 ]
|
||||||
|
and l_b = [ 3 ; 2 ; 5 ; 65 ] in
|
||||||
|
let det = Determinant.of_lists 66 l_a l_b in
|
||||||
|
Alcotest.(check bool) "phase" (Determinant.phase det = Phase.Neg) true;
|
||||||
|
let l_a = [ 1 ; 3 ; 2 ; 64 ; 5 ]
|
||||||
|
and l_b = [ 3 ; 2 ; 65 ; 5 ] in
|
||||||
|
let det = Determinant.of_lists 66 l_a l_b in
|
||||||
|
Alcotest.(check bool) "phase" (Determinant.phase det = Phase.Pos) true;
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_operators () =
|
||||||
|
let det =
|
||||||
|
let open Determinant in
|
||||||
|
let open Spin in
|
||||||
|
creation Alfa 1 @@ creation Alfa 3 @@ creation Alfa 2 @@ creation Alfa 5 @@
|
||||||
|
creation Beta 1 @@ creation Beta 3 @@ creation Beta 4 @@ creation Beta 5 @@ vac 10
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "creation 1" true
|
||||||
|
(det = Determinant.of_lists 10 [ 1 ; 3 ; 2 ; 5 ] [1 ; 3 ; 4 ; 5 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.single_excitation Spin.Alfa 3 6 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "single_exc 1" true
|
||||||
|
(det' = Determinant.of_lists 10 [ 1 ; 6 ; 2 ; 5 ] [1 ; 3 ; 4 ; 5 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.single_excitation Spin.Beta 3 6 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "single_exc 2" true
|
||||||
|
(det' = Determinant.of_lists 10 [ 1 ; 3 ; 2 ; 5 ] [1 ; 6 ; 4 ; 5 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.single_excitation Spin.Alfa 4 6 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "single_exc 3" true (Determinant.is_none det');
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.single_excitation Spin.Beta 1 5 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "single_exc 4" true (Determinant.is_none det');
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Alfa 3 6 Spin.Alfa 2 7 det
|
||||||
|
in
|
||||||
|
let det'' = Determinant.of_lists 10 [ 1 ; 6 ; 7 ; 5 ] [1 ; 3 ; 4 ; 5 ] in
|
||||||
|
Alcotest.(check bool) "double_exc 1" true (det' = det'');
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Beta 3 6 Spin.Beta 5 7 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "double_exc 2" true
|
||||||
|
(det' = Determinant.of_lists 10 [ 1 ; 3 ; 2 ; 5 ] [1 ; 6 ; 4 ; 7 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Alfa 3 6 Spin.Beta 5 7 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "double_exc 3" true
|
||||||
|
(det' = Determinant.of_lists 10 [ 1 ; 6 ; 2 ; 5 ] [1 ; 3 ; 4 ; 7 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Beta 5 7 Spin.Alfa 3 6 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "double_exc 4" true
|
||||||
|
(det' = Determinant.of_lists 10 [ 1 ; 6 ; 2 ; 5 ] [1 ; 3 ; 4 ; 7 ] );
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Alfa 4 6 Spin.Alfa 2 7 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "double_exc 5" true (Determinant.is_none det');
|
||||||
|
|
||||||
|
let det' =
|
||||||
|
Determinant.double_excitation Spin.Beta 1 5 Spin.Alfa 2 7 det
|
||||||
|
in
|
||||||
|
Alcotest.(check bool) "double_exc 6" true (Determinant.is_none det');
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
[
|
||||||
|
"Creation", `Quick, test_creation;
|
||||||
|
"Phase", `Quick, test_phase;
|
||||||
|
"Operators",`Quick, test_operators;
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
9
ci/test/dune
Normal file
9
ci/test/dune
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
(library
|
||||||
|
(name test_ci)
|
||||||
|
(synopsis "Test for ci library")
|
||||||
|
(libraries
|
||||||
|
alcotest
|
||||||
|
trexio
|
||||||
|
qcaml.ci
|
||||||
|
)
|
||||||
|
)
|
52
ci/test/excitation.ml
Normal file
52
ci/test/excitation.ml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
open Common
|
||||||
|
open Ci
|
||||||
|
|
||||||
|
let tests =
|
||||||
|
|
||||||
|
(*
|
||||||
|
let test_id () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ]
|
||||||
|
and l_b = [ 2 ; 3 ; 5 ; 65 ] in
|
||||||
|
let det1 = Determinant.of_lists l_a l_b in
|
||||||
|
let det2 = Determinant.negate_phase det1 in
|
||||||
|
in
|
||||||
|
*)
|
||||||
|
|
||||||
|
let test_single () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ]
|
||||||
|
and l_b = [ 2 ; 3 ; 5 ; 65 ] in
|
||||||
|
let det1 = Determinant.of_lists 66 l_a l_b in
|
||||||
|
let det2 = Determinant.single_excitation Spin.Alfa 3 7 det1 in
|
||||||
|
let t = Excitation.single_of_det det1 det2 in
|
||||||
|
Alcotest.(check bool) "single 1" true (t = Single (Phase.Pos, { hole=3 ; particle=7 ; spin=Spin.Alfa}) );
|
||||||
|
let det2 =
|
||||||
|
Determinant.single_excitation Spin.Alfa 2 7 det1
|
||||||
|
|> Determinant.negate_phase
|
||||||
|
in
|
||||||
|
let t = Excitation.single_of_det det1 det2 in
|
||||||
|
Alcotest.(check bool) "single 2" true (t = Single (Phase.Neg, { hole=2 ; particle=7 ; spin=Spin.Alfa }) );
|
||||||
|
let det2 = Determinant.single_excitation Spin.Beta 2 7 det1 in
|
||||||
|
let t = Excitation.single_of_det det1 det2 in
|
||||||
|
Alcotest.(check bool) "single 3" true (t = Single (Phase.Pos, { hole=2 ; particle=7 ; spin=Spin.Beta}) );
|
||||||
|
let det2 = Determinant.single_excitation Spin.Beta 3 256 det1 in
|
||||||
|
let t = Excitation.single_of_det det1 det2 in
|
||||||
|
Alcotest.(check bool) "single 4" true (t = Single (Phase.Pos, { hole=3 ; particle=256 ; spin=Spin.Beta}) );
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_double () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ]
|
||||||
|
and l_b = [ 2 ; 3 ; 5 ; 65 ] in
|
||||||
|
let det1 = Determinant.of_lists 66 l_a l_b in
|
||||||
|
let det2 = Determinant.double_excitation Spin.Alfa 3 7 Spin.Alfa 2 6 det1 in
|
||||||
|
let t = Excitation.double_of_det det1 det2 in
|
||||||
|
Alcotest.(check bool) "double 1" true
|
||||||
|
(t = Double (Phase.Neg,
|
||||||
|
{ hole=2 ; particle=7 ; spin=Spin.Alfa},
|
||||||
|
{ hole=3 ; particle=6 ; spin=Spin.Alfa}));
|
||||||
|
in
|
||||||
|
[
|
||||||
|
"Single", `Quick, test_single;
|
||||||
|
"Double", `Quick, test_double;
|
||||||
|
]
|
||||||
|
|
||||||
|
|
102
ci/test/spindeterminant.ml
Normal file
102
ci/test/spindeterminant.ml
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
open Alcotest
|
||||||
|
open Ci
|
||||||
|
open Ci.Spindeterminant
|
||||||
|
|
||||||
|
let tests =
|
||||||
|
|
||||||
|
let test_creation () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ] in
|
||||||
|
let det = of_list 10 l_a in
|
||||||
|
check (list int ) "bitstring 1" l_a (to_list det);
|
||||||
|
check bool "phase 2" true (phase det = Phase.Pos);
|
||||||
|
let l_b = [ 1 ; 3 ; 2 ; 5 ] in
|
||||||
|
let det = of_list 10 l_b in
|
||||||
|
check (list int ) "bitstring 2" l_a (to_list det);
|
||||||
|
check bool "phase 2" true (phase det = Phase.Neg);
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_a_operators () =
|
||||||
|
let det =
|
||||||
|
creation 5 @@ creation 2 @@ creation 2 @@ creation 1 @@ (vac 10)
|
||||||
|
in
|
||||||
|
check bool "none 1" true (is_none det);
|
||||||
|
|
||||||
|
let det =
|
||||||
|
creation 5 @@ creation 3 @@ creation 2 @@ creation 1 @@ (vac 10)
|
||||||
|
in
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ] in
|
||||||
|
check (list int) "bitstring 1" l_a (to_list det);
|
||||||
|
check bool "phase 1" true (phase det = Phase.Pos);
|
||||||
|
|
||||||
|
let det =
|
||||||
|
creation 1 @@ creation 3 @@ creation 2 @@ creation 5 @@ (vac 10)
|
||||||
|
in
|
||||||
|
check (list int) "bitstring 2" l_a (to_list det);
|
||||||
|
check bool "phase 2" true (phase det = Phase.Neg);
|
||||||
|
|
||||||
|
let l_b = [ 1 ; 3 ; 2 ; 5 ] in
|
||||||
|
let det = of_list 10 l_b in
|
||||||
|
check (list int ) "bitstring 3" l_a (to_list det);
|
||||||
|
check bool "phase 3" true (phase det = Phase.Neg);
|
||||||
|
|
||||||
|
check bool "none 1" true (annihilation 4 det |> is_none);
|
||||||
|
|
||||||
|
let det =
|
||||||
|
annihilation 1 det
|
||||||
|
in
|
||||||
|
check (list int ) "bitstring 4" (List.tl l_a) (to_list det);
|
||||||
|
check bool "phase 4" true (phase det = Phase.Neg);
|
||||||
|
|
||||||
|
let det =
|
||||||
|
annihilation 3 det
|
||||||
|
in
|
||||||
|
check (list int ) "bitstring 5" [ 2 ; 5 ] (to_list det);
|
||||||
|
check bool "phase 5" true (phase det = Phase.Pos);
|
||||||
|
|
||||||
|
let det =
|
||||||
|
annihilation 5 @@ annihilation 2 det
|
||||||
|
in
|
||||||
|
check (list int ) "bitstring 6" [] (to_list det);
|
||||||
|
check bool "phase 6" true (phase det = Phase.Pos);
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_exc_operators () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ] in
|
||||||
|
let det = of_list 10 l_a in
|
||||||
|
let l_b = [ 1 ; 7 ; 3 ; 5 ] in
|
||||||
|
let det2 = of_list 10 l_b in
|
||||||
|
Format.printf "%a@." pp det;
|
||||||
|
Format.printf "%a@." pp det2;
|
||||||
|
Format.printf "%a@." pp (Spindeterminant.single_excitation 2 7 det);
|
||||||
|
check bool "single 1" true (Spindeterminant.single_excitation 2 7 det = det2);
|
||||||
|
check bool "single 2" true (Spindeterminant.single_excitation 4 7 det |> is_none);
|
||||||
|
|
||||||
|
let l_c = [ 1 ; 7 ; 6 ; 5 ] in
|
||||||
|
let det3 = of_list 10 l_c in
|
||||||
|
check bool "double 1" true (double_excitation 2 7 3 6 det = det3);
|
||||||
|
check bool "double 2" true (double_excitation 4 7 3 6 det |> is_none);
|
||||||
|
in
|
||||||
|
|
||||||
|
let test_exc_spindet () =
|
||||||
|
let l_a = [ 1 ; 2 ; 3 ; 5 ] in
|
||||||
|
let det = of_list 10 l_a in
|
||||||
|
let l_b = [ 1 ; 7 ; 3 ; 5 ] in
|
||||||
|
let det2 = of_list 10 l_b in
|
||||||
|
check int "single" 1 (excitation_level det det2);
|
||||||
|
check (list int) "holes" [2] (holes_of det det2);
|
||||||
|
check (list int) "particles" [7] (particles_of det det2);
|
||||||
|
let l_b = [ 1 ; 7 ; 3 ; 6 ] in
|
||||||
|
let det2 = of_list 10 l_b in
|
||||||
|
check int "double" 2 (excitation_level det det2);
|
||||||
|
check (list int) "holes" [2 ; 5] (holes_of det det2);
|
||||||
|
check (list int) "particles" [6 ; 7] (particles_of det det2);
|
||||||
|
in
|
||||||
|
[
|
||||||
|
"Creation", `Quick, test_creation;
|
||||||
|
"Creation/Annihilation Operators", `Quick, test_a_operators;
|
||||||
|
"Excitation Operators", `Quick, test_exc_operators;
|
||||||
|
"Excitation of spindet", `Quick, test_exc_spindet;
|
||||||
|
]
|
||||||
|
|
||||||
|
|
204
examples/ex_trexio_integrals.org
Normal file
204
examples/ex_trexio_integrals.org
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#+TITLE: Integrals
|
||||||
|
|
||||||
|
#+PROPERTY
|
||||||
|
|
||||||
|
In this example, we write a program that reads the geometry of a
|
||||||
|
molecule in =xyz= format and a Gaussian atomic basis set in GAMESS
|
||||||
|
format. The output is written in a trexio file.
|
||||||
|
|
||||||
|
* Header
|
||||||
|
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
module Command_line = Qcaml.Common.Command_line
|
||||||
|
module Util = Qcaml.Common.Util
|
||||||
|
open Qcaml.Linear_algebra
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: module Command_line = Qcaml.Common.Command_line
|
||||||
|
: module Util = Qcaml.Common.Util
|
||||||
|
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let () =
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Command-line arguments
|
||||||
|
|
||||||
|
We use the =Command_line= module to define the following possible
|
||||||
|
arguments:
|
||||||
|
- =-b --basis= : The name of the file containing the basis set
|
||||||
|
- =-x --xyz= : The name of the file containing the atomic coordinates
|
||||||
|
- =-u --range-separation= : The value of $\mu$, the range-separation
|
||||||
|
parameter in range-separated DFT. If this option is not present,
|
||||||
|
no output file will be generated for the range-separated integrals.
|
||||||
|
|
||||||
|
** Definition
|
||||||
|
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let open Command_line in
|
||||||
|
begin
|
||||||
|
set_header_doc (Sys.argv.(0));
|
||||||
|
set_description_doc "Computes the one- and two-electron integrals on the Gaussian atomic basis set.";
|
||||||
|
set_specs
|
||||||
|
[ { short='b' ; long="basis" ; opt=Mandatory;
|
||||||
|
arg=With_arg "<string>";
|
||||||
|
doc="Name of the file containing the basis set"; } ;
|
||||||
|
|
||||||
|
{ short='x' ; long="xyz" ; opt=Mandatory;
|
||||||
|
arg=With_arg "<string>";
|
||||||
|
doc="Name of the file containing the nuclear coordinates in xyz format"; } ;
|
||||||
|
|
||||||
|
{ short='u' ; long="range-separation" ; opt=Optional;
|
||||||
|
arg=With_arg "<float>";
|
||||||
|
doc="Range-separation parameter."; } ;
|
||||||
|
]
|
||||||
|
end;
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
** Interpretation
|
||||||
|
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let basis_file = Util.of_some @@ Command_line.get "basis" in
|
||||||
|
let nuclei_file = Util.of_some @@ Command_line.get "xyz" in
|
||||||
|
|
||||||
|
let range_separation =
|
||||||
|
match Command_line.get "range-separation" with
|
||||||
|
| None -> None
|
||||||
|
| Some mu -> Some (float_of_string mu)
|
||||||
|
in
|
||||||
|
|
||||||
|
let operators =
|
||||||
|
match range_separation with
|
||||||
|
| None -> []
|
||||||
|
| Some mu -> [ Qcaml.Operators.Operator.of_range_separation mu ]
|
||||||
|
in
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Computation
|
||||||
|
We first read the =xyz= file to create a molecule:
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let nuclei =
|
||||||
|
Qcaml.Particles.Nuclei.of_xyz_file nuclei_file
|
||||||
|
in
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Then we create an Gaussian AO basis using the atomic coordinates,
|
||||||
|
and we optionally introduce the range-separation parameter via the
|
||||||
|
=operators=:
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let ao_basis =
|
||||||
|
Qcaml.Ao.Basis.of_nuclei_and_basis_filename ~kind:`Gaussian
|
||||||
|
~operators ~cartesian:true ~nuclei basis_file
|
||||||
|
in
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
We compute the required one-electron integrals:
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let overlap = Qcaml.Ao.Basis.overlap ao_basis in
|
||||||
|
let eN_ints = Qcaml.Ao.Basis.eN_ints ao_basis in
|
||||||
|
let kin_ints = Qcaml.Ao.Basis.kin_ints ao_basis in
|
||||||
|
let multipole = Qcaml.Ao.Basis.multipole ao_basis in
|
||||||
|
let x_mat = multipole "x" in
|
||||||
|
let y_mat = multipole "y" in
|
||||||
|
let z_mat = multipole "z" in
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
and the two-electron integrals (1/r and long range):
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
let ee_ints = Qcaml.Ao.Basis.ee_ints ao_basis in
|
||||||
|
let lr_ints =
|
||||||
|
match range_separation with
|
||||||
|
| Some _mu -> Some (Qcaml.Ao.Basis.ee_lr_ints ao_basis)
|
||||||
|
| None -> None
|
||||||
|
in
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Output
|
||||||
|
|
||||||
|
We write the one-electron integrals:
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
Matrix.to_file ~filename:"overlap.dat" ~sym:true overlap;
|
||||||
|
Matrix.to_file ~filename:"eN.dat" ~sym:true eN_ints;
|
||||||
|
Matrix.to_file ~filename:"kinetic.dat" ~sym:true kin_ints;
|
||||||
|
Matrix.to_file ~filename:"x.dat" ~sym:true x_mat;
|
||||||
|
Matrix.to_file ~filename:"y.dat" ~sym:true y_mat;
|
||||||
|
Matrix.to_file ~filename:"z.dat" ~sym:true z_mat;
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
and the the two-electron integrals:
|
||||||
|
#+BEGIN_SRC ocaml :comments link :exports code :tangle ex_integrals.ml
|
||||||
|
Four_idx_storage.to_file ~filename:"eri.dat" ee_ints;
|
||||||
|
match lr_ints with
|
||||||
|
| Some integrals -> Four_idx_storage.to_file ~filename:"eri_lr.dat" integrals;
|
||||||
|
| None -> ()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
|
* Interactive test :noexport:
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
#require "qcaml.top" ;;
|
||||||
|
#require "trexio" ;;
|
||||||
|
open Qcaml ;;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
:results:
|
||||||
|
:end:
|
||||||
|
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
let nuclei_file = "/dev/shm/f2.xyz"
|
||||||
|
let nuclei =
|
||||||
|
Qcaml.Particles.Nuclei.of_xyz_file nuclei_file
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
:results:
|
||||||
|
val nuclei_file : string = "/dev/shm/f2.xyz"
|
||||||
|
val nuclei : Qcaml.Particles.Nuclei.t =
|
||||||
|
|
||||||
|
Nuclear Coordinates (Angstrom)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Center Atomic Element Coordinates (Angstroms)
|
||||||
|
Number X Y Z
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
1 9 F 0.000000 0.000000 0.000000
|
||||||
|
2 9 F 0.000000 0.000000 1.411900
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
:end:
|
||||||
|
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
let trexio_file = Trexio.open_file "test.trexio" 'w' Trexio.HDF5
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
:results:
|
||||||
|
val trexio_file : Trexio.trexio_file = <abstr>
|
||||||
|
:end:
|
||||||
|
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
Qcaml.Particles.Nuclei.to_trexio trexio_file nuclei;;
|
||||||
|
Trexio.close_file trexio_file;;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
:results:
|
||||||
|
- : unit = ()
|
||||||
|
:end:
|
||||||
|
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
let basis_file = "/home/scemama/qp2/data/basis/cc-pvdz";;
|
||||||
|
let ao_basis =
|
||||||
|
Qcaml.Ao.Basis.of_nuclei_and_basis_filename ~nuclei basis_file
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
:results:
|
||||||
|
val ao_basis : Qcaml.Ao.Basis.t = Gaussian Basis, spherical, 30 AOs
|
||||||
|
:end:
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src ocaml :results drawer :session :cache no :exports none
|
||||||
|
Trexio.close_file trexio_file;;
|
||||||
|
#+end_src
|
@ -7,6 +7,7 @@
|
|||||||
)
|
)
|
||||||
(libraries
|
(libraries
|
||||||
qcaml.ao
|
qcaml.ao
|
||||||
|
qcaml.ci
|
||||||
qcaml.common
|
qcaml.common
|
||||||
qcaml.gaussian
|
qcaml.gaussian
|
||||||
qcaml.gaussian_integrals
|
qcaml.gaussian_integrals
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
(* Auto-generated by qcaml/README.org *)
|
|
||||||
module Ao = Ao
|
module Ao = Ao
|
||||||
|
module Ci = Ci
|
||||||
module Common = Common
|
module Common = Common
|
||||||
module Gaussian = Gaussian
|
module Gaussian = Gaussian
|
||||||
module Gaussian_integrals = Gaussian_integrals
|
module Gaussian_integrals = Gaussian_integrals
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
test_gaussian_integrals
|
test_gaussian_integrals
|
||||||
test_ao
|
test_ao
|
||||||
test_mo
|
test_mo
|
||||||
|
test_ci
|
||||||
test_perturbation
|
test_perturbation
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -14,6 +14,9 @@ let test_suites: unit Alcotest.test list = [
|
|||||||
"Mo.Guess", Test_mo.Guess.tests;
|
"Mo.Guess", Test_mo.Guess.tests;
|
||||||
"Mo.Hartree_Fock", Test_mo.Hf.tests;
|
"Mo.Hartree_Fock", Test_mo.Hf.tests;
|
||||||
"Perturbation.Mp2", Test_perturbation.Mp2.tests;
|
"Perturbation.Mp2", Test_perturbation.Mp2.tests;
|
||||||
|
"Ci.Spindeterminant", Test_ci.Spindeterminant.tests;
|
||||||
|
"Ci.Determinant", Test_ci.Determinant.tests;
|
||||||
|
"Ci.Excitation", Test_ci.Excitation.tests;
|
||||||
]
|
]
|
||||||
|
|
||||||
let () = Alcotest.run "QCaml" test_suites
|
let () = Alcotest.run "QCaml" test_suites
|
||||||
|
Loading…
Reference in New Issue
Block a user