10
0
mirror of https://github.com/LCPQ/quantum_package synced 2024-12-23 12:56:14 +01:00
quantum_package/ocaml/Molecule.ml

214 lines
4.6 KiB
OCaml
Raw Normal View History

2017-08-18 18:28:33 +02:00
open Qptypes
open Sexplib.Std
2014-08-24 20:00:26 +02:00
2017-08-18 18:28:33 +02:00
exception MultiplicityError of string
exception XYZError
2014-08-24 20:00:26 +02:00
type t = {
nuclei : Atom.t list ;
2014-10-23 14:42:14 +02:00
elec_alpha : Elec_alpha_number.t ;
elec_beta : Elec_beta_number.t ;
2017-08-18 18:28:33 +02:00
} [@@deriving sexp]
2014-08-24 20:00:26 +02:00
2014-08-26 14:39:23 +02:00
let get_charge { nuclei ; elec_alpha ; elec_beta } =
let result =
(Elec_alpha_number.to_int elec_alpha) +
(Elec_beta_number.to_int elec_beta)
in
2014-08-24 20:00:26 +02:00
let rec nucl_charge = function
2014-10-07 19:33:11 +02:00
| a::rest -> (Charge.to_float a.Atom.charge) +. nucl_charge rest
2014-08-24 20:00:26 +02:00
| [] -> 0.
in
2017-08-18 18:28:33 +02:00
Charge.of_float (nucl_charge nuclei -. (float_of_int result))
2014-08-24 20:00:26 +02:00
2014-08-26 14:39:23 +02:00
let get_multiplicity m =
let elec_alpha =
m.elec_alpha
in
2014-10-21 23:23:37 +02:00
Multiplicity.of_alpha_beta elec_alpha m.elec_beta
2014-08-24 20:00:26 +02:00
2014-08-27 16:38:13 +02:00
let get_nucl_num m =
let nmax =
List.length m.nuclei
in
2014-10-30 16:26:31 +01:00
Nucl_number.of_int nmax ~max:nmax
2014-08-27 16:38:13 +02:00
2014-08-24 20:00:26 +02:00
let name m =
let cm =
get_charge m
|> Charge.to_int
in
2014-08-24 20:00:26 +02:00
let c =
match cm with
| 0 -> ""
| 1 -> " (+)"
| (-1) -> " (-)"
| i when i>1 -> Printf.sprintf " (%d+)" i
| i -> Printf.sprintf " (%d-)" (-i)
in
let mult =
get_multiplicity m
|> Multiplicity.to_string
in
let { nuclei ; elec_alpha ; elec_beta } = m
in
2014-08-24 20:00:26 +02:00
let rec build_list accu = function
| a::rest ->
begin
let e = a.Atom.element in
2017-08-18 18:28:33 +02:00
try
let i = List.assoc e accu in
build_list ( (e,i+1)::(List.remove_assoc e accu) ) rest
with Not_found -> build_list ( (e,1)::accu ) rest
2014-08-24 20:00:26 +02:00
end
| [] -> accu
in
let rec build_name accu = function
| (a, n)::rest ->
let a =
Element.to_string a
in
2014-08-24 20:00:26 +02:00
begin
match n with
| 1 -> build_name (a::accu) rest
| i when i>1 ->
let tmp = Printf.sprintf "%s%d" a i
in build_name (tmp::accu) rest
| _ -> assert false
end
| [] -> accu
in
let result =
build_list [] nuclei |> build_name [c ; ", " ; mult]
2014-08-24 20:00:26 +02:00
in
2017-08-18 18:28:33 +02:00
String.concat "" result
2014-08-24 20:00:26 +02:00
let to_string_general ~f m =
let { nuclei ; elec_alpha ; elec_beta } = m
in
let n =
List.length nuclei
in
let title =
name m
in
2017-08-18 18:28:33 +02:00
[ string_of_int n ; title ] @ (List.map f nuclei)
|> String.concat "\n"
let to_string =
to_string_general ~f:(fun x -> Atom.to_string Units.Angstrom x)
let to_xyz =
to_string_general ~f:Atom.to_xyz
2014-08-24 20:00:26 +02:00
2014-08-26 14:39:23 +02:00
let of_xyz_string
?(charge=(Charge.of_int 0)) ?(multiplicity=(Multiplicity.of_int 1))
2014-10-07 19:33:11 +02:00
?(units=Units.Angstrom)
2014-08-26 14:39:23 +02:00
s =
2017-08-18 18:28:33 +02:00
let l = String_ext.split s ~on:'\n'
|> List.filter (fun x -> x <> "")
|> List.map (fun x -> Atom.of_string units x)
2014-08-24 20:00:26 +02:00
in
2014-08-26 14:39:23 +02:00
let ne = ( get_charge {
2014-08-24 20:00:26 +02:00
nuclei=l ;
2014-10-23 14:42:14 +02:00
elec_alpha=(Elec_alpha_number.of_int 1) ;
elec_beta=(Elec_beta_number.of_int 0) }
2014-10-07 19:33:11 +02:00
|> Charge.to_int
) + 1 - (Charge.to_int charge)
2014-10-23 14:42:14 +02:00
|> Elec_number.of_int
2014-08-24 20:00:26 +02:00
in
let (na,nb) =
Multiplicity.to_alpha_beta ne multiplicity
in
2014-08-24 20:00:26 +02:00
let result =
{ nuclei = l ;
2014-10-23 14:42:14 +02:00
elec_alpha = na ;
elec_beta = nb }
2014-08-24 20:00:26 +02:00
in
2014-08-26 14:39:23 +02:00
if ((get_multiplicity result) <> multiplicity) then
2014-08-24 20:00:26 +02:00
let msg = Printf.sprintf
"With %d electrons multiplicity %d is impossible"
2014-10-23 14:42:14 +02:00
(Elec_number.to_int ne)
2014-08-26 14:39:23 +02:00
(Multiplicity.to_int multiplicity)
2014-08-24 20:00:26 +02:00
in
raise (MultiplicityError msg);
else () ;
result
2014-08-26 14:39:23 +02:00
let of_xyz_file
?(charge=(Charge.of_int 0)) ?(multiplicity=(Multiplicity.of_int 1))
?(units=Units.Angstrom)
2014-08-26 14:39:23 +02:00
filename =
2017-08-18 18:28:33 +02:00
let lines =
match Io_ext.input_lines filename with
| natoms :: title :: rest ->
begin
try
if (int_of_string @@ String_ext.strip natoms) <= 0 then
raise XYZError
with
| _ -> raise XYZError
end;
String.concat "\n" rest
2017-09-11 23:37:31 +02:00
| _ -> raise XYZError
2017-08-18 18:28:33 +02:00
in
of_xyz_string ~charge:charge ~multiplicity:multiplicity
~units:units lines
2016-09-08 22:37:05 +02:00
let of_zmt_file
?(charge=(Charge.of_int 0)) ?(multiplicity=(Multiplicity.of_int 1))
?(units=Units.Angstrom)
filename =
2017-08-18 18:28:33 +02:00
Io_ext.read_all filename
2016-09-08 22:37:05 +02:00
|> Zmatrix.of_string
|> Zmatrix.to_xyz_string
|> of_xyz_string ~charge ~multiplicity ~units
let of_file
?(charge=(Charge.of_int 0)) ?(multiplicity=(Multiplicity.of_int 1))
?(units=Units.Angstrom)
filename =
try
of_xyz_file ~charge ~multiplicity ~units filename
2017-05-30 23:27:25 +02:00
with XYZError ->
2016-09-08 22:37:05 +02:00
of_zmt_file ~charge ~multiplicity ~units filename
let distance_matrix molecule =
let coord =
molecule.nuclei
2017-08-18 18:28:33 +02:00
|> List.map (fun x -> x.Atom.coord)
|> Array.of_list
in
let n =
Array.length coord
in
let result =
2017-08-18 18:28:33 +02:00
Array.make_matrix n n 0.
in
for i = 0 to (n-1)
do
for j = 0 to (n-1)
do
result.(i).(j) <- Point3d.distance coord.(i) coord.(j)
done;
done;
result
2017-08-18 18:28:33 +02:00
open Core ;;
include To_md5
let to_md5 = to_md5 sexp_of_t