#+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 

* Atomic shell pair
  :PROPERTIES:
  :header-args: :noweb yes :comments both
  :END:

 Data structure to represent pairs of atomic shells. The products of
 functions in the shell pair are one-electron functions.

 An atomic shell pair is an array of pairs of contracted shells.

** Type

   #+begin_src ocaml :tangle (eval mli)
type t

open Common
   #+end_src

   #+begin_src ocaml :tangle (eval ml) :exports none
open Common

type t =
{
  contracted_shell_pairs : Contracted_shell_pair.t list;
  atomic_shell_a         : Atomic_shell.t;
  atomic_shell_b         : Atomic_shell.t;
}


module Am  = Angular_momentum
module As  = Atomic_shell
module Co  = Coordinate
module Cs  = Contracted_shell
module Csp = Contracted_shell_pair
   #+end_src

** Access

   #+begin_src ocaml :tangle (eval mli)
val atomic_shell_a         : t -> Atomic_shell.t
val atomic_shell_b         : t -> Atomic_shell.t
val contracted_shell_pairs : t -> Contracted_shell_pair.t list
val ang_mom                : t -> Angular_momentum.t
val monocentric            : t -> bool
val norm_scales            : t -> float array
val a_minus_b              : t -> Coordinate.t
val a_minus_b_sq           : t -> float
   #+end_src

   | ~atomic_shell_a~         | Returns the first  ~Atomic_shell.t~ which was used to build the atomic shell pair.                                                 |
   | ~atomic_shell_b~         | Returns the second ~Atomic_shell.t~ which was used to build the atomic shell pair.                                                 |
   | ~contracted_shell_pairs~ | Returns an array of ~ContractedShellPair.t~, containing all the pairs of contracted functions used to build the atomic shell pair. |
   | ~norm_scales~            | norm_coef.(i) / norm_coef.(0)                                                                                                      |
   | ~ang_mom~                | Total angular Momentum                                                                                                             |
   | ~monocentric~            | If true, the two atomic shells have the same center.                                                                               |
   | ~a_minus_b~              | Returns $A-B$                                                                                                                      |
   | ~a_minus_b_sq~           | Returns $\vert A-B \vert^2$                                                                                                        |
 
   #+begin_src ocaml :tangle (eval ml) :exports none
let atomic_shell_a         x = x.atomic_shell_a
let atomic_shell_b         x = x.atomic_shell_b
let contracted_shell_pairs x = x.contracted_shell_pairs

let monocentric x =
  Csp.monocentric @@ List.hd x.contracted_shell_pairs

let a_minus_b x =
  Csp.a_minus_b @@ List.hd x.contracted_shell_pairs

let a_minus_b_sq x =
  Csp.a_minus_b_sq @@ List.hd x.contracted_shell_pairs

let ang_mom x =
  Csp.ang_mom @@ List.hd x.contracted_shell_pairs

let norm_scales x =
  Csp.norm_scales @@ List.hd x.contracted_shell_pairs

   #+end_src

** Creation

   #+begin_src ocaml :tangle (eval mli)
val make : ?cutoff:float -> Atomic_shell.t -> Atomic_shell.t -> t option
   #+end_src

  Creates an atomic shell pair from two atomic shells.

  The contracted shell pairs contains the only pairs of primitives for which
  the norm is greater than ~cutoff~. 

  If all the contracted shell pairs are not significant, the function returns
  ~None~.

   #+begin_src ocaml :tangle (eval mli)
val of_atomic_shell_array : ?cutoff:float -> Atomic_shell.t array -> t option array array
   #+end_src

   Creates all possible atomic shell pairs from an array of atomic shells.
   If an atomic shell pair is not significant, sets the value to ~None~.

   #+begin_src ocaml :tangle (eval ml) :exports none
let make ?(cutoff=Constants.epsilon) atomic_shell_a atomic_shell_b =

  let l_a = Array.to_list (As.contracted_shells atomic_shell_a)
  and l_b = Array.to_list (As.contracted_shells atomic_shell_b)
  in

  let contracted_shell_pairs =
    List.concat_map (fun s_a -> 
      List.map (fun s_b ->
        if Cs.index s_b <= Cs.index s_a then 
          Csp.make ~cutoff s_a s_b
        else
          None
      ) l_b
    ) l_a
    |> Util.list_some
  in
  match contracted_shell_pairs with
  | [] -> None
  | _  -> Some { atomic_shell_a ; atomic_shell_b ; contracted_shell_pairs }



let of_atomic_shell_array ?(cutoff=Constants.epsilon) basis =
  Array.mapi (fun i shell_a ->
    Array.map (fun shell_b -> 
      make ~cutoff shell_a shell_b)
    (Array.sub basis 0 (i+1)) 
  ) basis

   #+end_src


** Printers

   #+begin_src ocaml :tangle (eval mli)
val pp : Format.formatter -> t -> unit
   #+end_src

   #+begin_src ocaml :tangle (eval ml) :exports none
let pp ppf s =
  let open Format in
  fprintf ppf "@[%a@ %a@]"
    Atomic_shell.pp s.atomic_shell_a
    Atomic_shell.pp s.atomic_shell_b

   #+end_src

