type bohr 
type angstrom 

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

type 'a point = xyz

type t = bohr point

external make : 'a point -> t = "%identity"
external make_angstrom : 'a point -> angstrom point = "%identity"
  

type axis = X | Y | Z


let a_to_b a = Constants.a0_inv *. a
let b_to_a b = Constants.a0     *. b

let bohr_to_angstrom { x ; y ; z } =
  make 
  {
    x = b_to_a x ;
    y = b_to_a y ;
    z = b_to_a z ;
  }

let angstrom_to_bohr { x ; y ; z } =  
  make 
  {
    x = a_to_b x ;
    y = a_to_b y ;
    z = a_to_b z ;
  }


let zero =
  make { x = 0. ; y = 0. ; z = 0. } 


(** Linear algebra *)
let ( |. )  s { x ; y ; z } =
    make {
      x = s *. x ;
      y = s *. y ;
      z = s *. z ;
    }

let ( |+ ) { x = x1 ; y = y1 ; z = z1 } { x = x2 ; y = y2 ; z = z2 } =
  make {
    x = x1 +. x2 ;
    y = y1 +. y2 ;
    z = z1 +. z2 ;
  }


let ( |- ) { x = x1 ; y = y1 ; z = z1 } { x = x2 ; y = y2 ; z = z2 } =
  make {
    x = x1 -. x2 ;
    y = y1 -. y2 ;
    z = z1 -. z2 ;
  }


let neg a = -1. |. a


let dot { x = x1 ; y = y1 ; z = z1 } { x = x2 ; y = y2 ; z = z2 } =
  x1 *. x2 +. y1 *. y2 +. z1 *. z2


let norm u =
  sqrt ( dot u u )


let get axis { x ; y ; z } = 
  match axis with
  | X -> x 
  | Y -> y 
  | Z -> z  


open Format
let pp ppf c = 
  fprintf ppf "@[@[%8.4f@] @[%8.4f@] @[%8.4f@]@]" c.x c.y c.z

let pp_bohr ppf c = 
  fprintf ppf "@[(@[%10f@], @[%10f@], @[%10f@] Bohr)@]" c.x c.y c.z

let pp_angstrom ppf c = 
  let c = bohr_to_angstrom c in
  fprintf ppf "@[(@[%10f@], @[%10f@], @[%10f@] Angs)@]" c.x c.y c.z

