10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-06-16 18:25:20 +02:00
QCaml/particles/lib/nuclei.ml

205 lines
4.6 KiB
OCaml
Raw Normal View History

2024-02-28 10:34:39 +01:00
(** Type *)
2020-10-09 09:47:57 +02:00
open Common
2018-02-13 17:36:25 +01:00
2018-01-19 03:14:06 +01:00
type t = (Element.t * Coordinate.t) array
2020-12-29 18:06:54 +01:00
open Xyz_ast
2024-02-28 10:34:39 +01:00
(** Conversion *)
2018-01-17 15:56:57 +01:00
2020-04-16 19:49:23 +02:00
let of_xyz_lexbuf lexbuf =
2023-04-24 19:01:42 +02:00
let data =
2018-02-13 17:36:25 +01:00
Xyz_parser.input Nuclei_lexer.read_all lexbuf
in
let len = List.length data.nuclei in
if len <> data.number_of_atoms then
2023-04-24 19:01:42 +02:00
Printf.sprintf "Error: expected %d atoms but %d read"
2018-02-13 17:36:25 +01:00
data.number_of_atoms len
|> failwith;
List.map (fun nucleus ->
nucleus.element, Coordinate.angstrom_to_bohr nucleus.coord
) data.nuclei
|> Array.of_list
2018-01-17 15:56:57 +01:00
2023-04-24 19:01:42 +02:00
let of_xyz_string input_string =
2020-04-16 19:49:23 +02:00
Lexing.from_string input_string
|> of_xyz_lexbuf
let of_xyz_file filename =
let ic = open_in filename in
let lexbuf =
Lexing.from_channel ic
in
2023-04-24 19:01:42 +02:00
let result =
2020-04-16 19:49:23 +02:00
of_xyz_lexbuf lexbuf
in
close_in ic;
result
2018-01-17 15:56:57 +01:00
2018-06-29 16:04:40 +02:00
let of_zmt_string buffer =
Zmatrix.of_string buffer
|> Zmatrix.to_xyz
|> Array.map (fun (e,x,y,z) ->
2020-12-29 18:06:54 +01:00
(e, Coordinate.(angstrom_to_bohr @@ make_angstrom { x ; y ; z} ))
)
2018-06-29 16:04:40 +02:00
2018-03-03 22:13:14 +01:00
let of_zmt_file filename =
2018-01-17 15:56:57 +01:00
let ic = open_in filename in
let rec aux accu =
try
let line = input_line ic in
aux (line::accu)
with End_of_file ->
close_in ic;
List.rev accu
|> String.concat "\n"
in aux []
2020-12-29 18:06:54 +01:00
|> of_zmt_string
2018-02-09 00:37:25 +01:00
2018-01-18 17:39:10 +01:00
let to_string atoms =
2020-12-29 18:06:54 +01:00
"
2018-01-18 17:39:10 +01:00
Nuclear Coordinates (Angstrom)
------------------------------
-----------------------------------------------------------------------
Center Atomic Element Coordinates (Angstroms)
Number X Y Z
-----------------------------------------------------------------------
" ^
2020-12-29 18:06:54 +01:00
(Array.mapi (fun i (e, coord) ->
let open Coordinate in
let coord =
bohr_to_angstrom coord
in
Printf.sprintf " %5d %5d %5s %12.6f %12.6f %12.6f"
2023-04-24 19:01:42 +02:00
(i+1) (Element.to_int e) (Element.to_string e)
2020-12-29 18:06:54 +01:00
coord.x coord.y coord.z
) atoms
|> Array.to_list
|> String.concat "\n" ) ^
"
2018-01-18 17:39:10 +01:00
-----------------------------------------------------------------------
"
2018-03-03 22:13:14 +01:00
let of_filename filename =
2020-12-29 18:06:54 +01:00
of_xyz_file filename
let to_xyz_string t =
[ string_of_int (Array.length t) ; "" ] @
( Array.map (fun (e, coord) ->
let open Coordinate in
let coord =
bohr_to_angstrom coord
in
Printf.sprintf " %5s %12.6f %12.6f %12.6f"
(Element.to_string e) coord.x coord.y coord.z
2023-04-24 19:01:42 +02:00
) t
2020-12-29 18:06:54 +01:00
|> Array.to_list )
|> String.concat "\n"
2024-02-28 10:34:39 +01:00
(** Query *)
2020-12-29 18:06:54 +01:00
2021-01-01 11:46:11 +01:00
let formula t =
let dict = Hashtbl.create 67 in
Array.iter (fun (e,_) ->
let e = Element.to_string e in
let value =
try (Hashtbl.find dict e) + 1
with Not_found -> 1
in
Hashtbl.replace dict e value
) t;
Hashtbl.to_seq_keys dict
|> List.of_seq
|> List.sort String.compare
|> List.fold_left (fun accu key ->
let x = Hashtbl.find dict key in
accu ^ key ^ "_{" ^ (string_of_int x) ^ "}") ""
2023-04-24 19:01:42 +02:00
2018-03-03 22:13:14 +01:00
let repulsion nuclei =
2023-04-24 19:01:42 +02:00
let get_charge e =
2018-02-20 23:54:48 +01:00
Element.to_charge e
|> Charge.to_float
in
2023-04-24 19:01:42 +02:00
Array.fold_left ( fun accu (e1, coord1) ->
accu +.
2018-02-20 23:54:48 +01:00
Array.fold_left (fun accu (e2, coord2) ->
let r = Coordinate.(norm (coord1 |- coord2)) in
if r > 0. then
2020-12-29 18:06:54 +01:00
accu +. 0.5 *. (get_charge e2) *. (get_charge e1) /. r
2018-02-20 23:54:48 +01:00
else accu
2020-12-29 18:06:54 +01:00
) 0. nuclei
) 0. nuclei
2018-02-20 23:54:48 +01:00
2018-03-03 22:13:14 +01:00
2023-04-24 19:01:42 +02:00
let charge nuclei =
2018-03-03 22:13:14 +01:00
Array.fold_left (fun accu (e, _) -> accu + Charge.to_int (Element.to_charge e) )
2023-04-24 19:01:42 +02:00
0 nuclei
2018-03-03 22:13:14 +01:00
|> Charge.of_int
2018-06-29 16:04:40 +02:00
2023-04-24 19:01:42 +02:00
let small_core a =
2018-07-04 18:08:38 +02:00
Array.fold_left (fun accu (e,_) -> accu + (Element.small_core e)) 0 a
2023-04-24 19:01:42 +02:00
let large_core a =
2020-12-29 18:06:54 +01:00
Array.fold_left (fun accu (e,_) -> accu + (Element.large_core e)) 0 a
2023-04-24 14:13:36 +02:00
2024-02-28 10:34:39 +01:00
(** Read *)
2023-04-24 19:01:42 +02:00
let of_trexio f =
let num = Trexio.read_nucleus_num f in
let charge = Trexio.read_nucleus_charge f
|> Array.map Charge.of_float in
let coord = Trexio.read_nucleus_coord f in
Array.init num (fun i ->
let coord = Coordinate.{ x = coord.(3*i) ;
y = coord.(3*i+1) ;
z = coord.(3*i+2) } in
(Element.of_charge charge.(i), Coordinate.make coord)
)
2024-02-28 10:34:39 +01:00
(** Write *)
2023-04-24 14:13:36 +02:00
let to_trexio f t =
let num = Array.length t in
Trexio.write_nucleus_num f num;
2023-04-24 19:01:42 +02:00
Array.map (fun (e, _) -> Element.to_charge e |> Charge.to_float) t
2023-04-24 14:13:36 +02:00
|> Trexio.write_nucleus_charge f;
2023-04-24 19:01:42 +02:00
2023-04-24 14:13:36 +02:00
Array.map (fun (e, _) -> Element.to_string e) t
|> Trexio.write_nucleus_label f;
let coord = Array.init (num*3) (fun _ -> 0.) in
Array.iteri (fun i (_, xyz) ->
coord.(3*i) <- Coordinate.(get X xyz) ;
coord.(3*i+1) <- Coordinate.(get Y xyz) ;
coord.(3*i+2) <- Coordinate.(get Z xyz) ) t;
Trexio.write_nucleus_coord f coord;
2023-04-24 19:01:42 +02:00
2023-04-24 14:13:36 +02:00
repulsion t
|> Trexio.write_nucleus_repulsion f
2020-12-29 18:06:54 +01:00
2024-02-28 10:34:39 +01:00
(** Printers *)
2020-12-29 18:06:54 +01:00
let pp ppf t =
Format.fprintf ppf "@[%s@]" (to_string t)
2024-02-28 10:34:39 +01:00