(** General basis set read from a file *) type primitive = { exponent : float ; coefficient: float ; } type general_contracted_shell = AngularMomentum.t * (primitive array) type element_basis = Element.t * (general_contracted_shell array) type t = element_basis list exception No_shell exception Malformed_shell of string let read_shell line_stream = try let shell, n = try let line = Stream.next line_stream in if String.trim line = "$END" then raise End_of_file; Scanf.sscanf line " %c %d " (fun shell n -> shell, n) with | End_of_file -> raise No_shell | Stream.Failure -> raise No_shell | Scanf.Scan_failure m -> raise (Malformed_shell m) in let rec loop = function | 0 -> [] | i -> let contraction = let line = Stream.next line_stream in try Scanf.sscanf line " %_d %f %f " (fun exponent coefficient -> { exponent ; coefficient }) with _ -> raise (Malformed_shell (Printf.sprintf "Expected %d %c contractions, error at contraction %d:\n%s" n shell (n-i+1) line)) in contraction :: loop (pred i) in Some (AngularMomentum.of_char shell, Array.of_list (loop n)) with | No_shell -> None let read_element line_stream = try let line = Stream.next line_stream in let element = Scanf.sscanf line " %s " Element.of_string in let rec loop () = match read_shell line_stream with | Some shell -> shell :: loop () | None -> [] in Some (element, Array.of_list (loop ()) ) with | Stream.Failure -> None let read_stream line_stream = let rec loop accu = try match read_element line_stream with | Some e -> loop (e :: accu) | None -> accu with Element.ElementError _ -> loop accu in loop [] let read filename = let ic = open_in filename in let line_stream = Stream.from (fun _ -> try Some (input_line ic) with End_of_file -> None ) in let result = read_stream line_stream in close_in ic; result let combine basis_list = let h = Hashtbl.create 63 in List.concat basis_list |> List.iter (fun (k,v) -> let l = Hashtbl.find_all h k in Hashtbl.replace h k (Array.concat (l@[v]) ) ) ; Hashtbl.fold (fun k v accu -> (k, v)::accu) h [] let read_many filenames = List.map read filenames |> combine let string_of_primitive ?id prim = match id with | None -> (string_of_float prim.exponent)^" "^(string_of_float prim.coefficient) | Some i -> (string_of_int i)^" "^(string_of_float prim.exponent)^" "^(string_of_float prim.coefficient) let string_of_contracted_shell (angular_momentum, prim_array) = let n = Array.length prim_array in Printf.sprintf "%s %d\n%s" (AngularMomentum.to_string angular_momentum) n (Array.init n (fun i -> string_of_primitive ~id:(i+1) prim_array.(i)) |> Array.to_list |> String.concat "\n") let string_of_contracted_shell_array a = Array.map string_of_contracted_shell a |> Array.to_list |> String.concat "\n" let to_string (name, contracted_shell_array) = Printf.sprintf "%s\n%s" name (string_of_contracted_shell_array contracted_shell_array) let of_string input_string = String.split_on_char '\n' input_string |> Stream.of_list |> read_stream