(** Type for coordinates in 3D space.

  All operations on points are done in atomic units. Therefore, 
  all coordinates are given in bohr and manipulated with this
  module.
 *)

type bohr 
type angstrom 

type xyz = {
  x : float ;
  y : float ;
  z : float ;
}

type 'a point = xyz

type t = bohr point

val make : 'a point -> t
(** Creates a point in atomic units *)

val make_angstrom : 'a point -> angstrom point
(** Creates a point in Angstrom *)

type axis = X | Y | Z

val bohr_to_angstrom : bohr point -> angstrom point
(** Converts a point in bohr to angstrom. *)


val angstrom_to_bohr : angstrom point -> bohr point
(** Converts a point in Angstrom to bohr. *)


val zero : bohr point
(** [zero = { x = 0. ; y=0. ; z=0. }] *)


val get : axis -> bohr point -> float
(** Extracts the projection of the coordinate on an axis.

  Example:
  
  [Coordinate.(get Y) { x=1. ; y=2. ; z=3. } -> 2.]

*)

(** {1 Vector operations} *)


val ( |. ) : float -> t -> t
(** Scale by a float.

  Example:

  [ 2. |. { x=1. ; y=2. ; z=3. } -> { x=2. ; y=4. ; z=6. } ]

 *)


val ( |+ ) : t -> t -> t
(** Add two vectors.

  Example:

  {[{ x=1. ; y=2. ; z=3. } |+ { x=2. ; y=3. ; z=1. } ->
    { x=3. ; y=5. ; z=4. }]}

 *)


val ( |- ) : t -> t -> t
(** Subtract two vectors.

  Example:

  {[{ x=1. ; y=2. ; z=3. } |- { x=2. ; y=3. ; z=1. } ->
    { x=-1. ; y=-1. ; z=2. }]}

 *)


val neg : t -> t
(** Example:

{[Coordinate.neg { x=1. ; y=2. ; z=-3. } ->
    { x=-1. ; y=-2. ; z=3. }]}

 *)

val dot : t -> t -> float
(** Dot product. *)


val norm : t -> float
(** L{^2} norm of the vector. *)


(** {2 Printers} *)

val pp: Format.formatter -> t -> unit

val pp_bohr: Format.formatter -> t -> unit

val pp_angstrom : Format.formatter -> t -> unit

