2014-08-24 20:00:26 +02:00
|
|
|
open Core.Std ;;
|
|
|
|
open Qptypes ;;
|
|
|
|
|
|
|
|
exception MultiplicityError of string;;
|
|
|
|
|
|
|
|
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 ;
|
2014-10-25 21:24:21 +02:00
|
|
|
} with 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 } =
|
2015-11-17 22:25:26 +01:00
|
|
|
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
|
2014-10-07 19:33:11 +02:00
|
|
|
Charge.of_float (nucl_charge nuclei -. (Float.of_int result))
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2014-08-24 20:00:26 +02:00
|
|
|
|
2014-08-26 14:39:23 +02:00
|
|
|
let get_multiplicity m =
|
2015-11-17 22:25:26 +01:00
|
|
|
let elec_alpha =
|
|
|
|
m.elec_alpha
|
|
|
|
in
|
2014-10-21 23:23:37 +02:00
|
|
|
Multiplicity.of_alpha_beta elec_alpha m.elec_beta
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2014-08-24 20:00:26 +02:00
|
|
|
|
2014-08-27 16:38:13 +02:00
|
|
|
let get_nucl_num m =
|
2015-11-17 22:25:26 +01:00
|
|
|
let nmax =
|
|
|
|
List.length m.nuclei
|
|
|
|
in
|
2014-10-30 16:26:31 +01:00
|
|
|
Nucl_number.of_int nmax ~max:nmax
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2014-08-27 16:38:13 +02:00
|
|
|
|
2014-08-24 20:00:26 +02:00
|
|
|
let name m =
|
2015-11-17 22:25:26 +01:00
|
|
|
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
|
2015-11-17 22:25:26 +01:00
|
|
|
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
|
|
|
|
match (List.Assoc.find accu e) with
|
|
|
|
| None -> build_list (List.Assoc.add accu e 1) rest
|
|
|
|
| Some i -> build_list (List.Assoc.add accu e (i+1)) rest
|
|
|
|
end
|
|
|
|
| [] -> accu
|
|
|
|
in
|
|
|
|
let rec build_name accu = function
|
|
|
|
| (a, n)::rest ->
|
2015-11-17 22:25:26 +01:00
|
|
|
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
|
2015-11-17 22:25:26 +01:00
|
|
|
let result =
|
|
|
|
build_list [] nuclei |> build_name [c ; ", " ; mult]
|
2014-08-24 20:00:26 +02:00
|
|
|
in
|
|
|
|
String.concat (result)
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2014-08-24 20:00:26 +02:00
|
|
|
|
2016-03-22 13:28:03 +01:00
|
|
|
let to_string_general ~f m =
|
2015-11-17 22:25:26 +01:00
|
|
|
let { nuclei ; elec_alpha ; elec_beta } = m
|
|
|
|
in
|
|
|
|
let n =
|
|
|
|
List.length nuclei
|
|
|
|
in
|
|
|
|
let title =
|
|
|
|
name m
|
|
|
|
in
|
2016-03-22 13:28:03 +01:00
|
|
|
[ Int.to_string n ; title ] @ (List.map ~f nuclei)
|
2014-08-26 14:39:23 +02:00
|
|
|
|> String.concat ~sep:"\n"
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2016-03-22 13:28:03 +01:00
|
|
|
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
|
2014-10-26 17:29:11 +01:00
|
|
|
?(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 =
|
2014-08-24 20:00:26 +02:00
|
|
|
let l = String.split s ~on:'\n'
|
|
|
|
|> List.filter ~f:(fun x -> x <> "")
|
2014-09-18 17:01:43 +02:00
|
|
|
|> List.map ~f:(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
|
2014-10-26 17:29:11 +01:00
|
|
|
) + 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
|
2015-11-17 22:25:26 +01:00
|
|
|
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
|
2015-11-17 22:25:26 +01:00
|
|
|
|
2014-08-26 14:39:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
let of_xyz_file
|
2014-10-26 17:29:11 +01:00
|
|
|
?(charge=(Charge.of_int 0)) ?(multiplicity=(Multiplicity.of_int 1))
|
|
|
|
?(units=Units.Angstrom)
|
2014-08-26 14:39:23 +02:00
|
|
|
filename =
|
|
|
|
let (_,buffer) = In_channel.read_all filename
|
|
|
|
|> String.lsplit2_exn ~on:'\n' in
|
|
|
|
let (_,buffer) = String.lsplit2_exn buffer ~on:'\n' in
|
2016-09-08 22:37:05 +02:00
|
|
|
of_xyz_string ~charge ~multiplicity ~units buffer
|
2014-10-26 17:29:11 +01:00
|
|
|
|
2015-11-17 22:25:26 +01:00
|
|
|
|
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 =
|
|
|
|
In_channel.read_all filename
|
|
|
|
|> 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
|
|
|
|
with _ ->
|
|
|
|
of_zmt_file ~charge ~multiplicity ~units filename
|
|
|
|
|
2015-11-17 22:25:26 +01:00
|
|
|
|
|
|
|
let distance_matrix molecule =
|
|
|
|
let coord =
|
|
|
|
molecule.nuclei
|
|
|
|
|> List.map ~f:(fun x -> x.Atom.coord)
|
|
|
|
|> Array.of_list
|
|
|
|
in
|
|
|
|
let n =
|
|
|
|
Array.length coord
|
|
|
|
in
|
|
|
|
let result =
|
|
|
|
Array.make_matrix ~dimx:n ~dimy: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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
include To_md5
|
2014-10-26 17:29:11 +01:00
|
|
|
let to_md5 = to_md5 sexp_of_t
|
2015-11-17 22:25:26 +01:00
|
|
|
|