#+begin_src elisp tangle: no :results none :exports none (setq pwd (file-name-directory buffer-file-name)) (setq name (file-name-nondirectory (substring buffer-file-name 0 -4))) (setq lib (concat pwd "lib/")) (setq testdir (concat pwd "test/")) (setq mli (concat lib name ".mli")) (setq ml (concat lib name ".ml")) (setq test-ml (concat testdir name ".ml")) (org-babel-tangle) #+end_src * Coordinate :PROPERTIES: :header-args: :noweb yes :comments both :END: 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 #+NAME: types #+begin_src ocaml :tangle (eval mli) type bohr type angstrom type xyz = { x : float ; y : float ; z : float ; } type 'a point = xyz type t = bohr point type axis = X | Y | Z #+end_src #+begin_src ocaml :tangle (eval ml) :exports none type bohr type angstrom type xyz = { x : float ; y : float ; z : float ; } type 'a point = xyz type t = bohr point type axis = X | Y | Z #+end_src ** Creation #+begin_src ocaml :tangle (eval mli) val make : 'a point -> t val make_angstrom : 'a point -> angstrom point val zero : bohr point #+end_src | ~make~ | Creates a point in atomic units | | ~make_angstrom~ | Creates a point in angstrom | | ~zero~ | $(0., 0., 0.)$ | #+begin_src ocaml :tangle (eval ml) :exports none external make : 'a point -> t = "%identity" external make_angstrom : 'a point -> angstrom point = "%identity" let zero = make { x = 0. ; y = 0. ; z = 0. } #+end_src ** Conversion #+begin_src ocaml :tangle (eval mli) val bohr_to_angstrom : bohr point -> angstrom point val angstrom_to_bohr : angstrom point -> bohr point #+end_src | ~bohr_to_angstrom~ | Converts a point in bohr to angstrom | | ~angstrom_to_bohr~ | Converts a point in angstrom to bohr | #+begin_src ocaml :tangle (eval ml) :exports none 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 a_to_b a = Constants.a0_inv *. a let angstrom_to_bohr { x ; y ; z } = make { x = a_to_b x ; y = a_to_b y ; z = a_to_b z ; } #+end_src ** Vector operations #+begin_src ocaml :tangle (eval mli) val neg : t -> t val get : axis -> bohr point -> float val dot : t -> t -> float val norm : t -> float val ( |. ) : float -> t -> t val ( |+ ) : t -> t -> t val ( |- ) : t -> t -> t #+end_src | ~neg~ | Negative of a point | | ~get~ | Extracts the projection of the coordinate on an axis | | ~dot~ | Dot product | | ~norm~ | $\ell{^2}$ norm of the vector | | ~¦.~ | Scales the vector by a constant | | ~¦+~ | Adds two vectors | | ~¦-~ | Subtracts two vectors | #+begin_example Coordinate.neg { x=1. ; y=2. ; z=3. } ;; - : Coordinate.t = -1.0000 -2.0000 -3.0000 Coordinate.(get Y { x=1. ; y=2. ; z=3. }) ;; - : float = 2. Coordinate.( 2. |. { x=1. ; y=2. ; z=3. } ) ;; - : Coordinate.t = 2.0000 4.0000 6.0000 Coordinate.( { x=1. ; y=2. ; z=3. } |+ { x=2. ; y=3. ; z=1. } );; - : Coordinate.t = 3.0000 5.0000 4.0000 Coordinate.( { x=1. ; y=2. ; z=3. } |- { x=2. ; y=3. ; z=1. } );; - : Coordinate.t = -1.0000 -1.0000 2.0000 #+end_example #+begin_src ocaml :tangle (eval ml) :exports none let get axis { x ; y ; z } = match axis with | X -> x | Y -> y | Z -> z 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 ) #+end_src ** Printers #+begin_src ocaml :tangle (eval mli) val pp : Format.formatter -> t -> unit val pp_bohr: Format.formatter -> t -> unit val pp_angstrom : Format.formatter -> t -> unit #+end_src Coordinates can be printed in bohr or angstrom. #+begin_src ocaml :tangle (eval ml) :exports none 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 #+end_src