Index: trunk/circe2/share/examples/circe2_compare
===================================================================
--- trunk/circe2/share/examples/circe2_compare	(revision 0)
+++ trunk/circe2/share/examples/circe2_compare	(revision 8898)
@@ -0,0 +1,130 @@
+#! /bin/sh
+########################################################################
+
+########################################################################
+# process command line
+########################################################################
+
+usage () {
+  echo "usage: $0 gp_output circe2_input design cms_energy [num_events] [num_bins]" 1>&2
+  exit 2
+}
+
+if [ "$#" -lt 4 -o "$#" -gt 6 ]; then
+  usage
+else
+  gp_output="$1"
+  circe2_input="$2"
+  design="$3"
+  cms_energy="$4"
+fi
+
+if [ -n "$5" ]; then
+  n_events="$5"
+else
+  n_events=10000000
+fi
+  
+if [ -n "$6" ]; then
+  n_bins="$6"
+else
+  n_bins=1000
+fi
+
+########################################################################
+# sanity checks
+########################################################################
+
+if [ ! -d "$gp_output" ]; then
+  echo "guinea pig output directory $gp_output missing" 1>&2
+  exit 2
+fi
+
+if [ ! -r "$circe2_input" ]; then
+  echo "circe2 input file $circe2_input missing" 1>&2
+  exit 2
+fi
+
+########################################################################
+# check that the tools are in the PATH
+########################################################################
+
+if circe2_tool >/dev/null 2>&1; then
+  circe2_tool=circe2_tool
+elif circe2_tool.opt >/dev/null 2>&1; then
+  circe2_tool=circe2_tool.opt
+elif circe2_tool.bin >/dev/null 2>&1; then
+  circe2_tool=circe2_tool.bin
+else
+  echo "neither of circe2_tool circe2_tool.opt circe2_tool.bin in PATH" 1>&2
+  exit 2
+fi
+
+if circe2_generate >/dev/null 2>&1; then
+  circe2_generate=circe2_generate
+else
+  echo "circe2_generate not in PATH" 1>&2
+  exit 2
+fi
+
+if gnuplot --version >/dev/null 2>&1; then
+  gnuplot=gnuplot
+else
+  echo "gnuplot not found: install it or plot the *.gp and *.circe2 histograms yourself!"
+  gnuplot=true
+fi
+
+########################################################################
+# produce plots
+########################################################################
+
+gnuplot_compare () {
+  gp_tag="$1"
+  histogram="$2"
+  name="$histogram.$gp_tag"
+  $gnuplot -e "\
+    set term pdf; \
+    set output \"$name.pdf\"; \
+    set title \"Comparing Circe2 parametrizations to Guinea-Pig output\"; \
+    set xlabel \"$2\"; \
+    set ylabel \"N\"; \
+    set logscale y; \
+    plot \"$name.gp\" with lines title \"Guinea-Pig\", \
+         \"$name.circe2\" with lines title \"Circe2\";"
+}
+
+########################################################################
+# prepare histograms
+########################################################################
+
+histograms () {
+  circe2_output="$1"
+  gp_tag="$2"
+  p1="$3"
+  p2="$4"
+  awk -v CMS="$cms_energy" '$1 != "" {print 2*$1/CMS, 2*$2/CMS, 1}' $gp_output/lumi.$gp_tag.out > $gp_tag.events.gp
+  $circe2_tool -b $n_bins -p .$gp_tag.gp -h -ha $gp_tag.events.gp
+  $circe2_generate $circe2_output $design $cms_energy $p1 $p2 $n_events | sed '1,2d' > $gp_tag.events.circe2
+  $circe2_tool -b $n_bins -p .$gp_tag.circe2 -h -ha $gp_tag.events.circe2
+  gnuplot_compare $gp_tag xy
+  gnuplot_compare $gp_tag x
+  gnuplot_compare $gp_tag y
+  gnuplot_compare $gp_tag x-y
+}
+
+########################################################################
+# run circe2 and visually compare inout and output
+########################################################################
+
+$circe2_tool -f "$circe2_input" >circe2.log 2>&1
+circe2_output="`sed -n '/^writing/ { s/writing: //; s/ \.\.\. done\.$//; p }' circe2.log`"
+
+histograms "$circe2_output" ee 11 -11 >ee.log 2>&1 &
+histograms "$circe2_output" eg 11  22 >eg.log 2>&1 &
+histograms "$circe2_output" ge 22 -11 >ge.log 2>&1 &
+histograms "$circe2_output" gg 22  22 >gg.log 2>&1 &
+
+echo -n "waiting for jobs ..."
+wait
+echo " done."
+

Property changes on: trunk/circe2/share/examples/circe2_compare
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/circe2/share/examples/Makefile.am
===================================================================
--- trunk/circe2/share/examples/Makefile.am	(revision 8897)
+++ trunk/circe2/share/examples/Makefile.am	(revision 8898)
@@ -1,15 +1,18 @@
 # Makefile.am --
 ########################################################################
 
+TOOLS = \
+  circe2_compare
+
 TEMPLATES = \
   fill_circe2_template \
   template.circe2_input \
   acc.dat
 
 EXAMPLES = prepare_ilc
 
-EXTRA_DIST = $(TEMPLATES) $(EXAMPLES)
+EXTRA_DIST = $(TEMPLATES) $(EXAMPLES) $(TOOLS)
 
 examplescirce2dir = $(pkgdatadir)/examples
-dist_examplescirce2_DATA = $(TEMPLATES) $(EXAMPLES)
+dist_examplescirce2_DATA = $(TEMPLATES) $(EXAMPLES) $(TOOLS)
 
Index: trunk/circe2/src/division.ml
===================================================================
--- trunk/circe2/src/division.ml	(revision 8897)
+++ trunk/circe2/src/division.ml	(revision 8898)
@@ -1,511 +1,580 @@
 (* circe2/division.ml --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 open Printf
 
 let epsilon_100 = 100.0 *. Float.Double.epsilon
 
 let equidistant n x_min x_max =
   if n <= 0 then
     invalid_arg "Division.equidistant: n <= 0"
   else
     let delta = (x_max -. x_min) /. (float n) in
     Array.init (n + 1) (fun i -> x_min +. delta *. float i)
 
 exception Above_max of float * (float * float) * int
 exception Below_min of float * (float * float) * int
 exception Out_of_range of float * (float * float)
 exception Rebinning_failure of string
 
 let find_raw d x =
   let n_max = Array.length d - 1 in
   let eps = epsilon_100 *. (d.(n_max) -. d.(0)) in
   let rec find' a b =
     if b <= a + 1 then
       a
     else
       let m = (a + b) / 2 in
       if x < d.(m) then
 	find' a m
       else
 	find' m b in
   if x < d.(0) -. eps then
     raise (Below_min (x, (d.(0), d.(n_max)), 0))
   else if x > d.(n_max) +. eps then
     raise (Above_max (x, (d.(0), d.(n_max)), n_max - 1))
   else if x <= d.(0) then
     0
   else if x >= d.(n_max) then
     n_max - 1
   else
     find' 0 n_max
 
 module type T =
   sig
 
     type t
 
     val copy : t -> t
 
     val find : t -> float -> int
     val record : t -> float -> float -> unit
 
     val rebin : ?power:float -> ?fixed_min:bool -> ?fixed_max:bool -> t -> t
 
     val caj : t -> float -> float
+    val is_null : t -> float -> bool
+    val null_bins : t -> int list
 
     val n_bins : t -> int
     val bins : t -> float array
     val to_channel : out_channel -> t -> unit
 
   end
 
 (* \subsubsection{Primary Divisions} *)
 
 module type Mono =
   sig
     include T
     val create : ?bias:(float -> float) -> int -> float -> float -> t
   end
 
 module Mono (* [: T] *) =
   struct
 
     type t =
         { x : float array;
           mutable x_min : float;
           mutable x_max : float;
           n : int array;
           w : float array;
           w2 : float array;
           bias : float -> float } 
 
     let copy d =
       { x = Array.copy d.x;
         x_min = d.x_min;
         x_max = d.x_max;
         n = Array.copy d.n;
         w = Array.copy d.w;
         w2 = Array.copy d.w2;
         bias = d.bias }
 
     let create ?(bias = fun x -> 1.0) n x_min x_max =
       { x = equidistant n x_min x_max;
         x_min = x_max;
         x_max = x_min;
         n = Array.make n 0;
         w = Array.make n 0.0;
         w2 = Array.make n 0.0;
         bias = bias }
 
     let bins d = d.x
     let n_bins d = Array.length d.x - 1
 
     let find d = find_raw d.x
 
     let normal_float x =
       match classify_float x with
       | FP_normal | FP_subnormal | FP_zero -> true
       | FP_infinite | FP_nan -> false
 
     let report_denormal x f b what =
       eprintf
         "circe2: Division.record: ignoring %s (x=%g, f=%g, b=%g)\n"
         what x f b;
       flush stderr
       
 (*i let report_denormal x f b what = () i*)
 
     let caj d x = 1.0
+    let is_null d x = false
 
     let record d x f =
       if x < d.x_min then
         d.x_min <- x;
       if x > d.x_max then
         d.x_max <- x;
       let i = find d x in
       d.n.(i) <- succ d.n.(i);
       let b = d.bias x in
       let w = f *. b in
       match classify_float w with
       | FP_normal | FP_subnormal | FP_zero ->
           d.w.(i) <- d.w.(i) +. w;
           let w2 = f *. w in
           begin match classify_float w2 with
           | FP_normal | FP_subnormal | FP_zero ->
               d.w2.(i) <- d.w2.(i) +. w2
           | FP_infinite -> report_denormal x f b "w2 = [inf]"
           | FP_nan -> report_denormal x f b "w2 = [nan]"
           end
       | FP_infinite -> report_denormal x f b "w2 = [inf]"
       | FP_nan -> report_denormal x f b "w2 = [nan]"
 
     (* \begin{equation}
          \begin{aligned}
            d_1     &\to \frac{1}{2}(d_1+d_2) \\
            d_2     &\to \frac{1}{3}(d_1+d_2+d_3) \\
                    &\ldots\\
            d_{n-1} &\to \frac{1}{3}(d_{n-2}+d_{n-1}+d_n) \\
            d_n     &\to \frac{1}{2}(d_{n-1}+d_n)
          \end{aligned}
        \end{equation} *)
 
     let smooth3 f =
       match Array.length f with
       | 0 -> f
       | 1 -> Array.copy f
       | 2 -> Array.make 2 ((f.(0) +. f.(1)) /. 2.0)
       | n ->
           let f' = Array.make n 0.0 in
           f'.(0) <- (f.(0) +. f.(1)) /. 2.0;
           for i = 1 to n - 2 do
             f'.(i) <- (f.(i-1) +. f.(i) +. f.(i+1)) /. 3.0
           done;
           f'.(n-1) <- (f.(n-2) +. f.(n-1)) /. 2.0;
           f'
 
     (* \begin{equation}
          m_i = \left(
            \frac{\frac{\bar f_i \Delta x_i}{\sum_j\bar f_j \Delta x_j}-1}
                 {\ln\left(\frac{\bar f_i \Delta x_i}{\sum_j\bar f_j \Delta x_j}\right)}
              \right)^\alpha
        \end{equation} *)
 
     let rebinning_weights' power fs =
       let sum_f = Array.fold_left (+.) 0.0 fs in
       if sum_f <= 0.0 then
         Array.make (Array.length fs) 1.0
       else
         Array.map (fun f ->
           let f' = f /. sum_f in
           if f' < 1.0e-12 then
             0.
           else
             ((f' -. 1.0) /. (log f')) ** power) fs
 
 (*i\begin{figure}
      \begin{center}
        \empuse{weights}
        \begin{empgraph}(70,30)
          randomseed := 720.251;
          pickup pencircle scaled 0.7pt;
          path m[], g[];
          numeric pi; pi = 180;
          numeric dx; dx = 0.05;
          numeric dg; dg = -0.04;
          vardef adap_fct (expr x) = (x + sind(4*x*pi)/16) enddef;
          autogrid (,);
          frame.bot;
          setrange (0, 0, 1, 1.2);
          for x = 0 step dx until 1+dx/2:
            numeric r;
            r = 1 + normaldeviate/10;
            augment.m[x] (adap_fct (x), r);
            augment.m[x] (adap_fct (x+dx), r);
            augment.m[x] (adap_fct (x+dx), 0);
            augment.m[x] (adap_fct (x), 0);
            augment.g[x] (adap_fct (x), 0);
            augment.g[x] (adap_fct (x), dg);
          endfor
          for x = 0 step dx until 1-dx/2:
            gfill m[x] -- cycle withcolor 0.7white;
            gdraw m[x] -- cycle;
          endfor
          for x = 0 step dx until 1+dx/2:
            gdraw g[x];
          endfor
          glabel.bot (btex $x_0$     etex, (adap_fct (0*dx), dg));
          glabel.bot (btex $x_1$     etex, (adap_fct (1*dx), dg));
          glabel.bot (btex $x_2$     etex, (adap_fct (2*dx), dg));
          glabel.bot (btex $x_{n-1}$ etex, (adap_fct (1-dx), dg));
          glabel.bot (btex $x_n$     etex, (adap_fct (1), dg));
          glabel.lft (btex $\displaystyle
                       \bar f_i\approx\frac{m_i}{\Delta x_i}$ etex, OUT);
        \end{empgraph}
      \end{center}
      \caption{\label{fig:rebin}%
        Typical weights used in the rebinning algorithm.}
    \end{figure}
 i*)
 
     (* The nested loops can be turned into recursions, of course.  But arrays aren't
        purely functional anyway \ldots *)
 
     let rebin' m x =
       let n = Array.length x - 1 in
       let x' = Array.make (n + 1) 0.0 in
       let sum_m = Array.fold_left (+.) 0.0 m in
       if sum_m <= 0.0 then
         Array.copy x
       else begin
         let step = sum_m /. (float n) in
         let k = ref 0
         and delta = ref 0.0 in
         x'.(0) <- x.(0);
         for i = 1 to n - 1 do
 
           (* We increment~$k$ until another $\Delta$ (a.\,k.\,a.~[step]) of the
              integral has been accumulated.  % (cf.~figure~\ref{fig:rebin}). 
 	  *)
           while !delta < step do
             incr k;
             delta := !delta +. m.(!k-1)
           done;
     
           (* Correct the mismatch. *)
           delta := !delta -. step;
 
           (* Linearly interpolate the next bin boundary.  *)
           x'.(i) <- x.(!k) -. (x.(!k) -. x.(!k-1)) *. !delta /. m.(!k-1);
 
           if x'.(i) < x'.(i-1) then
             raise (Rebinning_failure
                      (sprintf "x(%d)=%g < x(%d)=%g" i x'.(i) (i-1) x'.(i-1)))
 
         done;
         x'.(n) <- x.(n);
         x'
       end
 
     (* \begin{dubious}
          Check that [x_min] and [x_max] are implemented correctly!!!!
        \end{dubious} *)
 
     (* \begin{dubious}
          One known problem is that the second outermost bins hinder the
          outermost bins from moving.
        \end{dubious} *)
 
     let rebin ?(power = 1.5) ?(fixed_min = false) ?(fixed_max = false) d =
       let n = Array.length d.w in
       let x = rebin' (rebinning_weights' power (smooth3 d.w2)) d.x in
       if not fixed_min then
         x.(0) <- (x.(0) +. min d.x_min x.(1)) /. 2.;
       if not fixed_max then
         x.(n) <- (x.(n) +. max d.x_max x.(n-1)) /. 2.;
       { x = x;
         x_min = d.x_min;
         x_max = d.x_max;
         n = Array.make n 0;
         w = Array.make n 0.0;
         w2 = Array.make n 0.0;
         bias = d.bias }
 
+    let null_bins d = []
+
     let to_channel oc d =
       Array.iter (fun x ->
         fprintf oc " %s 0 1 0 0 1 1\n" (Float.Double.to_string x)) d.x
 
   end
 
 (* \subsubsection{Polydivisions} *)
 
 module type Poly =
   sig
 
     module M : Diffmaps.Real
 
     include T
 
     val create : ?bias:(float -> float) ->
       (int * M.t) list -> int -> float -> float -> t
 
   end
 
 module Make_Poly (M : Diffmaps.Real) (* [: Poly] *) =
   struct
 
     module M = M
 
     type t =
         { x : float array;
           d : Mono.t array;
           n_bins : int;
           ofs : int array;
           maps : M.t array;
           n : int array;
           w : float array;
           w2 : float array }
 
     let copy pd =
       { x = Array.copy pd.x;
         d = Array.map Mono.copy pd.d;
         n_bins = pd.n_bins;
         ofs = Array.copy pd.ofs;
         maps = Array.copy pd.maps;
         n = Array.copy pd.n;
         w = Array.copy pd.w;
         w2 = Array.copy pd.w2 }
 
     let n_bins pd = pd.n_bins
 
     let find pd y =
       let i = find_raw pd.x y in
       let x = M.ihp pd.maps.(i) y in
       pd.ofs.(i) + Mono.find pd.d.(i) x
 
     let bins pd =
       let a = Array.make (pd.n_bins + 1) 0.0 in
       let bins0 = Mono.bins pd.d.(0) in
       let len = Array.length bins0 in
       Array.blit bins0 0 a 0 len;
       let ofs = ref len in
       for i = 1 to Array.length pd.d - 1 do
         let len = Mono.n_bins pd.d.(i) in
         Array.blit (Mono.bins pd.d.(i)) 1 a !ofs len;
         ofs := !ofs + len
       done;
       a
         
     type interval =
         { nbin : int;
           x_min : float;
           x_max : float;
           map : M.t }
 
     let interval nbin map =
       { nbin = nbin;
         x_min = M.x_min map;
         x_max = M.x_max map;
         map = map }
 
     let id_map n y_min y_max =
       interval n (M.id ~x_min:y_min ~x_max:y_max y_min y_max)
 
     let sort_intervals intervals =
       List.sort (fun i1 i2 -> compare i1.x_min i2.x_min) intervals
 
     (* Fill the gaps between adjacent intervals, using
        [val default : int -> float -> float -> interval] to
        construct intermediate intervals. *)
 
     let fill_gaps default n x_min x_max intervals =
       let rec fill_gaps' prev_x_max acc = function
         | i :: rest ->
             if i.x_min = prev_x_max then
               fill_gaps' i.x_max (i :: acc) rest
             else if i.x_min > prev_x_max then
               fill_gaps' i.x_max
                 (i :: (default n prev_x_max i.x_min) :: acc) rest
             else
               invalid_arg "Polydivision.fill_gaps: overlapping"
         | [] ->
             if x_max = prev_x_max then
               List.rev acc
             else if x_max > prev_x_max then
               List.rev (default n prev_x_max x_max :: acc)
             else
               invalid_arg "Polydivision.fill_gaps: sticking out" in
       match intervals with
       | i :: rest ->
           if i.x_min = x_min then
             fill_gaps' i.x_max [i] rest
           else if i.x_min > x_min then
             fill_gaps' i.x_max (i :: [default n x_min i.x_min]) rest
           else
             invalid_arg "Polydivision.fill_gaps: sticking out"
       | [] -> [default n x_min x_max]
 
     let create ?bias intervals n x_min x_max =
       let intervals = List.map (fun (n, m) -> interval n m) intervals in
       match fill_gaps id_map n x_min x_max (sort_intervals intervals) with
       | [] -> failwith "Division.Poly.create: impossible"
       | interval :: _ as intervals ->
           let ndiv = List.length intervals in
           let x = Array.of_list (interval.x_min ::
                                  List.map (fun i -> i.x_max) intervals) in
           let d = Array.of_list
               (List.map (fun i ->
                 Mono.create ?bias i.nbin i.x_min i.x_max) intervals) in
           let ofs = Array.make ndiv 0 in
           for i = 1 to ndiv - 1 do
             ofs.(i) <- ofs.(i-1) + Mono.n_bins d.(i-1)
           done;
           let n_bins = ofs.(ndiv-1) + Mono.n_bins d.(ndiv-1) in
           { x = x;
             d = d;
             n_bins = n_bins;
             ofs = ofs;
             maps = Array.of_list (List.map (fun i -> i.map) intervals);
             n = Array.make ndiv 0;
             w = Array.make ndiv 0.0;
             w2 = Array.make ndiv 0.0 }
 
     (* We can safely assume that [find_raw pd.x y = find_raw pd.x x].
        \begin{equation}
          w = \frac{f}{{\displaystyle\frac{\mathrm{d}x}{\mathrm{d}y}}}
            = f\cdot\frac{\mathrm{d}y}{\mathrm{d}x}
        \end{equation}
        Here, the jacobian makes no difference for the final result, but
        it steers VEGAS/VAMP into the right direction.  *)
 
     let caj pd y =
       let i = find_raw pd.x y in
       let m = pd.maps.(i)
       and d = pd.d.(i) in
       let x = M.ihp m y in
       M.caj m y *. Mono.caj d x
 
+    let is_null pd y =
+      let i = find_raw pd.x y in
+      let m = pd.maps.(i) in
+      M.is_null m
+
     let record pd y f =
       let i = find_raw pd.x y in
       let m = pd.maps.(i) in
-      let x = M.ihp m y in
-      let w = M.jac m x *. f in
-      Mono.record pd.d.(i) x w;
-      pd.n.(i) <- succ pd.n.(i);
-      pd.w.(i) <- pd.w.(i) +. w;
-      pd.w2.(i) <- pd.w2.(i) +. w *. w
+      if M.is_null m then
+        ()
+      else
+        let x = M.ihp m y in
+        let w = M.jac m x *. f in
+        Mono.record pd.d.(i) x w;
+        pd.n.(i) <- succ pd.n.(i);
+        pd.w.(i) <- pd.w.(i) +. w;
+        pd.w2.(i) <- pd.w2.(i) +. w *. w
 
     (* Rebin the divisions, enforcing fixed boundaries for the inner
        intervals. *)
     let rebin ?(power = 1.5) ?(fixed_min = false) ?(fixed_max = false) pd =
       let ndiv = Array.length pd.d in
       let rebin_mono i d =
         if ndiv <= 1 then
           Mono.rebin ~power ~fixed_min ~fixed_max d
         else if i = 0 then
           Mono.rebin ~power ~fixed_min ~fixed_max:true d
         else if i = ndiv - 1 then
           Mono.rebin ~power ~fixed_min:true ~fixed_max d
         else
           Mono.rebin ~power ~fixed_min:true ~fixed_max:true d in
       { x = Array.copy pd.x;
         d = Array.init ndiv (fun i -> rebin_mono i pd.d.(i));
         n_bins = pd.n_bins;
         ofs = pd.ofs;
         maps = Array.copy pd.maps;
         n = Array.make ndiv 0;
         w = Array.make ndiv 0.0;
         w2 = Array.make ndiv 0.0 }
 
+    let range n1 n2 =
+      let rec range' n =
+        if n > n2 then
+          []
+        else
+          n :: range' (succ n) in
+      range' n1
+
+    let null_bins pd =
+      let num_intervals = Array.length pd.d in
+      let rec null_bins' (acc, i) n =
+        if n >= num_intervals then
+          List.rev acc
+        else
+          let d = pd.d.(n)  in
+          let i' = i + Mono.n_bins d in
+          if M.is_null pd.maps.(n) then
+            null_bins' (List.rev_append (range i (pred i')) acc, i') (succ n)
+          else
+            null_bins' (acc, i') (succ n) in
+      null_bins' ([], 0) 0
+
     let to_channel oc pd =
       for i = 0 to Array.length pd.d - 1 do
         let map = M.encode pd.maps.(i)
         and bins = Mono.bins pd.d.(i)
         and j0 = if i = 0 then 0 else 1 in
         for j = j0 to Array.length bins - 1 do
           fprintf oc " %s %s\n" (Float.Double.to_string bins.(j)) map;
         done
       done
 
   end
 
 module Poly = Make_Poly (Diffmaps.Default)
 
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
+module Test =
+  struct
+
+    open OUnit
+
+    let int_list_to_string l =
+      "[" ^ String.concat "; " (List.map string_of_int l) ^ "]"
+
+    let assert_int_list = assert_equal ~printer:int_list_to_string
+
+    module D = Poly
+    module M = D.M
+
+    let null_maps maps =
+      D.null_bins (D.create maps 100 0. 1.)
+
+    let null_map_suite =
+      "null map" >:::
+        [ "0" >:: (fun () ->
+            assert_int_list [0] (null_maps [(1, M.null 0. 0.1)]));
+
+          "[0;1;2]" >:: (fun () ->
+            assert_int_list [0;1;2] (null_maps [(3, M.null 0. 0.1)]));
+
+          "[100]" >:: (fun () ->
+            assert_int_list [100] (null_maps [(1, M.null 0.1 0.2)]));
+
+          "[100;201]" >:: (fun () ->
+            assert_int_list [100;201] (null_maps [(1, M.null 0.1 0.2);
+                                                  (1, M.null 0.3 0.4)]));
+
+          "[100;101;202;203;204]" >:: (fun () ->
+            assert_int_list [100;101;202;203;204] (null_maps [(2, M.null 0.1 0.2);
+                                                              (3, M.null 0.3 0.4)])) ]
+
+    let suite =
+      let open OUnit in
+      "Division" >:::
+        [null_map_suite]
+
+  end
Index: trunk/circe2/src/parser.mly
===================================================================
--- trunk/circe2/src/parser.mly	(revision 8897)
+++ trunk/circe2/src/parser.mly	(revision 8898)
@@ -1,249 +1,259 @@
 /* parser.mly --
  */
 
 %{
 open Syntax
 module Maps = Diffmaps.Default
 let parse_error msg =
   raise (Syntax_Error (msg, symbol_start (), symbol_end ()))
 %}
 
 %token < int > INT
 %token < float > FLOAT
 %token < string > STRING
 %token SLASH EQUALS STAR PLUS MINUS
 %token LBRACKET LPAREN LANGLE COMMA RBRACKET RPAREN RANGLE
 %token LBRACE RBRACE
 %token Ascii Binary
 %token Beta Eta
 %token Bins Scale
 %token Center
 %token Columns
 %token Comment
 %token Design
-%token Electron Positron Photon
+%token Electron Positron Photon Muon Antimuon
 %token Events Histogram File
 %token Fix
 %token Free
 %token Id
 %token Iterations
 %token Lumi Roots
 %token Map
 %token Min Max
 %token Notriangle
+%token Null
 %token Pid
 %token Pol Unpol
 %token Power Resonance
 %token Smooth
 %token Triangle
 %token Width
 %token END
 
 %start main
 %type < Syntax.file_cmds list > main
 
 %%
 
 main:
     files END                       { $1 }
 ;
 
 files:
                                     { [] }
   | file files                      { $1 :: $2 }
 ;
 
 file:
   | LBRACE file_cmds RBRACE         { $2 }
 ;
 
 file_cmds:
                                     { [] }
   | file_cmd file_cmds              { $1 :: $2 }
 ;
 
 file_cmd:
     File EQUALS STRING              { Syntax.File $3 }
   | LBRACE design_cmds RBRACE       { Syntax.Designs $2 }
 ;
 
 design_cmds:
                                     { [] }
   | design_cmd design_cmds          { $1 :: $2 }
 ;
 
 design_cmd:
     Bins coord EQUALS INT           { Syntax.Design_Bins ($4, $2) }
   | Scale coord EQUALS float        { Syntax.Design_Scale ($4, $2) }
   | Design EQUALS STRING            { Syntax.Design $3 }
   | Roots EQUALS float              { Syntax.Roots $3 }
   | LBRACE channel_cmds RBRACE      { Syntax.Channels $2 }
   | Comment EQUALS STRING           { Syntax.Comment $3 }
 ;
 
 channel_cmds:
                                     { [] }
   | channel_cmd channel_cmds        { $1 :: $2 }
 ;
 
 channel_cmd:
     Pid coord EQUALS particle       { Syntax.Pid ($4, $2) }
   | Pol coord EQUALS polarization   { Syntax.Pol ($4, $2) }
   | Fix coord EQUALS side           { Syntax.Fix (true, $2, $4) }
   | Free coord EQUALS side          { Syntax.Fix (false, $2, $4) }
   | Bins coord EQUALS INT           { Syntax.Bins ($4, $2) }
   | Scale coord EQUALS float        { Syntax.Scale ($4, $2) }
   | Min coord EQUALS float          { Syntax.Xmin ($4, $2) }
   | Max coord EQUALS float          { Syntax.Xmax ($4, $2) }
   | Map coord EQUALS map            { Syntax.Diffmap ($4, $2) }
   | Lumi EQUALS float               { Syntax.Lumi $3 }
   | Columns EQUALS INT              { Syntax.Columns $3 }
   | Iterations EQUALS INT           { Syntax.Iterations $3 }
   | Events EQUALS STRING            { Syntax.Events $3 }
   | Histogram EQUALS STRING         { Syntax.Histogram $3 }
   | Binary                          { Syntax.Binary true }
   | Ascii                           { Syntax.Binary false }
   | Smooth EQUALS float area        { Syntax.Smooth ($3, $4) }
   | Triangle                        { Syntax.Triangle true }
   | Notriangle                      { Syntax.Triangle false }
 ;
 
 particle:
     INT                             { $1 }
   | Electron                        { 11 }
   | Positron                        { -11 }
+  | Muon                            { 13 }
+  | Antimuon                        { -13 }
   | Photon                          { 22 }
 ;
 
 polarization:
     INT                             { $1 }
   | Unpol                           { 0 }
 ;
 
 coord:
                                     { Syntax.X12 }
   | SLASH STAR                      { Syntax.X12 }
   | SLASH INT                       {
       match $2 with
       | 1 -> Syntax.X1
       | 2 -> Syntax.X2
       | n ->
           Printf.eprintf "circe2: ignoring dimension %d (not 1, 2, or *)\n" n;
           Syntax.X12 }
 ;
 
 side:
     Min                             { Syntax.Min }
   | Max                             { Syntax.Max }
   | STAR                            { Syntax.Minmax }
 ;
 
 map:
    Id LBRACE id RBRACE              { $3 }
+ | Null LBRACE null RBRACE          { $3 }
  | Power LBRACE power RBRACE        { $3 }
  | Resonance LBRACE resonance RBRACE{ $3 }
 ;
 
 area:
    interval interval                { Syntax.Rect ($1, $2) }
  | interval point                   { Syntax.Slice1 ($1, $2) }
  | point interval                   { Syntax.Slice2 ($1, $2) }
 ;
 
 point:
  | LBRACKET float RBRACKET          { Syntax.Delta $2 }
  | LANGLE INT RANGLE                { Syntax.Box $2 }
 ;
 
 id:
    INT real_interval                {
      let x_min, x_max = $2 in
      ($1, Maps.id x_min x_max) }
 ;
 
+null:
+   INT real_interval                    {
+     let x_min, x_max = $2 in
+     ($1, Maps.null x_min x_max) }
+;
+
 real_interval:
     left float COMMA float right    { ($2, $4) }
 ;
 
 left:
     LBRACKET                        { }
   | LPAREN                          { }
 ;
 
 right:
     RBRACKET                        { }
   | RPAREN                          { }
 ;
 
 interval:
     lower COMMA upper               { ($1, $3) }
 ;
 
 lower:
     LBRACKET float                  { Syntax.Closed $2 }
   | LPAREN float                    { Syntax.Open $2 }
   | LANGLE INT                      { Syntax.Bin $2 }
 ;
 
 upper:
     float RBRACKET                  { Syntax.Closed $1 }
   | float RPAREN                    { Syntax.Open $1 }
   | INT RANGLE                      { Syntax.Bin $1 }
 ;
 
 power:
    INT real_interval power_params   {
      let x_min, x_max = $2
      and beta, eta = $3 in
      if beta <= -1.0 then begin
        Printf.eprintf "circe2: ignoring invalid beta: %g <= -1\n" beta;
        flush stderr;
        ($1, Maps.id x_min x_max)
      end else
        let alpha = 1.0 /. (1.0 +. beta) in
        ($1, Maps.power ~alpha ~eta x_min x_max) }
 ;
 
 power_params:
     beta eta                        { ($1, $2) }
   | eta beta                        { ($2, $1) }
 ;
 
 beta:
     Beta EQUALS float               { $3 }
 ;
 
 eta:
     Eta EQUALS float                { $3 }
 ;
 
 resonance:
    INT real_interval resonance_params {
      let x_min, x_max = $2
      and eta, a = $3 in
      ($1, Maps.resonance ~eta ~a x_min x_max) }
 ;
 
 resonance_params:
     center width                    { ($1, $2) }
   | width center                    { ($2, $1) }
 ;
 
 center:
     Center EQUALS float             { $3 }
 ;
 
 width:
     Width EQUALS float              { $3 }
 ;
 
 float:
     float_or_int                    { $1 }
   | float_or_int PLUS               { $1 +. Syntax.epsilon }
   | float_or_int MINUS              { $1 -. Syntax.epsilon }
 ;
 
 float_or_int:
     INT                             { float $1 }
   | FLOAT                           { $1 }
 ;
Index: trunk/circe2/src/circe2_tool.ml
===================================================================
--- trunk/circe2/src/circe2_tool.ml	(revision 8897)
+++ trunk/circe2/src/circe2_tool.ml	(revision 8898)
@@ -1,496 +1,502 @@
 (* circe2/circe2_tool.ml --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 (* \subsubsection{Large Numeric File I/O} *)
 
 type input_file =
   | ASCII_ic of in_channel
   | ASCII_inf of string
   | Binary_inf of string
 
 type output_file =
   | ASCII_oc of out_channel
   | ASCII_outf of string
   | Binary_outf of string
 
 let read columns = function
   | ASCII_ic ic -> Events.of_ascii_channel columns ic
   | ASCII_inf inf -> Events.of_ascii_file columns inf
   | Binary_inf inf -> Events.of_binary_file columns inf
 
 let write output array =
   match output with
   | ASCII_oc oc -> Events.to_ascii_channel oc array
   | ASCII_outf outf -> Events.to_ascii_file outf array
   | Binary_outf outf -> Events.to_binary_file outf array
 
 (* The special case of writing a binary file with mapped I/O
    can be treated most efficiently: *)
 let cat columns input output =
   match input, output with
   | ASCII_ic ic, Binary_outf outf ->
       ignore (Events.of_ascii_channel ~file:outf columns ic)
   | _, _ -> write output (read columns input)
 
 let map_xy fx fy columns input output =
   let a = read columns input in
   for i2 = 1 to Bigarray.Array2.dim2 a do
     Bigarray.Array2.set a 1 i2 (fx (Bigarray.Array2.get a 1 i2));
     Bigarray.Array2.set a 2 i2 (fy (Bigarray.Array2.get a 2 i2))
   done;
   write output a
 
 let log10_xy = map_xy log10 log10
 let exp10_xy = map_xy (fun x -> 10.0 ** x) (fun y -> 10.0 ** y)
 
 (* \subsubsection{Histogramming} *)
 
 let scan_string s =
   let tokens = Lexing.from_string s in
   let t1 = Events.next_float tokens in
   let t2 = Events.next_float tokens in
   let t3 = Events.next_float tokens in
   (t1, t2, t3)
 
 let histogram_ascii name histograms =
   let ic = open_in name
   and histos =
     List.map (fun (tag, f, n, x_min, x_max) ->
       (tag, f, Histogram.create n x_min x_max)) histograms in
   begin try
     while true do
       let x, y, w = scan_string (input_line ic) in
       List.iter (fun (_, f, h) -> Histogram.record h (f x y) w) histos
     done
   with
   | End_of_file -> ()
   end;
   close_in ic;
   List.map (fun (t, _, h) -> (t, h)) histos
 
 let histogram_binary_channel ic histograms =
   let histos =
     List.map (fun (tag, f, n, x_min, x_max) ->
       (tag, f, Histogram.create n x_min x_max)) histograms in
   begin try
     while true do
       let x = Float.Double.input_binary_float ic
       and y = Float.Double.input_binary_float ic
       and w = Float.Double.input_binary_float ic in
       List.iter (fun (_, f, h) -> Histogram.record h (f x y) w) histos
     done
   with
   | End_of_file -> ()
   end;
   List.map (fun (t, _, h) -> (t, h)) histos
 
 let histogram_binary name histograms =
   let a = Events.of_binary_file 3 name
   and histos =
     List.map (fun (tag, f, n, x_min, x_max) ->
       (tag, f, Histogram.create n x_min x_max)) histograms in
   for i2 = 1 to Bigarray.Array2.dim2 a do
     let x = Bigarray.Array2.get a 1 i2
     and y = Bigarray.Array2.get a 2 i2
     and w = Bigarray.Array2.get a 3 i2 in
     List.iter (fun (_, f, h) -> Histogram.record h (f x y) w) histos
   done;
   List.map (fun (t, _, h) -> (t, h)) histos
 
 (*i
 let histogram_binary name histograms =
   let a = Events.of_binary_file 3 name
   and histos =
     List.map (fun (tag, f, n, x_min, x_max) ->
       (tag, f, Histogram.create n x_min x_max)) histograms in
   for i2 = 1 to Bigarray.Array2.dim2 a do
     let x = a.{1,i2}
     and y = a.{2,i2}
     and w = a.{3,i2} in
     List.iter (fun (_, f, h) -> Histogram.record h (f x y) w) histos
   done;
   List.map (fun (t, _, h) -> (t, h)) histos
 i*)
 
 let histogram_data to_file n reader suffix =
   let histograms = reader
       [ ("x", (fun x y -> x), n, 0.0, 1.0);
         ("x_low", (fun x y -> x), n, 0.0, 1.0e-4);
         ("1-x_low", (fun x y -> 1.0 -. x), n, 0.0, 1.0e-2);
         ("1-x_low2", (fun x y -> 1.0 -. x), n, 1.0e-10, 1.0e-2);
         ("y", (fun x y -> y), n, 0.0, 1.0);
         ("y_low", (fun x y -> y), n, 0.0, 1.0e-4);
         ("1-y_low", (fun x y -> 1.0 -. y), n, 0.0, 1.0e-2);
         ("1-y_low2", (fun x y -> 1.0 -. y), n, 1.0e-10, 1.0e-2);
         ("xy", (fun x y -> x *. y), n, 0.0, 1.0);
         ("xy_low", (fun x y -> x *. y), n, 0.0, 1.0e-8);
         ("z", (fun x y -> sqrt (x *. y)), n, 0.0, 1.0);
         ("z_low", (fun x y -> sqrt (x *. y)), n, 0.0, 1.0e-4);
         ("x-y", (fun x y -> x -. y), n, -1.0, 1.0);
         ("x_fine", (fun x y -> x), n, 0.75, 0.85);
         ("y_fine", (fun x y -> y), n, 0.75, 0.85);
         ("xy_fine", (fun x y -> x *. y), n, 0.5, 0.7);
         ("x-y_fine", (fun x y -> x -. y), n, -0.1, 0.1) ] in
   List.iter (fun (tag, h) ->
     to_file (tag ^ suffix) (Histogram.normalize h))
     histograms
 
 (* \subsubsection{Moments} *)
 
 let moments_ascii name moments =
   let ic = open_in name
   and f = Array.of_list (List.map (fun (tag, f) -> f) moments)
   and m = Array.of_list (List.map (fun (tag, f) -> 0.0) moments)
   and sum_w = ref 0.0 in
   begin try
     while true do
       let x, y, w = scan_string (input_line ic) in
       sum_w := !sum_w +. w;
       for i = 0 to Array.length f - 1 do
         m.(i) <- m.(i) +. w *. (f.(i) x y)
       done
     done
   with
   | End_of_file -> ()
   end;
   close_in ic;
   List.map2 (fun (tag, f) m -> (tag, m /. !sum_w)) moments (Array.to_list m)
 
 let moments_binary name moments =
   let a = Events.of_binary_file 3 name in
   let f = Array.of_list (List.map (fun (tag, f) -> f) moments)
   and m = Array.of_list (List.map (fun (tag, f) -> 0.0) moments)
   and sum_w = ref 0.0 in
   for i2 = 1 to Bigarray.Array2.dim2 a do
     let x = Bigarray.Array2.get a 1 i2
     and y = Bigarray.Array2.get a 2 i2
     and w = Bigarray.Array2.get a 3 i2 in
     sum_w := !sum_w +. w;
     for i = 0 to Array.length f - 1 do
       m.(i) <- m.(i) +. w *. (f.(i) x y)
     done
   done;
   List.map2 (fun (tag, f) m -> (tag, m /. !sum_w)) moments (Array.to_list m)
 
 let fmt var = function
   | 0 -> ""
   | 1 -> var
   | n -> var ^ "^" ^ string_of_int n
 
 let moment nx ny =
   (fmt "x" nx ^ fmt "y" ny, (fun x y -> x ** (float nx) *. y ** (float ny)))
   
 let diff_moment n =
   (fmt "|x-y|" n, (fun x y -> (abs_float (x -. y)) ** (float n)))
   
 let moments_data reader =
   let moments = reader
       (List.map (moment 0) [1; 2; 3; 4; 5; 6] @
        List.map (moment 1) [0; 1; 2; 3; 4; 5] @
        List.map (moment 2) [0; 1; 2; 3; 4] @
        List.map (moment 3) [0; 1; 2; 3] @
        List.map (moment 4) [0; 1; 2] @
        List.map (moment 5) [0; 1] @
        List.map (moment 6) [0] @
        List.map diff_moment [1; 2; 3; 4; 5; 6]) in
   List.iter (fun (tag, m) -> Printf.printf "%s = %g\n" tag m) moments
 
 (* \subsubsection{Regression} *)
 
 let regression_interval (tag, h) (log_min, log_max) =
   let a, b =
     Histogram.regression h
       (fun x -> x >= log_min && x <= log_max) (fun x -> x) (fun x -> log x) in
   Printf.printf "%g<%s<%g: a = %g, b = %g\n" log_min tag log_max a b
 
 let intervals =
   [ (-7.0, -6.0);
     (-6.0, -5.0);
     (-5.0, -4.0);
     (-4.0, -3.0);
     (-3.0, -2.0);
     (-7.0, -5.0);
     (-6.0, -4.0);
     (-5.0, -3.0);
     (-4.0, -2.0);
     (-7.0, -4.0);
     (-6.0, -3.0);
     (-5.0, -2.0);
     (-7.0, -3.0);
     (-6.0, -2.0) ]
 
 let intervals =
   [ (-7.0, -4.0);
     (-6.0, -3.0);
     (-7.0, -3.0);
     (-6.0, -2.0) ]
 
 let regression_data n reader =
   let histograms = reader
       [ ("log(x1)", (fun x1 x2 -> log x1), n, -8.0, 0.0);
         ("log(x2)", (fun x1 x2 -> log x2), n, -8.0, 0.0) ] in
   List.iter (fun (tag, h) ->
     List.iter (regression_interval (tag, h)) intervals) histograms
 
 (* \subsubsection{Visually Adapting Powermaps} *)
 
 let power_map beta eta =
   Diffmap.Power.create ~alpha:(1.0 /. (1.0 +. beta)) ~eta 0.0 1.0
 
 let power_data to_file n center resolution reader suffix =
   let histograms = reader
       (List.flatten
          (List.map (fun p ->
            let pm = power_map p 0.0 in
            let ihp = Diffmap.Power.ihp pm in
            [((Printf.sprintf "1-x_low.%.2f" p), (fun x1 x2 -> ihp (1.0-.x1)), n, 0.0, ihp 1.0e-4);
             ((Printf.sprintf "1-y_low.%.2f" p), (fun x1 x2 -> ihp (1.0-.x2)), n, 0.0, ihp 1.0e-4);
             ((Printf.sprintf "x_low.%.2f" p), (fun x1 x2 -> ihp x1), n, 0.0, ihp 1.0e-4);
             ((Printf.sprintf "y_low.%.2f" p), (fun x1 x2 -> ihp x2), n, 0.0, ihp 1.0e-4)])
             [center -. 2.0 *. resolution;
              center -. resolution; center; center +. resolution;
              center +. 2.0 *. resolution])) in
   List.iter (fun (tag, h) ->
     to_file (tag ^ suffix) (Histogram.normalize h)) histograms
 
 (* \subsubsection{Testing} *)
 
 let make_test_data n (x_min, x_max) (y_min, y_max) f =
   let delta_x = x_max -. x_min
   and delta_y = y_max -. y_min in
   let array =
     Bigarray.Array2.create Bigarray.float64 Bigarray.fortran_layout 3 n in
   for i = 1 to n do
     let x = x_min +. Random.float delta_x
     and y = y_min +. Random.float delta_y in
     Bigarray.Array2.set array 1 i x;
     Bigarray.Array2.set array 2 i y;
     Bigarray.Array2.set array 3 i (f x y)
   done;
   array
 
 (*i
 let make_test_data n (x_min, x_max) (y_min, y_max) f =
   let delta_x = x_max -. x_min
   and delta_y = y_max -. y_min in
   let array =
     Bigarray.Array2.create Bigarray.float64 Bigarray.fortran_layout 3 n in
   for i = 1 to n do
     let x = x_min +. Random.float delta_x
     and y = y_min +. Random.float delta_y in
     array.{1,i} <- x;
     array.{2,i} <- y;
     array.{3,i} <- f x y
   done;
   array
 i*)
 
 module Div = Division.Mono
 module Grid = Grid.Make (Div)
 
 let test_design grid =
   let channel =
     { Grid.pid1 = 22; Grid.pol1 = 0;
       Grid.pid2 = 22; Grid.pol2 = 0;
       Grid.lumi = 0.0; Grid.g = grid } in
   { Grid.name = "TEST";
     Grid.roots = 500.0;
     Grid.channels = [ channel ];
     Grid.comments = [ "unphysical test" ]}
 
 let test verbose triangle shrink nbins name f =
   let data = make_test_data 100000 (0.4, 0.9) (0.2, 0.7) f in
   let initial_grid =
     Grid.create ~triangle
       (Div.create nbins 0.0 1.0)
       (Div.create nbins 0.0 1.0) in
   let grid =
     Grid.of_bigarray ~verbose
       ~fixed_x1_min:(not shrink) ~fixed_x1_max:(not shrink)
       ~fixed_x2_min:(not shrink) ~fixed_x2_max:(not shrink)
       data initial_grid in
   Grid.designs_to_file name [test_design grid]
 
 let random_interval () =
   let x1 = Random.float 1.0
   and x2 = Random.float 1.0 in
   (min x1 x2, max x1 x2)
 
 module Test_Power = Diffmap.Make_Test (Diffmap.Power)
 module Test_Resonance = Diffmap.Make_Test (Diffmap.Resonance)
 
 let test_maps seed =
   Random.init seed;
   let x_min, x_max = random_interval ()
   and y_min, y_max = random_interval () in
   let alpha = 1.0 +. Random.float 4.0
   and eta =
     if Random.float 1.0 > 0.5 then
       y_max +. Random.float 5.0
     else
       y_min -. Random.float 5.0 in
   Test_Power.all
     (Diffmap.Power.create ~alpha ~eta ~x_min ~x_max y_min y_max);
   let a = Random.float 1.0
   and eta = y_min +. Random.float (y_max -. y_min) in
   Test_Resonance.all
     (Diffmap.Resonance.create ~eta ~a ~x_min ~x_max y_min y_max)
   
 (* \subsubsection{Main Program} *)
 
 type format = ASCII | Binary
 
 type action =
   | Nothing
   | Command_file of string
   | Commands of string
   | Cat
   | Histo of format * string
   | Moments of format * string
   | Regression of format * string
   | Test of string * (float -> float -> float)
   | Test_Diffmaps of int
   | Unit_Tests
   | Log10
   | Exp10
   | Power of format * string
 
 let rec passed = function
   | [] -> true
   | (OUnit.RFailure _ | OUnit.RError _ | OUnit.RTodo _ ) :: _ -> false
   | (OUnit.RSuccess _ | OUnit.RSkip _) :: tail -> passed tail
 
 let _ =
   let usage = "usage: " ^ Sys.argv.(0) ^ " [options]" in
   let nbins = ref 100
   and triangle = ref false
   and shrink = ref false
   and verbose = ref false
   and action = ref Nothing
   and suffix = ref ".histo"
   and input = ref (ASCII_ic stdin)
   and output = ref (ASCII_oc stdout)
   and columns = ref 3
   and histogram_to_file = ref Histogram.to_file
   and center = ref 0.0
   and resolution = ref 0.01 in
   Arg.parse
-    [("-c", Arg.String (fun s -> action := Commands s), "commands");
-     ("-f", Arg.String (fun f -> action := Command_file f), "command file");
-     ("-ia", Arg.String (fun n -> input := ASCII_inf n),
-      "ASCII input file");
-     ("-ib", Arg.String (fun n -> input := Binary_inf n),
-      "Binary input file");
-     ("-oa", Arg.String (fun n -> output := ASCII_outf n),
-      "ASCII output file");
-     ("-ob", Arg.String (fun n -> output := Binary_outf n),
-      "Binary output file");
-     ("-cat", Arg.Unit (fun () ->
-       input := ASCII_ic stdin; output := ASCII_oc stdout;
-       action := Cat), "copy stdin to stdout");
-     ("-log10", Arg.Unit (fun () ->
-       input := ASCII_ic stdin; output := ASCII_oc stdout;
-       action := Log10), "");
-     ("-exp10", Arg.Unit (fun () ->
-       input := ASCII_ic stdin; output := ASCII_oc stdout;
-       action := Exp10), "");
-     ("-ha", Arg.String (fun s -> action := Histo (ASCII, s)),
-      "ASCII histogramming tests");
-     ("-hb", Arg.String (fun s -> action := Histo (Binary, s)),
-      "binary histogramming tests");
-     ("-ma", Arg.String (fun s -> action := Moments (ASCII, s)),
-      "ASCII moments  tests");
-     ("-mb", Arg.String (fun s -> action := Moments (Binary, s)),
-      "binary moments tests");
-     ("-pa", Arg.String (fun s -> action := Power (ASCII, s)), "");
-     ("-pb", Arg.String (fun s -> action := Power (Binary, s)), "");
-     ("-C", Arg.Float (fun c -> center := c), "");
-     ("-R", Arg.Float (fun r -> resolution := r), "");
-     ("-Pa", Arg.String (fun s -> action := Regression (ASCII, s)), "");
-     ("-Pb", Arg.String (fun s -> action := Regression (Binary, s)), "");
-     ("-p", Arg.String (fun s -> suffix := s), "histogram name suffix");
-     ("-h", Arg.Unit (fun () ->
-       histogram_to_file := Histogram.as_bins_to_file), "");
-     ("-b", Arg.Int (fun n -> nbins := n), "#bins");
-     ("-s", Arg.Set shrink, "shrinkwrap interval");
-     ("-S", Arg.Clear shrink, "don't shrinkwrap interval [default]");
-     ("-t", Arg.Set triangle,
-      "project symmetrical distribution onto triangle");
-     ("-v", Arg.Set verbose, "verbose");
-     ("-test", Arg.Unit (fun () -> action := Unit_Tests),
-      "run unit test suite");
-     ("-test1", Arg.String (fun s ->
-       action := Test (s, fun x y -> 1.0)), "testing");
-     ("-test2", Arg.String (fun s ->
-       action := Test (s, fun x y -> x *. y)), "testing");
-     ("-test3", Arg.String (fun s ->
-       action := Test (s, fun x y -> 1.0 /. x +. 1.0 /. y)), "testing");
-     ("-testm", Arg.Int (fun seed -> action := Test_Diffmaps seed),
-      "testing maps") ]
+    (Arg.align
+       [("-c", Arg.String (fun s -> action := Commands s),
+         "string commands to execute");
+        ("-f", Arg.String (fun f -> action := Command_file f),
+         "name command file to read");
+        ("-ia", Arg.String (fun n -> input := ASCII_inf n),
+         "name ASCII input file");
+        ("-ib", Arg.String (fun n -> input := Binary_inf n),
+         "name Binary input file");
+        ("-oa", Arg.String (fun n -> output := ASCII_outf n),
+         "name ASCII output file");
+        ("-ob", Arg.String (fun n -> output := Binary_outf n),
+         "name Binary output file");
+        ("-cat", Arg.Unit (fun () ->
+                     input := ASCII_ic stdin; output := ASCII_oc stdout;
+                     action := Cat),
+         " copy stdin to stdout");
+        ("-log10", Arg.Unit (fun () ->
+                       input := ASCII_ic stdin; output := ASCII_oc stdout;
+                       action := Log10),
+         " apply log10 to all histogram projections");
+        ("-exp10", Arg.Unit (fun () ->
+                       input := ASCII_ic stdin; output := ASCII_oc stdout;
+                       action := Exp10),
+         " apply 10** to all histogram projections");
+        ("-ha", Arg.String (fun s -> action := Histo (ASCII, s)),
+         "name histogramming tests of ASCII file");
+        ("-hb", Arg.String (fun s -> action := Histo (Binary, s)),
+         "name histogramming tests of binary file");
+        ("-ma", Arg.String (fun s -> action := Moments (ASCII, s)),
+         "name moments tests of ASCII file");
+        ("-mb", Arg.String (fun s -> action := Moments (Binary, s)),
+         "name moments tests of binary file");
+        ("-pa", Arg.String (fun s -> action := Power (ASCII, s)),
+         "name apply powers to ASCII file");
+        ("-pb", Arg.String (fun s -> action := Power (Binary, s)),
+         "name apply powers to binary file");
+        ("-C", Arg.Float (fun c -> center := c),
+         Printf.sprintf "center parameter of power map (default=%f)" !center);
+        ("-R", Arg.Float (fun r -> resolution := r),
+         Printf.sprintf "resolution parameter of power map (default=%f)" !resolution);
+        ("-Pa", Arg.String (fun s -> action := Regression (ASCII, s)),
+         "name apply simple regression to ASCII file");
+        ("-Pb", Arg.String (fun s -> action := Regression (Binary, s)),
+         "name apply simple regression to binary file");
+        ("-p", Arg.String (fun s -> suffix := s),
+         "suffix histogram file name suffix");
+        ("-h", Arg.Unit (fun () -> histogram_to_file := Histogram.as_bins_to_file),
+         " write endpoints of histogram bins instead of midpoints");
+        ("-b", Arg.Int (fun n -> nbins := n), "# number of bins");
+        ("-s", Arg.Set shrink, " shrinkwrap interval");
+        ("-S", Arg.Clear shrink, " don't shrinkwrap interval [default]");
+        ("-t", Arg.Set triangle,
+         " project symmetrical distribution onto triangle");
+        ("-v", Arg.Set verbose, " verbose");
+        ("-test", Arg.Unit (fun () -> action := Unit_Tests),
+         " run unit test suite");
+        ("-test1", Arg.String (fun s -> action := Test (s, fun x y -> 1.0)),
+         " testing");
+        ("-test2", Arg.String (fun s -> action := Test (s, fun x y -> x *. y)),
+         " testing");
+        ("-test3", Arg.String (fun s -> action := Test (s, fun x y -> 1.0 /. x +. 1.0 /. y)),
+         " testing");
+        ("-testm", Arg.Int (fun seed -> action := Test_Diffmaps seed),
+         " testing maps") ])
     (fun names -> prerr_endline usage; exit 2)
     usage;
   begin try
     match !action with
     | Nothing -> ()
     | Commands name -> Commands.execute (Commands.parse_string name)
     | Command_file name -> Commands.execute (Commands.parse_file name)
     | Histo (ASCII, name) ->
         histogram_data !histogram_to_file !nbins
           (histogram_ascii name) !suffix
     | Histo (Binary, "-") ->
         histogram_data !histogram_to_file !nbins
           (histogram_binary_channel stdin) !suffix
     | Histo (Binary, name) ->
         histogram_data !histogram_to_file !nbins
           (histogram_binary name) !suffix
     | Moments (ASCII, name) -> moments_data (moments_ascii name)
     | Moments (Binary, name) -> moments_data (moments_binary name)
     | Power (ASCII, name) ->
         power_data !histogram_to_file !nbins !center !resolution
           (histogram_ascii name) !suffix
     | Power (Binary, name) ->
         power_data !histogram_to_file !nbins !center !resolution
           (histogram_binary name) !suffix
     | Regression (ASCII, name) -> regression_data !nbins (histogram_ascii name)
     | Regression (Binary, name) -> regression_data !nbins (histogram_binary name)
     | Cat -> cat !columns !input !output 
     | Log10 -> log10_xy !columns !input !output 
     | Exp10 -> exp10_xy !columns !input !output 
     | Test (name, f) -> test !verbose !triangle !shrink !nbins name f
     | Test_Diffmaps seed -> test_maps seed
     | Unit_Tests ->
         let suite =
           OUnit.(>:::) "All"
             [ThoArray.suite;
              ThoMatrix.suite;
+             Division.Test.suite;
              Filter.suite] in
         if passed (OUnit.run_test_tt ~verbose:!verbose suite) then
           exit 0
         else
           exit 1
 
   with
   | Syntax.Syntax_Error (msg, _, _) ->
       Printf.eprintf "%s: parse error: %s\n" Sys.argv.(0) msg;
       exit 1
   end;
   exit 0
-
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
Index: trunk/circe2/src/diffmap.mli
===================================================================
--- trunk/circe2/src/diffmap.mli	(revision 8897)
+++ trunk/circe2/src/diffmap.mli	(revision 8898)
@@ -1,197 +1,196 @@
 (* circe2/diffmap.mli --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 module type T =
   sig
 
     type t
 
     (* An invertible differentiable map is characterized by its
        domain~$\lbrack x_{\min},x_{\max}\rbrack$ *)
     type domain
     val x_min : t -> domain
     val x_max : t -> domain
 
     (* and codomain~$\lbrack y_{\min},y_{\max}\rbrack$ *)
     type codomain
     val y_min : t -> codomain
     val y_max : t -> codomain
 
     (* the map proper
        \begin{equation}
          \begin{aligned}
            \phi : \lbrack x_{\min},x_{\max}\rbrack 
                &\to \lbrack y_{\min},y_{\max}\rbrack  \\
              x &\mapsto y = \phi(x)
          \end{aligned}
        \end{equation} *)
     val phi : t -> domain -> codomain
 
     (* the inverse map
        \begin{equation}
          \begin{aligned}
            \phi^{-1} : \lbrack y_{\min},y_{\max}\rbrack 
                &\to \lbrack x_{\min},x_{\max}\rbrack  \\
              y &\mapsto x = \phi^{-1}(y)
          \end{aligned}
        \end{equation} *)
     val ihp : t -> codomain -> domain
 
     (* the jacobian of the map
        \begin{equation}
          \begin{aligned}
            J : \lbrack x_{\min},x_{\max}\rbrack 
                &\to \mathbf{R} \\
              x &\mapsto J(x) = \frac{\mathrm{d}\phi}{\mathrm{d}x}(x)
          \end{aligned}
        \end{equation} *)
     val jac : t -> domain -> float
 
     (* and finally the jacobian of the inverse map
        \begin{equation}
          \begin{aligned}
            J^{*} : \lbrack y_{\min},y_{\max}\rbrack 
                &\to \mathbf{R} \\
              y &\mapsto J^{*}(y)
                   = \frac{\mathrm{d}\phi^{-1}}{\mathrm{d}y}(y)
                   = \left(\frac{\mathrm{d}\phi}{\mathrm{d}x}(\phi^{-1}(y))\right)^{-1}
          \end{aligned}
        \end{equation} *)
     val caj : t -> codomain -> float
 
+    val is_null : t -> bool
+
     (* [with_domain map x_min x_max] takes the map [map] and
        returns the `same' map with the new
        domain~$\lbrack x_{\min},x_{\max}\rbrack$ *)
     val with_domain : t -> x_min:domain -> x_max:domain -> t
 
     (* There is also a convention for encoding the map so that
        it can be read by \KirkeTwo/: *)
     val encode : t -> string
 
   end
 
 (* For the application in \KirkeTwo/, it suffices to consider real maps.
    Introducing [domain] and [codomain] does not make any difference for
    the typechecker as long as we only use [Diffmap.Real], but it provides
    documentation and keeps the door for extensions open. *)
 module type Real = T with type domain = float and type codomain = float
 
 (* \subsection{Testing Real Maps} *)
 
 module type Test =
   sig
     module M : Real
     val domain : M.t -> unit
     val inverse : M.t -> unit
     val jacobian : M.t -> unit
     val all : M.t -> unit
   end
 
 module Make_Test (M : Real) : Test with module M = M
 
 (* \subsection{Specific Real Maps} *)
 
 module Id :
     sig
       include Real
  
       (* [create x_min x_max y_min y_max] creates an identity map
          $\lbrack x_{\min},x_{\max}\rbrack\to
           \lbrack y_{\min},y_{\max}\rbrack$.
          \begin{equation}
             \begin{aligned}
               \iota : \lbrack x_{\min},x_{\max}\rbrack
                  &\to \lbrack x_{\min},x_{\max}\rbrack  \\
                x &\mapsto \iota(x) = x
             \end{aligned}
          \end{equation}
          Default values for [x_min] and~[x_max] are [y_min] and~[y_max],
          respectively.   Indeed, they are the only
          possible values and other values raise an exception. *)
       val create :
           ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     end
 
+module Null :
+    sig
+      include Real
+      val create :
+          ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
+    end
+
 module Linear :
     sig
       include Real
 
       (* [create x_min x_max y_min y_max] creates a linear map
          $\lbrack x_{\min},x_{\max}\rbrack\to\lbrack y_{\min},y_{\max}\rbrack$.
          The parameters~$a$ and~$b$ are determined from domain and codomain.
          \begin{equation}
             \begin{aligned}
               \lambda_{a,b} :
                 \lbrack x_{\min},x_{\max}\rbrack  &\to \lbrack y_{\min},y_{\max}\rbrack  \\
                x &\mapsto \lambda_{a,b}(x) = ax + b
             \end{aligned}
          \end{equation}
          Default values for [x_min] and~[x_max] are [y_min] and~[y_max],
          respectively. *)
       val create :
           ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     end
 
 module Power :
     sig
       include Real
 
       (* [create alpha eta x_min x_max y_min y_max] creates a power map
          $\lbrack x_{\min},x_{\max}\rbrack\to\lbrack y_{\min},y_{\max}\rbrack$.
          The parameters~$\xi$, $a$ and~$b$ are determined from~$\alpha$,
          $\eta$, domain and codomain. 
          \begin{equation}
             \begin{aligned}
               \psi_{a,b}^{\alpha,\xi,\eta} : \lbrack x_{\min},x_{\max}\rbrack
                  &\to \lbrack y_{\min},y_{\max}\rbrack  \\
                x &\mapsto \psi_{a,b}^{\alpha,\xi,\eta}(x)
                       = \frac{1}{b}(a(x-\xi))^{\alpha} + \eta
             \end{aligned}
          \end{equation}
          Default values for [x_min] and~[x_max] are [y_min] and~[y_max],
          respectively. *) 
       val create : alpha:float -> eta:float ->
         ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     end
 
 module Resonance :
     sig
       include Real
 
       (* [create eta a x_min x_max y_min y_max] creates a resonance map
          $\lbrack x_{\min},x_{\max}\rbrack\to\lbrack y_{\min},y_{\max}\rbrack$.
          \begin{equation}
             \begin{aligned}
               \rho_{a,b}^{\xi,\eta}: \lbrack x_{\min},x_{\max}\rbrack 
                  &\to \lbrack y_{\min},y_{\max}\rbrack  \\
                x &\mapsto \rho_{a,b}^{\xi,\eta}(x)
                   = a \tan\left(\frac{a}{b^2}(x-\xi)\right) + \eta
             \end{aligned}
          \end{equation}
          The parameters~$\xi$ and~$b$ are determined from~$\eta$, $a$,
          domain and codomain. Default values for [x_min] and~[x_max] are
          [y_min] and~[y_max], respectively. *) 
       val create : eta:float -> a:float ->
         ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     end
-
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
-
-
Index: trunk/circe2/src/circe2.nw
===================================================================
--- trunk/circe2/src/circe2.nw	(revision 8897)
+++ trunk/circe2/src/circe2.nw	(revision 8898)
@@ -1,1941 +1,1959 @@
 % -*- ess-noweb-default-code-mode: f90-mode; noweb-default-code-mode: f90-mode; -*- 
 % circe2/circe2.nw -- 
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Implementation of [[circe2]]}
 <<Version>>=
 'Version 3.1.2.1'
 @ 
 <<[[implicit none]]>>=
 implicit none
 @ 
 <<[[circe2.f90]]>>=
 ! circe2.f90 -- correlated beam spectra for linear colliders
 <<Copyleft notice>>
 <<Separator>>
 module circe2
   use kinds
   implicit none
   private
   <<[[circe2]] parameters>>
   <<[[circe2]] declarations>>
 contains
   <<[[circe2]] implementation>>
 end module circe2
 @ 
 <<Separator>>=
 !-----------------------------------------------------------------------
 @ The following is usually not needed for scientific programs.  Nobody
 is going to hijack such code.  But let us include it anyway to spread
 the gospel of free software:
 <<Copyleft notice>>=
 ! Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
 !
 ! Circe2 is free software; you can redistribute it and/or modify it
 ! under the terms of the GNU General Public License as published by
 ! the Free Software Foundation; either version 2, or (at your option)
 ! any later version.
 !
 ! Circe2 is distributed in the hope that it will be useful, but
 ! WITHOUT ANY WARRANTY; without even the implied warranty of
 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ! GNU General Public License for more details.
 !
 ! You should have received a copy of the GNU General Public License
 ! along with this program; if not, write to the Free Software
 ! Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Data}
 <<[[circe2]] declarations>>=
 type circe2_division
   <<[[circe2_division]] members>>
 end type circe2_division
 @
 <<[[circe2]] declarations>>=
 type circe2_channel
   <<[[circe2_channel]] members>>
 end type circe2_channel
 @
 <<[[circe2]] declarations>>=
 type circe2_state
   <<[[circe2_state]] members>>
 end type circe2_state
 public :: circe2_state
 @ 
 \begin{figure}
   \begin{center}
     \begin{empgraph}(110,60)
       setrange (0, 0, 1, 1);
       autogrid (,);
       pickup pencircle scaled 0.5pt;
       for i = 2 step 2 until 8:
         x := i / 10;
         gdraw (0,x) -- (1,x);
         gdraw (x,0) -- (x,1);
       endfor
       glabel (btex $x_{1}^{\min}$ etex, (0.0,-0.1));
       glabel (btex $x_{1}^{\max}$ etex, (1.0,-0.1));
       glabel (btex $x_{2}^{\min}$ etex, (-0.1,0.0));
       glabel (btex $x_{3}^{\max}$ etex, (-0.1,1.0));
       glabel (btex $i_1=1$ etex, (0.1,-0.1));
       glabel (btex $2$ etex, (0.3,-0.1));
       glabel (btex $3$ etex, (0.5,-0.1));
       glabel (btex $\ldots$ etex, (0.7,-0.1));
       glabel (btex $n_1$ etex, (0.9,-0.1));
       glabel (btex $1$ etex, (-0.1,0.1));
       glabel (btex $2$ etex, (-0.1,0.3));
       glabel (btex $3$ etex, (-0.1,0.5));
       glabel (btex $\ldots$ etex, (-0.1,0.7));
       glabel (btex $i_2=n_2$ etex, (-0.1,0.9));
       glabel (btex $1$ etex, (0.1,0.1));
       glabel (btex $2$ etex, (0.3,0.1));
       glabel (btex $3$ etex, (0.5,0.1));
       glabel (btex $\ldots$ etex, (0.7,0.1));
       glabel (btex $n_1$ etex, (0.9,0.1));
       glabel (btex $n_1+1$ etex, (0.1,0.3));
       glabel (btex $n_1+2$ etex, (0.3,0.3));
       glabel (btex $\ldots$ etex, (0.5,0.3));
       glabel (btex $\ldots$ etex, (0.7,0.3));
       glabel (btex $2n_1$ etex, (0.9,0.3));
       glabel (btex $2n_1+1$ etex, (0.1,0.5));
       glabel (btex $\ldots$ etex, (0.3,0.5));
       glabel (btex $\ldots$ etex, (0.5,0.5));
       glabel (btex $\ldots$ etex, (0.7,0.5));
       glabel (btex $\ldots$ etex, (0.9,0.5));
       glabel (btex $\ldots$ etex, (0.1,0.7));
       glabel (btex $\ldots$ etex, (0.3,0.7));
       glabel (btex $\ldots$ etex, (0.5,0.7));
       glabel (btex $\ldots$ etex, (0.7,0.7));
       glabel (btex $n_1(n_2-1)$ etex, (0.9,0.7));
       glabel (btex $\displaystyle {n_1(n_2-1)\atop\mbox{}+1}$ etex, (0.1,0.9));
       glabel (btex $\displaystyle {n_1(n_2-1)\atop\mbox{}+2}$ etex, (0.3,0.9));
       glabel (btex $\ldots$ etex, (0.5,0.9));
       glabel (btex $n_1n_2-1$ etex, (0.7,0.9));
       glabel (btex $n_1n_2$ etex, (0.9,0.9));
       pickup pencircle scaled 1.0pt;
     \end{empgraph}
   \end{center}
   \caption{\label{fig:linear-enumeration}%
     Enumerating the bins linearly, starting from 1 (Fortran style).
     Probability distribution functions will have a sentinel at~0
     that's always~0.}
 \end{figure}
 We store the probability distribution function as a one-dimensional
 array~[[wgt]]\footnote{The second ``dimension'' is just an index for
 the channel.}, since this simplifies the binary search used for
 inverting the distribution.  [wgt(0,ic)] is always 0 and serves as a
 convenient sentinel for the binary search.  It is \emph{not} written
 in the file, which contains the normalized weight of the bins.
 <<[[circe2_state]] members>>=
 type(circe2_channel), dimension(:), allocatable :: ch
 @
 <<[[circe2_channel]] members>>=
 real(kind=default), dimension(:), allocatable :: wgt
 @ 
 <<[[circe2_channel]] members>>=
 type(circe2_division), dimension(2) :: d
 @ Using figure~\ref{fig:linear-enumeration}, calculating the
 index of a bin from the two-dimensional coordinates is
 straightforward, of course:
 \begin{equation}
   i = i_1 + (i_2 - 1) n_1\,.
 \end{equation}
 The inverse
 \begin{subequations}
 \begin{align}
   i_1 &= 1 + ((i - 1) \mod n_1) \\
   i_2 &= 1 + \lfloor (i - 1) / n_1 \rfloor
 \end{align}
 \end{subequations}
 can also be written
 \begin{subequations}
 \begin{align}
   i_2 &= 1 + \lfloor (i - 1) / n_1 \rfloor \\
   i_1 &= i - (i_2 - 1) n_1
 \end{align}
 \end{subequations}
 because
 \begin{subequations}
 \begin{multline}
    1 + \lfloor (i - 1) / n_1 \rfloor
     = 1 + \lfloor i_2 - 1 + (i_1 - 1) / n_1 \rfloor \\
     = 1 + \lfloor (i_1 + (i_2 - 1) n_1 - 1) / n_1 \rfloor
     = 1 + i_2 - 1 + \underbrace{\lfloor (i_1 - 1) / n_1 \rfloor}_{=0}
     = i_2
 \end{multline}
 and trivially
 \begin{equation}
    i - (i_2 - 1) n_1
     = i_1 + (i_2 - 1) n_1 - (i_2 - 1) n_1 = i_1
 \end{equation}
 \end{subequations}
 <<$([[i1]],[[i2]]) \leftarrow [[i]]$>>=
 i2 = 1 + (i - 1) / ubound (ch%d(1)%x, dim=1)
 i1 = i - (i2 - 1) * ubound (ch%d(1)%x, dim=1)
 @ 
 <<$[[ib]] \leftarrow [[i]]$>>=
 ib(2) = 1 + (i - 1) / ubound (ch%d(1)%x, dim=1)
 ib(1) = i - (ib(2) - 1) * ubound (ch%d(1)%x, dim=1)
 @ The density normalized to the bin size
 \begin{equation*}
    v = \frac{w}{\Delta x_1 \Delta x_2}
 \end{equation*}
 such that
 \begin{equation*}
    \int\!\mathrm{d}x_1\mathrm{d}x_2\; v = \sum w = 1
 \end{equation*}
 For mapped distributions, on the level of bins, we can either use the
 area of the domain and apply a jacobian or the area of the codomain
 directly
 \begin{equation}
 \label{eq:jacobian-Delta_x-Delta_y}
  \frac{\mathrm{d}x}{\mathrm{d}y}\cdot\frac{1}{\Delta x}
    \approx \frac{1}{\Delta y}
 \end{equation}
 We elect to use the former, because this reflects the distribution
 of the events generated by~[[circe2_generate]] \emph{inside} the bins as well.
 This quantity is more conveniently stored as a true two-dimensional array:
 <<[[circe2_channel]] members>>=
 real(kind=default), dimension(:,:), allocatable :: val
 @
 \begin{figure}
   \begin{center}
     \begin{empgraph}(50,50)
       pickup pencircle scaled 1.0pt;
       setrange (0, 0, 1, 1);
       autogrid (,);
       for i = 1 upto 15:
         xi := i / 16;
         x := 1 - xi * xi * xi;
         gdraw (0,x) -- (1,x);
         gdraw (x,0) -- (x,1);
       endfor
     \end{empgraph}
   \end{center}
   \caption{%
     Almost factorizable distributions, like $\mathrm{e}^+\mathrm{e}^-$.}
 \end{figure}
 <<[[circe2_division]] members>>=
 real(kind=default), dimension(:), allocatable :: x
 @
 \begin{figure}
   \begin{center}
     \begin{empgraph}(50,50)
       setrange (0, 0, 1, 1);
       autogrid (,);
       for i = 1 upto 15:
         xi := i / 16;
         x := 1 - xi * xi * xi;
         pickup pencircle scaled 1.0pt;
         gdraw (0,0) -- (1,x);
         pickup pencircle scaled 0.5pt;
         gdraw (0,0) -- (x,1);
       endfor
       for i = 1 upto 15:
         xi := i / 16;
         x := 0.8 * (1 - xi * xi * xi);
         pickup pencircle scaled 1.0pt;
         gdraw (x,0) -- (x,x);
         pickup pencircle scaled 0.5pt;
         gdraw (0,x) -- (x,x);
       endfor
       pickup pencircle scaled 1.0pt;
       gdraw (0,0) -- (1,1);
     \end{empgraph}
   \end{center}
   \caption{%
     Symmetrical, strongly correlated distributions, e.\,g.~with a
     ridge on the diagonal, like $\gamma\gamma$ at a $\gamma$-collider.}
 \end{figure}
 <<[[circe2_channel]] members>>=
 logical :: triang
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Channels}
 The number of available channels $\gamma\gamma$, $\mathrm{e}^-\gamma$,
 $\mathrm{e}^-\mathrm{e}^+$, etc. can be found with
 [[size (circe2_state%ch)]].
 @ The particles that are described by this channel and their
 polarizations:
 <<[[circe2_channel]] members>>=
 integer, dimension(2) :: pid, pol
 @ The integrated luminosity of the channel
 <<[[circe2_channel]] members>>=
 real(kind=default) :: lumi
 @ The integrated luminosity of the channel
 <<[[circe2_state]] members>>=
 real(kind=default), dimension(:), allocatable :: cwgt
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Maps}
 <<[[circe2_division]] members>>=
 integer, dimension(:), allocatable :: map
 @ 
 <<[[circe2_division]] members>>=
 real(kind=default), dimension(:), allocatable :: y
 @ 
 <<[[circe2_division]] members>>=
 real(kind=default), dimension(:), allocatable :: alpha, xi, eta, a, b
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Random Number Generation}
 We use the new WHIZARD interface.
 <<[[circe2]] declarations>>=
 public :: rng_type
 type, abstract :: rng_type
   contains
     procedure(rng_generate), deferred :: generate
 end type rng_type
 @
 <<[[circe2]] declarations>>=
 abstract interface
    subroutine rng_generate (rng_obj, u)
      import :: rng_type, default
      class(rng_type), intent(inout) :: rng_obj
      real(kind=default), intent(out) :: u
    end subroutine rng_generate
 end interface
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Generation}
 Generate a two-dimensional distribution for~$([[x1]],[[x2]])$
 according to the histogram for channel [[ic]].
 @
 <<[[circe2]] declarations>>=
 public :: circe2_generate
 interface circe2_generate
    module procedure circe2_generate_ph
 end interface circe2_generate
 @ 
 <<[[circe2]] implementation>>=
 subroutine circe2_generate_ph (c2s, rng, y, p, h)
   type(circe2_state), intent(in) :: c2s
   class(rng_type), intent(inout) :: rng
   real(kind=default), dimension(:), intent(out) :: y
   integer, dimension(:), intent(in) :: p
   integer, dimension(:), intent(in) :: h
   integer :: i, ic
   <<Find [[ic]] for [[p]] and [[h]]>>
   <<Complain and [[return]] iff $[[ic]] \le 0$>>
   call circe2_generate_channel (c2s%ch(ic), rng, y)
 end subroutine circe2_generate_ph
 <<Separator>>
 @
 <<[[circe2]] declarations>>=
 interface circe2_generate
    module procedure circe2_generate_channel
 end interface circe2_generate
 @ 
 <<[[circe2]] implementation>>=
 subroutine circe2_generate_channel (ch, rng, y)
   type(circe2_channel), intent(in) :: ch
   class(rng_type), intent(inout) :: rng
   real(kind=default), dimension(:), intent(out) :: y
   integer :: i, d, ibot, itop
   integer, dimension(2) :: ib
   real(kind=default), dimension(2) :: x, v
   real(kind=default) :: u, tmp
   call rng%generate (u)
   <<Do a binary search for $[[wgt(i-1)]] \le [[u]] < [[wgt(i)]]$>>
   <<$[[ib]] \leftarrow [[i]]$>>
   <<$[[x]]\in[ [[x(ib-1)]], [[x(ib)]] ]$>>
   y = circe2_map (ch%d, x, ib)
   <<Inverse triangle map>>
 end subroutine circe2_generate_channel
 <<Separator>>
 @
 <<[[circe2_state]] members>>=
 integer :: polspt
 @
 <<[[circe2]] parameters>>=
 integer, parameter :: POLAVG = 1, POLHEL = 2, POLGEN = 3
 @ A linear search for a matching channel should suffice, because the
 number if channels~[[nc]] will always be a small number.  The most
 popular channels should be first in the list, anyway.
 <<Find [[ic]] for [[p]] and [[h]]>>=
 ic = 0
 if ((c2s%polspt == POLAVG .or. c2s%polspt == POLGEN) .and. any (h /= 0)) then
    write (*, '(2A)') 'circe2: current beam description ', &
         'supports only polarization averages'
 else if (c2s%polspt == POLHEL .and. any (h == 0)) then
    write (*, '(2A)') 'circe2: polarization averages ', &
         'not supported by current beam description'
 else
    do i = 1, size (c2s%ch)
       if (all (p == c2s%ch(i)%pid .and. h == c2s%ch(i)%pol)) then
          ic = i
       end if
    end do
 end if
 @
 <<Complain and [[return]] iff $[[ic]] \le 0$>>=
 if (ic <= 0) then
    write (*, '(A,2I4,A,2I3)') &
         'circe2: no channel for particles', p, &
         ' and polarizations', h
    y = - huge (y)
    return
 end if
 @ The number of bins is typically \emph{much} larger and we must use a
 binary search to get a reasonable performance.
 <<Do a binary search for $[[wgt(i-1)]] \le [[u]] < [[wgt(i)]]$>>=
 ibot = 0
 itop = ubound (ch%wgt, dim=1)
 do
    if (itop <= ibot + 1) then
       i = ibot + 1
       exit
    else
       i = (ibot + itop) / 2
       if (u < ch%wgt(i)) then
          itop = i
       else
          ibot = i
       end if
    end if
 end do
 @
 <<$[[x]]\in[ [[x(ib-1)]], [[x(ib)]] ]$>>=
 call rng%generate (v(1))
 call rng%generate (v(2))
 do d = 1, 2
   x(d) = ch%d(d)%x(ib(d))*v(d) + ch%d(d)%x(ib(d)-1)*(1-v(d))
 end do
 @ The NAG compiler is picky and doesn't like $(-0)^\alpha$ at all.
 <<$y\leftarrow(a(x-\xi))^\alpha/b + \eta$>>=
 z = d%a(b) * (x - d%xi(b))
 if (abs (z) <= tiny (z)) then
    z = abs (z)
 end if
 y = z**d%alpha(b) / d%b(b) + d%eta(b)
 @ 
 <<[[circe2]] implementation>>=
 elemental function circe2_map (d, x, b) result (y)
    type(circe2_division), intent(in) :: d
    real(kind=default), intent(in) :: x
    integer, intent(in) :: b
    real(kind=default) :: y
    real(kind=default) :: z
    select case (d%map(b))
    case (0)
       y = x
    case (1)
       <<$y\leftarrow(a(x-\xi))^\alpha/b + \eta$>>
    case (2)
       y = d%a(b) * tan (d%a(b)*(x-d%xi(b)) / d%b(b)**2) + d%eta(b)
    case default
       y = - huge (y)
    end select
 end function circe2_map
 @ cf.~(\ref{eq:jacobian-Delta_x-Delta_y})
 <<[[circe2]] implementation>>=
 elemental function circe2_jacobian (d, y, b) result (j)
    type(circe2_division), intent(in) :: d
    real(kind=default), intent(in) :: y
    integer, intent(in) :: b
    real(kind=default) :: j
    select case (d%map(b))
    case (0)
       j = 1
    case (1)
       j = d%b(b) / (d%a(b)*d%alpha(b)) &
         * (d%b(b)*(y-d%eta(b)))**(1/d%alpha(b)-1)
    case (2)
       j = d%b(b)**2 / ((y-d%eta(b))**2 + d%a(b)**2)
    case default
       j = - huge (j)
    end select
 end function circe2_jacobian
 @
 \begin{dubious}
   There's still something wrong with \emph{unweighted} events
   for the case that there is a triangle map \emph{together} with a
   non-trivial $[[x(2)]]\to[[y(2)]]$ map. \emph{Fix this!!!}
 \end{dubious}
 <<Inverse triangle map>>=
 if (ch%triang) then
    y(2) = y(1) * y(2)
    <<Swap [[y(1)]] and [[y(2)]] in 50\%{} of the cases>>
 end if
 @
 <<Swap [[y(1)]] and [[y(2)]] in 50\%{} of the cases>>=
 call rng%generate (u)
 if (2*u >= 1) then
    tmp = y(1)
    y(1) = y(2)
    y(2) = tmp
 end if
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Channel selection}
 We could call [[circe2_generate]] immediately, but then [[circe2_generate]] and
 [[cir2_choose_channel]] would have the same calling conventions and might have
 caused a lot of confusion.
 <<[[circe2]] declarations>>=
 public :: circe2_choose_channel
 interface circe2_choose_channel
    module procedure circe2_choose_channel
 end interface circe2_choose_channel
 @ 
 <<[[circe2]] implementation>>=
 subroutine circe2_choose_channel (c2s, rng, p, h)
   type(circe2_state), intent(in) :: c2s
   class(rng_type), intent(inout) :: rng
   integer, dimension(:), intent(out) :: p, h
   integer :: ic, ibot, itop
   real(kind=default) :: u
   call rng%generate (u)
   ibot = 0
   itop = size (c2s%ch)
   do
      if (itop <= ibot + 1) then
         ic = ibot + 1
         p = c2s%ch(ic)%pid
         h = c2s%ch(ic)%pol
         return
      else
         ic = (ibot + itop) / 2
         if (u < c2s%cwgt(ic)) then
            itop = ic
         else
            ibot = ic
         end if
      end if
   end do
   write (*, '(A)') 'circe2: internal error'
   stop
 end subroutine circe2_choose_channel
 @ Below, we will always have $[[h]]=0$. but we don't have to
 check this explicitely, because [[circe2_density_matrix]] will do it anyway.  The
 procedure could be made more efficient, since most of [[circe2_density_matrix]] is
 undoing parts of [[circe2_generate]].  
 <<[[circe2]] declarations>>=
 public :: circe2_generate_polarized
 interface circe2_generate_polarized
    module procedure circe2_generate_polarized
 end interface circe2_generate_polarized
 @
 <<[[circe2]] implementation>>=
 subroutine circe2_generate_polarized (c2s, rng, p, pol, x)
   type(circe2_state), intent(in) :: c2s
   class(rng_type), intent(inout) :: rng
   integer, dimension(:), intent(out) :: p
   real(kind=default), intent(out) :: pol(0:3,0:3)
   real(kind=default), dimension(:), intent(out) :: x
   integer, dimension(2) :: h
   integer :: i1, i2
   real(kind=default) :: pol00
   call circe2_choose_channel (c2s, rng, p, h)
   call circe2_generate (c2s, rng, x, p, h)
   call circe2_density_matrix (c2s, pol, p, x)
   pol00 = pol(0,0)
   do i1 = 0, 3
      do i2 = 0, 3
         pol(i1,i2) = pol(i1,i2) / pol00
      end do
   end do
 end subroutine circe2_generate_polarized
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Luminosity}
 <<[[circe2]] declarations>>=
 public :: circe2_luminosity
 @ 
 <<[[circe2]] implementation>>=
 function circe2_luminosity (c2s, p, h)
   type(circe2_state), intent(in) :: c2s
   integer, dimension(:), intent(in) :: p
   integer, dimension(:), intent(in) :: h
   real(kind=default) :: circe2_luminosity
   integer :: ic
   circe2_luminosity = 0
   do ic = 1, size (c2s%ch)
      if (       all (p == c2s%ch(ic)%pid .or. p == 0) &
           .and. all (h == c2s%ch(ic)%pol .or. h == 0)) then
         circe2_luminosity = circe2_luminosity + c2s%ch(ic)%lumi
      end if
   end do
 end function circe2_luminosity
 <<Separator>>
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{2D-Distribution}
 <<[[circe2]] declarations>>=
 public :: circe2_distribution
 interface circe2_distribution
    module procedure circe2_distribution_ph
 end interface circe2_distribution
 @ 
 <<[[circe2]] implementation>>=
 function circe2_distribution_ph (c2s, p, h, yy)
   type(circe2_state), intent(in) :: c2s
   integer, dimension(:), intent(in) :: p
   real(kind=default), dimension(:), intent(in)  :: yy
   integer, dimension(:), intent(in) :: h
   real(kind=default) :: circe2_distribution_ph
   integer :: i, ic
   <<Find [[ic]] for [[p]] and [[h]]>>
   if (ic <= 0) then
      circe2_distribution_ph = 0
   else
      circe2_distribution_ph = circe2_distribution_channel (c2s%ch(ic), yy)
   end if
 end function circe2_distribution_ph
 <<Separator>>
 @ 
 <<[[circe2]] declarations>>=
 interface circe2_distribution
    module procedure circe2_distribution_channel
 end interface circe2_distribution
 @
 <<[[circe2]] implementation>>=
 function circe2_distribution_channel (ch, yy)
   type(circe2_channel), intent(in) :: ch
   real(kind=default), dimension(:), intent(in)  :: yy
   real(kind=default) :: circe2_distribution_channel
   real(kind=default), dimension(2) :: y
   integer :: d, ibot, itop
   integer, dimension(2) :: ib
   <<$[[y]])\leftarrow[[yy]]$>>
   if (      y(1) < ch%d(1)%y(0) &
        .or. y(1) > ch%d(1)%y(ubound (ch%d(1)%y, dim=1)) &
        .or. y(2) < ch%d(2)%y(0) &
        .or. y(2) > ch%d(2)%y(ubound (ch%d(2)%y, dim=1))) then
      circe2_distribution_channel = 0
      return
   end if
   <<Do a binary search for $[[y(ib-1)]] \le [[y]] < [[y(ib)]]$>>
   circe2_distribution_channel = &
       ch%val(ib(1),ib(2)) * product (circe2_jacobian (ch%d, y, ib))
   <<Apply Jacobian for triangle map>>
 end function circe2_distribution_channel
 <<Separator>>
 @ The triangle map
 \begin{equation}
   \begin{aligned}
     \tau : \{(x_{1},x_{2}) \in [0,1]\times[0,1] : x_{2} \le x_{1} \}
                     &\to [0,1]\times[0,1] \\
       (x_{1},x_{2}) &\mapsto (y_{1},y_{2}) = (x_{1},x_{1}x_{2})
   \end{aligned}
 \end{equation}
 and its inverse
 \begin{equation}
   \begin{aligned}
     \tau^{-1} : [0,1]\times[0,1]
        &\to \{(x_{1},x_{2}) \in [0,1]\times[0,1] : x_{2} \le x_{1} \} \\
       (y_{1},y_{2}) &\mapsto (x_{1},x_{2}) = (y_{1},y_{2}/y_{1})
   \end{aligned}
 \end{equation}
 <<$[[y]])\leftarrow[[yy]]$>>=
 if (ch%triang) then
    y(1) = maxval (yy)
    y(2) = minval (yy) / y(1)
 else
    y = yy
 end if
 @ with the jacobian~$J^*(y_{1},y_{2})=1/y_{2}$ from
 \begin{equation}
   \mathrm{d}x_{1}\wedge\mathrm{d}x_{2}
     = \frac{1}{y_{2}} \cdot \mathrm{d}y_{1}\wedge\mathrm{d}y_{2}
 \end{equation}
 <<Apply Jacobian for triangle map>>=
 if (ch%triang) then
    circe2_distribution_channel = circe2_distribution_channel / y(1)
 end if
 @ Careful: the loop over [[d]] \emph{must} be executed sequentially,
 because of the shared local variables [[ibot]] and [[itop]].
 <<Do a binary search for $[[y(ib-1)]] \le [[y]] < [[y(ib)]]$>>=
 do d = 1, 2
    ibot = 0
    itop = ubound (ch%d(d)%x, dim=1)
    search: do
       if (itop <= ibot + 1) then
          ib(d) = ibot + 1
          exit search
       else
          ib(d) = (ibot + itop) / 2
          if (y(d) < ch%d(d)%y(ib(d))) then
             itop = ib(d)
          else
             ibot = ib(d)
          end if
       end if
    end do search
 end do
 @ 
 <<[[circe2]] declarations>>=
 public :: circe2_density_matrix
 @ 
 <<[[circe2]] implementation>>=
 subroutine circe2_density_matrix (c2s, pol, p, x)
   type(circe2_state), intent(in) :: c2s
   real(kind=default), dimension(0:,0:), intent(out) :: pol
   integer, dimension(:), intent(in) :: p
   real(kind=default), dimension(:), intent(in) :: x
   <<Test support for density matrices>>
   print *, 'circe2: circe2_density_matrix not implemented yet!'
   if (p(1) < p(2) .and. x(1) < x(2)) then
      ! nonsense test to suppress warning
   end if
   pol = 0
 end subroutine circe2_density_matrix
 <<Separator>>
 @ 
 <<Test support for density matrices>>=
 if (c2s%polspt /= POLGEN) then
    write (*, '(2A)') 'circe2: current beam ', &
         'description supports no density matrices'
    return
 end if
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Reading Files}
 <<[[circe2]] declarations>>=
 public :: circe2_load
 <<Error codes for [[circe2_load]]>>
 @
 <<Error codes for [[circe2_load]]>>=
 integer, parameter, public :: &
      EOK = 0, EFILE = -1, EMATCH = -2, EFORMT = -3, ESIZE = -4
 @ 
 <<[[circe2]] implementation>>=
 subroutine circe2_load (c2s, file, design, roots, ierror)
   type(circe2_state), intent(out) :: c2s
   character(len=*), intent(in) :: file, design
   real(kind=default), intent(in) :: roots
   integer, intent(out) :: ierror
   character(len=72) :: buffer, fdesgn, fpolsp
   real(kind=default) :: froots
   integer :: lun, loaded, prefix
   logical match
   <<Local variables in [[circe2_load]]>>
   <<Find free logical unit for [[lun]]>>
   if (lun < 0) then
      write (*, '(A)') 'circe2_load: no free unit'
      ierror = ESIZE
      return
   end if
   loaded = 0
   <<Open [[name]] for reading on [[lun]]>>
   if (ierror .gt. 0) then
      write (*, '(2A)') 'circe2_load: ', <<Version>>                         
   end if
   prefix = index (design, '*') - 1
   do
      <<Skip comments until [[CIRCE2]]>>
      if (buffer(8:15) == 'FORMAT#1') then
         read (lun, *)
         read (lun, *) fdesgn, froots
         <<Check if [[design]] and [[fdesgn]] do [[match]]>>
         if (match .and. abs (froots - roots) <= 1) then
            <<Load histograms>>
            loaded = loaded + 1
         else
            <<Skip data until [[ECRIC2]]>>
            cycle
         end if
      else
         write (*, '(2A)') 'circe2_load: invalid format: ', buffer(8:72)
         ierror = EFORMT
         return
      end if
      <<Check for [[ECRIC2]]>>
   end do
 end subroutine circe2_load
 <<Separator>>
 @ 
 <<Check if [[design]] and [[fdesgn]] do [[match]]>>=
 match = .false.
 if (fdesgn == design) then
    match = .true.
 else if (prefix == 0) then
    match = .true.
 else if (prefix .gt. 0) then
    if (fdesgn(1:min(prefix,len(fdesgn))) &
         == design(1:min(prefix,len(design)))) then
       match = .true.
    end if
 end if
 @ 
 <<Load histograms>>=
 read (lun, *) 
 read (lun, *) nc, fpolsp
 allocate (c2s%ch(nc), c2s%cwgt(0:nc))
 <<Decode polarization support>>
 c2s%cwgt(0) = 0
 do ic = 1, nc
    call circe2_load_channel (c2s%ch(ic), c2s%polspt, lun, ierror)
    c2s%cwgt(ic) = c2s%cwgt(ic-1) + c2s%ch(ic)%lumi
 end do
 c2s%cwgt = c2s%cwgt / c2s%cwgt(nc)
 @
 <<[[circe2]] implementation>>=
 subroutine circe2_load_channel (ch, polspt, lun, ierror)
   type(circe2_channel), intent(out) :: ch
   integer, intent(in) :: polspt, lun
   integer, intent(out) :: ierror
   integer :: d, i, ib
   integer :: i1, i2
   integer, dimension(2) :: nb
   real(kind=default) :: w
   <<Load channel [[ch]]>>
   <<Load divisions [[x]]>>
   <<Calculate [[y]]>>
   <<Load weights [[wgt]] and [[val]]>>
 end subroutine circe2_load_channel
 @ 
 @ 
 <<Decode polarization support>>=
 if (fpolsp(1:1)=='a' .or. fpolsp(1:1)=='A') then
    c2s%polspt = POLAVG
 else if (fpolsp(1:1)=='h' .or. fpolsp(1:1)=='H') then
    c2s%polspt = POLHEL
 else if (fpolsp(1:1)=='d' .or. fpolsp(1:1)=='D') then
    c2s%polspt = POLGEN
 else
    write (*, '(A,I5)') 'circe2_load: invalid polarization support: ', fpolsp
    ierror = EFORMT
    return
 end if
 @ 
 <<Local variables in [[circe2_load]]>>=
 integer :: ic, nc
 @ 
 <<Load channel [[ch]]>>=
 read (lun, *)
 read (lun, *) ch%pid(1), ch%pol(1), ch%pid(2), ch%pol(2), ch%lumi
 <<Check polarization support>>
 @
 <<Check polarization support>>=
 if (polspt == POLAVG .and. any (ch%pol /= 0)) then
    write (*, '(A)') 'circe2_load: expecting averaged polarization'
    ierror = EFORMT
    return
 else if (polspt == POLHEL .and. any (ch%pol == 0)) then
    write (*, '(A)') 'circe2_load: expecting helicities'
    ierror = EFORMT
    return
 else if (polspt == POLGEN) then
    write (*, '(A)') 'circe2_load: general polarizations not supported yet'
    ierror = EFORMT
    return
 else if (polspt == POLGEN .and. any (ch%pol /= 0)) then
    write (*, '(A)') 'circe2_load: expecting pol = 0'
    ierror = EFORMT
    return
 end if
 @ 
 <<Load channel [[ch]]>>=
 read (lun, *)
 read (lun, *) nb, ch%triang
 @ 
 <<Load divisions [[x]]>>=
 do d = 1, 2
    read (lun, *)
    allocate (ch%d(d)%x(0:nb(d)), ch%d(d)%y(0:nb(d)))
    allocate (ch%d(d)%map(nb(d)), ch%d(d)%alpha(nb(d)))
    allocate (ch%d(d)%xi(nb(d)), ch%d(d)%eta(nb(d)))
    allocate (ch%d(d)%a(nb(d)), ch%d(d)%b(nb(d)))
    read (lun, *) ch%d(d)%x(0)
    do ib = 1, nb(d)
       read (lun, *) ch%d(d)%x(ib), ch%d(d)%map(ib), &
            ch%d(d)%alpha(ib), ch%d(d)%xi(ib), ch%d(d)%eta(ib), &
            ch%d(d)%a(ib), ch%d(d)%b(ib)
       if (ch%d(d)%map(ib) < 0 .or. ch%d(d)%map(ib) > 2) then
          write (*, '(A,I3)') 'circe2_load: invalid map: ', ch%d(d)%map(ib)
          ierror = EFORMT
          return
       end if
    end do
 end do
 @ The boundaries are guaranteed to be fixed points of the maps
 only if the boundaries are not allowed to float. This doesn't affect
 the unweighted events, because they never see the codomain grid, but
 distribution would be distorted significantly.   In the following sums
 [[i1]] and [[i2]] run over the maps, while [[i]] runs over the
 boundaries.
 \begin{dubious}
 An alternative would be to introduce sentinels [[alpha(1,0,:)]],
 [[xi(1,0,:)]], etc.
 \end{dubious}
 <<Calculate [[y]]>>=
 do d = 1, 2
    do i = 0, ubound (ch%d(d)%x, dim=1)
       ch%d(d)%y(i) = circe2_map (ch%d(d), ch%d(d)%x(i), max (i, 1))
    end do
 end do
 @ cf.~(\ref{eq:jacobian-Delta_x-Delta_y})
 <<Load weights [[wgt]] and [[val]]>>=
 read (lun, *)
 allocate (ch%wgt(0:product(nb)), ch%val(nb(1),nb(2)))
 ch%wgt(0) = 0
 do i = 1, ubound (ch%wgt, dim=1)
    read (lun, *) w
    ch%wgt(i) = ch%wgt(i-1) + w
    <<$([[i1]],[[i2]]) \leftarrow [[i]]$>>
    ch%val(i1,i2) = w &
         / (  (ch%d(1)%x(i1) - ch%d(1)%x(i1-1)) &
            * (ch%d(2)%x(i2) - ch%d(2)%x(i2-1)))
 end do
 ch%wgt(ubound (ch%wgt, dim=1)) = 1
 @ 
 <<Local variables in [[circe2_load]]>>=
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Auxiliary Code For Reading Files}
 <<Open [[name]] for reading on [[lun]]>>=
 open (unit = lun, file = file, status = 'old', iostat = status)
 if (status /= 0) then
    write (*, '(2A)') 'circe2_load: can''t open ', file
    ierror = EFILE
    return
 end if
 @ 
 <<Local variables in [[circe2_load]]>>=
 integer :: status
 @ The outer [[do]] loop is never repeated!
 <<Skip comments until [[CIRCE2]]>>=
 find_circe2: do
    skip_comments: do
       read (lun, '(A)', iostat = status) buffer
       if (status /= 0) then
          close (unit = lun)
          if (loaded > 0) then           
             ierror = EOK
          else
             ierror = EMATCH
          end if
          return
       else
          if (buffer(1:6) == 'CIRCE2') then
             exit find_circe2
          else if (buffer(1:1) == '!') then
             if (ierror > 0) then
                write (*, '(A)') buffer
             end if
          else
             exit skip_comments
          end if
        end if
     end do skip_comments
     write (*, '(A)') 'circe2_load: invalid file'
     ierror = EFORMT
     return
  end do find_circe2
 @ 
 <<Skip data until [[ECRIC2]]>>=
 skip_data: do
    read (lun, *) buffer
    if (buffer(1:6) == 'ECRIC2') then
       exit skip_data
    end if
 end do skip_data
 @ 
 <<Check for [[ECRIC2]]>>=
 read (lun, '(A)') buffer
 if (buffer(1:6) /= 'ECRIC2') then
    write (*, '(A)') 'circe2_load: invalid file'
    ierror = EFORMT
    return
 end if
 @ 
 <<Find free logical unit for [[lun]]>>=
 scan: do lun = 10, 99
    inquire (unit = lun, exist = exists, opened = isopen, iostat = status)
    if (status == 0 .and. exists .and. .not.isopen) exit scan
 end do scan
 if (lun > 99) lun = -1
 @ 
 <<Local variables in [[circe2_load]]>>=
 logical exists, isopen
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \appendix
 \section{Tests and Examples}
 \subsection{Object-Oriented interface to [[tao_random_numbers]]}
 We need the object oriented interface to [[tao_random_numbers]]
 to be able to talk to the WHIZARD
 <<[[tao_random_objects.f90]]>>=
 module tao_random_objects
   use kinds
   use tao_random_numbers
   use circe2
   implicit none
   private
   <<[[tao_random_objects]] declarations>>
 contains
   <<[[tao_random_objects]] implementation>>
 end module tao_random_objects
 @ 
 <<[[tao_random_objects]] declarations>>=
 public :: rng_tao
 type, extends (rng_type) :: rng_tao
    integer :: seed = 0
    integer :: n_calls = 0
    type(tao_random_state) :: state
  contains
    procedure :: generate => rng_tao_generate
    procedure :: init => rng_tao_init
 end type rng_tao
 @ 
 <<[[tao_random_objects]] implementation>>=
 subroutine rng_tao_generate (rng_obj, u)
   class(rng_tao), intent(inout) :: rng_obj
   real(default), intent(out) :: u
   call tao_random_number (rng_obj%state, u)
   rng_obj%n_calls = rng_obj%n_calls + 1
 end subroutine rng_tao_generate
 @ 
 <<[[tao_random_objects]] implementation>>=
 subroutine rng_tao_init (rng_obj, seed)
   class(rng_tao), intent(inout) :: rng_obj
   integer, intent(in) :: seed
   rng_obj%seed = seed
   call tao_random_create (rng_obj%state, seed)
 end subroutine rng_tao_init
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{[[circe2_generate]]: Standalone Generation of Samples}
 <<[[circe2_generate.f90]]>>=
 program circe2_generate_program
   use kinds
   use circe2
   use tao_random_objects 
   implicit none
   type(circe2_state) :: c2s
   type(rng_tao), save :: rng
   character(len=1024) :: filename, design, buffer
   integer :: status, nevents, seed
   real(kind=default) :: roots
   real(kind=default), dimension(2) :: x
-  integer :: i, ierror
+  integer :: p1, p2, i, ierror
   <<Process command line arguments for [[circe2_generate_program]]>>
   call circe2_load (c2s, trim(filename), trim(design), roots, ierror)
   if (ierror /= 0) then
      print *, "circe2_generate: failed to load design ", trim(design), &
           " for ", real (roots, kind=single), &
           " GeV from  ", trim(filename)
      stop
   end if
   do i = 1, nevents
-     call circe2_generate (c2s, rng, x, [11, -11], [0, 0])
-     write (*, '(F12.10,1X,F12.10)') x
+     call circe2_generate (c2s, rng, x, [p1, p2], [0, 0])
+     write (*, '(F12.10,1X,F12.10,1X,F3.1)') x, 1.0_default
   end do
   contains
      <<Module procedures for [[circe2_generate_program]]>>
 end program circe2_generate_program
 @
 <<Process command line arguments for [[circe2_generate_program]]>>=
 call get_command_argument (1, value = filename, status = status)
 if (status /= 0) filename = ""
 @
 <<Process command line arguments for [[circe2_generate_program]]>>=
 call get_command_argument (2, value = design, status = status)
 if (status /= 0) design = ""
 if (filename == "" .or. design == "") then
-   print *, "usage: circe2_generate filename design [roots] [#events] [seed]"
+   print *, "usage: circe2_generate filename design [roots] [p1] [p2] [#events] [seed]"
    stop
 end if
 @
 <<Process command line arguments for [[circe2_generate_program]]>>=
 call get_command_argument (3, value = buffer, status = status)
 if (status == 0) then
    read (buffer, *, iostat = status) roots
    if (status /= 0) roots = 500
 else
    roots = 500
 end if
 @
 <<Process command line arguments for [[circe2_generate_program]]>>=
 call get_command_argument (4, value = buffer, status = status)
 if (status == 0) then
+   read (buffer, *, iostat = status) p1
+   if (status /= 0) nevents = 1000
+else
+   p1 = 11
+end if
+@
+<<Process command line arguments for [[circe2_generate_program]]>>=
+call get_command_argument (5, value = buffer, status = status)
+if (status == 0) then
+   read (buffer, *, iostat = status) p2
+   if (status /= 0) nevents = 1000
+else
+   p2 = -11
+end if
+@
+<<Process command line arguments for [[circe2_generate_program]]>>=
+call get_command_argument (6, value = buffer, status = status)
+if (status == 0) then
    read (buffer, *, iostat = status) nevents
    if (status /= 0) nevents = 1000
 else
    nevents = 1000
 end if
 @
 <<Process command line arguments for [[circe2_generate_program]]>>=
-call get_command_argument (5, value = buffer, status = status)
+call get_command_argument (7, value = buffer, status = status)
 if (status == 0) then
    read (buffer, *, iostat = status) seed
    if (status == 0) then
       call random2_seed (rng, seed)
    else
       call random2_seed (rng)
    end if
 else
    call random2_seed (rng)
 end if
 @
 <<Module procedures for [[circe2_generate_program]]>>=
 subroutine random2_seed (rng, seed)
   class(rng_tao), intent(inout) :: rng
   integer, intent(in), optional:: seed
   integer, dimension(8) :: date_time
   integer :: seed_value
   if (present (seed)) then
      seed_value = seed
   else
      call date_and_time (values = date_time)
      seed_value = product (date_time)
   endif
   call rng%init (seed_value)
 end subroutine random2_seed
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{[[circe2_ls]]: Listing File Contents}
 Here's a small utility program for listing the contents of \KirkeTwo/
 data files.  It performs \emph{no} verification and assumes that the
 file is in the correct format (cf.~table~\ref{tab:fileformat}).
 <<[[circe2_ls.f90]]>>=
 ! circe2_ls.f90 -- beam spectra for linear colliders and photon colliders
 <<Copyleft notice>>
 <<Separator>>
 program circe2_ls
    use circe2
    use kinds
    implicit none
    integer :: i, lun
    character(len=132) :: buffer
    character(len=60) :: design, polspt
    integer :: pid1, hel1, pid2, hel2, nc
    real(kind=default) :: roots, lumi
    integer :: status
    logical :: exists, isopen
    character(len=1024) :: filename
    <<Find free logical unit for [[lun]]>>
    if (lun < 0) then
       write (*, '(A)') 'circe2_ls: no free unit'
       stop
    end if
    files: do i = 1, command_argument_count ()
       call get_command_argument (i, value = filename, status = status)
       if (status /= 0) then
          exit files
       else
          open (unit = lun, file = filename, status = 'old', iostat = status)
          if (status /= 0) then
             write (*, "(A,1X,A)") "circe2: can't open", trim(filename)
          else
             write (*, "(A,1X,A)") "file:", trim(filename)
             lines: do
                read (lun, '(A)', iostat = status) buffer
                if (status /= 0) exit lines
                if (buffer(1:7) == 'design,') then
                   read (lun, *) design, roots
                   read (lun, *)
                   read (lun, *) nc, polspt
                   <<Write design/beam data>>
                   <<Write channel header>>
                else if (buffer(1:5) == 'pid1,') then
                   read (lun, *) pid1, hel1, pid2, hel2, lumi
                   <<Write channel data>>
                end if
             end do lines
          end if
          close (unit = lun)
       end if
    end do files
 end program circe2_ls
 <<Separator>>
 @ 
 <<Write design/beam data>>=
 write (*, '(A,1X,A)')    '        design:', trim(design)
 write (*, '(A,1X,F7.1)') '       sqrt(s):', roots
 write (*, '(A,1X,I3)')   '     #channels:', nc
 write (*, '(A,1X,A)')      '  polarization:', trim(polspt)
 @ 
 <<Write channel header>>=
 write (*, '(4X,4(A5,2X),A)') &
      'pid#1', 'hel#1', 'pid#2', 'hel#2', 'luminosity / (10^32cm^-2sec^-1)'
 @ 
 <<Write channel data>>=
 write (*, '(4X,4(I5,2X),F10.2)') pid1, hel1, pid2, hel2, lumi
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsection{$\beta$-distribitions}
 @ We need a fast generator of $\beta$-distribitions:
 \begin{equation}
   \beta_{x_{\text{min}},x_{\text{max}}}^{a,b}(x)
     = x^{a-1}(1-x)^{b-1}\cdot
         \frac{\Theta(x_{\text{max}}-x)\Theta(x-x_{\text{min}})}%
              {I(x_{\text{min}},a,b)-I(x_{\text{max}},a,b)}
 \end{equation}
 with the \emph{incomplete Beta-function~$I$:}
 \begin{align}
   I(x,a,b) & = \int_x^1\!d\xi\, \xi^{a-1}(1-\xi)^{b-1} \\
   I(0,a,b) & = B(a,b) = \frac{\Gamma(a)\Gamma(b)}{\Gamma(a+b)}
 \end{align}
 This problem has been studied
 extensively~\cite{Devroye:1986:random_deviates} and we can use 
 an algorithm~\cite{Atkinson/Whittaker:1979:beta_distribution} that is
 very fast for~$0<a\le1\le b$, 
 which turns out to be the case in our application.
 <<[[circe2_moments_library]] declarations>>=
   public :: generate_beta
 @
 <<[[circe2_moments_library]] implementation>>=
   subroutine generate_beta (rng, x, xmin, xmax, a, b)
     class(rng_type), intent(inout) :: rng
     real(kind=default), intent(out) :: x
     real(kind=default), intent(in) :: xmin, xmax, a, b
     real(kind=default) :: t, p, u, umin, umax, w
     <<Check [[a]] and [[b]]>>
     <<Set up [[generate_beta]] parameters>>
     do 
        <<Generate a trial [[x]] and calculate its weight [[w]]>>
        call rng%generate (u)
        if (w > u) exit
     end do
   end subroutine generate_beta
 @ %def generate_beta
 @ In fact, this algorithm works for~$0<a\le1\le b$ only:
 <<Check [[a]] and [[b]]>>=
       if (a >= 1 .or. b <= 1) then
          x = -1
          print *, 'ERROR: beta-distribution expects a<1<b'
          return
       end if
 @ The trick is to split the interval~$[0,1]$ into two parts~$[0,t]$
 and~$[t,1]$.  In these intervals we obviously have
 \begin{equation}
     x^{a-1} (1-x)^{b-1} \le
       \begin{cases}
         x^{a-1}             & \text{for}\; x \le t\\
         t^{a-1} (1-x)^{b-1} & \text{for}\; x \ge t
       \end{cases}
 \end{equation}
 because we have assumed that~$0<a<1<b$.
 The integrals of the two dominating distributions are~$t^a/a$
 and~$t^{a-1}(1-t)^b/b$ respectively and therefore the probability for
 picking a random number from the first interval is
 \begin{equation}
    P(x\le t) = \frac{bt}{bt+a(1- t)^b}
 \end{equation}
 We postpone the discussion of the choice of~$t$ until later:
 <<Set up [[generate_beta]] parameters>>=
       <<Set up best value for $t$>>
       p = b*t / (b*t + a * (1 - t)**b)
 @ The dominating distributions can be generated by simple mappings
 \begin{align}
   \phi: [0,1] & \to [0,1] \\
             u & \mapsto
     \begin{cases}
       t\left(\frac{u}{p}\right)^\frac{1}{a}             &<t\;\text{for}\;u<p\\
       t                                                 &=t\;\text{for}\;u=p\\
       1 - (1-t)\left(\frac{1-u}{1-p}\right)^\frac{1}{b} &>t\;\text{for}\;u>p
     \end{cases}
 \end{align}
 The beauty of the algorithm is that we can use a single uniform
 deviate~$u$ for both intervals:
 <<Generate a trial [[x]] and calculate its weight [[w]]>>=
       call rng%generate (u)
       u = umin + (umax - umin) * u
       if (u <= p) then
          x = t * (u/p)**(1/a)
          w = (1 - x)**(b-1)
       else
          x = 1 - (1 - t) * ((1 - u)/(1 - p))**(1/b)
          w = (x/t)**(a-1)
       end if
 @ The weights that are derived by dividing the distribution by the
 dominating distributions are already normalized correctly:
 \begin{align}
      w: [0,1] & \to [0,1] \\
             x & \mapsto
     \begin{cases}
       (1-x)^{b-1}                     &\in[(1-t)^{b-1},1]\;\text{for}\;x\le t\\
       \left(\frac{x}{t}\right)^{a-1}  &\in[t^{1-a},1]    \;\text{for}\;x\ge t
     \end{cases}
 \end{align}
 @ To derive~$u_{\text{min},\text{max}}$
 from~$x_{\text{min},\text{max}}$ we can use~$\phi^{-1}$:
 \begin{align}
   \phi^{-1}: [0,1] & \to [0,1] \\
                  x & \mapsto
     \begin{cases}
       p\left(\frac{x}{t}\right)^a             &<p\;\text{for}\;x<t\\
       p                                       &=p\;\text{for}\;x=t\\
       1 - (1-p)\left(\frac{1-x}{1-t}\right)^b &>p\;\text{for}\;x>t
     \end{cases}
 \end{align}
 We start with~$u_{\text{min}}$. For efficiency, we handle the most
 common cases (small~$x_{\text{min}}$) first:
 <<Set up [[generate_beta]] parameters>>=
       if (xmin <= 0) then
          umin = 0
       elseif (xmin < t) then
          umin = p * (xmin/t)**a
       elseif (xmin == t) then
          umin = p
       elseif (xmin < 1) then
          umin = 1 - (1 - p) * ((1 - xmin)/(1 - t))**b
       else
          umin = 1
       endif
 @ Same procedure for~$u_{\text{max}}$; again, handle the most common
 cases (large~$x_{\text{max}}$) first: 
 <<Set up [[generate_beta]] parameters>>=
       if (xmax >= 1) then
          umax = 1
       elseif (xmax > t) then
          umax = 1 - (1 - p) * ((1 - xmax)/(1 - t))**b
       elseif (xmax == t) then
          umax = p
       elseif (xmax > 0) then
          umax = p * (xmax/t)**a
       else
          umax = 0
       endif
 @ Check for absurd cases.
 <<Set up [[generate_beta]] parameters>>=
       if (umax < umin) then
          x = -1
          return
       endif
 @ It remains to choose he best value for~$t$.
 The rejection efficiency~$\epsilon$ of the algorithm is given by the
 ratio of the dominating distribution and the distribution
 \begin{equation}
   \frac{1}{\epsilon(t)}
     = \frac{B(a,b)}{ab} \left(bt^{a} + at^{a-1}(1-t)^b\right).
 \end{equation}
 It is maximized for
 \begin{equation}
    bt - bt(1-t)^{b-1} + (a-1)(1-t)^b = 0
 \end{equation}
 This equation has a solution which can be determined numerically.
 While this determination is far too expensive compared to a moderate
 loss in efficiency, we could perform it once after fitting the
 coefficients~$a$, $b$.  Nevertheless, it has been
 shown,\cite{Atkinson/Whittaker:1979:beta_distribution}
 that
 \begin{equation}
    t = \frac{1-a}{b+1-a}
 \end{equation}
 results in non-vanishing efficiency for all values~$1<a\le1\le b$.
 Empirically we have found efficiencies of at least 80\%{} for this
 choice, which is enough for our needs.
 <<Set up best value for $t$>>=
       t = (1 - a) / (b + 1 - a)
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsection{Sampling}
 <<[[circe2_moments.f90]]>>=
 module sampling
   use kinds
   implicit none
   private
   <<[[sampling]] declarations>>
 contains
   <<[[sampling]] implementation>>
 end module sampling
 @ 
 <<[[sampling]] declarations>>=
 type sample
   integer :: n = 0
   real(kind=default) :: w = 0
   real(kind=default) :: w2 = 0
 end type sample
 public :: sample
 @ 
 <<[[sampling]] declarations>>=
 public :: reset, record
 @
 <<[[sampling]] implementation>>=
 elemental subroutine reset (s)
   type(sample), intent(inout) :: s
   s%n = 0
   s%w = 0
   s%w2 = 0
 end subroutine reset
 @
 <<[[sampling]] implementation>>=
 elemental subroutine record (s, w)
   type(sample), intent(inout) :: s
   real(kind=default), intent(in), optional :: w
   s%n = s%n + 1
   if (present (w)) then
     s%w = s%w + w
     s%w2 = s%w2 + w*w
   else
     s%w = s%w + 1
     s%w2 = s%w2 + 1
   endif
 end subroutine record
 @ 
 <<[[sampling]] declarations>>=
 public :: mean, variance
 @
 <<[[sampling]] implementation>>=
 elemental function mean (s)
   type(sample), intent(in) :: s
   real(kind=default) :: mean
   mean = s%w / s%n
 end function mean
 @
 <<[[sampling]] implementation>>=
 elemental function variance (s)
   type(sample), intent(in) :: s
   real(kind=default) :: variance
   variance = (s%w2 / s%n - mean(s)**2) / s%n
   variance = max (variance, epsilon (variance))
 end function variance
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsection{Moments}
 This would probably be a good place for inheritance
 <<[[circe2_moments_library]] declarations>>=
 type moment
   integer, dimension(2) :: n, m
   type(sample) :: sample = sample (0, 0.0_default, 0.0_default)
 end type moment
 public :: moment
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: init_moments
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine init_moments (moments)
   type(moment), dimension(0:,0:,0:,0:), intent(inout) :: moments
   integer :: nx, mx, ny, my
   do nx = lbound(moments,1), ubound(moments,1)
      do mx = lbound(moments,2), ubound(moments,2)
         do ny = lbound(moments,3), ubound(moments,3)
            do my = lbound(moments,4), ubound(moments,4)
               moments(nx,mx,ny,my) = moment([nx,ny],[mx,my])
            end do
         end do
      end do
   end do
   call reset_moment (moments)
 end subroutine init_moments
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: reset_moment, record_moment
 @
 <<[[circe2_moments_library]] implementation>>=
 elemental subroutine reset_moment (m)
   type(moment), intent(inout) :: m
   call reset (m%sample)
 end subroutine reset_moment
 @ If we were pressed for time, we would compute the moments
 by iterative multiplications instead by powers, of course.
 In any case, we would like to combine [[x1]] and [[x2]] into an array.
 Unfortunately this is not possible for [[elemental]] procedures.
 NB: the NAG compiler appears to want a more careful evaluation of
 the powers.  We enforce [[0.0**0 == 0]].
 <<[[circe2_moments_library]] implementation>>=
 elemental subroutine record_moment (m, x1, x2, w)
   type(moment), intent(inout) :: m
   real(kind=default), intent(in) :: x1, x2
   real(kind=default), intent(in), optional :: w
   real(kind=default) :: p
   p = pwr (x1, m%n(1)) * pwr (1-x1, m%m(1)) &
     * pwr (x2, m%n(2)) * pwr (1-x2, m%m(2))
   if (present (w)) p = p*w
   call record (m%sample, p)
 contains
   pure function pwr (x, n)
     real(kind=default), intent(in) :: x
     integer, intent(in) :: n
     real(kind=default) :: pwr
     if (n == 0) then
        pwr = 1
     else 
        pwr = x**n
     end if
   end function pwr
 end subroutine record_moment
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: mean_moment, variance_moment
 @
 <<[[circe2_moments_library]] implementation>>=
 elemental function mean_moment (m)
   type(moment), intent(in) :: m
   real(kind=default) :: mean_moment
   mean_moment = mean (m%sample)
 end function mean_moment
 @
 <<[[circe2_moments_library]] implementation>>=
 elemental function variance_moment (m)
   type(moment), intent(in) :: m
   real(kind=default) :: variance_moment
   variance_moment = variance (m%sample)
 end function variance_moment
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{Moments of $\beta$-distributions}
 <<[[circe2_moments_library]] declarations>>=
 public :: beta_moment
 @
 \begin{multline}
   M_{n,m}(a,b)
     = \int_0^1\!\dd x\, x^n(1-x)^m \beta_{0,1}^{a,b}(x)
     = \int_0^1\!\dd x\, x^n(1-x)^m \frac{x^{a-1}(1-x)^{b-1}}{B(a,b)} \\
     = \frac{1}{B(a,b)} \int_0^1\!\dd x\, x^{n+a-1}(1-x)^{m+b-1}
     = \frac{B(n+a,m+b)}{B(a,b)} \\
     = \frac{\Gamma(n+a)\Gamma(m+b)\Gamma(a+b)}%
            {\Gamma(n+a+m+b)\Gamma(a)\Gamma(b)}
     = \frac{\Gamma(n+a)}{\Gamma(a)} \frac{\Gamma(m+b)}{\Gamma(b)}
       \frac{\Gamma(n+m+a+b)}{\Gamma(a+b)} \\
     = \frac{(a+n)(a+n-1)\cdots(a+1)a(b+m)(b+m-1)\cdots(b+1)b}%
            {(a+b+n+m)(a+b+n+m-1)\cdots(a+b+1)(a+b)}
 \end{multline}
 <<[[circe2_moments_library]] implementation>>=
 elemental function beta_moment (n, m, a, b)
   integer, intent(in) :: n, m
   real(kind=default), intent(in) :: a, b
   real(kind=default) :: beta_moment
   beta_moment = &
     gamma_ratio (a, n) * gamma_ratio (b, m) / gamma_ratio (a+b, n+m)
 end function beta_moment
 @
 \begin{equation}
   \frac{\Gamma(x+n)}{\Gamma(x)}
     = (x+n)(x+n-1)\cdots(x+1)x
 \end{equation}
 <<[[circe2_moments_library]] implementation>>=
 elemental function gamma_ratio (x, n)
   real(kind=default), intent(in) :: x
   integer, intent(in) :: n
   real(kind=default) :: gamma_ratio
   integer :: i
   gamma_ratio = 1
   do i = 0, n - 1
     gamma_ratio = gamma_ratio * (x + i)
   end do
 end function gamma_ratio
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{Channels}
 <<[[circe2_moments_library]] declarations>>=
 type channel
   real(kind=default) :: w = 1
   real(kind=default), dimension(2) :: a = 1, b = 1
   logical, dimension(2) :: delta = .false.
 end type channel
 public :: channel
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: generate_beta_multi, beta_moments_multi
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine generate_beta_multi (rng, x, channels)
   class(rng_type), intent(inout) :: rng
   real(kind=default), dimension(:), intent(out) :: x
   type(channel), dimension(:), intent(in) :: channels
   real(kind=default) :: u, accum
   integer :: i, n
   <<Select [[n]] according to the weight [[channels(n)%w]]>>
   do i = 1, size (x)
     if (channels(n)%delta(i)) then
       x(i) = 1
     else
       if (channels(n)%a(i) == 1 .and. channels(n)%b(i) == 1) then
         call rng%generate (x(i))
       else if (channels(n)%b(i) < channels(n)%a(i)) then
         call generate_beta (rng, x(i), 0.0_default, 1.0_default, &
                             channels(n)%b(i), channels(n)%a(i))
         x(i) = 1 - x(i)
       else
         call generate_beta (rng, x(i), 0.0_default, 1.0_default, &
                             channels(n)%a(i), channels(n)%b(i))
       end if
     end if
   end do
 end subroutine generate_beta_multi
 @ Subtlety: if the upper limit of the do loop where
 [[size(channels)]], we could end up with [[n]] set to
 [[size(channels)+1]] when rounding errors produce
 $[[accum]]>[[sum(channels%w)]]$.
 <<Select [[n]] according to the weight [[channels(n)%w]]>>=
 call rng%generate (u)
 u = u * sum (channels%w)
 accum = 0
 scan: do n = 1, size (channels) - 1
   accum = accum + channels(n)%w
   if (accum >= u) exit scan
 end do scan
 @
 <<[[circe2_moments_library]] implementation>>=
 pure function beta_moments_multi (n, m, channels)
   integer, intent(in), dimension(2) :: n, m
   type(channel), dimension(:), intent(in) :: channels
   real(kind=default) :: beta_moments_multi
   real(kind=default) :: w
   integer :: c, i
   beta_moments_multi = 0
   do c = 1, size (channels)
     w = channels(c)%w
     do i = 1, 2
       if (channels(c)%delta(i)) then
         if (m(i) > 0) w = 0
       else
         w = w * beta_moment (n(i), m(i), channels(c)%a(i), channels(c)%b(i))
       end if
     end do
     beta_moments_multi = beta_moments_multi + w
   end do
   beta_moments_multi = beta_moments_multi / sum (channels%w)
 end function beta_moments_multi
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{Selftest}
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: selftest
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine selftest (rng, nevents)
   class(rng_type), intent(inout) :: rng
   integer, intent(in) :: nevents
   integer, parameter :: N = 1
   type(moment), dimension(0:N,0:N,0:N,0:N) :: moments
   integer :: i
   real(kind=default), dimension(2) :: x
   type(channel), dimension(:), allocatable :: channels
   call read_channels (channels)
   call init_moments (moments)
   do i = 1, nevents
      call generate_beta_multi (rng, x, channels)
      call record_moment (moments, x(1), x(2))
   end do
   call report_results (moments, channels)
 end subroutine selftest
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: random2_seed
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine random2_seed (rng, seed)
   class(rng_tao), intent(inout) :: rng
   integer, intent(in), optional:: seed
   integer, dimension(8) :: date_time
   integer :: seed_value
   if (present (seed)) then
      seed_value = seed
   else
      call date_and_time (values = date_time)
      seed_value = product (date_time)
   endif
   call rng%init (seed_value)
 end subroutine random2_seed
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: read_channels
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine read_channels (channels)
   type(channel), dimension(:), allocatable, intent(out) :: channels
   type(channel), dimension(100) :: buffer
   real(kind=default) :: w
   real(kind=default), dimension(2) :: a, b
   logical, dimension(2) :: delta
   integer :: n, status
   do n = 1, size (buffer)
     read (*, *, iostat = status) w, a(1), b(1), a(2), b(2), delta
     if (status == 0) then
       buffer(n) = channel (w, a, b, delta)
     else
       exit
     end if
   end do
   allocate (channels(n-1))
   channels = buffer(1:n-1)
 end subroutine read_channels
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: report_results
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine report_results (moments, channels)
   type(moment), dimension(0:,0:,0:,0:), intent(in) :: moments
   type(channel), dimension(:), intent(in) :: channels
   integer :: nx, mx, ny, my
   real(kind=default) :: truth, estimate, sigma, pull, eps
   do nx = lbound(moments,1), ubound(moments,1)
      do mx = lbound(moments,2), ubound(moments,2)
         do ny = lbound(moments,3), ubound(moments,3)
            do my = lbound(moments,4), ubound(moments,4)
               truth = beta_moments_multi ([nx, ny], [mx, my], channels)
               estimate = mean_moment (moments(nx,mx,ny,my))
               sigma = sqrt (variance_moment (moments(nx,mx,ny,my)))
               pull = estimate - truth
               eps = pull / max (epsilon (1.0_default), epsilon (1.0_double))
               if (sigma /= 0.0_default) pull = pull / sigma
               write (*, "(' x^', I1, ' (1-x)^', I1, &
                          &' y^', I1, ' (1-y)^', I1, &
                          &': ', F8.5, ': est = ', F8.5, &
                          &' +/- ', F8.5,&
                          &', pull = ', F8.2,&
                          &', eps = ', F8.2)") &
                    nx, mx, ny, my, truth, estimate, sigma, pull, eps
            end do
         end do
      end do
   end do
 end subroutine report_results
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: results_ok
 @
 <<[[circe2_moments_library]] implementation>>=
 function results_ok (moments, channels, threshold, fraction)
   ! use, intrinsic :: ieee_arithmetic
   type(moment), dimension(0:,0:,0:,0:), intent(in) :: moments
   type(channel), dimension(:), intent(in) :: channels
   real(kind=default), intent(in), optional :: threshold, fraction
   logical :: results_ok
   integer :: nx, mx, ny, my, failures
   real(kind=default) :: thr, frac, eps
   real(kind=default) :: truth, estimate, sigma
   ! we mut not expect to measure zero better than the
   ! double precision used in the ocaml code:
   eps = 200 * max (epsilon (1.0_default), epsilon (1.0_double))
   if (present(threshold)) then
      thr = threshold
   else
      thr = 5
   end if
   if (present(fraction)) then
      frac = fraction
   else
      frac = 0.01_default
   end if
   failures = 0
   do nx = lbound(moments,1), ubound(moments,1)
      do mx = lbound(moments,2), ubound(moments,2)
         do ny = lbound(moments,3), ubound(moments,3)
            do my = lbound(moments,4), ubound(moments,4)
               truth = beta_moments_multi ([nx, ny], [mx, my], channels)
               estimate = mean_moment (moments(nx,mx,ny,my))
               sigma = sqrt (variance_moment (moments(nx,mx,ny,my)))
               if (.not. (      ieee_is_normal (truth) &
                          .and. ieee_is_normal (estimate) &
                          .and. ieee_is_normal (sigma)) &
                   .or. abs (estimate - truth) > max (thr * sigma, eps)) then
                  failures = failures + 1
               end if
            end do
         end do
      end do
   end do
   if (failures >= frac * size (moments)) then
     results_ok = .false.
   else
     results_ok = .true.
   end if
 contains
   <<The old [[ieee_is_normal]] kludge>>
 end function results_ok
 @ gfortran doesn't have the intrinsic [[ieee_arithmetic]] module
 yet \ldots
 <<The old [[ieee_is_normal]] kludge>>=
 function ieee_is_normal (x)
   real(kind=default), intent(in) :: x
   logical :: ieee_is_normal
   ieee_is_normal = .not. (x /= x)
 end function ieee_is_normal
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{Generate Sample}
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: generate
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine generate (rng, nevents)
   class(rng_type), intent(inout) :: rng
   integer, intent(in) :: nevents
   type(channel), dimension(:), allocatable :: channels
   real(kind=default), dimension(2) :: x
   integer :: i
   call read_channels (channels)
   do i = 1, nevents
      call generate_beta_multi (rng, x, channels)
      write (*, "(3(5x,F19.17))") x, 1.0_default
   end do
 end subroutine generate
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{List Moments}
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: compare
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine compare (rng, nevents, file)
   class(rng_type), intent(inout) :: rng
   integer, intent(in) :: nevents
   character(len=*), intent(in) :: file
   type(channel), dimension(:), allocatable :: channels
   integer, parameter :: N = 1
   type(moment), dimension(0:N,0:N,0:N,0:N) :: moments
   real(kind=default), dimension(2) :: x
   character(len=128) :: design
   real(kind=default) :: roots
   integer :: ierror
   integer, dimension(2) :: p, h
   integer :: i
   type(circe2_state) :: c2s
   call read_channels (channels)
   call init_moments (moments)
   design = "CIRCE2/TEST"
   roots = 42
   p = [11, -11]
   h = 0
   call circe2_load (c2s, trim(file), trim(design), roots, ierror)
   do i = 1, nevents
      call circe2_generate (c2s, rng, x, p, h)
      call record_moment (moments, x(1), x(2))
   end do
   call report_results (moments, channels)
 end subroutine compare
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsubsection{Check Generator}
 @
 <<[[circe2_moments_library]] declarations>>=
 public :: check
 @
 <<[[circe2_moments_library]] implementation>>=
 subroutine check (rng, nevents, file, distributions, fail)
   class(rng_type), intent(inout) :: rng
   integer, intent(in) :: nevents
   character(len=*), intent(in) :: file
   logical, intent(in), optional :: distributions, fail
   type(channel), dimension(:), allocatable :: channels
   type(channel), dimension(1) :: unit_channel
   integer, parameter :: N = 1
   type(moment), dimension(0:N,0:N,0:N,0:N) :: moments, unit_moments
   real(kind=default), dimension(2) :: x
   character(len=128) :: design
   real(kind=default) :: roots, weight
   integer :: ierror
   integer, dimension(2) :: p, h
   integer :: i
   logical :: generation_ok, distributions_ok
   logical :: check_distributions, expect_failure
   type(circe2_state) :: c2s
   if (present (distributions)) then
      check_distributions = distributions
   else
      check_distributions = .true.
   end if
   if (present (fail)) then
      expect_failure = fail
   else
      expect_failure = .false.
   end if
   call read_channels (channels)
   call init_moments (moments)
   if (check_distributions) call init_moments (unit_moments)
   design = "CIRCE2/TEST"
   roots = 42
   p = [11, -11]
   h =   0
   call circe2_load (c2s, trim(file), trim(design), roots, ierror)
   do i = 1, nevents
      call circe2_generate (c2s, rng, x, p, h)
      call record_moment (moments, x(1), x(2))
      if (check_distributions) then
         weight = circe2_distribution (c2s, p, h, x)
         call record_moment (unit_moments, x(1), x(2), w = 1 / weight)
      end if
   end do
   generation_ok = results_ok (moments, channels)
   if (check_distributions) then
      distributions_ok = results_ok (unit_moments, unit_channel)
   else
      distributions_ok = .not. expect_failure
   end if
   if (expect_failure) then
      if (generation_ok .and. distributions_ok) then
         print *, "FAIL: unexpected success"
      else
         if (.not. generation_ok) then
            print *, "OK: expected failure in generation"
         end if
         if (.not. distributions_ok) then
            print *, "OK: expected failure in distributions"
         end if
      end if
      call report_results (moments, channels)
   else
      if (generation_ok .and. distributions_ok) then
         print *, "OK"
      else
         if (.not. generation_ok) then
            print *, "FAIL: generation"
            call report_results (moments, channels)
         end if
         if (.not. distributions_ok) then
            print *, "FAIL: distributions"
            call report_results (unit_moments, unit_channel)
         end if
      end if
   end if
 end subroutine check
 @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @ \subsection{[[circe2_moments]]: Compare Moments of distributions}
 <<Main program>>=
 program circe2_moments
   use circe2
   use circe2_moments_library !NODEP!
   use tao_random_objects !NODEP!
   implicit none
   type(rng_tao), save :: rng
   character(len=1024) :: mode, filename, buffer
   integer :: status, nevents, seed
   call get_command_argument (1, value = mode, status = status)
   if (status /= 0) mode = ""
   call get_command_argument (2, value = filename, status = status)
   if (status /= 0) filename = ""
   call get_command_argument (3, value = buffer, status = status)
   if (status == 0) then
      read (buffer, *, iostat = status) nevents
      if (status /= 0) nevents = 1000
   else
      nevents = 1000
   end if
   call get_command_argument (4, value = buffer, status = status)
   if (status == 0) then
      read (buffer, *, iostat = status) seed
      if (status == 0) then
         call random2_seed (rng, seed)
      else
         call random2_seed (rng)
      end if
   else
      call random2_seed (rng)
   end if
   select case (trim (mode))
   case ("check")
      call check (rng, nevents, trim (filename))
   case ("!check")
      call check (rng, nevents, trim (filename), fail = .true.)
   case ("check_generation")
      call check (rng, nevents, trim (filename), distributions = .false.)
   case ("!check_generation")
      call check (rng, nevents, trim (filename), fail = .true., &
                                                 distributions = .false.)
   case ("compare")
      call compare (rng, nevents, trim (filename))
   case ("generate")
      call generate (rng, nevents)
   case ("selftest")
      call selftest (rng, nevents)
   case default
      print *, &
       "usage: circe2_moments " // &
       "[check|check_generation|generate|selftest] " // &
       "filename [events] [seed]"
   end select
 end program circe2_moments
 @
 <<[[circe2_moments.f90]]>>=
 module circe2_moments_library
   use kinds
   use tao_random_objects !NODEP!
   use sampling !NODEP!
   use circe2
   implicit none
   private
   <<[[circe2_moments_library]] declarations>>
 contains
   <<[[circe2_moments_library]] implementation>>
 end module circe2_moments_library
 @
 <<[[circe2_moments.f90]]>>=
 <<Main program>>
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \begin{thebibliography}{10}
 \bibitem{Atkinson/Whittaker:1979:beta_distribution}
   A. Atkinson and J. Whittaker, Appl.\ Stat.\ {\bf 28},  90  (1979).
 \bibitem{Devroye:1986:random_deviates}
   L. Devroye, {\em Non-uniform Random Variate Generation}, Springer,
   1986.
 \end{thebibliography}
Index: trunk/circe2/src/grid.ml
===================================================================
--- trunk/circe2/src/grid.ml	(revision 8897)
+++ trunk/circe2/src/grid.ml	(revision 8898)
@@ -1,476 +1,488 @@
 (* circe2/grid.ml --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 exception Out_of_range of string * float * (float * float)
 
 open Printf
 
 module type T =
   sig
     module D : Division.T
 
     type t
     val copy : t -> t
     val create : ?triangle:bool -> D.t -> D.t -> t
 
     val record : t -> float -> float -> float -> unit
 
     val rebin : ?power:float ->
       ?fixed_x1_min:bool -> ?fixed_x1_max:bool ->
         ?fixed_x2_min:bool -> ?fixed_x2_max:bool -> t -> t
 
     val normalize : t -> t
 
     val of_bigarray : ?verbose:bool -> ?power:float ->
       ?iterations:int -> ?margin:float -> ?cutoff:int ->
         ?fixed_x1_min:bool -> ?fixed_x1_max:bool ->
           ?fixed_x2_min:bool -> ?fixed_x2_max:bool ->
             ?areas:Syntax.area list ->
               (float, Bigarray.float64_elt,
                Bigarray.fortran_layout) Bigarray.Array2.t -> t -> t
 
     val smooth : float -> Syntax.area -> t -> t
 
     val variance_area : Syntax.area -> t -> float
 
     val to_channel_2d : out_channel -> t -> unit
 
     type channel =
         { pid1 : int;
           pol1 : int;
           pid2 : int;
           pol2 : int;
           lumi : float;
           g : t }
 
     val to_channel : out_channel -> channel -> unit
 
     type design =
         { name : string;
           roots : float;
           channels : channel list;
           comments : string list }
 
     val design_to_channel : out_channel -> design -> unit
     val designs_to_channel : out_channel ->
       ?comments:string list-> design list -> unit
     val designs_to_file : string ->
       ?comments:string list -> design list -> unit
 
     val variance : t -> float
 
   end
 
 module Make (D : Division.T) =
   struct
     module D = D
 
     type t =
         { d1 : D.t;
           d2 : D.t;
           w : float array array;
           var : float array array;
           triangle : bool }
 
     let copy grid =
       { d1 = D.copy grid.d1;
         d2 = D.copy grid.d2;
         w = ThoMatrix.copy grid.w;
         var = ThoMatrix.copy grid.var;
         triangle = grid.triangle }
 
     let create ?(triangle = false) d1 d2 =
       let n1 = D.n_bins d1
       and n2 = D.n_bins d2 in
       { d1 = d1;
         d2 = d2;
         w = Array.make_matrix n1 n2 0.0;
         var = Array.make_matrix n1 n2 0.0;
         triangle = triangle }
 
     (* We need
        \begin{subequations}
        \begin{align}
          \textit{upper}\; x\rbrack &= \textit{lower}\; \lbrack x \\
          \textit{upper}\; x\rbrack &= \textit{lower}\; (x - 1 \\
          \textit{upper}\; x) &= \textit{lower}\; \lbrack x - 1 \\
          \textit{upper}\; x) &= \textit{lower}\; (x - 2
        \end{align}
        \end{subequations}
        and
        \begin{subequations}
        \begin{align}
          \textit{upper}\; x\rbrack &= \textit{upper}\; x) + 1 \\
          \textit{lower}\; \lbrack x &= \textit{lower}\; (x - 1
        \end{align}
        \end{subequations} *)
 
     (* [lower_bin] had [Open] and [Closed] mixed up! (tho:2014-12-09) *)
 
     let lower_bin div limit =
       try
         begin match limit with
         | Syntax.Closed x -> D.find div x
         | Syntax.Open x -> D.find div x + 1
         | Syntax.Bin n -> n
         end
       with
       | Division.Below_min (_, _, n) -> n
       | Division.Above_max (x, range, _) ->
           raise (Out_of_range ("Grid.lower_bin", x, range))
 
     let upper_bin div limit =
       try
         begin match limit with
         | Syntax.Closed x -> D.find div x
         | Syntax.Open x -> D.find div x - 1
         | Syntax.Bin n -> n
         end
       with
       | Division.Above_max (_, _, n) -> n
       | Division.Below_min (x, range, _) ->
           raise (Out_of_range ("Grid.upper_bin", x, range))
 
     let enclosed_bins div (x1, x2) =
       (lower_bin div x1, upper_bin div x2)
 
     let enclosing_bin div = function
       | Syntax.Delta x -> D.find div x
       | Syntax.Box n -> n
 
     let smooth width area grid =
       let gaussian = Filter.gaussian width in
       let w =
         begin match area with
         | Syntax.Rect (i1, i2) ->
             let nx1, nx2 = enclosed_bins grid.d1 i1
             and ny1, ny2 = enclosed_bins grid.d2 i2 in
             Filter.apply12
               ~inf1:nx1 ~sup1:nx2 ~inf2:ny1 ~sup2:ny2
               gaussian gaussian grid.w
         | Syntax.Slice1 (i1, y) ->
             let nx1, nx2 = enclosed_bins grid.d1 i1
             and ny = enclosing_bin grid.d2 y in
             Filter.apply1
                 ~inf1:nx1 ~sup1:nx2 ~inf2:ny ~sup2:ny
                 gaussian grid.w
         | Syntax.Slice2 (x, i2) ->
             let nx = enclosing_bin grid.d1 x
             and ny1, ny2 = enclosed_bins grid.d2 i2 in
             Filter.apply2
               ~inf1:nx ~sup1:nx ~inf2:ny1 ~sup2:ny2
               gaussian grid.w
         end in
       { grid with w }
 
+    let nullify grid =
+      let grid = copy grid in
+      List.iter
+        (fun i1 ->
+          for i2 = 0 to D.n_bins grid.d2 -1 do
+            grid.w.(i1).(i2) <- 0.
+          done)
+        (D.null_bins grid.d1);
+      List.iter
+        (fun i2 ->
+          for i1 = 0 to D.n_bins grid.d1 -1 do
+            grid.w.(i1).(i2) <- 0.
+          done)
+        (D.null_bins grid.d2);
+      grid
+
+    let normalize grid =
+      let sum_w = ThoMatrix.sum_float grid.w in
+      if sum_w > 0. then
+        { d1 = D.copy grid.d1;
+          d2 = D.copy grid.d2;
+          w = ThoMatrix.map (fun w -> w /. sum_w) grid.w;
+          var = ThoMatrix.copy grid.var;
+          triangle = grid.triangle }
+      else
+        failwith "Grid.normalize: non-positive sum of weights"
+
     let to_channel_2d oc grid =
+      let grid = normalize (nullify grid) in
       for i = 0 to D.n_bins grid.d1 - 1 do
         Printf.fprintf oc "%g" grid.w.(i).(0);
         for j = 1 to D.n_bins grid.d2 - 1 do
           Printf.fprintf oc " %g" grid.w.(i).(j)
         done;
         Printf.fprintf oc "\n"
       done
       
     let project_triangle triangle x y =
       if triangle then begin
         if x >= y then begin
           (x, y /. x)
         end else begin
           (y, x /. y)
         end
       end else
         (x, y)
 
     (* Note that there is \emph{no} jacobian here.  It is
        applied later by the Fortran program interpreting the grid as
        a distribution.  It is not needed for the event generator
        anyway. *)
     let record grid x y f =
-      let x', y' = project_triangle grid.triangle x y in
-      D.record grid.d1 x' f;
-      D.record grid.d2 y' f;
-      let n1 = D.find grid.d1 x'
-      and n2 = D.find grid.d2 y' in
-      grid.w.(n1).(n2) <- grid.w.(n1).(n2) +. f;
-      grid.var.(n1).(n2) <- grid.var.(n1).(n2)
-          +. f /. D.caj grid.d1 x' /. D.caj grid.d2 y'
+      if not (D.is_null grid.d1 x || D.is_null grid.d2 y) then
+        let x', y' = project_triangle grid.triangle x y in
+        D.record grid.d1 x' f;
+        D.record grid.d2 y' f;
+        let n1 = D.find grid.d1 x'
+        and n2 = D.find grid.d2 y' in
+        grid.w.(n1).(n2) <- grid.w.(n1).(n2) +. f;
+        grid.var.(n1).(n2) <- grid.var.(n1).(n2) +. f /. D.caj grid.d1 x' /. D.caj grid.d2 y'
 
     let rebin ?power ?fixed_x1_min ?fixed_x1_max
         ?fixed_x2_min ?fixed_x2_max grid =
       let n1 = D.n_bins grid.d1
       and n2 = D.n_bins grid.d2 in
       { d1 = D.rebin ?power
           ?fixed_min:fixed_x1_min ?fixed_max:fixed_x1_max grid.d1;
         d2 = D.rebin ?power
           ?fixed_min:fixed_x2_min ?fixed_max:fixed_x2_max grid.d2;
         w = Array.make_matrix n1 n2 0.0;
         var = Array.make_matrix n1 n2 0.0;
         triangle = grid.triangle }
 
-    let normalize grid =
-      let sum_w = ThoMatrix.sum_float grid.w in
-      { d1 = D.copy grid.d1;
-        d2 = D.copy grid.d2;
-        w = ThoMatrix.map (fun w -> w /. sum_w) grid.w;
-        var = ThoMatrix.copy grid.var;
-        triangle = grid.triangle }
-
     (* Monitoring the variance in each cell is \emph{not} a good idea for
        approximating distributions of unweighted events: it always vanishes
        for unweighted events, even if they are distributed very unevenly.
        Therefore, we monitor the \emph{global} variance instead: *)
 
     let variance_area area grid =
       let (nx1, nx2), (ny1, ny2) =
         begin match area with
         | Syntax.Rect (i1, i2) ->
             (enclosed_bins grid.d1 i1, enclosed_bins grid.d2 i2)
         | Syntax.Slice1 (i1, y) ->
             let ny = enclosing_bin grid.d2 y in
             (enclosed_bins grid.d1 i1, (ny, ny))
         | Syntax.Slice2 (x, i2) ->
             let nx = enclosing_bin grid.d1 x in
             ((nx, nx), enclosed_bins grid.d2 i2)
         end in
       let n = float ((nx2 - nx1 + 1) * (ny2 - ny1 + 1)) in
       let w =
         ThoMatrix.sum_float
           ~inf1:nx1 ~sup1:nx2 ~inf2:ny1 ~sup2:ny2 grid.w /. n
       and w2 =
         ThoMatrix.fold_left
           ~inf1:nx1 ~sup1:nx2 ~inf2:ny1 ~sup2:ny2
           (fun acc w -> acc +. w *. w) 0.0 grid.w /. n in
       w2 -. w *. w
 
     let variance grid =
       let n = float (D.n_bins grid.d1 * D.n_bins grid.d2) in
       let w = ThoMatrix.sum_float grid.w /. n
       and w2 =
         ThoMatrix.fold_left (fun acc w -> acc +. w *. w) 0.0 grid.w /. n in
       w2 -. w *. w
 
     (* Find the grid with the lowest variance.  Allow local fluctuations and
        stop only after moving to twice the lowest value. *)
 
     let start_progress_report verbose var =
       if verbose then begin
         eprintf "adapting variance: %g" var;
         flush stderr
       end
 
     let progress_report verbose soft_limit best_var var =
       if verbose then begin
         if var < best_var then begin
           eprintf ", %g" var;
           flush stderr
         end else begin
           eprintf " [%d]" soft_limit;
           flush stderr
         end
       end
 
     let stop_progress_report verbose =
       if verbose then begin
         eprintf " done.\n";
         flush stderr
       end
 
 (* Scan a bigarray.  Assume a uniform weight,
    if it has only 2 columns. *)
 
     let record_data data grid =
       let columns = Bigarray.Array2.dim1 data in
       if columns < 2 then
         eprintf "error: not enough columns"
       else
         for i2 = 1 to Bigarray.Array2.dim2 data do
           let x = Bigarray.Array2.get data 1 i2
           and y = Bigarray.Array2.get data 2 i2
           and w =
             if columns > 2 then
               Bigarray.Array2.get data 3 i2
             else
               1.0 in
           try
             record grid x y w
           with
           | Division.Out_of_range (x, (x_min, x_max)) ->
               eprintf "internal error: %g not in [%g,%g]\n" x x_min x_max
       done
 
 (* The main routine constructing an adapted grid. *)
 
     let of_bigarray ?(verbose = false)
         ?power ?(iterations = 1000) ?(margin = 1.5) ?(cutoff = 10)
         ?fixed_x1_min ?fixed_x1_max ?fixed_x2_min ?fixed_x2_max
         ?areas data initial =
 
       let rebinner grid =
         rebin ?power
           ?fixed_x1_min ?fixed_x1_max ?fixed_x2_min ?fixed_x2_max grid in
 
       let rec improve_bigarray hard_limit soft_limit best_var best_grid grid =
         if soft_limit <= 0 || hard_limit <= 0 then
           normalize best_grid
         else begin
           record_data data grid;
           let var = variance grid in
           begin match areas with
           | None | Some [] -> ()
           | Some areas ->
               let normalized_grid = normalize grid in
               let variances =
                 List.map
                   (fun area ->
                     variance_area area normalized_grid) areas in
               let msg =
                 " (" ^ Printf.sprintf "%g" (variance normalized_grid) ^ ": " ^
                 String.concat "; "
                   (List.map (fun x -> Printf.sprintf "%g" x) variances) ^
                 ")" in
               prerr_string msg;
               flush stderr
           end;
           progress_report verbose soft_limit best_var var;
           if var >= margin *. best_var then
             normalize best_grid
           else
             let best_var, best_grid, soft_limit =
               if var < best_var then
                 (var, grid, cutoff)
               else
                 (best_var, best_grid, pred soft_limit) in
 
             (* Continuation passing makes recursion with exception handling
                tail recursive.  This is not really needed, because the
                data structures are not to big and recursion is not expected
                to be too deep. It doesn't hurt either, since the idiom is
                sufficiently transparent. *)
             let continue =
               try
                 let grid' = rebinner grid in
                 fun () -> improve_bigarray
                     (pred hard_limit) soft_limit best_var best_grid grid'
               with
               | Division.Rebinning_failure msg ->
                   eprintf "circe2: rebinning failed: %s!\n" msg;
                   fun () -> best_grid in
             continue ()
         end in
 
       record_data data initial;
       let var = variance initial in
       start_progress_report verbose var;
 
       let result =
         improve_bigarray iterations cutoff var initial (rebinner initial) in
       stop_progress_report verbose;
       result
 
     type channel =
         { pid1 : int;
           pol1 : int;
           pid2 : int;
           pol2 : int;
           lumi : float;
           g : t }
 
     (* NB: we need to transpose the weight matrix to
        get from our row major to \texttt{Fortran}'s
        column major array format expected by
        \texttt{circe2}! *)
     let to_channel oc ch =
       fprintf oc "pid1, pol1, pid2, pol2, lumi\n";
       fprintf oc " %d %d %d %d %G\n"
         ch.pid1 ch.pol1 ch.pid2 ch.pol2 ch.lumi;
+      let g = normalize (nullify ch.g) in
       fprintf oc "#bins1, #bins2, triangle?\n";
       fprintf oc " %d %d %s\n"
-        (D.n_bins ch.g.d1) (D.n_bins ch.g.d2)
-        (if ch.g.triangle then "T" else "F");
+        (D.n_bins g.d1) (D.n_bins g.d2) (if g.triangle then "T" else "F");
       fprintf oc "x1, map1, alpha1, xi1, eta1, a1, b1\n";
-      D.to_channel oc ch.g.d1;
+      D.to_channel oc g.d1;
       fprintf oc "x2, map2, alpha2, xi2, eta2, a2, b2\n";
-      D.to_channel oc ch.g.d2;
+      D.to_channel oc g.d2;
       fprintf oc "weights\n";
       ThoMatrix.iter
         (fun x -> fprintf oc " %s\n" (Float.Double.to_string x))
-        (ThoMatrix.transpose ch.g.w)
+        (ThoMatrix.transpose g.w)
 
     type design =
         { name : string;
           roots : float;
           channels : channel list;
           comments : string list }
 
     type polarization_support =
       | Averaged
       | Helicities
       | Density_Matrices
 
     let polarization_support design =
       if List.for_all (fun ch -> ch.pol1 = 0 && ch.pol2 = 0)
           design.channels then
         Averaged
       else if List.for_all (fun ch -> ch.pol1 <> 0 && ch.pol2 <> 0)
           design.channels then
         Helicities
       else
         invalid_arg
           "Grid.polarization_support: mixed polarization support!"
 
     let format_polarization_support = function
       | Averaged -> "averaged"
       | Helicities -> "helicities"
       | Density_Matrices -> "density matrices"
 
     let getlogin () =
       (Unix.getpwuid (Unix.getuid ())).Unix.pw_name
 
     let design_to_channel oc design =
       let utc = Unix.gmtime (Unix.time ()) in
       List.iter (fun s -> fprintf oc "! %s\n" s) design.comments;
       fprintf oc "! generated with %s by %s@%s, "
         (Sys.argv.(0)) (getlogin ()) (Unix.gethostname ());
       fprintf oc "%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d GMT\n"
         (utc.Unix.tm_year + 1900) (utc.Unix.tm_mon + 1) utc.Unix.tm_mday
         utc.Unix.tm_hour utc.Unix.tm_min utc.Unix.tm_sec;
       fprintf oc "CIRCE2 FORMAT#1\n";
       fprintf oc "design, roots\n";
       fprintf oc " '%s' %G\n" design.name design.roots;
       fprintf oc "#channels, pol.support\n";
       fprintf oc " %d '%s'\n"
         (List.length design.channels)
         (format_polarization_support (polarization_support design));
       List.iter (to_channel oc) design.channels;
       fprintf oc "ECRIC2\n"
 
     let designs_to_channel oc ?(comments = []) designs =
       List.iter (fun c -> fprintf oc "! %s\n" c) comments;
       List.iter (design_to_channel oc) designs
 
     let designs_to_file name ?comments designs =
       let oc = open_out name in
       designs_to_channel oc ?comments designs;
       close_out oc
 
   end
-
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
Index: trunk/circe2/src/diffmaps.ml
===================================================================
--- trunk/circe2/src/diffmaps.ml	(revision 8897)
+++ trunk/circe2/src/diffmaps.ml	(revision 8898)
@@ -1,119 +1,137 @@
 (* circe2/diffmaps.ml --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 module type T =
   sig
     include Diffmap.T
     val id : ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
+    val null : ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
   end
 
 module type Real = T with type domain = float and type codomain = float
 
 module type Default =
   sig
 
     include Real
 
     val power : alpha:float -> eta:float ->
       ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     val resonance : eta:float -> a:float ->
       ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
 
   end
 
 module Default =
   struct
 
     type domain = float
     type codomain = float
 
     type t = 
         { encode : string;
           with_domain : x_min:domain -> x_max:domain -> t;
           x_min : domain;
           x_max : domain;
           y_min : codomain;
           y_max : codomain;
           phi : domain -> codomain;
           ihp : codomain -> domain;
           jac : domain -> float;
-          caj : codomain -> float }
+          caj : codomain -> float;
+          is_null : bool }
 
     let encode m = m.encode
     let with_domain m = m.with_domain
 
     let x_min m = m.x_min
     let x_max m = m.x_max
     let y_min m = m.y_min
     let y_max m = m.y_max
 
     let phi m = m.phi
     let ihp m = m.ihp
     let jac m = m.jac
     let caj m  = m.caj
+    let is_null m = m.is_null
+
+    (* \begin{dubious}
+         Functors or first class modules should streamline this.
+       \end{dubious} *)
 
     let rec id ?x_min ?x_max y_min y_max =
       let m = Diffmap.Id.create ?x_min ?x_max y_min y_max in
       let with_domain ~x_min ~x_max =
         id ~x_min ~x_max y_min y_max in
       { encode = Diffmap.Id.encode m;
         with_domain = with_domain;
         x_min = Diffmap.Id.x_min m;
         x_max = Diffmap.Id.x_max m;
         y_min = Diffmap.Id.y_min m;
         y_max = Diffmap.Id.y_max m;
         phi = Diffmap.Id.phi m;
         ihp = Diffmap.Id.ihp m;
         jac = Diffmap.Id.jac m;
-        caj = Diffmap.Id.caj m }
+        caj = Diffmap.Id.caj m;
+        is_null = Diffmap.Id.is_null m }
+
+    let rec null ?x_min ?x_max y_min y_max =
+      let m = Diffmap.Null.create ?x_min ?x_max y_min y_max in
+      let with_domain ~x_min ~x_max =
+        null ~x_min ~x_max y_min y_max in
+      { encode = Diffmap.Null.encode m;
+        with_domain = with_domain;
+        x_min = Diffmap.Null.x_min m;
+        x_max = Diffmap.Null.x_max m;
+        y_min = Diffmap.Null.y_min m;
+        y_max = Diffmap.Null.y_max m;
+        phi = Diffmap.Null.phi m;
+        ihp = Diffmap.Null.ihp m;
+        jac = Diffmap.Null.jac m;
+        caj = Diffmap.Null.caj m;
+        is_null = Diffmap.Null.is_null m }
 
     let rec power ~alpha ~eta ?x_min ?x_max y_min y_max =
       let m = Diffmap.Power.create ~alpha ~eta ?x_min ?x_max y_min y_max in
       let with_domain ~x_min ~x_max =
         power ~alpha ~eta ~x_min ~x_max y_min y_max in
       { encode = Diffmap.Power.encode m;
         with_domain = with_domain;
         x_min = Diffmap.Power.x_min m;
         x_max = Diffmap.Power.x_max m;
         y_min = Diffmap.Power.y_min m;
         y_max = Diffmap.Power.y_max m;
         phi = Diffmap.Power.phi m;
         ihp = Diffmap.Power.ihp m;
         jac = Diffmap.Power.jac m;
-        caj = Diffmap.Power.caj m }
+        caj = Diffmap.Power.caj m;
+        is_null = Diffmap.Power.is_null m }
 
     let rec resonance ~eta ~a ?x_min ?x_max y_min y_max =
       let m = Diffmap.Resonance.create ~eta ~a ?x_min ?x_max y_min y_max  in
       let with_domain ~x_min ~x_max =
         resonance ~eta ~a ~x_min ~x_max y_min y_max in
       { encode = Diffmap.Resonance.encode m;
         with_domain = with_domain;
         x_min = Diffmap.Resonance.x_min m;
         x_max = Diffmap.Resonance.x_max m;
         y_min = Diffmap.Resonance.y_min m;
         y_max = Diffmap.Resonance.y_max m;
         phi = Diffmap.Resonance.phi m;
         ihp = Diffmap.Resonance.ihp m;
         jac = Diffmap.Resonance.jac m;
-        caj = Diffmap.Resonance.caj m }
+        caj = Diffmap.Resonance.caj m;
+        is_null = Diffmap.Resonance.is_null m }
 
   end
-
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
Index: trunk/circe2/src/lexer.mll
===================================================================
--- trunk/circe2/src/lexer.mll	(revision 8897)
+++ trunk/circe2/src/lexer.mll	(revision 8898)
@@ -1,76 +1,79 @@
 (* lexer.mll -- 
  *)
 
 {
 open Parser
 let unquote s =
   String.sub s 1 (String.length s - 2)
 }
 
 let digit = ['0'-'9']
 let upper = ['A'-'Z']
 let lower = ['a'-'z']
 let char = upper | lower
 let white = [' ' '\t' '\n']
 
 rule token = parse
     white        { token lexbuf }     (* skip blanks *)
   | '#' [^'\n']* '\n'
                  { token lexbuf }     (* skip comments *)
   | ['+''-']? digit+
-    ( '.' digit* ( ['e''E'] digit+ )? | ['e''E'] digit+ )
+    ( '.' digit* ( ['e''E'] '-'? digit+ )? | ['e''E'] '-'? digit+ )
                  { FLOAT (float_of_string (Lexing.lexeme lexbuf)) }
   | ['+''-']? digit+
                  { INT (int_of_string (Lexing.lexeme lexbuf)) }
   | '"' [^'"']* '"'
                  { STRING (unquote (Lexing.lexeme lexbuf)) }
   | '/'          { SLASH }
   | '['          { LBRACKET }
   | '('          { LPAREN }
   | '<'          { LANGLE }
   | ','          { COMMA }
   | ']'          { RBRACKET }
   | ')'          { RPAREN }
   | '>'          { RANGLE }
   | '{'          { LBRACE }
   | '}'          { RBRACE }
   | '='          { EQUALS }
   | '*'          { STAR }
   | '+'          { PLUS }
   | '-'          { MINUS }
+  | "antimuon"   { Antimuon }
   | "ascii"      { Ascii }
   | "beta"       { Beta }
   | "binary"     { Binary }
   | "bins"       { Bins }
   | "center"     { Center }
   | "columns"    { Columns }
   | "comment"    { Comment }
   | "design"     { Design }
   | "electron"   { Electron }
   | "eta"        { Eta }
   | "events"     { Events }
   | "file"       { File }
   | "fix"        { Fix }
   | "free"       { Free }
+  | "gamma"      { Photon }
   | "histogram"  { Histogram }
   | "id"         { Id }
   | "iterations" { Iterations }
   | "lumi"       { Lumi }
   | "map"        { Map }
   | "max"        { Max }
   | "min"        { Min }
+  | "muon"       { Muon }
   | "notriangle" { Notriangle }
+  | "null"       { Null }
   | "photon"     { Photon }
-  | "gamma"      { Photon }
   | "pid"        { Pid }
   | "pol"        { Pol }
   | "positron"   { Positron }
   | "power"      { Power }
   | "resonance"  { Resonance }
   | "roots"      { Roots }
   | "scale"      { Scale }
   | "smooth"     { Smooth }
   | "triangle"   { Triangle }
   | "unpol"      { Unpol }
   | "width"      { Width }
   | eof          { END }
Index: trunk/circe2/src/division.mli
===================================================================
--- trunk/circe2/src/division.mli	(revision 8897)
+++ trunk/circe2/src/division.mli	(revision 8898)
@@ -1,106 +1,103 @@
 (* circe2/division.mli --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 (* We have divisions ([Mono]) and divisions of divisions ([Poly]).
    Except for creation, they share the same interface ([T]), which
    can be used as a signature for functor arguments.  In particular,
    both kinds of divisions can be used with the [Grid.Make] functor. *)
 
 module type T =
   sig
 
     type t
 
     (* Copy a division, allocating fresh arrays with identical contents. *)
     val copy : t -> t
 
     (* Using~$\{x_0,x_1,\ldots,x_n\}$, find~$i$, such that~$x_i\le x<x_{i+1}$.
        We need to export this, if we want to maintain additional histograms
        in user modules.  *)
     val find : t -> float -> int
 
     (* [record d x f] records the value~$f$ at coordinate~$x$.  NB: this
        function modifies~[d]. *)
     val record : t -> float -> float -> unit
 
     (* VEGAS style rebinning.  The default values for [power] and both
         [fixed_min], [fixed_max] are~$1.5$ and~[false] respectively.  *)
     val rebin : ?power:float -> ?fixed_min:bool -> ?fixed_max:bool -> t -> t
 
     (* $J^*(y)$
        \begin{dubious}
          Should this include the $1/\Delta y$?
        \end{dubious} *)
     val caj : t -> float -> float
 
+    (* Check if there is a [Diffmaps.Null] for~$x$. *)
+    val is_null : t -> float -> bool
+    val null_bins : t -> int list
+
     val n_bins : t -> int
     val bins : t -> float array
     val to_channel : out_channel -> t -> unit
 
   end
 
 exception Above_max of float * (float * float) * int
 exception Below_min of float * (float * float) * int
 exception Out_of_range of float * (float * float)
 exception Rebinning_failure of string
 
 (* \subsubsection{Primary Divisions} *)
 
 module type Mono =
   sig
     include T
 
     (* [create bias n x_min x_max] creates a division with~$n$
        equidistant bins spanning $[x_{\min},x_{\max}]$. The [bias]
        is a function that is multiplied with the weights for
        VEGAS/VAMP rebinning.  It can be used to highlight the
        regions of phasespace that are expected to be most relevant
        in applications.  The default is [fun x -> 1.0], of course. *)
     val create : ?bias:(float -> float) -> int -> float -> float -> t
 
   end
 
 module Mono : Mono
 
 (* \subsubsection{Polydivisions} *)
 
 module type Poly =
   sig
 
     module M : Diffmaps.Real
 
     include T
 
-    (* [create n x_min x_max intervals] creates a polydivision of the
+    (* [create intervals n x_min x_max] creates a polydivision of the
        interval from [x_min] to [x_max] described by the list of [intervals],
        filling the gaps among intervals and between the intervals and the
        outer borders with an unmapped divisions with [n] bins each.  *)
     val create : ?bias:(float -> float) ->
       (int * M.t) list -> int -> float -> float -> t
 
   end
 
 module Make_Poly (M : Diffmaps.Real) : Poly with module M = M
 
 module Poly : Poly
 
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
-
-
+module Test : sig val suite : OUnit.test end
+ 
Index: trunk/circe2/src/diffmaps.mli
===================================================================
--- trunk/circe2/src/diffmaps.mli	(revision 8897)
+++ trunk/circe2/src/diffmaps.mli	(revision 8898)
@@ -1,47 +1,38 @@
 (* circe2/diffmaps.mli --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 (* \subsection{Combined Differentiable Maps} *)
 
 module type T =
   sig
     include Diffmap.T
     val id : ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
+    val null : ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
   end
 
 module type Real = T with type domain = float and type codomain = float
 
 module type Default =
   sig
 
     include Real
 
     val power : alpha:float -> eta:float ->
       ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
     val resonance : eta:float -> a:float ->
       ?x_min:domain -> ?x_max:domain -> codomain -> codomain -> t
 
   end
 
 module Default : Default
-
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
-
-
Index: trunk/circe2/src/diffmap.ml
===================================================================
--- trunk/circe2/src/diffmap.ml	(revision 8897)
+++ trunk/circe2/src/diffmap.ml	(revision 8898)
@@ -1,510 +1,518 @@
 (* circe2/diffmap.ml --  *)
 (* Copyright (C) 2001-2023 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 open Printf
 
 module type T =
   sig
 
     type t
 
     type domain
     val x_min : t -> domain
     val x_max : t -> domain
 
     type codomain
     val y_min : t -> codomain
     val y_max : t -> codomain
 
     val phi : t -> domain -> codomain
     val ihp : t -> codomain -> domain
     val jac : t -> domain -> float
     val caj : t -> codomain -> float
 
+    val is_null : t -> bool
+
     val with_domain : t -> x_min:domain -> x_max:domain -> t
 
     val encode : t -> string
 
   end
 
 module type Real = T with type domain = float and type codomain = float
 
 (* \subsection{Testing Real Maps} *)
 
 module type Test =
   sig
     module M : Real
     val domain : M.t -> unit
     val inverse : M.t -> unit
     val jacobian : M.t -> unit
     val all : M.t -> unit
   end
 
 module Make_Test (M : Real) =
   struct
 
     module M = M
 
     let steps = 1000
     let epsilon = 1.0e-6
 
     let diff ?(tolerance = 1.0e-13) x1 x2 =
       let d = (x1 -. x2)  in
       if abs_float d < (abs_float x1 +. abs_float x2) *. tolerance then
         0.0
       else
         d
 
     let derive x_min x_max f x =
       let xp = min x_max (x +. epsilon)
       and xm = max x_min (x -. epsilon) in
       (f xp -. f xm) /. (xp -.xm)
 
     let domain m =
       let x_min = M.x_min m
       and x_max = M.x_max m
       and y_min = M.y_min m
       and y_max = M.y_max m in
       let x_min' = M.ihp m y_min
       and x_max' = M.ihp m y_max
       and y_min' = M.phi m x_min
       and y_max' = M.phi m x_max in
       printf "   f: [%g,%g] -> [%g,%g] ([%g,%g])\n"
         x_min x_max y_min' y_max' (diff y_min' y_min) (diff y_max' y_max);
       printf "f^-1: [%g,%g] -> [%g,%g] ([%g,%g])\n"
         y_min y_max x_min' x_max' (diff x_min' x_min) (diff x_max' x_max)
 
     let inverse m =
       let x_min = M.x_min m
       and x_max = M.x_max m
       and y_min = M.y_min m
       and y_max = M.y_max m in
       for i = 1 to steps do
         let x = x_min +. Random.float (x_max -. x_min)
         and y = y_min +. Random.float (y_max -. y_min) in
         let x' = M.ihp m y
         and y' = M.phi m x in
         let x'' = M.ihp m y'
         and y'' = M.phi m x' in
         let dx = diff x'' x
         and dy = diff y'' y in
         if dx <> 0.0 then
           printf "f^-1 o f   : %g -> %g -> %g (%g)\n" x y' x'' dx;
         if dy <> 0.0 then
           printf "   f o f^-1: %g -> %g -> %g (%g)\n" y x' y'' dy
       done
 
     let jacobian m =
       let x_min = M.x_min m
       and x_max = M.x_max m
       and y_min = M.y_min m
       and y_max = M.y_max m in
       for i = 1 to steps do
         let x = x_min +. Random.float (x_max -. x_min)
         and y = y_min +. Random.float (y_max -. y_min) in
         let jac_x' = derive x_min x_max (M.phi m) x
         and jac_x = M.jac m x
         and inv_jac_y' = derive y_min y_max (M.ihp m) y
         and inv_jac_y = M.caj m y in
         let dj = diff ~tolerance:1.0e-9 jac_x' jac_x
         and dij = diff ~tolerance:1.0e-9 inv_jac_y' inv_jac_y in
         if dj <> 0.0 then
           printf "dy/dx: %g -> %g (%g)\n" x jac_x' dj;
         if dij <> 0.0 then
           printf "dx/dy: %g -> %g (%g)\n" y inv_jac_y' dij
       done
 
     let all m =
       printf "phi(domain) = codomain and phi(codomain) = domain";
       domain m;
       printf "ihp o phi = id (domain) and phi o ihp = id(codomain)";
       inverse m;
       printf "jacobian";
       jacobian m
 
   end
 
 (* \subsection{Specific Real Maps} *)
 
 module Id =
   struct
 
     type domain = float
     type codomain = float
 
     type t =
         { x_min : domain;
           x_max : domain;
           y_min : codomain;
           y_max : codomain;
           phi : float -> float;
           ihp : float -> float;
           jac : float -> float;
           caj : float -> float }
 
     let encode m = "0 1 0 0 1 1"
 
     let closure ~x_min ~x_max ~y_min ~y_max =
       let phi x = x
       and ihp y = y
       and jac x = 1.0
       and caj y = 1.0 in
       { x_min = x_min;
         x_max = x_max;
         y_min = y_min;
         y_max = y_max;
         phi = phi;
         ihp = ihp;
         jac = jac;
         caj = caj }
 
     let idmap ~x_min ~x_max ~y_min ~y_max =
       if x_min <> y_min && x_max <> y_max then
         invalid_arg "Diffmap.Id.idmap"
       else
         closure ~x_min ~x_max ~y_min ~y_max
 
     let with_domain m ~x_min ~x_max =
       idmap ~x_min ~x_max ~y_min:m.y_min ~y_max:m.y_max
 
     let create ?x_min ?x_max y_min y_max =
       idmap
         ~x_min:(match x_min with Some x -> x | None -> y_min)
         ~x_max:(match x_max with Some x -> x | None -> y_max)
         ~y_min ~y_max
 
     let x_min m = m.x_min
     let x_max m = m.x_max
     let y_min m = m.y_min
     let y_max m = m.y_max
 
     let phi m = m.phi
     let ihp m = m.ihp
     let jac m = m.jac
-    let caj m  = m.caj
+    let caj m = m.caj
+
+    let is_null m = false
 
   end
 
+module Null =
+  struct
+    include Id
+    let is_null m = true
+  end
+
 module Linear =
   struct
 
     type domain = float
     type codomain = float
 
     type t =
         { x_min : domain;
           x_max : domain;
           y_min : codomain;
           y_max : codomain;
           a : float;
           b : float;
           phi : domain -> codomain;
           ihp : codomain -> domain;
           jac : domain -> float;
           caj : codomain -> float }
 
     let encode m = failwith "Diffmap.Linear: not used in Circe2"
 
     let closure ~x_min ~x_max ~y_min ~y_max ~a ~b =
 
 (* \begin{equation}
       x \mapsto \lambda_{a,b}(x) = ax + b
    \end{equation} *)
       let phi x = a *. x +. b
 
 (* \begin{equation}
       y \mapsto (\lambda_{a,b})^{-1}(y) = \frac{y-b}{a}
    \end{equation} *)
       and ihp y = (y -. b) /. a
 
       and jac x = a
       and caj y = 1.0 /. a in
 
       { x_min = x_min;
         x_max = x_max;
         y_min = y_min;
         y_max = y_max;
         a = a;
         b = b;
         phi = phi;
         ihp = ihp;
         jac = jac;
         caj = caj }
 
     let linearmap ~x_min ~x_max ~y_min ~y_max =
       let delta_x = x_max -. x_min
       and delta_y = y_max -. y_min in
       let a = delta_y /. delta_x
       and b = (y_min *. x_max -. y_max *. x_min) /. delta_x in
       closure ~x_min ~x_max ~y_min ~y_max ~a ~b
 
     let with_domain m ~x_min ~x_max =
       linearmap ~x_min ~x_max ~y_min:m.y_min ~y_max:m.y_max
 
     let create ?x_min ?x_max y_min y_max =
       linearmap
         ~x_min:(match x_min with Some x -> x | None -> y_min)
         ~x_max:(match x_max with Some x -> x | None -> y_max)
         ~y_min ~y_max
 
     let x_min m = m.x_min
     let x_max m = m.x_max
     let y_min m = m.y_min
     let y_max m = m.y_max
 
     let phi m = m.phi
     let ihp m = m.ihp
     let jac m = m.jac
-    let caj m  = m.caj
+    let caj m = m.caj
+
+    let is_null m = false
 
   end
 
 module Power =
   struct
 
     type domain = float
     type codomain = float
 
     type t =
         { x_min : domain;
           x_max : domain;
           y_min : codomain;
           y_max : codomain;
           alpha : float;
           xi : float;
           eta : float;
           a : float;
           b : float;
           phi : domain -> codomain;
           ihp : codomain -> domain;
           jac : domain -> float;
           caj : codomain -> float }
 
     let encode m =
       sprintf "1 %s %s %s %s %s"
         (Float.Double.to_string m.alpha)
         (Float.Double.to_string m.xi)
         (Float.Double.to_string m.eta)
         (Float.Double.to_string m.a)
         (Float.Double.to_string m.b)
 
     let closure ~x_min ~x_max ~y_min ~y_max ~alpha ~xi ~eta ~a ~b =
 
 (* \begin{equation}
       x \mapsto \psi_{a,b}^{\alpha,\xi,\eta}(x)
           = \frac{1}{b}(a(x-\xi))^{\alpha} + \eta
    \end{equation} *)
       let phi x =
         (a *. (x -. xi)) ** alpha /. b +. eta
 
 (* \begin{equation}
       y \mapsto (\psi_{a,b}^{\alpha,\xi,\eta})^{-1}(y)
           = \frac{1}{a} (b(y-\eta))^{1/\alpha} + \xi
    \end{equation} *)
       and ihp y =
         (b *. (y -. eta)) ** (1.0 /. alpha) /. a +. xi
 
 (* \begin{equation}
      \frac{\mathrm{d}y}{\mathrm{d}x} (x)
         = \frac{a\alpha}{b} (a(x-\xi))^{\alpha-1}
    \end{equation} *)
       and jac x =
         a *. alpha *. (a *. (x -. xi)) ** (alpha -. 1.0) /. b
 
 (* \begin{equation}
      \frac{\mathrm{d}x}{\mathrm{d}y} (y)
         = \frac{b}{a\alpha} (b(y-\eta))^{1/\alpha-1}
    \end{equation} *)
       and caj y =
         b *. (b *. (y -. eta)) ** (1.0 /. alpha -. 1.0) /. (a *. alpha) in
 
       { x_min = x_min;
         x_max = x_max;
         y_min = y_min;
         y_max = y_max;
         alpha = alpha;
         xi = xi;
         eta = eta;
         a = a;
         b = b;
         phi = phi;
         ihp = ihp;
         jac = jac;
         caj = caj }
 
 (* \begin{subequations}
    \begin{align}
      a_{i}   &= \frac{   (b_{i}(y_{i}-\eta_{i}))^{1/\alpha_{i}}
                        - (b_{i}(y_{i-1}-\eta_{i}))^{1/\alpha_{i}}}%
                      {x_{i} - x_{i-1}} \\
      \xi_{i} &= \frac{   x_{i-1}|y_{i}  -\eta_{i}|^{1/\alpha_{i}}
                        - x_{i}  |y_{i-1}-\eta_{i}|^{1/\alpha_{i}}}%
                      {          |y_{i}  -\eta_{i}|^{1/\alpha_{i}}
                        -        |y_{i-1}-\eta_{i}|^{1/\alpha_{i}}}
    \end{align}
    \end{subequations}
    The degeneracy~(\ref{eq:ab-semigroup}) can finally be resolved by
    demanding~$|b|=1$ in~(\ref{eq:ai}). *)
 
     let powermap ~x_min ~x_max ~y_min ~y_max ~alpha ~eta =
       let b =
         if eta <= y_min then
           1.
         else if eta >= y_max then
           -1.
         else
           invalid_arg "singular" in
       let pow y = (b *. (y -. eta)) ** (1. /. alpha) in
       let delta_pow = pow y_max -. pow y_min
       and delta_x = x_max -. x_min in
       let a = delta_pow /. delta_x
       and xi = (x_min *. pow y_max -. x_max *. pow y_min) /. delta_pow in
       closure ~x_min ~x_max ~y_min ~y_max ~alpha ~xi ~eta ~a ~b
 
     let with_domain m ~x_min ~x_max =
       powermap ~x_min ~x_max ~y_min:m.y_min ~y_max:m.y_max
         ~alpha:m.alpha ~eta:m.eta
 
     let create ~alpha ~eta ?x_min ?x_max y_min y_max =
       powermap
         ~x_min:(match x_min with Some x -> x | None -> y_min)
         ~x_max:(match x_max with Some x -> x | None -> y_max)
         ~y_min ~y_max ~alpha ~eta
 
     let x_min m = m.x_min
     let x_max m = m.x_max
     let y_min m = m.y_min
     let y_max m = m.y_max
 
     let phi m = m.phi
     let ihp m = m.ihp
     let jac m = m.jac
     let caj m  = m.caj
 
+    let is_null m = false
+
   end
 
 module Resonance =
   struct
 
     type domain = float
     type codomain = float
 
     type t =
         { x_min : domain;
           x_max : domain;
           y_min : codomain;
           y_max : codomain;
           xi : float;
           eta : float;
           a : float;
           b : float;
           phi : domain -> codomain;
           ihp : codomain -> domain;
           jac : domain -> float;
           caj : codomain -> float }
 
     let encode m =
       sprintf "2 0 %s %s %s %s"
         (Float.Double.to_string m.xi)
         (Float.Double.to_string m.eta)
         (Float.Double.to_string m.a)
         (Float.Double.to_string m.b)
 
     let closure ~x_min ~x_max ~y_min ~y_max ~xi ~eta ~a ~b =
 
 (* \begin{equation}
      x \mapsto \rho_{a,b}^{\xi,\eta}(x)
          = a \tan\left(\frac{a}{b^2}(x-\xi)\right) + \eta
    \end{equation} *)
       let phi x = a *. tan (a *. (x -. xi) /. (b *. b)) +. eta
 
 (* \begin{equation}
      y \mapsto (\rho_{a,b}^{\xi,\eta})^{-1}(y)
          = \frac{b^2}{a} \textrm{atan}\left(\frac{y-\eta}{a}\right) + \xi
    \end{equation} *)
       and ihp y = b *. b *. (atan2 (y -. eta) a) /. a +. xi
 
 (* \begin{equation}
      \frac{\mathrm{d}y}{\mathrm{d}x}(x(y))
        = \frac{1}{{\displaystyle\frac{\mathrm{d}x}{\mathrm{d}y}(y)}}
        = \left(\frac{b^2}{(y-\eta)^2+a^2}\right)^{-1}
    \end{equation} *)
       and caj y = b *. b /. ((y -. eta) ** 2.0 +. a *. a) in
 
       let jac x = 1.0 /. caj (phi x) in
 
       { x_min = x_min;
         x_max = x_max;
         y_min = y_min;
         y_max = y_max;
         xi = xi;
         eta = eta;
         a = a;
         b = b;
         phi = phi;
         ihp = ihp;
         jac = jac;
         caj = caj }
 
 (* \begin{subequations}
    \begin{align}
      b_{i}
        &= \sqrt{a_{i}
             \frac{x_{i}-x_{i-1}}%
                  {   \textrm{atan}\left(\frac{y_{i}  -\eta_{i}}{a_{i}}\right)
                    - \textrm{atan}\left(\frac{y_{i-1}-\eta_{i}}{a_{i}}\right)}} \\
      \xi_{i}
        &= \frac{   x_{i-1}\textrm{atan}\left(\frac{y_{i}  -\eta_{i}}{a_{i}}\right)
                  - x_{i}  \textrm{atan}\left(\frac{y_{i-1}-\eta_{i}}{a_{i}}\right)}%
                {x_{i}-x_{i-1}}
    \end{align}
    \end{subequations} *)
    
    let resonancemap ~x_min ~x_max ~y_min ~y_max ~eta ~a =
      let arc y = atan2 (y -. eta) a in
      let delta_arc = arc y_max -. arc y_min
      and delta_x = x_max -. x_min in
      let b = sqrt (a *. delta_x /. delta_arc)
      and xi = (x_min *. arc y_max -. x_max *. arc y_min) /. delta_arc in
      closure ~x_min ~x_max ~y_min ~y_max ~xi ~eta ~a ~b
    
     let with_domain m ~x_min ~x_max =
       resonancemap ~x_min ~x_max ~y_min:m.y_min ~y_max:m.y_max
         ~eta:m.eta ~a:m.a
 
     let create ~eta ~a ?x_min ?x_max y_min y_max =
       resonancemap
         ~x_min:(match x_min with Some x -> x | None -> y_min)
         ~x_max:(match x_max with Some x -> x | None -> y_max)
         ~y_min ~y_max ~eta ~a
 
     let x_min m = m.x_min
     let x_max m = m.x_max
     let y_min m = m.y_min
     let y_max m = m.y_max
 
     let phi m = m.phi
     let ihp m = m.ihp
     let jac m = m.jac
     let caj m  = m.caj
 
-  end
+    let is_null m = false
 
-(*i
- *  Local Variables:
- *  mode:caml
- *  indent-tabs-mode:nil
- *  page-delimiter:"^(\\* .*\n"
- *  End:
-i*)
+  end
Index: trunk/circe2/src/prelude.nw
===================================================================
--- trunk/circe2/src/prelude.nw	(revision 8897)
+++ trunk/circe2/src/prelude.nw	(revision 8898)
@@ -1,3027 +1,3053 @@
 % circe2/prelude.nw -- 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \def\circe/{\texttt{circe}}
 \def\Version/{2.0}
 \def\Date/{June 2014}
 %BEGIN LATEX
 \special{%
   !userdict
   begin
     /bop-hook {
       gsave
         50 650 translate
         300 rotate
         /Times-Roman findfont
         216 scalefont
         setfont
         0 0 moveto
         0.9 setgray
         (DRAFT) show
       grestore
     } def
   end}
 %END LATEX
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %BEGIN LATEX
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{ifpdf}
 %END LATEX
 \ifpdf
   \documentclass[12pt,a4paper]{article}
   \usepackage{type1cm}
   %%% FIXME: hyperref doesn't work ...
   %usepackage[pdftex,colorlinks]{hyperref}
   \usepackage[pdftex]{graphics,emp}
   \DeclareGraphicsRule{*}{mps}{*}{}
 \else
   \documentclass[a4paper]{article}
   \usepackage[nologo]{thopp}
   \usepackage{graphics,emp}
 \fi
 %BEGIN IMAGE
 \setlength{\unitlength}{1mm}
 \empaddtoprelude{input graph}
 \empaddtoprelude{input sarith}
 %END IMAGE
 \usepackage{amsmath,amssymb,alltt,units}
 %HEVEA \newcommand{\tr}{\mathrm{tr}}
 %BEGIN LATEX
 \DeclareMathOperator{\tr}{tr}
 \providecommand{\dd}{\mathrm{d}}
 \allowdisplaybreaks
 \makeindex
 \IfFileExists{hevea.sty}%
   {\usepackage{hevea}}
   {\def\ahref##1##2{{##2}}%
    \def\ahrefloc##1##2{{##2}}%
    \def\aname##1##2{{##2}}%
    \def\ahrefurl##1{\url{##1}}%
    \def\footahref##1##2{##2\footnote{\url{##1}}}%
    \def\mailto##1{\texttt{##1}}%
    \def\imgsrc##1##2[]{}%
    \def\home##1{\protect\raisebox{-.75ex}{\char126}##1}%
    \def\latexonly{\relax}%
    \def\endlatexonly{\relax}}
 %END LATEX
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \usepackage[noweb,bypages]{ocamlweb}
 \empaddtoTeX{\usepackage{ocamlweb}}
 \renewcommand{\ocwinterface}[1]{\subsection{Interface of \ocwupperid{#1}}}
 \renewcommand{\ocwmodule}[1]{\subsection{Implementation of \ocwupperid{#1}}}
 \renewcommand{\ocwinterfacepart}{\relax}
 \renewcommand{\ocwcodepart}{\relax}
 \renewcommand{\ocwbeginindex}{\begin{theindex}}
 \newcommand{\thocwmodulesection}[1]{\subsubsection{#1}}
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \usepackage{noweb}
 %%% \usepackage{nocondmac}
 \setlength{\nwmarginglue}{1em}
 \noweboptions{smallcode,noidentxref}%%%{webnumbering}
 %%% Saving paper:
 \def\nwendcode{\endtrivlist\endgroup}
 \nwcodepenalty=0
 \let\nwdocspar\relax
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%% Some decorations depend on local stuff.  Make it optional.
 \IfFileExists{thohacks.sty}%
   {\usepackage{thohacks}}%
   {\let\timestamp\today}%
 %BEGIN LATEX
 \ifpdf
   \def\Kirke/{K$\acute\iota${}$\rho${}$\kappa${}$\eta$}
   \def\KirkeOne/{\texttt{circe1}}
   \def\KirkeTwo/{\texttt{circe2}}
 \else
   % \IfFileExists{greek.sty}%
   %   {\usepackage{greek}%
   %    \def\Kirke/{{\greek Ki'rkh}}}%
   %   {\def\Kirke/{K$\acute\iota${}$\rho${}$\kappa${}$\eta$}}
   \def\Kirke/{K$\acute\iota${}$\rho${}$\kappa${}$\eta$}
   \def\KirkeOne/{\Kirke/\kern0.2em1}
   \def\KirkeTwo/{\Kirke/\kern0.2em2}
 \fi
 %END LATEX 
 %HEVEA \def\Kirke/{\begin{toimage}K$\acute\iota${}$\rho${}$\kappa${}$\eta$\end{toimage}\imageflush}
 %HEVEA \def\KirkeOne/{\texttt{circe1}}
 %HEVEA \def\KirkeTwo/{\texttt{circe2}}
 
 \newcommand{\modpoly}{%
   \;(\text{modulo } 2 \text{ and } z^{100}+z^{37}+1)}
 \newenvironment{params}%
  {\begin{list}{}%
    {\setlength{\leftmargin}{2em}%
     \setlength{\rightmargin}{2em}%
     \setlength{\itemindent}{-1em}%
     \setlength{\listparindent}{0pt}%
     \renewcommand{\makelabel}{\hfil}}}%
  {\end{list}}
 \newenvironment{itemized}%
  {\begin{list}{}%
    {\setlength{\leftmargin}{2em}%
     \setlength{\rightmargin}{2em}%
     \setlength{\itemindent}{-1em}%
     \setlength{\listparindent}{0pt}%
     \renewcommand{\makelabel}{\hfil}}}%
  {\end{list}}
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%% LOTS of floats:
 \setcounter{topnumber}{3}              % 2
 \setcounter{bottomnumber}{3}           % 2
 \setcounter{totalnumber}{5}            % 3
 \renewcommand{\topfraction}{0.95}      % 0.7
 \renewcommand{\bottomfraction}{0.95}   % 0.3
 \renewcommand{\textfraction}{0.05}     % 0.2
 \renewcommand{\floatpagefraction}{0.8} % 0.5
 \setlength{\abovecaptionskip}{.5\baselineskip}
 \setlength{\belowcaptionskip}{\baselineskip}
 \widowpenalty=4000
 \clubpenalty=4000
 \displaywidowpenalty=4000
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \makeindex
 \begin{document}
 %BEGIN IMAGE
 \begin{empfile}
 %END IMAGE
 \bibliographystyle{prsty}%%%{unsrt}%%%{physics}
 \title{%
   \Kirke/ Version \Version/:\\
   Beam Spectra for Simulating Linear Collider Physics}
 \author{%
   Thorsten Ohl%
     \thanks{e-mail: \texttt{ohl@physik.uni-wuerzburg.de}}\\
   \hfil\\
     Institute for Theoretical Physics and Astrophysics\\
     W\"urzburg University\\
     Campus Hubland Nord\\
     Emil-Hilb-Weg 22\\
     97074 W\"urzburg\\
     Germany}
 \date{%
   \Date/\\
   \textbf{DRAFT: \timestamp}}
 \maketitle
 \begin{abstract}
   \ldots
 \end{abstract}
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %tableofcontents\newpage                                       %!MANUAL%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \newpage
 \section*{Caveat}
 \begin{Large}\bfseries
   This manual is outdated and describes the old Fortran77 interface.
   This interface has been replaced by a similar, but thoroughly modern
   Fortran~2003 interface.
   
   Also the new smoothing feature of \verb+circe2_tool+ ist not
   described here.
   
   Please see the annotated template and other files in
   \verb+share/examples/+ for a starting point for rolling your own
   beam descriptions.
 \end{Large}
 \newpage
 \section*{Program Summary:}
 \begin{raggedright}
 \begin{itemize}
   \item \textbf{Title of program:}
     \Kirke/, Version \Version/ (\Date/)
 %CPC%  \item \textbf{Catalogue number:}
 %CPC%    ????
   \item \textbf{Program obtainable}
 %CPC%    from CPC Program Library, Queen's University of Belfast,
 %CPC%    N.~Ireland (see application form in this issue) or
     from \verb|http://www.hepforge.org/downloads/whizard|.
   \item \textbf{Licensing provisions:}
     Free software under the GNU General Public License.
   \item \textbf{Programming languages used:}
     Fortran, OCaml\cite{O'Caml}
     (available from \verb|http://caml.inria.fr/ocaml| and
      \verb|http://ocaml.org|).
   \item \textbf{Number of program lines in distributed program}
     $\approx$ ??? lines of Fortran (excluding comments) for the library;
     $\approx$ ??? lines of OCaml for the utility program
   \item \textbf{Computer/Operating System:}
     Any with a Fortran programming environment.
   \item \textbf{Memory required to execute with typical data:}
     Negligible on the scale of typical applications calling the library.
   \item \textbf{Typical running time:}
     A negligible fraction of the running time of
     applications calling the library.
   \item \textbf{Purpose of program:}
     Provide efficient, realistic and reproducible parameterizations of
     the correlated $e^\pm$- and $\gamma$-beam spectra for linear
     colliders and photon colliders. 
   \item \textbf{Nature of physical problem:}
     The intricate beam dynamics in the interaction region of a
     high luminosity linear collider at $\sqrt s = 500$GeV result in
     non-trivial energy spectra of the scattering electrons, positrons and
     photons.  Physics simulations require efficient, reproducible,
     realistic and easy-to-use parameterizations of these spectra.
   \item \textbf{Method of solution:}
     Parameterization, curve fitting, adaptive sampling, Monte Carlo
     event generation. 
   \item \textbf{Keywords:}
     Event generation, beamstrahlung, linear colliders, photon
     colliders.
 \end{itemize}
 \end{raggedright}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \newpage
 \tableofcontents
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \newpage
 \section{Introduction}
 
 The expeditious construction of a high-energy, high-luminosity
 $\mathrm{e}^+\mathrm{e}^-$ Linear Collider~(LC) to complement the
 Large Hadron Collider~(LHC) has been identified as the next world wide
 project for High Energy Physics~(HEP).  The dynamics of the dense
 colliding beams providing the high luminosities required by such a
 facility is highly non-trivial and detailed simulations have to be
 performed to predict the energy spectra provided by these beams.  The
 microscopic simulations of the beam dynamics require too much computer
 time and memory for direct use in physics programs.  Nevertheless, the
 results of such simulations have to be available as input for physics
 studies, since these spectra affect the sensitivity of experiments for
 the search for deviations from the standard model and to new physics.
 
 \Kirke/ Version~1.x (\KirkeOne/ for short)~\cite{Ohl:1996:Circe} has
 become a de-facto standard for inclusion of realistic energy spectra
 of TeV-scale $\mathrm{e}^+\mathrm{e}^-$ LCs in physics calculations
 and event generators.  It is supported by the major multi purpose
 event generators~\cite{PYTHIA,HERWIG} and has been used in many
 dedicated analysises.  \Kirke/ provides a fast, concise and convenient
 parameterization of the results of such simulations.
 
 \KirkeOne/ assumed strictly factorized distributions with a very
 restricted functional form (see~\cite{Ohl:1996:Circe} for details).
 This approach was sufficient for exploratory studies of physics at
 TeV-scale $\mathrm{e}^+\mathrm{e}^-$ LCs.  Future studies
 of physics at $\mathrm{e}^+\mathrm{e}^-$ LCs will require
 a more detailed description and the estimation of non-factorized
 contributions.  In particular, all distributions at laser
 backscattering $\gamma\gamma$
 colliders~\cite{Ginzburg/Telnov/etal:1983:gamma-collider} and at
 multi-TeV $\mathrm{e}^+\mathrm{e}^-$ LCs are correlated and can not
 be approximated by \KirkeOne/ at all.  In addition, the proliferation
 of accelerator designs since the release of \KirkeOne/ has make the
 maintenance of parameterizations as FORTRAN77 \texttt{BLOCK DATA}
 unwieldy.
 
 \Kirke/ Version 2.0 (\KirkeTwo/ for short) successfully addresses
 these shortcomings of \KirkeOne/, as can be seen in
 figure~\ref{fig:z}.  It should be noted that the large~$z$ region and
 the blown-up $z\to0$~region are taken from the \emph{same} pair of datasets.  In
 section~\ref{sec:demonstration} below, figures~\ref{fig:z/20/q}
 to~\ref{fig:z/20/m2} demonstrate the interplay of \KirkeTwo/'s
 features. The algorithms
 implemented\footnote{A small number of well defined extensions that
 has have not been implemented yet are identified in
 section~\ref{sec:API} below.} in \KirkeTwo/ should suffice for all
 studies until $\mathrm{e}^+\mathrm{e}^-$ LCs and photon colliders come
 on-line and probably beyond.  The implementation \KirkeTwo/
 bears no resemblance at all with the implementation of \KirkeOne/.
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(53,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.50m2.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(53,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.50m2.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z}%
     Comparison of a simulated realistic $\gamma\gamma$ luminosity
     spectrum (helicities:~$(+,+)$) for a \unit[500]{GeV} photon collider
     at TESLA~\cite{Telnov:2001:priv} (filled area) with its \KirkeTwo/
     parameterization (solid line) using 50~bins in both directions.
     The $10^4$-fold blow-up of the $z\to0$~region is
     taken from the same pair of datasets as the plot including the
     large~$z$ region.}
 \end{figure}
 
 \KirkeTwo/ describes the distributions by two-dimensional grids that
 are optimized using an algorithm derived from
 VEGAS~\cite{VEGAS}.  The implementation
 was modeled on the implementation in
 VAMP~\cite{VAMP}, but changes were required
 for sampling static event sets instead of distributions given as
 functions.  The problem solved by \KirkeTwo/ is rather different from
 the Monte Carlo integration with importance or stratified sampling
 that is the focus of~VEGAS and~VAMP.  In the case of VEGAS/VAMP the function is
 given as a mathematical function, either analytically or
 numerically. In this case, while the adapted grid is being be refined,
 resources can be invested for studying the function more closely in
 problematic regions.  \KirkeTwo/ does not have this luxury, because it
 must reconstruct (``\emph{guess}'') a function from a \emph{fixed} and
 \emph{finite} sample.  Therefore it cannot avoid to introduce biases,
 either through a fixed global functional form (as in \KirkeOne/)
 through step functions (histograms).  \KirkeTwo/ combines the two approaches and
 uses automatically adapted histograms mapped by a patchwork of
 functions.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Notes on the Implementation}
 The FORTRAN77 library is extremely simple (about 800 lines) and
 performs only two tasks: one small set of subroutines efficiently
 generates pairs of random numbers distributed according to two
 dimensional histograms with factorized non-uniform bins stored in a
 file.  A second set of functions calculates the value of the
 corresponding distributions.
 
 FORTRAN77 has been chosen solely for practical reasons: at the time of
 writing, the majority of programs expected to use the \KirkeTwo/ are
 legacy applications written in FORTRAN77.  The simple functionality of
 the FORTRAN77 library can however be reproduced trivially in any other
 programming language that will be needed in the future.
 
 The non-trivial part of constructing an optimized histogram from an
 arbitrary distribution is performed by a utility program
 \verb+circe2_tool+ written in Objective Caml~\cite{O'Caml} (or O'Caml
 for short).  O'Caml is available as Free Software for almost all
 computers and operating systems currently used in high energy physics.
 Bootstrapping the O'Caml compiler is straightforward and quick.  Furthermore,
 parameterizations are distributed together with \KirkeTwo/, and most
 users will not even need to compile \verb+circe2_tool+.  Therefore
 there are no practical problems in using a modern programming language
 like O'Caml that allows---in the author's experience---a both more rapid
 and safer development than FORTRAN77 or~C++.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Overview}
 The remainder of this paper is organized as follows.  For the benefit
 of users of the library, the Application Program Interface~(API) is
 described immediately in section~\ref{sec:API} after defining the
 notation in section~\ref{sec:physics}.  Section~\ref{sec:API-samples}
 shows some examples using the procedures described in
 section~\ref{sec:API}.
 
 A description of the inner workings of \KirkeTwo/ that is more
 detailed than required for using the library starts in
 section~\ref{sec:algorithms}.  An understanding of the algorithms
 employed is helpful for preparing beam descriptions using the program
 \texttt{circe2\_tool} which is described in
 section~\ref{sec:circe2_tool-user}.  Details of the implementation of
 \texttt{circe2\_tool} can be found in
 section~\ref{sec:circe2_tool-implementation}, where also the benefits
 provided by modern functional programming languages for program
 organization in the large are discussed.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Physics}
 \label{sec:physics}
 
 The customary parametrization of polarization in beam physics~\cite{%
   Ginzburg/Telnov/etal:1984:gamma-collider,%
   Chen/etal:1995:CAIN}
 is in terms of density matrices for the leptons
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \rho_{\mathrm{e}^{\pm}}(\zeta)
     = \frac{1}{2}\left(1+\zeta_{i}\sigma_{i}\right)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 and the so-called Stokes' parameters for photons
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \rho_{\gamma}(\xi)
     = \frac{1}{2}\left(1+\xi_{i}\sigma_{i}\right)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 where the pseudo density matrix $2\times2$-matrix~$\rho_{\gamma}$ for
 a pure polarization state~$\epsilon_{\mu}$ is given by
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   [\rho_{\gamma}]_{ij}
     = \langle(\epsilon e_{i})(\epsilon^{*} e_{j})\rangle
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 using two unit vectors~$e_{1/2}$ orthogonal to the momentum.
 Keeping in mind the different interpretations of~$\zeta$ and~$\xi$, we
 will from now on unify the mathematical treatment and use the two
 interchangably, since the correct interpretation will always be clear
 from the context.  Using the notation~$\sigma_{0}=1$, the joint
 polarization density matrix for two colliding particles can be written
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
 \label{eq:rho(chi)}
   \rho(\chi)
     = \sum_{a,a'=0}^{3} \frac{\chi_{aa'}}{4}\, \sigma_{a} \otimes \sigma_{a'}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 with~$\chi_{0,0}=\tr\rho(\chi)=1$. Averaging density matrices
 will in general lead to correlated density matrices, even if the
 density matrices that are being averaged are factorized or correspond
 to pure states.
 
 The most complete description~$B$ of a pair of colliding beams is
 therefore provided by a probability density and a density matrix for
 each pair~$(x_{1},x_{2})$ of energy fractions:
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \begin{aligned}
      B: [0,1]\times[0,1] &\to \mathbf{R}^{+}\times M \\
            (x_{1},x_{2}) &\mapsto (D(x_{1},x_{2}), \rho(x_{1},x_{2}))
   \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 where~$\rho(x_{1},x_{2})$ will conveniently be given using the
 parametrization~(\ref{eq:rho(chi)}).  Sophisticated event generators
 can use~$D(x_{1},x_{2})$ and~$\rho(x_{1},x_{2})$ to account for all
 spin correlations with the on-shell transition matrix~$T$
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \mathrm{d}\sigma
     = \int\!\mathrm{d}x_{1}\wedge\mathrm{d}x_{2}\,D(x_{1},x_{2})\,
         \tr\left( P_{\Omega} T(x_{1}x_{2}s)
                           \rho(x_{1},x_{2})T^{\dagger}(x_{1}x_{2}s) \right)\,
         \mathrm{dLIPS}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Polarization Averaged Distributions}
 \label{sec:averaged}
 
 Physics applications that either ignore polarization (this is often not
 advisable, but can be a necessary compromise in some cases) or know
 that polarization will play no significant role can ignore the density
 matrix, which
 amounts to summing over all polarization states.  If the microscopic
 simulations that have been used to obtain the distributions described
 by \KirkeTwo/ do not keep track of polarization, 93\%~of disk space
 can be saved by supporting simplified interfaces that ignore
 polarization altogether.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Helicity Distributions}
 \label{sec:helicities}
 
 Between the extremes of polarization averaged distributions on one
 end and full correlated density matrices on the other end, there is
 one particularly important case for typical applications, that
 deserves a dedicated implementation.
 
 In the approximation of projecting on the subspace consisting of
 circular polarizations
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \rho(\chi) = \frac{1}{4} \left(
       \chi_{0,0} \cdot 1          \otimes 1
     + \chi_{0,3} \cdot 1          \otimes \sigma_{3}
     + \chi_{3,0} \cdot \sigma_{3} \otimes 1
     + \chi_{3,3} \cdot \sigma_{3} \otimes \sigma_{3} \right)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 the density matrix can be rewritten as a convex combination of
 manifest projection operators build out
 of~$\sigma_{\pm}=(1\pm\sigma_{3})/2$:
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \rho(\chi) =
       \chi_{++} \cdot \sigma_{+} \otimes \sigma_{+}
     + \chi_{+-} \cdot \sigma_{+} \otimes \sigma_{-}
     + \chi_{-+} \cdot \sigma_{-} \otimes \sigma_{+}
     + \chi_{--} \cdot \sigma_{-} \otimes \sigma_{-}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 The coefficients are given by
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{subequations}
 \begin{align}
   \chi_{++} &= \frac{1}{4}\left(\chi_{0,0}+\chi_{0,3}+\chi_{3,0}+\chi_{3,3}\right) \ge 0 \\
   \chi_{+-} &= \frac{1}{4}\left(\chi_{0,0}-\chi_{0,3}+\chi_{3,0}-\chi_{3,3}\right) \ge 0 \\
   \chi_{-+} &= \frac{1}{4}\left(\chi_{0,0}+\chi_{0,3}-\chi_{3,0}-\chi_{3,3}\right) \ge 0 \\
   \chi_{--} &= \frac{1}{4}\left(\chi_{0,0}-\chi_{0,3}-\chi_{3,0}+\chi_{3,3}\right) \ge 0
 \end{align}
 \end{subequations}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 and satisfy
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \chi_{++} + \chi_{+-} + \chi_{-+} + \chi_{--}
     = \tr\rho(\chi) = 1
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Of course, the~$\chi_{\epsilon_1\epsilon_2}$ are recognized as the probabilities for
 finding a particular combination of helicities for particles moving
 along the $\pm\vec{e}_{3}$ direction and we can introduce partial
 probability distributions
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   D_{p_1p_2}^{\epsilon_1\epsilon_2}(x_{1},x_{2})
    = \chi_{\epsilon_1\epsilon_2} \cdot D_{p_1p_2}(x_{1},x_{2}) \ge 0
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 that are to be combined with the polarized cross sections
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \frac{\mathrm{d}\sigma}{\mathrm{d}\Omega}(s)
     = \sum_{\epsilon_1,\epsilon_2=\pm}
       \int\!\mathrm{d}x_{1}\wedge\mathrm{d}x_{2}\,
         D^{\epsilon_1\epsilon_2}(x_{1},x_{2})\,
         \left(\frac{\mathrm{d}\sigma}%
                    {\mathrm{d}\Omega}\right)^{\epsilon_1\epsilon_2}
         (x_{1}x_{2}s)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 This case deserves special consideration because it is a good
 approximation for a majority of applications and, at the same time, it
 is the most general case that allows an interpretation as classical
 probabilities.  The latter feature allows the preparation of
 separately tuned probability densities for all four helicity
 combinations. In practical applications this turns out to be useful
 because the power law behaviour of the extreme low energy tails turns
 out to have a mild polarization dependence.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{API}
 \label{sec:API}
 
 \begin{table}
   \begin{center}
     \begin{tabular}{llll}
       load beam
         & from file                  & \texttt{cir2ld}
         & (p.~\pageref{pg:cir2ld}) \\\hline
       distributions      
         & luminosity                 & \texttt{cir2lm}
         & (p.~\pageref{pg:cir2lm}) \\
         & probability density        & \texttt{cir2dn}
         & (p.~\pageref{pg:cir2dn}) \\
         & density matrix             & \texttt{cir2dm}
         & (extension, p.~\pageref{pg:cir2dm}) \\\hline
       event generation
         & flavors/helicities         & \texttt{cir2ch}
         & (p.~\pageref{pg:cir2ch}) \\
         & $(x_{1},x_{2})$            & \texttt{cir2gn}
         & (p.~\pageref{pg:cir2gn}) \\
         & general polarization       & \texttt{cir2gp}
         & (extension, p.~\pageref{pg:cir2gp}) \\\hline\hline
       internal
         & current beam               & \texttt{/cir2cm/}
         & (p.~\pageref{pg:cir2cm}) \\
         & beam data base             & \texttt{cir2bd}
         & (optional, p.~\pageref{pg:cir2cm}) \\
         & (cont'd)                   & \texttt{/cir2cd/}
         & (optional, p.~\pageref{pg:cir2cm})
     \end{tabular}
   \end{center}
   \caption{\label{tab:API}
     Summary of all functions, procedures and comon blocks.}
 \end{table}
 
 All floating point numbers in the interfaces are declared as
 \texttt{double precision}.  In most applications, the accuracy
 provided by single precision floating point numbers is likely to
 suffice.  However most application programs will use double precision
 floating point numbers anyway so the most convenient choice is to use
 double precision in the interfaces as well.
 
 In all interfaces, the integer particle codes follow the conventions
 of the Particle Data Group~\cite{PDG}.  In particular
 \label{pg:PDG-codes}
 \begin{params}
    \item \texttt{p =  11}: electrons
    \item \texttt{p = -11}: positrons
    \item \texttt{p =  22}: photons
 \end{params}
 while other particles are unlikely to appear in the context
 of~\KirkeTwo/ before the design of $\mu$-colliders enters a more
 concrete stage.  Similarly, in all interfaces, the sign of the
 helicities are denoted by integers
 \begin{params}
    \item \texttt{h =  1}: helicity~$+1$ for photons or~$+1/2$ for
      leptons (electrons and positrons)
    \item \texttt{h = -1}: helicity~$-1$ for photons or~$-1/2$ for
      leptons (electrons and positrons)
 \end{params}
 As part of tis API, we also define a few extensions, which will be
 available in future versions, but have not been implemented yet.  This
 allows application programs to anticipate these extensions.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Initialization}
 \label{sec:initialization}
 
 Before any of the event generation routines or the functions computing
 probability densities can be used, beam descriptions have to be
 loaded.  This is accomplished by the routine \texttt{cir2ld}
 (mnemonic: \textit{LoaD}), which must have been called at least once
 before any other procedure is invoked:
 \begin{params}
    \item \texttt{subroutine cir2ld (file, design, roots, ierror)}
      \label{pg:cir2ld}
      \begin{params}
        \item \texttt{character*(*) file} (input): name of a \KirkeTwo/
          parameter file in the format described in
          table~\ref{tab:fileformat}. Conventions for filenames are
          system dependent and the names of files will consequently be
          installation dependent.  This can not be avoided. 
        \item \texttt{character*(*) design} (input): name of the accelerator
          design.  The name must not be longer than 72
          characters. It is expected that design names follow the
          following naming scheme for
          $\mathrm{e}^{+}\mathrm{e}^{-}$~LCs
          \begin{params}
            \item \texttt{TESLA}: TESLA supercoducting design (DESY)
            \item \texttt{XBAND}: NLC/JLC X-band design (KEK, SLAC)
            \item \texttt{CLIC}: CLIC two-beam design (CERN)
          \end{params}
          Special operating modes should be designated by a qualifier
          \begin{params}
            \item \texttt{/GG}: laser backscattering $\gamma\gamma$
              collider (e.\,g.~\verb+'TESLA/GG'+)
            \item \texttt{/GE}: laser backscattering $\gamma\mathrm{e}^{-}$
              collider
            \item \texttt{/EE}: $\mathrm{e}^{-}\mathrm{e}^{-}$ collider
          \end{params}
          If there is more than one matching beam description, the
          \emph{last} of them is used.  If \texttt{design}
          contains a~\verb+'*'+, only the characters \emph{before}
          the~\verb+'*'+ matter in the match. E.\,g.:
          \begin{params}
            \item \verb+design = 'TESLA'+ matches only \verb+'TESLA'+
            \item \verb+design = 'TESLA*'+ matches any of
              \verb+'TESLA (Higgs factory)'+, \verb+'TESLA (GigaZ)'+,
              \verb+'TESLA'+, etc.
            \item \verb+design = '*'+ matches everything and is a
              convenient shorthand for the case that there is only a
              single design per file
          \end{params}
          NB: \verb+'*'+ is not a real wildcard: everything after
          the first \verb+'*'+ is ignored.
        \item \texttt{double precision roots} (input): $\sqrt{s}/\unit{GeV}$
          of the accelerator.  This must match within
          $\Delta\sqrt{s}=\unit[1]{GeV}$.  There is currently no facility for
          interpolation between fixed energy designs (see
          section~\ref{sec:interpolation}, however). 
        \item \texttt{integer ierror} (input/output):
          if~$\text{\texttt{ierror}}>0$ on input, comments will be echoed to the
          standard output stream.  On output, if no errors have been
          encountered \texttt{cir2ld} guarantees that
          $\text{\texttt{ierror}}=0$.  If $\text{\texttt{ierror}}<0$,
          an error has occured:
          \begin{params}
            \item \texttt{ierror = -1}: file not found
            \item \texttt{ierror = -2}: no match for design and~$\sqrt{s}$
            \item \texttt{ierror = -3}: invalid format of parameter file
            \item \texttt{ierror = -4}: parameter file too large
          \end{params}
      \end{params}
 \end{params}
 A typical application, assuming that a file named
 \texttt{photon\_colliders.circe} contains beam descriptions for photon
 colliders (including \texttt{TESLA/GG}) is
 \begin{alltt}\small
       integer ierror
       ...
       ierror = 1
       call cir2ld ('photon_colliders.circe', 'TESLA/GG', 500D0, ierror)
       if (ierror .lt. 0)
         print *, 'error: cir2ld failed: ', ierror
         stop
       end if
       ...
 \end{alltt}
 In order to allow application programs to be as independent from
 operating system dependent file naming conventions, the file formal
 has been designed so beam descriptions can be concatenated and
 application programs can hide file names from the user completely, as
 in
 \begin{alltt}\small
       subroutine ldbeam (design, roots, ierror)
       implicit none
       character*(*) design
       double precision roots
       integer ierror
       call cir2ld ('beam_descriptions.circe', design, roots, ierror)
       if (ierror .eq. -1)
         print *, 'ldbeam: internal error: file not found'
         stop
       end if
       end
 \end{alltt}
 The other extreme uses one file per design and uses the \verb+'*'+
 wildcard to make the \texttt{design} argument superfluous.
 \begin{alltt}\small
       subroutine ldfile (name, roots, ierror)
       implicit none
       character*(*) name
       double precision roots
       integer ierror
       call cir2ld (name, '*', roots, ierror)
       end
 \end{alltt}
 Note that while it is in principle possible to use a data file
 intended for helicity states for polarization averaged distributions
 instead, no convenience procedures for this purpose are provided.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Luminosities}
 One of the results of the simulations that provide the input for
 \KirkeTwo/ are the partial luminosities for all combinations of
 flavors and helicities.  The luminosities for a combination of flavors
 and helicities can be inspected with the function \texttt{cir2lm}
 (\textit{LuMinosity}).  The return value is given in the convenient units
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \unit{fb}^{-1}\upsilon^{-1} = 10^{32} \unit{cm}^{-2}\unit{sec}^{-1}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 where $\upsilon=\unit[10^7]{sec}\approx \unit{year}/\pi$ is an
 ``effective year'' of running with about 30\%\ up-time
 \begin{params}
    \item \texttt{double precision function cir2lm (p1, h1, p2, h2)}
      \label{pg:cir2lm}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer h1} (input):
          helicity of the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{integer h2} (input):
          helicity of the second particle
      \end{params}
 \end{params}
 For the particle codes and helicities the special value~$0$ can be
 used to imply a sum over all flavors and helicities.  E.\,g.~the total
 luminosity is obtained with
 \begin{alltt}\small
       lumi = cir2lm (0, 0, 0, 0)
 \end{alltt}
 and the $\gamma\gamma$ luminosity summed over all helicities
 \begin{alltt}\small
       lumigg = cir2lm (22, 0, 22, 0)
 \end{alltt}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Sampling and Event Generation}
 
 Given a combination of flavors and helicities, the routine
 \texttt{cir2gn} (\textit{GeNerate}) can be called repeatedly to obtain
 a sample of pairs~$(x_{1},x_{2})$ distributed according to the
 currently loaded beam description:
 \begin{params}
    \item \texttt{subroutine cir2gn (p1, h1, p2, h2, x1, x2, rng)}
      \label{pg:cir2gn}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer h1} (input):
          helicity of the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{integer h2} (input):
          helicity of the second particle
        \item \texttt{double precision x1} (output): fraction of the beam
          energy carried by the first particle
        \item \texttt{double precision x2} (output): fraction of the beam
          energy carried by the second particle
        \item \texttt{external rng}: subroutine
 \begin{alltt}\small
       subroutine rng (u)
       double precision u
       u = ...
       end
 \end{alltt}
          generating a uniform deviate, i.\,e.~a random number
          uniformly distributed in~$[0,1]$.
      \end{params}
 \end{params}
 If the combination of flavors and helicities has zero luminosity for
 the selected accelerator design parameters, \emph{no error code} is
 available (\texttt{x1} and \texttt{x2} are set to a very large
 negative value in this case).  Applications should use
 \texttt{cir2lm} to test that the luminosity is non vanishing.
 
 Instead of scanning the luminosities for all possible combinations of
 flavors and helicities, applications can call the procedure
 \texttt{cir2ch} (\textit{CHannel}) which chooses a ``channel'' (a
 combination of flavors and helicities) for the currently loaded
 beam description with the relative probabilities given by the luminosities:
 \begin{params}
    \item \texttt{subroutine cir2ch (p1, h1, p2, h2, rng)}
      \label{pg:cir2ch}
      \begin{params}
        \item \texttt{integer p1} (output):
          particle code for the first particle
        \item \texttt{integer h1} (output):
          helicity of the first particle
        \item \texttt{integer p2} (output):
          particle code for the second particle
        \item \texttt{integer h2} (output):
          helicity of the second particle
        \item \texttt{external rng}: subroutine generating a uniform
          deviate (as above)
      \end{params}
 \end{params}
 Many applications will use these two functions only in the combination
 \begin{alltt}\small
       subroutine circe2 (p1, h1, p2, h2, x1, x2, rng)
       integer p1, h1, p2, h2
       double precision x1, x2
       external rng
       call cir2ch (p1, h1, p2, h2, rng)
       call cir2gn (p1, h1, p2, h2, x1, x2, rng)
       end
 \end{alltt}
 after which randomly distributed \texttt{p1}, \texttt{h1},
 \texttt{p2}, \texttt{h2}, \texttt{x1}, and \texttt{x2} are available
 for further processing.
 
 NB: a function like \texttt{circe2} has not been added to the default
 FORTRAN77 API, because \texttt{cir2gn} and \texttt{circe2} have the
 same number and types of arguments, differing only in the input/output
 direction of four of the arguments.  This is a source of errors that a
 FORTRAN77 compiler can not help the application programmer to spot.
 The current design should be less error prone and is only minimally
 less convenient because of the additional procedure call
 \begin{alltt}\small
       integer p1, h1, p2, h2
       double precision x1, x2
       integer n, nevent
       external rng
       ...
       do 10 n = 1, nevent
         call cir2ch (p1, h1, p2, h2, rng)
         call cir2gn (p1, h1, p2, h2, x1, x2, rng)
         ...
   10  continue
       ...
 \end{alltt}
 Implementations in more modern programming languages (Fortran90/95,
 C++, Java, O'Caml, etc.) can and will provide a richer API with
 reduced name space pollution and danger of confusion.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Extensions: General Polarizations}
 
 Given a pair of flavors, triples $(x_{1},x_{2},\rho)$ of momentum
 fractions together with density matrices for the polarizations
 distributed according to the currently loaded beam descriptions can be
 obtained by repeatedly calling \texttt{cir2gp}
 (\textit{GeneratePolarized}):
 \begin{params}
    \item \texttt{subroutine cir2gp (p1, p2, x1, x2, pol, rng)}
      \label{pg:cir2gp}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{double precision x1} (output): fraction of the beam
          energy carried by the first particle
        \item \texttt{double precision x2} (output): fraction of the beam
          energy carried by the second particle
        \item \texttt{double precision pol(0:3,0:3)} (output):
          the joint density matrix of the two polarizations is
          parametrized by a real $4\times4$-matrix
 %HEVEA\begin{center}
 %BEGIN IMAGE
          \begin{equation}
            \rho(\chi) = \sum_{a,a'=0}^{3} \frac{\chi_{aa'}}{4}\,
              \sigma_{a} \otimes \sigma_{a'}
          \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
          using the notation~$\sigma_{0}=1$. We have
          $\text{\texttt{pol(0,0)}}=1$ since~$\tr\rho=1$.
        \item \texttt{external rng}: subroutine generating a uniform deviate
      \end{params}
 \end{params}
 \textit{This procedure has not been implemented in version~2.0 and
 will be provided in release~2.1.}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Distributions}
 The normalized luminosity density~$D_{p_{1}p_{2}} (x_{1},x_{2})$ for
 the given flavor and helicity combination for the currently loaded
 beam description satisfies
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \int\!\mathrm{d}x_{1}\wedge\mathrm{d}x_{2}\,
     D_{p_{1}p_{2}} (x_{1},x_{2}) = 1
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 and is calculated by~\texttt{cir2dn} \textit{(DistributioN)}:
 \begin{params}
    \item \texttt{double precision function cir2dn (p1, h1, p2, h2, x1, x2)}
      \label{pg:cir2dn}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer h1} (input):
          helicity of the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{integer h2} (input):
          helicity of the second particle
        \item \texttt{double precision x1} (input): fraction of the beam
          energy carried by the first particle
        \item \texttt{double precision x2} (input): fraction of the beam
          energy carried by the second particle
      \end{params}
 \end{params}
 If any of the helicities is~0 and the loaded beam description is not
 summed over polarizations, the result is \emph{not} the polarization
 summed distribution and~0 is returned instead.  Application programs
 must either sum by themselves or load a more efficient abbreviated beam
 description.
 
 \KirkeOne/ users should take note that the densities are now
 normalized \emph{individually} and no longer relative to a master
 $\mathrm{e}^{+}\mathrm{e}^{-}$ distribution.  Users of \KirkeOne/
 should also take note that the special treatment of
 $\delta$-distributions at the endpoints has been removed.  The
 corresponding contributions have been included in small bins close to
 the endpoints.  For small enough bins, this approach is sufficiently
 accurate and avoids the pitfalls of the approach of \KirkeOne/.
 
 \begin{dubious}
 Applications that convolute the \KirkeTwo/ distributions with other
 distributions can benefit from accessing the map employed by
 \KirkeTwo/ internally through \texttt{cir2mp} (\textit{MaP}):
 \begin{params}
    \item \texttt{subroutine cir2mp (p1, h1, p2, h2, x1, x2, m1, m2, d)}
      \label{pg:cir2mp}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer h1} (input):
          helicity of the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{integer h2} (input):
          helicity of the second particle
        \item \texttt{double precision x1} (input): fraction of the beam
          energy carried by the first particle
        \item \texttt{double precision x2} (input): fraction of the beam
          energy carried by the second particle
        \item \texttt{integer m1} (output): map
        \item \texttt{integer m2} (output): map
        \item \texttt{double precision d} (output):
      \end{params}
 \end{params}
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Extensions: General Polarizations}
 The product of the normalized luminosity density~$D_{p_{1}p_{2}}
 (x_{1},x_{2})$ and the joint polarization density mattrix for
 the given flavor and helicity combination for the currently loaded
 beam description is calculated by~\texttt{cir2dm} (\textit{DensityMatrices}):
 \begin{params}
    \item \texttt{double precision function cir2dm (p1, p2, x1, x2, pol)}
      \label{pg:cir2dm}
      \begin{params}
        \item \texttt{integer p1} (input):
          particle code for the first particle
        \item \texttt{integer p2} (input):
          particle code for the second particle
        \item \texttt{double precision x1} (input): fraction of the beam
          energy carried by the first particle
        \item \texttt{double precision x2} (input): fraction of the beam
          energy carried by the second particle
        \item \texttt{double precision pol(0:3,0:3)} (output):
          the joint density matrix multiplied by the normalized
          probability density.  The density matrix is
          parametrized by a real $4\times4$-matrix
 %HEVEA\begin{center}
 %BEGIN IMAGE
          \begin{equation}
            D_{p_{1}p_{2}} (x_{1},x_{2})\cdot\rho(\chi)
               = \sum_{a,a'=0}^{3} \frac{1}{4}\chi_{p_{1}p_{2},aa'}(x_{1},x_{2})\,
                   \sigma_{a} \otimes \sigma_{a'}
          \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
          using the notation~$\sigma_{0}=1$. We have
          $\text{\texttt{pol(0,0)}}=D_{p_{1}p_{2}} (x_{1},x_{2})$
          since~$\tr\rho=1$.
      \end{params}
 \end{params}
 \textit{This procedure has not been implemented in version~2.0 and
 will be provided in release~2.1.}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Private Parts}
 The following need not concern application programmer, except that
 there must be no clash with any other global name in the application
 program:
 \begin{params}
    \item \texttt{common /cir2cm/}: the internal data store for \KirkeTwo/,
      which \emph{must not} be accessed by application programs.\label{pg:cir2cm}
 \end{params}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Examples}
 \label{sec:API-samples}
 
 In this section, we collect some simple yet complete examples using
 the API described in section~\ref{sec:API}.  In all examples, the role
 of the physics application is played by a \texttt{write} statement,
 which would be replaced by an appropriate event generator for hard
 scattering physics or background events.  The examples assume the
 existence of either a file \texttt{default.circe} describing
 polarized $\sqrt{s}=\unit[500]{GeV}$ beams or an abbreviated file
 \texttt{default\_polavg.circe} where the helicities are summed over.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Unweighted Event Generation}
 \label{sec:API-samples-unweighted}
 
 \KirkeTwo/ has been designed for the efficient generation of
 unweighted events, i.\,e.~event samples that are distributed according
 to the given probability density.  Examples of weighted events are
 discussed in section~\ref{sec:API-samples-weighted} below.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Mixed Flavors and Helicities}
 The most straightforward application uses a stream of events with a
 mixture of flavors and helicities in \emph{random} order.  If the
 application can consume events without the need for costly
 reinitializations when the flavors are changed, a simple loop around
 \texttt{cir2ch} and \texttt{cir2gn} suffices:
 \begin{alltt}\small
       program demo1
       implicit none
       integer p1, h1, p2, h2, n, nevent, ierror
       double precision x1, x2
       external random
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       write (*, '(A7,4(X,A4),2(X,A10))')
      $     '#', 'pdg1', 'hel1', 'pdg2', 'hel2', 'x1', 'x2'
       do 10 n = 1, nevent
         call cir2ch (p1, h1, p2, h2, random)
         call cir2gn (p1, h1, p2, h2, x1, x2, random)
         write (*, '(I7,4(X,I4),2(X,F10.8))') n, p1, h1, p2, h2, x1, x2
  10   continue
       end
 \end{alltt}
 The following minimalistic linear congruential random number
 generator can be used for demonstrating the interface, but it is known
 to produce correlations and \emph{must} be replaced by a more
 sophisticated one in real applications:
 \begin{alltt}\small
       subroutine random (r)
       implicit none
       double precision r
       integer M, A, C
       parameter (M = 259200, A = 7141, C = 54773)
       integer n
       save n
       data n /0/
       n = mod (n*A + C, M)
       r = dble (n) / dble (M)
       end
 \end{alltt}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Separated Flavors and Helicities}
 If the application can not switch efficiently among flavors and
 helicities, another approach is more useful.  It walks through the
 flavors and helicities sequentially and uses the partial luminosities
 \texttt{cir2lm} to determine the correct number of events for each
 combination:
 \begin{alltt}\small
       program demo2
       implicit none
       integer i1, i2, pdg(3), h1, h2, i, n, nevent, nev, ierror
       double precision x1, x2, lumi, cir2lm
       external random, cir2lm
       data pdg /22, 11, -11/
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       lumi = cir2lm (0, 0, 0, 0)
       write (*, '(A7,4(X,A4),2(X,A10))')
      $     '#', 'pdg1', 'hel1', 'pdg2', 'hel2', 'x1', 'x2'
       i = 0
       do 10 i1 = 1, 3
         do 11 i2 = 1, 3
           do 12 h1 = -1, 1, 2
             do 13 h2 = -1, 1, 2
               nev = nevent * cir2lm (pdg(i1), h1, pdg(i2), h2) / lumi
               do 20 n = 1, nev
                 call cir2gn (pdg(i1), h1, pdg(i2), h2, x1, x2, random)
                 i = i + 1
                 write (*, '(I7,4(X,I4),2(X,F10.8))')
      $               i, pdg(i1), h1, pdg(i2), h2, x1, x2
  20           continue
  13         continue
  12       continue
  11     continue
  10   continue
       end
 \end{alltt}
 More care can be taken to guarantee that the total number of events
 is not reduced by rounding \texttt{new} towards~$0$, but the error
 will be negligible for reasonably high statistics anyway.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Polarization Averaged}
 
 If the helicities are to be ignored, the abbreviated file
 \texttt{default\_polavg.circe} can be read. 
 The code remains unchanged, but the variables~\texttt{h1}
 and~\texttt{h2} will always be set to~0.
 \begin{alltt}\small
       program demo3
       implicit none
       integer p1, h1, p2, h2, n, nevent, ierror
       double precision x1, x2
       external random
       nevent = 20
       ierror = 1
       call cir2ld ('default_polavg.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       write (*, '(A7,2(X,A4),2(X,A10))')
      $     '#', 'pdg1', 'pdg2', 'x1', 'x2'
       do 10 n = 1, nevent
         call cir2ch (p1, h1, p2, h2, random)
         call cir2gn (p1, h1, p2, h2, x1, x2, random)
         write (*, '(I7,2(X,I4),2(X,F10.8))') n, p1, p2, x1, x2
  10   continue
       end
 \end{alltt}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Flavors and Helicity Projections}
 There are three ways to produce samples with a fixed subset of flavors
 or helicities. As an example, we generate a sample of two photon
 events with~$L=0$. The first approach generates the two channels~$++$ and~$--$
 sequentially:
 \begin{alltt}\small
       program demo4
       implicit none
       double precision x1, x2, lumipp, lumimm, cir2lm
       integer n, nevent, npp, nmm, ierror
       external random, cir2lm
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       lumipp = cir2lm (22,  1, 22,  1)
       lumimm = cir2lm (22, -1, 22, -1)
       npp = nevent * lumipp / (lumipp + lumimm)
       nmm = nevent - npp
       write (*, '(A7,2(X,A10))') '#', 'x1', 'x2'
       do 10 n = 1, npp
         call cir2gn (22,  1, 22,  1, x1, x2, random)
         write (*, '(I7,2(X,F10.8))') n, x1, x2
  10   continue
       do 20 n = 1, nmm
         call cir2gn (22, -1, 22, -1, x1, x2, random)
         write (*, '(I7,2(X,F10.8))') n, x1, x2
  20   continue
       end
 \end{alltt}
 a second approach alternates between the two possibilities
 \begin{alltt}\small
       program demo5
       implicit none
       double precision x1, x2, u, lumipp, lumimm, cir2lm
       integer n, nevent, ierror
       external random, cir2lm
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       lumipp = cir2lm (22,  1, 22,  1)
       lumimm = cir2lm (22, -1, 22, -1)
       write (*, '(A7,2(X,A10))') '#', 'x1', 'x2'
       do 10 n = 1, nevent
         call random (u)
         if (u * (lumipp + lumimm) .lt. lumipp) then
           call cir2gn (22,  1, 22,  1, x1, x2, random)
         else
           call cir2gn (22, -1, 22, -1, x1, x2, random)
         endif
         write (*, '(I7,2(X,F10.8))') n, x1, x2
  10   continue
       end
 \end{alltt}
 finally, the third approach uses rejection to select the desired
 flavors and helicities
 \begin{alltt}\small
       program demo6
       implicit none
       integer p1, h1, p2, h2, n, nevent, ierror
       double precision x1, x2
       external random
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       write (*, '(A7,2(X,A10))') '#', 'x1', 'x2'
       n = 0
  10   continue
         call cir2ch (p1, h1, p2, h2, random)
         call cir2gn (p1, h1, p2, h2, x1, x2, random)
         if ((p1 .eq. 22) .and. (p2 .eq. 22) .and.
      $      (((h1 .eq.  1) .and. (h2 .eq.  1)) .or.
      $       ((h1 .eq. -1) .and. (h2 .eq. -1)))) then
           n = n + 1
           write (*, '(I7,2(X,F10.8))') n, x1, x2
         end if
         if (n .lt. nevent) then
           goto 10
         end if
       end
 \end{alltt}
 All generated distributions are equivalent, but the chosen
 subsequences of random numbers will be different.  It depends on the
 application and the channels under consideration, which approach is the most
 appropriate.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Distributions and Weighted Event Generation}
 \label{sec:API-samples-weighted}
 
 If no events are to be generated, \texttt{cir2dn} can be used to
 calculate the probability density~$D(x_{1},x_{2})$ at a given point.
 This can be used for numerical integration other than Monte Carlo or
 for importance sampling in the case that the distribution to be folded
 with~$D$ is more rapidly varying than~$D$ itself.
 
 Depending on the beam descriptions, these distributions are available
 either for fixed helicities 
 \begin{alltt}\small
       program demo7
       implicit none
       integer n, nevent, ierror
       double precision x1, x2, w, cir2dn
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       write (*, '(A7,3(X,A10))') '#', 'x1', 'x2', 'weight'
       do 10 n = 1, nevent
         call random (x1)
         call random (x2)
         w = cir2dn (22, 1, 22, 1, x1, x2)
         write (*, '(I7,2(X,F10.8),X,E10.4)') n, x1, x2, w
  10   continue
       end
 \end{alltt}
 or summed over all helicities if the beam description is
 polarization averaged:
 \begin{alltt}\small
       program demo8
       implicit none
       integer n, nevent, ierror
       double precision x1, x2, w, cir2dn
       nevent = 20
       ierror = 1
       call cir2ld ('default_polavg.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       write (*, '(A7,3(X,A10))') '#', 'x1', 'x2', 'weight'
       do 10 n = 1, nevent
         call random (x1)
         call random (x2)
         w = cir2dn (22, 0, 22, 0, x1, x2)
         write (*, '(I7,2(X,F10.8),X,E10.4)') n, x1, x2, w
  10   continue
       end
 \end{alltt}
 If the beam description is not polarization averaged, the application
 can perform the averaging itself (note that each distribution is
 normalized):
 \begin{alltt}\small
       program demo9
       implicit none
       integer n, nevent, ierror
       double precision x1, x2, w, cir2dn, cir2lm
       double precision lumi, lumipp, lumimp, lumipm, lumimm
       nevent = 20
       ierror = 1
       call cir2ld ('default.circe', '*', 500D0, ierror)
       if (ierror .lt. 0) stop
       lumipp = cir2lm (22,  1, 22,  1)
       lumipm = cir2lm (22,  1, 22, -1)
       lumimp = cir2lm (22, -1, 22,  1)
       lumimm = cir2lm (22, -1, 22, -1)
       lumi = lumipp + lumimp + lumipm + lumimm
       write (*, '(A7,3(X,A10))') '#', 'x1', 'x2', 'weight'
       do 10 n = 1, nevent
         call random (x1)
         call random (x2)
         w = (   lumipp * cir2dn (22,  1, 22,  1, x1, x2)
      $        + lumipm * cir2dn (22,  1, 22, -1, x1, x2)
      $        + lumimp * cir2dn (22, -1, 22,  1, x1, x2)
      $        + lumimm * cir2dn (22, -1, 22, -1, x1, x2)) / lumi
         write (*, '(I7,2(X,F10.8),X,E10.4)') n, x1, x2, w
  10   continue
       end
 \end{alltt}
 The results produced by the preceeding pair of examples will differ
 point-by-point, because the
 polarized and the polarization summed distribution will be binned
 differently.  However, all histograms of the results with reasonable bin sizes
 will agree.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Scans and Interpolations}
 \label{sec:interpolation}
 
 Currently there is no supported mechanism for interpolating among
 distributions for the discrete parameter sets.  The most useful
 application of such a facility would be a scan of the energy
 dependence of an observable
 \begin{subequations}
 \label{eq:scan}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \mathcal{O}(s) =
      \int\!\mathrm{d}x_1\mathrm{d}x_2 \mathrm{d}\Omega\,
         D(x_1,x_2,s)
         \frac{\mathrm{d}\sigma}{\mathrm{d}\Omega}(x_1,x_2,s,\Omega)
         O(x_1,x_2,s,\Omega)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 which has to take into account the $s$-dependence of the
 distribution~$D(x_1,x_2,s)$.  Full simulations of the beam dynamics
 for each value of~$s$ are too costly and
 \KirkeOne/~\cite{Ohl:1996:Circe} supported linear interpolation
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \bar D(x_1,x_2,s)
     = \frac{(s-s_{-})D(x_1,x_2,s_{+}) + (s_{+}-s)D(x_1,x_2,s_{-})}%
            {s_{+}-s_{-}}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 as an economical compromise.  However, since
 $\mathcal{O}$~in~(\ref{eq:scan}) is a strictly \emph{linear}
 functional of~$D$, it is mathematically equivalent to
 interpolating~$\mathcal{O}$ itself
 \begin{subequations}
 \label{eq:scan'}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \bar{\mathcal{O}}(s)
     = \frac{(s-s_{-})\tilde{\mathcal{O}}(s,s_{+})
               + (s_{+}-s)\tilde{\mathcal{O}}(s,s_{-})}%
            {s_{+}-s_{-}}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 where
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \tilde{\mathcal{O}}(s,s_0) =
      \int\!\mathrm{d}x_1\mathrm{d}x_2 \mathrm{d}\Omega\,
         D(x_1,x_2,s_0)
         \frac{\mathrm{d}\sigma}{\mathrm{d}\Omega}(x_1,x_2,s,\Omega)
         O(x_1,x_2,s,\Omega)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 Of course, evaluating the two integrals in~(\ref{eq:scan'}) with
 comparable accuracy demands four times the calculational effort of the
 single integral in~(\ref{eq:scan}). 
 Therefore, if overwhelming demand arises, support for~(\ref{eq:scan})
 can be reinstated, but at the price of a considerably more involved
 API for loading distributions.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Algorithms}
 \label{sec:algorithms}
 
 \KirkeTwo/ attempts to recover a probability density~$w(x_{1},x_{2})$
 from a finite set of
 triples~$\left.\{(x_{1,i},x_{2,i},w_{i})\}\right|_{i=1,\ldots,N}$ that
 are known to be distributed according to~$w(x_{1},x_{2})$.  This recovery
 should introduce as little bias as possible.  The solution should
 provide a computable form of~$w(x_{1},x_{2})$ as well as a procedure
 for generating more sets of triples~$\{(x_{1,i},x_{2,i},w_{i})\}$ with
 ``the same'' distribution.
 
 The discrete distribution
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \hat w(x_{1},w_{2})
     = \sum_i w_{i}\delta(x_{1}-x_{1,i})\delta(x_{2}-x_{2,i})
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 adds no bias, but is obviously not an adequate solution of the
 problem, because it depends qualitatively on the sample.  While the
 sought after distribution may contain singularities, their
 number and the dimension of their support
 must not depend on the sample size.  There is, of course, no
 unique solution to this problem and we must allow some prejudices to
 enter in order to single out the most adequate solution.
 
 The method employed by \KirkeOne/ was to select a family of analytical
 distributions that are satisfy reasonable criteria suggested by
 physics~\cite{Ohl:1996:Circe} and select representatives by fitting
 the parameters of these distributions.  This has been unreasonably successful
 for modelling the general properties, but must fail eventually if
 finer details are studied.  Enlarging the families is theoretically
 possible but empirically it turns out that the number of free
 parameters grows faster than the descriptive power of the families.
 
 Another approach is to forego functions that are defined globally by
 an analytical expression and to perform interpolation of binned
 samples, requiring continuity of the distribution and their
 derivatives.  Again, this fails in practice, this time because such
 interpolations tend to create wild fluctuations for statistically
 distributed data and the resulting distributions will often violate
 basic conditions like positivity.
 
 Any attempt to recover the distributions that uses local properties
 will have to bin the data
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   N_{i} = \int_{\Delta_{i}}\!\mathrm{d}x\,w(x)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 with
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \Delta_{i} \cap \Delta_{j} = \emptyset\quad(i\not=j), \qquad
   \bigcup_{i} \Delta_{i} = [0,1]\times[0,1]
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Therefore it appears to be eminently reasonable to approximate~$w$ by
 a piecewise constant
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \hat w(x) = \sum_i \frac{N_{i}}{|\Delta_{i}|}\Theta(x\in\Delta_{i})\,.
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 However, this
 procedure alse introduces a bias and if the number of bins is to
 remain finite, this bias cannot be removed.
 
 Nevertheless, one can tune this bias to the problem under study and
 obtain better approximations by making use of the well known fact that
 probability distributions are not invariant under coordinate
 transformations.
 %%% seems not to exist
 % , as described in section~\ref{sec:transformations} below. 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Histograms}
 The obvious approach to histogramming is to cover the unit
 square~$[0,1]\times[0,1]$ uniformly with~$n_{b}^2$ squares, but this
 approach is not economical in its use of storage.
 For example, high energy physics studies at
 a~$\sqrt{s}=\unit[500]{GeV}$ LC will require an energy
 resolution of better than~$\unit[1]{GeV}$ and we should bin each beam
 in steps of~$\unit[500]{MeV}$, i.\,e.~$n_{b}=500$.  This results in a
 two dimensional histogram of~$500^{2}=25000$ bins for each combination
 of flavor and helicity.  Using non-portable binary storage, this
 amounts to~\unit[100]{KB} for typical single precision floating point
 numbers and~\unit[200]{KB} for typical double precision floating point
 numbers.
 
 Obviously, binary storage is not a useful exchange format and we have
 to use an ASCII exchange format, which in its human readable form uses
 14~bytes for single precision and 22~bytes for double precision and
 the above estimates have to be changed to~\unit[350]{KB}
 and~\unit[550]{KB} respectively.  We have four flavor combinations if
 pair creation is ignored and nine flavor combinations if it is taken
 into account.  For each flavor combination there are four helicity
 combinations and we arrive at~16 or~$36$ combinations.
 
 Altogether, a fixed bin histogram requires up to~$\unit[20]{MB}$ of
 data for \emph{each} accelerator design at \emph{each} energy step for
 a mere~$1\%$ energy resolution.  While this could be handled with
 modern hardware, we have to keep in mind that the storage requirements
 grow quadratically with the resolution and that several generations of
 designs should be kept available for comparison studies.
 
 For background studies, low energy tails down to the pair production
 threshold~$m_{e}=\unit[511]{KeV}\approx10^{-6}\cdot\sqrt{s}$ have to
 be described correctly.  Obviously, fixed bin histograms are not an
 option at all in this case.
 
 \begin{dubious}
   mention 2-D Delauney triangulations here
 \end{dubious}
 \begin{dubious}
   mention Stazsek's FOAM~\cite{Jadach:2000:FOAM} here
 \end{dubious}
 \begin{dubious}
   praise VEGAS/VAMP
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Coordinate Dependence of Sampling Distributions}
 \label{sec:jacobians}
 The contents of this section is well known to all practitioners and is repeated only for
 establishing notation.  For any sufficiently smooth (piecewise
 differentiable suffices) map
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \phi : D_{x} &\to D_{y} \\
       x &\mapsto y = \phi(x)
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 integrals of distribution functions $w:D_{y}\to\mathbf{R}$ are
 invariant, as long as we apply the correct Jacobian factor
 \begin{subequations}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \int_{D_{y}}\!\mathrm{d}y\,w(y)
     = \int_{D_{x}}\!\mathrm{d}x\,\frac{\mathrm{d}\phi}{\mathrm{d}x}\cdot(w\circ\phi)(x)
     = \int_{D_{x}}\!\mathrm{d}x\,w^{\phi}(x)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 where
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   w^{\phi}(x)
     = (w\circ\phi)(x)\cdot\frac{\mathrm{d}\phi}{\mathrm{d}x}(x)
     = \frac{(w\circ\phi)(x)}%
            {{\displaystyle\left(\frac{\mathrm{d}\phi^{-1}}{\mathrm{d}y}\circ\phi\right)(x)}}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 The fraction can be thought of as being defined by the product, if the
 map~$\phi$ is not invertible.  Below, we will always deal with
 invertible maps and the fraction is more suggestive for our purposes.
 Therefore, $\phi$ induces a pull-back map~$\phi^{*}$ on the space of
 integrable functions
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
 \label{eq:pull-back}
    \begin{aligned}
      \phi^{*} : L_1(D_{y},\mathbf{R}) &\to L_1(D_{x},\mathbf{R}) \\
       w &\mapsto w^{\phi}
             = \frac{w\circ\phi}%
                    {{\displaystyle\left(\frac{\mathrm{d}\phi^{-1}}%
                                              {\mathrm{d}y}\circ\phi\right)}}
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 If we find a map~$\phi_{w}$ with~$\mathrm{d}\phi^{-1}/\mathrm{d}y\sim
 w$, then sampling the transformed weight~$w^{\phi_{w}}$ will be very
 stable, even if sampling the original weight~$w$ is not.
 
 On the other hand, the inverse map
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      (\phi^{*})^{-1} : L_1(D_{x},\mathbf{R}) &\to L_1(D_{y},\mathbf{R}) \\
       w &\mapsto w^{(\phi^{-1})}
           = \left(\frac{\mathrm{d}\phi^{-1}}{\mathrm{d}y}\right)
               \cdot(w\circ\phi^{-1})
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 with $(\phi^{-1})^{*}=(\phi^{*})^{-1}$ can be used to transform a
 uniform distribution into the potentially much more
 interesting~$\mathrm{d}\phi^{-1}/\mathrm{d}y$.
 
 \subsection{Sampling Distributions With Integrable Singularities}
 A typical example appearing in \KirkeOne/
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \int^{1}\!\mathrm{d}x\,w(x)
     \approx \int^{1}\!\mathrm{d}x\,(1-x)^{\beta}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 converges for~$\beta>-1$, while the variance
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \int^{1}\!\mathrm{d}x\,(w(x))^{2}
     \approx \int^{1}\!\mathrm{d}x\,(1-x)^{2\beta}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 does not converge for~$\beta\le-1/2$.  Indeed, this case is the
 typical case for realistic beamstrahlung spectra at
 $\mathrm{e}^+\mathrm{e}^-$ LCs and has to covered.
 
 Attempting a naive VEGAS/VAMP adaption fails, because the
 \emph{nonintegrable} variance density acts as a sink for bins, even
 though the density itself is integrable.
 \begin{dubious}
   \begin{itemize}
     \item examples show that moments of distributions are reproduced
       \emph{much} better after mapping, even if histograms look
       indistinguishable.
     \item biasing doesn't appear to work as well as fences
   \end{itemize}
 \end{dubious}
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(50,40)
       pickup pencircle scaled 1.0pt;
       setrange (0, 0, 1, 0.8);
       autogrid (otick.bot,);
       frame.bot;
       path p;
       for x = 0.001 step 0.01 until 0.9:
         augment.p (x, 0.2 * (x ** (-0.2)) + 0.001 / ((x - 0.7)**2 + 0.003));
       endfor
       gdraw p;
       glabel.top (btex $\epsilon$ etex, (0.02, 0.02));
       glabel.top (btex $\hat y$ etex, (0.4, 0.02));
       glabel.lft (btex $w(y)$ etex, (-0.02, 0.7));
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:sample-distribution}%
     Distribution with both an integrable singularity $\propto x^{-0.2}$
     and a peak at finite~$x\approx 0.7$.}
 \end{figure}
 The distributions that we want to describe can contain integrable
 singularities and $\delta$-distributions at the endpoints.  Since
 there is always a finite resolution, both contributions can be
 handled by a finite binsize at the endpoints.  However, we can expect
 to improve the convergence of the grid adaption in neighborhoods of the
 singularities by canceling the singularities with the Jacobian of a
 power map. Also the description of the distribution \emph{inside} each
 bin will be improved for reasonable maps.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Piecewise Differentiable Maps}
 \label{sec:PDM}
 \begin{dubious}
    blah, blah, blah
 \end{dubious}
 Ansatz:
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \Phi_{\{\phi\}} : [X_{0},X_{1}]
         &\to [Y_{0},Y_{1}] \\
       x &\mapsto \Phi_{\{\phi\}}(x)
            = \sum_{i=1}^{n} \Theta(x_{i}-x) \Theta(x-x_{i-1}) \phi(x)
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 with~$x_{0}=X_{0}$, $x_{n}=X_{1}$ and~$x_{i} > x_{i-1}$. In each
 interval 
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \phi_{i} : [x_{i-1},x_{i}]
         &\to [y_{i-1},y_{i}] \\
       x &\mapsto y = \phi_{i}(x)
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 with $y_{0}=Y_{0}$, $y_{n}=Y_{1}$
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Powers}
 \begin{dubious}
   integrable singularities
 \end{dubious}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}} :
        [x_{i-1},x_{i}] &\to [y_{i-1},y_{i}] \\
       x &\mapsto \psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}}(x)
              = \frac{1}{b_{i}}(a_{i}(x-\xi_{i}))^{\alpha_{i}} + \eta_{i}
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 We assume~$\alpha_{i}\not=0$, $a_{i}\not=0$ and~$b_{i}\not=0$.
 Note that~$\psi_{a,b}^{\alpha,\xi,\eta}$ encompasses both typical cases
 for integrable endpoint singularities ~$x\in[0,1]$:
 \begin{subequations}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{align}
    \psi_{1,1}^{\alpha,0,0}(x) & = x^{\alpha} \\
    \psi_{-1,-1}^{\alpha,1,1}(x) & = 1 - (1-x)^{\alpha}
 \end{align}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 The inverse maps are
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      (\psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}})^{-1} :
       [y_{i-1},y_{i}] &\to [x_{i-1},x_{i}] \\
       y &\mapsto (\psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}})^{-1}(y)
                = \frac{1}{a_{i}} (b_{i}(y-\eta_{i}))^{1/\alpha_{i}} + \xi_{i}
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 and incidentally:
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   (\psi_{a,b}^{\alpha,\xi,\eta})^{-1} = \psi_{b,a}^{1/\alpha,\eta,\xi}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 The Jacobians are
 \begin{subequations}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{align}
   \frac{\mathrm{d}y}{\mathrm{d}x} (x)
      &= \frac{a\alpha}{b} (a(x-\xi))^{\alpha-1} \\
 \label{eq:pull-back-power}
   \frac{\mathrm{d}x}{\mathrm{d}y} (y)
      &= \frac{b}{a\alpha} (b(y-\eta))^{1/\alpha-1}
 \end{align}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 and satisfy, of course,
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \frac{\mathrm{d}x}{\mathrm{d}y} (y(x))
     = \frac{1}{{\displaystyle\frac{\mathrm{d}y}{\mathrm{d}x} (x)}}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 In order to get a strictly monotonous function, we require
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \frac{a\alpha}{b} > 0
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Since we will see below that almost always in practical
 applications~$\alpha>0$, this means~$\epsilon(a)=\epsilon(b)$.
 
 From~(\ref{eq:pull-back}) and~(\ref{eq:pull-back-power}), we see that
 this map is useful for handling weights\footnote{%
   The limiting case~$(y-\eta)^{-1}$ could be covered by
   maps~$x\mapsto\mathrm{e}^{a(x-\xi)}/b+\eta$, where the
   non-integrability of the density is reflected in the fact that the
   domain of the map is semi-infinite
   (i.\,e.~$x\to-\epsilon(a)\cdot\infty$).  In physical applications,
   the densities are usually integrable and we do not consider this
   case in the following.}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    w(y) \propto (y-\eta)^{\beta}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 for $\beta>-1$, if we choose~$\beta-(1/\alpha-1)\ge0$,
 i.\,e.~$\alpha\gtrsim 1/(1+\beta)$.
 
 The five parameters $(\alpha,\xi,\eta,a,b)$ are partially redundant.
 Indeed, there is a one parameter semigroup of transformations
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
 \label{eq:ab-semigroup}
   (\alpha,\xi,\eta,a,b) \to (\alpha,\xi,\eta,at,bt^{\alpha}),
      \qquad (t > 0)
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 that leaves~$\psi_{a,b}^{\alpha,\xi,\eta}$ invariant:
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \psi_{a,b}^{\alpha,\xi,\eta} = \psi_{at,bt^{\alpha}}^{\alpha,\xi,\eta}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Assuming that multiplications are more efficient than sign transfers,
 the redundant representation is advantageous.  Unless sign transfers
 are implemented directly in hardware, they involve a branch in the
 code and the assumption appears to be reasonable.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Identity}
 The identity map
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \iota : [x_{i-1},x_{i}]
         &\to [y_{i-1},y_{i}] = [x_{i-1},x_{i}] \\
       x &\mapsto \iota(x) = x
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 is a special case of the power map~$\iota=\psi_{1,1}^{1,0,0}$, but,
 for efficiency,  it is useful to provide a dedicated
 ``implementation'' anyway.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{Null}
+The null map
+%HEVEA\begin{center}
+%BEGIN IMAGE
+\begin{equation}
+   \begin{aligned}
+     \iota : [x_{i-1},x_{i}]
+        &\to [y_{i-1},y_{i}] = [x_{i-1},x_{i}] \\
+      x &\mapsto \iota(x) = x
+   \end{aligned}
+\end{equation}
+%END IMAGE
+%HEVEA\imageflush
+%HEVEA\end{center}
+is a special case of the identity map, where all weights are set to zero.
+This is useful for the regions where the beam simulations do not produce enough
+events and should be ignored.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Resonances}
 \begin{dubious}
   \begin{itemize}
     \item not really needed in the applications so far, because the
       variance remains integrable.
     \item no clear example for significantly reduced numbers of bins
       for the same qualitaty with mapping.
     \item added for illustration.
   \end{itemize}
 \end{dubious}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      \rho_{a_{i},b_{i}}^{\xi_{i},\eta_{i}}: [x_{i-1},x_{i}]
         &\to [y_{i-1},y_{i}] \\
       x &\mapsto \rho_{a_{i},b_{i}}^{\xi_{i},\eta_{i}}(x)
          = a_{i} \tan\left(\frac{a_{i}}{b_{i}^2}(x-\xi_{i})\right) + \eta_{i}
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Inverse
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \begin{aligned}
      (\rho_{a_{i},b_{i}}^{\xi_{i},\eta_{i}})^{-1}: [y_{i-1},y_{i}]
         &\to [x_{i-1},x_{i}] \\
       y &\mapsto (\rho_{a_{i},b_{i}}^{\xi_{i},\eta_{i}})^{-1}(y)
           = \frac{b_{i}^2}{a_{i}}
             \textrm{atan}\left(\frac{y-\eta_{i}}{a_{i}}\right) + \xi_{i}
    \end{aligned}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 is useful for mapping \emph{known} peaks, since
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
    \frac{\mathrm{d}\phi^{-1}}{\mathrm{d}y}(y)
      = \frac{\mathrm{d}x}{\mathrm{d}y}(y)
      = \frac{b^2}{(y-\eta)^2+a^2}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Patching Up}
 Given a collection of intervals with associated maps, it remains to
 construct a combined map.  Since \emph{any} two intervals can be mapped
 onto each other by a map with constant Jacobian, we have a ``gauge''
 freedom and must treat~$x_{i-1}$ and~$x_{i}$ as free parameters in
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   \psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}} :
      [x_{i-1},x_{i}] \to [y_{i-1},y_{i}]
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 i.\,e.
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
 \label{eq:interval-constraint}
     x_{j} = (\psi_{a_{i},b_{i}}^{\alpha_{i},\xi_{i},\eta_{i}})^{-1}(y_{j})
           = \frac{1}{a_{i}}(b_{i}(y_{j}-\eta_{i}))^{1/\alpha_{i}} + \xi_{i}
     \qquad \text{for}\; j\in\{i-1,i\}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 Since $\alpha$~and~$\eta$ denote the strength and the location of the
 singularity, respectively, they are the relevant input parameters and
 we must solve the constraints~(\ref{eq:interval-constraint})
 for~$\xi_{i}$, $a_{i}$ and~$b_{i}$.  Indeed a family of solutions is
 \begin{subequations}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{align}
 \label{eq:ai}
   a_{i}   &= \frac{   (b_{i}(y_{i}-\eta_{i}))^{1/\alpha_{i}}
                     - (b_{i}(y_{i-1}-\eta_{i}))^{1/\alpha_{i}}}%
                   {x_{i} - x_{i-1}} \\
   \xi_{i} &= \frac{   x_{i-1}|y_{i}  -\eta_{i}|^{1/\alpha_{i}}
                     - x_{i}  |y_{i-1}-\eta_{i}|^{1/\alpha_{i}}}%
                   {          |y_{i}  -\eta_{i}|^{1/\alpha_{i}}
                     -        |y_{i-1}-\eta_{i}|^{1/\alpha_{i}}}
 \end{align}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 which is unique up to~(\ref{eq:ab-semigroup}).  The
 degeneracy~(\ref{eq:ab-semigroup}) can finally be resolved by
 demanding~$|b|=1$ in~(\ref{eq:ai}).
 
 It remains to perform a `gauge fixing' and choose the
 domains~$[x_{i-1},x_{i}]$. The minimal solution is~$x_{i}=y_{i}$ for
 all~$i$, which maps the boundaries between different mappings onto
 themselves and we need only to store
 either~$\{x_{0},x_{1},\ldots,x_{n}\}$
 or~$\{y_{0},y_{1},\ldots,y_{n}\}$. 
 
 For the resonance map
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{equation}
   x_{j} = (\rho_{a_{i},b_{i}}^{\xi_{i},\eta_{i}})^{-1}(y_{j})
         = \frac{b_{i}^2}{a_{i}}
             \textrm{atan}\left(\frac{y_{j}-\eta_{i}}{a_{i}}\right)
               + \xi_{i}
     \qquad \text{for}\; j\in\{i-1,i\}
 \end{equation}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 i.\,e.
 \begin{subequations}
 %HEVEA\begin{center}
 %BEGIN IMAGE
 \begin{align}
   b_{i}
     &= \sqrt{a_{i}
          \frac{x_{i}-x_{i-1}}%
               {   \textrm{atan}\left(\frac{y_{i}  -\eta_{i}}{a_{i}}\right)
                 - \textrm{atan}\left(\frac{y_{i-1}-\eta_{i}}{a_{i}}\right)}} \\
   \xi_{i}
     &= \frac{   x_{i-1}\textrm{atan}\left(\frac{y_{i}  -\eta_{i}}{a_{i}}\right)
               - x_{i}  \textrm{atan}\left(\frac{y_{i-1}-\eta_{i}}{a_{i}}\right)}%
             {x_{i}-x_{i-1}}
 \end{align}
 %END IMAGE
 %HEVEA\imageflush
 %HEVEA\end{center}
 \end{subequations}
 as a function of the physical peak location~$\eta$ and width~$a$.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Preparing Beam Descriptions with \texttt{circe2\_tool}}
 \label{sec:circe2_tool-user}
 \begin{dubious}
   rationale
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{\texttt{circe2\_tool} Files}
 \begin{dubious}
   \texttt{\{} and \texttt{\}}
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Per File Options}
 
 \begin{params}
   \item \texttt{file}: a double quote delimited string denoting the
     name of the output file that will be read by \texttt{cir2ld} (in
     the format described in table~\ref{tab:fileformat}).
 \end{params}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Per Design Options}
 
 \begin{params}
   \item \texttt{design}: a double quote delimited string denoting a
     name for the design.  See the description of~\texttt{cir2ld} on
     page~\pageref{pg:cir2ld} for conventions for these names.
   \item \texttt{roots}: $\sqrt{s}/\unit{GeV}$ of the accelerator design.
   \item \texttt{bins}: number of bins for the histograms in both
     directions. \texttt{bins/1} and \texttt{bins/2} apply only
     to~$x_{1}$ and~$x_{2}$ respectively.  This number can be
     overwritten by channel options.
   \item \texttt{comment}: a double quote delimited string denoting a
     one line comment that will be copied to the output file.  This
     command can be repeated.
 \end{params}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsubsection{Per Channel Options}
 
 If an option can apply to either beam or both, it can be qualified
 by~\texttt{/1} or~\texttt{/2}.  For example, \texttt{bins} applies to
 both beams, while \texttt{bins/1} and \texttt{bins/2} apply only
 to~$x_{1}$ and~$x_{2}$ respectively.
 \begin{params}
   \item \texttt{bins}: number of bins for the histograms.  These
     overwrite the per-design option.
   \item \texttt{pid}: particle identification: either a PDG
     code~\cite{PDG} (see page~\ref{pg:PDG-codes}) or one of
     \texttt{gamma}, \texttt{photon}, \texttt{electron},
     \texttt{positron}.
   \item \texttt{pol}: polarization: one of~$\{-1,0,1\}$, where
     $0$~means unpolarized (see page~\ref{pg:PDG-codes}).
   \item \texttt{min}: minimum value of the coordinate(s).  The default is~$0$.
   \item \texttt{max}: maximum value of the coordinate(s).  The default is~$1$.
-  \item \texttt{fix}
-  \item \texttt{free}
+  \item \texttt{fix}: fix the boundaries: \texttt{min}, \texttt{max} or \texttt{*}.
+  \item \texttt{free}: lower the lower boundary or raise the upper boundary,
+    if necessary.
   \item \texttt{map}: apply a map to a subinterval.  Currently, three
     types of maps are supported:
     \begin{params}
       \item \verb+id {+ $n$
         \verb+[+$x_{\min}$\verb+,+$x_{\max}$\verb+] }+: apply an
         identity map in the interval~$[x_{\min},x_{\max}]$ subdivided
         into~$n$ bins.  The non-trivial effect of this map is that the
         endpoints~$x_{\min}$ and~$x_{\max}$ are frozen.
+      \item \verb+null {+ $n$
+        \verb+[+$x_{\min}$\verb+,+$x_{\max}$\verb+] }+: apply a
+        null map in the interval~$[x_{\min},x_{\max}]$ subdivided
+        into~$n$ bins.  $n$ will almost always be~$1$.  The non-trivial
+        effect of this map is that the weights between~$x_{\min}$ and~$x_{\max}$
+        are set to zero.
       \item \verb+power {+ $n$
         \verb+[+$x_{\min}$\verb+,+$x_{\max}$%
         \verb+] beta = +$\beta$\verb+ eta = +$\eta$\verb+ }+: apply a
         power map in the interval~$[x_{\min},x_{\max}]$ subdivided
         into~$n$ bins.  $\alpha = 1 / (1 + \beta)$, such that an
         integrable singularity at~$\eta$ with power~$\beta$ is mapped
         away. This is the most important map in practical applications
         and manual fine tuning is rewarded.
       \item \verb+resonance {+ $n$
         \verb+[+$x_{\min}$\verb+,+$x_{\max}$%
         \verb+] center = +$\eta$\verb+ width = +$a$\verb+ }+: apply a
         resonance map in the interval~$[x_{\min},x_{\max}]$ subdivided
         into~$n$ bins.  This map is hardly ever needed, since
         VEGAS/VAMP appears to be able to handle non-singular peaks very well.
     \end{params}
-  \item \texttt{triangle}
-  \item \texttt{notriangle}
+  \item \texttt{triangle}: \textit{experimental, do not use!}
+  \item \texttt{notriangle}: \textit{experimental, do not use!}
   \item \texttt{lumi}: luminosity of the beam design, it units of
     \begin{equation}
       \unit{fb}^{-1}\upsilon^{-1} = 10^{32} \unit{cm}^{-2}\unit{sec}^{-1}
     \end{equation}
     where $\upsilon=\unit[10^7]{sec}\approx \unit{year}/\pi$ is an
     ``effective year'' of running with about 30\%\ up-time
   \item \texttt{events}: a double quote delimited string denoting the
     name of the input file.
   \item \texttt{ascii}: input file contains formatted ASCII numbers.
   \item \texttt{binary}: input file is in raw binary format that can
     be accessed by fast memory mapped I/O.  Such files are not
     portable and must not contain Fortran record markers.
   \item \texttt{columns}: number of columns in a binary file.
   \item \texttt{iterations}: maximum number of iterations of the
     VEGAS/VAMP refinement.  It is not necessary to set this
     parameter, but e.\,g.~\texttt{iterations = 0} is useful for
     illustrating the effect of adaption.
 \end{params}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{\texttt{circe2\_tool} Demonstration}
 \label{sec:demonstration}
 
 We can use the example of figure~\ref{fig:z} (a simulated realistic
 $\gamma\gamma$ luminosity spectrum (helicities:~$(+,+)$) for a
 \unit[500]{GeV} photon collider at TESLA~\cite{Telnov:2001:priv}) to
 demonstrate the effects of different options.  In order to amplify the
 effects, only 20~bins are used in each direction, but
 figure~\ref{fig:z/20/m} will show that adequate results are achievable
 in this case too.
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.20q.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.20q.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       gdata ("z_low.50q.histo", $,
         augment.circe[1] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       gdraw circe[1];
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z/20/q}%
     Using 20~equidistant bins in each direction. In the region blown
     up on the right neither 20~equidistant bins nor 50~equidistant bin
     produce enough events to be visible.  In this and all following
     plots, the simulated input data is shown as a filled histogram,
     and the \KirkeTwo/ parametrization is shown as a solid line.}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 8);
       path simulation, circe[];
       gdata ("x.input.histo", $,
         augment.simulation ($1, smin (8, 100 Smul $2));)
       gdata ("x.20q.histo", $,
         augment.circe[0] ($1, smin (8, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $x_{1}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 8);
       path simulation, circe[];
       gdata ("x.input.histo", $,
         augment.simulation ($1, smin (8, 100 Smul $2));)
       gdata ("x.20.histo", $,
         augment.circe[0] ($1, smin (8, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $x_{1}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:x/20/q}%
     Using 20~bins, both equidistant~(left) and adapted~(right).}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.20.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.20.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       gdata ("z_low.50.histo", $,
         augment.circe[1] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       gdraw circe[1];
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z/20}%
     20~adapted bins.  In the blow-up, the 50~bin result is shown for
     illustration as a thin line, while the 20~bin result remains
     almost invisible.}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.20qm.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.20qm.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z/20/qm}%
     Using 20~equidistant bins in each direction with a power map
     appropriate for~$x^{-0.67}$.}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 8);
       path simulation, circe[];
       gdata ("x.input.histo", $,
         augment.simulation ($1, smin (8, 100 Smul $2));)
       gdata ("x.20qm.histo", $,
         augment.circe[0] ($1, smin (8, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $x_{1}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 8);
       path simulation, circe[];
       gdata ("x.input.histo", $,
         augment.simulation ($1, smin (8, 100 Smul $2));)
       gdata ("x.20m.histo", $,
         augment.circe[0] ($1, smin (8, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $x_{1}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:x/20/m}%
     Using 20~bins with a power map appropriate for~$x^{-0.67}$,
     equidistant~(left) and adapted~(right).}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.20m.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.20m.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z/20/m}%
     Using 20~adapted bins in each direction with a power map
     appropriate for~$x^{-0.67}$.}
 \end{figure}
 
 \begin{figure}
   \begin{center}
 %BEGIN IMAGE
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z.input.histo", $,
         augment.simulation ($1, smin (4, 100 Smul $2));)
       gdata ("z.20m2.histo", $,
         augment.circe[0] ($1, smin (4, 100 Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}$ etex, OUT);
     \end{empgraph}
     \quad
     \begin{empgraph}(55,40)
       vardef smin (expr a, b) = if a Sleq b: a else: b fi enddef;
       setrange (0, 0, 1, 4);
       path simulation, circe[];
       gdata ("z_low.input.histo", $,
         augment.simulation ("1.0e4" Smul $1, "1.0e4" Smul $2);)
       gdata ("z_low.20m2.histo", $,
         augment.circe[0] ("1.0e4" Smul $1, smin (4, "1.0e4" Smul $2));)
       pickup pencircle scaled 0.5pt;
       augment.simulation (1,0);
       augment.simulation (0,0);
       gfill (simulation -- cycle) withcolor (0.7,0.7,0.7);
       pickup pencircle scaled 1pt;
       gdraw circe[0];
       pickup pencircle scaled 0.5pt;
       glabel.bot (btex $z=\sqrt{x_{1}x_{2}}\times10^{4}$ etex, OUT);
     \end{empgraph}
 %END IMAGE
 %HEVEA\imageflush
   \end{center}
   \caption{\label{fig:z/20/m2}%
     Using $4+16$~adapted bins in each direction with a power map
     appropriate for~$x^{-0.67}$ in the 4~bins below~$x<0.05$.}
 \end{figure}
 
 In figure~\ref{fig:z/20/q}, 20~equidistant bins in each direction
 \begin{alltt}
   bins = 20 iterations = 0
 \end{alltt}
 produce an acceptable description of the high energy peak but are
 clearly inadequate for~$z<0.2$.  In the blown up region, neither
 20~equidistant bins nor 50~equidistant bin produce more than a handful
 of events and remain almost invisible.  The bad low energy behaviour
 can be understood from the convolution of the obviously coarse
 approximations in left figure of figure~\ref{fig:x/20/q}.  Letting the
 grid adapt
 \begin{alltt}
   bins = 20
 \end{alltt}
 produces a much better approximation in the right figure of
 figure~\ref{fig:x/20/q}.  And indeed, the convolution in
 figure~\ref{fig:z/20} is significantly improved for~$x\lesssim0.2$,
 but remains completely inadequate in the very low energy region, blown
 up on the right hand side.
 
 A better description of the low energy tail requires a power map
 and figure~\ref{fig:z/20/qm} shows that equidistant bins
 \begin{alltt}
   map = power \{ 20 [0,1] beta = -0.67 eta = 0 \} iterations = 0
 \end{alltt}
 already produce a much improved description of the low energy region,
 including the blow-up on the right hand side.  However, the
 description of the peak has gotten much worse, which is explained by
 the coarsening of the bins in the high energy region, as shown in
 figure~\ref{fig:x/20/m}.  The best result is obtained by combining a
 power map with adaption
 \begin{alltt}
   map = power \{ 20 [0,1] beta = -0.67 eta = 0 \}
 \end{alltt}
 with the results depicted in figure~\ref{fig:z/20/m}.  Balancing the
 number of bins used for a neighborhood of the integrable singularity
 at~$x_{i}\to0$ and the remainder can be improved by allocating a fixed
 number of bins for each
 \begin{alltt}
   map = power \{ 4 [0,0.05] beta = -0.67 eta = 0 \}
   map = id \{ 16 [0.05,1] \}
 \end{alltt}
 as shown in figure~\ref{fig:z/20/m2}.  If the data were not
 stochastic, this manual allocation would not be necessary, because the
 neighborhood of the singularity would not contribute to the variance
 and consequently use few bins.  However, the stochastic variance an
 not be suppressed and will pull in more bins than useful.  If the
 power of the map were overcompensating the power of the singularity,
 instead of being tuned to it, the limit~$x_{i}\to0$ would would be
 suppressed automatically.  But in this case, the low-energy tail could
 not be described accurately.
 
 The description with 20~bins in figure~\ref{fig:z/20/m2} is not as
 precise as the 50~bins
 \begin{alltt}
   map = power \{ 10 [0,0.05] beta = -0.67 eta = 0 \}
   map = id \{ 40 [0.05,1] \}
 \end{alltt}
 in figure~\ref{fig:z}, but can suffice for many studies and requires
 less than one sixth of the storage space.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{More \texttt{circe2\_tool} Examples}
 Here is an example that can be used to demonstrate the beneficial
 effects of powermaps.  The simulated events in
 \texttt{teslagg\_500.gg.++.events} are processed once with map and
 once without a map.  Both times 50~bins are used in each direction.
 \begin{verbatim}
 { file = "test_mappings.circe"
   { design = "TESLA" roots = 500
     { pid/1 = 22 pid/2 = 11 pol/1 = 1 pol/2 = 1
       events = "teslagg_500.gg.++.events" binary lumi = 110.719
       bins/1 = 50
       map/2 = id { 49 [0,0.9999999999] }
       map/2 = id { 1 [0.9999999999,1] } } }
   { design = "TESLA (mapped)" roots = 500
     { pid/1 = 22 pid/2 = 11 pol/1 = 1 pol/2 = 1
       events = "teslagg_500.gg.++.events" binary lumi = 110.719
       map/1 = power { 50 [0,1] beta = -0.67 eta = 0 }
       map/2 = power { 49 [0,0.9999999999] beta = -0.6 eta = 1 }
       map/2 = id { 1 [0.9999999999,1] } } } }
 \end{verbatim}
 In a second step, the distributions generated from both designs in
 \texttt{test\_mappings.circe} can be compared with the original
 distribution.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \begin{table}
   \begin{center}
     \begin{tabular}{lcl}
        \verb+!+ \textit{any comment}               & & optional, repeatable \\
        \verb+CIRCE2 FORMAT#1+                      & & mandatory start line \\
        \verb+design, roots+                        & & \\
        \verb+'+\textit{name}\verb+'+\quad$\sqrt{s}$& & mandatory quotes! \\
        \verb+#channels, pol.support+               & & \\
        $n_{c}$\quad\verb+'+\textit{name}\verb+'+   & & mandatory quotes! \\
        \verb+pid1, pol1, pid2, pol2, lumi+
          & $\rceil$ & repeat $n_{c}$ times \\
        $p_1\;h_1\;p_2\;h_2\;\int\!\mathcal{L}$     & & \\
        \verb+#bins1, #bins2, triangle?+            & & \\
        $n_{1}\;n_{2}\;t$                           & & \\
        \verb+x1, map1, alpha1, xi1, eta1, a1, b1+
          & & \\
        $x_{1,0}^{\hphantom{2,n_{2}}}$
          & & \\
        $x_{1,1}^{\hphantom{2,n_{2}}}\;
         m_{1,1}^{\hphantom{2,n_{2}}}\;
         \alpha_{1,1}^{\hphantom{2,n_{2}}}\;
         \xi_{1,1}^{\hphantom{2,n_{2}}}\;
         \eta_{1,1}^{\hphantom{2,n_{2}}}\;
         a_{1,1}^{\hphantom{2,n_{2}}}\;
         b_{1,1}$
          & & \\
        $\ldots$
          & & \\
        $x_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         m_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         \alpha_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         \xi_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         \eta_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         a_{1,n_{1}}^{\hphantom{2,n_{2}}}\;
         b_{1,n_{1}}$
          & & \\
        \verb+x2, map2, alpha2, xi2, eta2, a2, b2+
          & & \\
        $x_{2,0}^{\hphantom{2,n_{2}}}$
          & & \\
        $x_{2,1}^{\hphantom{2,n_{2}}}\;
         m_{2,1}^{\hphantom{2,n_{2}}}\;
         \alpha_{2,1}^{\hphantom{2,n_{2}}}\;
         \xi_{2,1}^{\hphantom{2,n_{2}}}\;
         \eta_{2,1}^{\hphantom{2,n_{2}}}\;
         a_{2,1}^{\hphantom{2,n_{2}}}\;
         b_{2,1}^{\hphantom{2,n_{2}}}$
          & & \\
        $\ldots$
          & & \\
        $x_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         m_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         \alpha_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         \xi_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         \eta_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         a_{2,n_{2}}^{\hphantom{2,n_{2}}}\;
         b_{2,n_{2}}^{\hphantom{2,n_{2}}}$
          & & \\
        \verb+weights+                              & & \\
        $w_{1}\;\;[w_1\chi_{1}^{0,1}\;\;w_1\chi_{1}^{0,2}\;\;
                   \ldots\;\;w_1\chi_{1}^{3,3}]$
          & & optional $w\cdot\chi$ \\
        $w_{2}\;\;[w_1\chi_{2}^{0,1}\;\;w_1\chi_{2}^{0,2}\;\;
                   \ldots\;\;w_1\chi_{2}^{3,3}]$        & & \\
        $\ldots$                                    & & \\
        $w_{n_1n_2}\;\;[w_1\chi_{n_1n_2}^{0,1}\;\;w_1\chi_{n_1n_2}^{0,2}\;\;
                        \ldots\;\;w_1\chi_{n_1n_2}^{3,3}]$ 
          & $\rfloor$ & end repeat \\
        \verb+ECRIC2+
          & & mandatory end line
     \end{tabular}
   \end{center}
   \caption{\label{tab:fileformat}
     File format.  The variable input lines (except comments) are
     designed to be readable by FORTRAN77 `list-directed' input.  The
     files are generated from simulation data with the program
     \texttt{circe2\_tool} and are read transparently by the procedure
     \texttt{cir2ld}. The format is documented here only for
     completeness.}
 \end{table}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{On the Implementation of \texttt{circe2\_tool}}
 \label{sec:circe2_tool-implementation}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Divisions}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Division =
   sig
     type t
     val copy : t -> t
     val record : t -> float -> float -> unit
     val rebin : ?power:float -> t -> t
     val find : t -> float -> int
     val bins : t -> float array
     val to_channel : out_channel -> t -> unit
   end
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:division}%
     O'Caml signature for divisions. \texttt{Division.t} is
     the abstract data type for division of a real interval.
     Note that \texttt{Division} does \emph{not} contain a function
     \texttt{create : \ldots{} -> t} for constructing maps.  This
     is provided by concrete implementations (see
     figures~\protect\ref{fig:mono_division}
     and~\protect\ref{fig:poly_division}), that can be
     projected on \texttt{Diffmap}}
 \end{figure}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Mono_Division =
   sig
     include Division
     val create : int -> float -> float -> t
   end
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:mono_division}%
     O'Caml signature for simple divisions of an interval.
     The \texttt{create} function returns an equidistant
     starting division.}
 \end{figure}
 
 \begin{dubious}
   VEGAS/VAMP, basically \ldots
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Differentiable Maps}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Diffmap =
   sig
     type t
     type domain
     val x_min : t -> domain
     val x_max : t -> domain
     type codomain
     val y_min : t -> codomain
     val y_max : t -> codomain
     val phi : t -> domain -> codomain
     val ihp : t -> codomain -> domain
     val jac : t -> domain -> float
     val caj : t -> codomain -> float
   end
 
 module type Real_Diffmap =
   T with type domain = float and type codomain = float
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:diffmap}%
     O'Caml signature for differentiable maps.  \texttt{Diffmap.t} is
     the abstract data type for differentiable maps.  Note that
     \texttt{Diffmap} does \emph{not} contain a functions like
     \texttt{create : \ldots{} -> t} for constructing maps.  These
     are provided by concrete implementations, that can be
     projected onto \texttt{Diffmap}.}
 \end{figure}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Real_Diffmaps =
   sig
     include Real_Diffmap
     val id : float -> float -> t
   end
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:diffmaps}%
     Collections of real differentiable maps, including at least
     the identity.  The function \texttt{id} returns an identity
     map from a real interval onto itself.}
 \end{figure}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Polydivisions}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Poly_Division =
   sig
     include Division
     module M : Real_Diffmaps
     val create :
       (int * M.t) list -> int -> float -> float -> t
   end
 
 module Make_Poly_Division (M : Real_Diffmaps) :
   Poly_Division with module Diffmaps = M
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:poly_division}%
     O'Caml signature for divisions of an interval, with
     piecewise differentiable mappings, as specified by
     the first argument of \texttt{create}.  The functor
     \texttt{Make\_Poly\_Division} \ldots}
 \end{figure}
 
 \begin{dubious}
   patched divisions \ldots
 \end{dubious}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection{Grids}
 
 \begin{figure}
 %BEGIN LATEX
   \begin{center}
     \begin{minipage}{0.8\textwidth}
 %END LATEX
 \begin{alltt}\small
 module type Grid =
   sig
     module D : Division
     type t
     val create : D.t -> D.t -> t
     val copy : t -> t
     val record : t -> float -> float -> float -> unit
     val rebin : ?power:float -> t -> t
     val variance : t -> float
     val to_channel : out_channel -> t -> unit
   end
 
 module Make_Grid (D : Division) : Grid with module D = D
 \end{alltt}
 %BEGIN LATEX
     \end{minipage}
   \end{center}
 %END LATEX
   \caption{\label{fig:grids}%
     O'Caml signature for grids.  The functor \texttt{Make\_Grid}
     can be applied to \emph{any} module of type \texttt{Division},
     in particular both \texttt{Mono\_Division}
     and~\texttt{Poly\_Division}.}
 \end{figure}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{The Next Generation}
 \label{sec:TNG}
 Future generations can try to implement the following features:
 
 \subsection{Variable \#{} of Bins}
 One can monitor the total variance in each interval of the
 polydivisions and move bins from smooth intervals to wildly varying
 intervals, keeping tho total number of bins constant.
 
 \subsection{Adapting Maps Per-Cell}
 Iff there is enough statistics, one can adapt the mapping class and
 parameters per bin.
 \begin{dubious}
   There's a nice duality between adapting bins for a constant mapping
   on one side and adapting mappings for constant bins.  Can one
   merge the two approaches.
 \end{dubious}
 
 \subsection{Non-Factorized Polygrids}
 One could think of a non-factorized distribution of mappings.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Conclusions}
 \label{sec:conclusions}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \subsection*{Acknowledgements}
 Thanks to Valery Telnov for useful discussions.  Thanks to the
 worldwide Linear Collider community and the ECFA/DESY study groups in
 particular for encouragement. This research is supported by
 Bundesministerium f\"ur Bildung und Forschung, Germany, (05\,HT9RDA).
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%% \bibliography{circe}
 \begin{thebibliography}{10}
   \bibitem{Ohl:1996:Circe}
     T. Ohl, Comput.{} Phys.{} Commun.{} \textbf{101} (1997) 269
       [hep-ph/9607454].
 %%CITATION = HEP-PH 9607454;%%
   \bibitem{PYTHIA}
     T.~Sjostrand, L.~Lonnblad and S.~Mrenna,
       \textit{PYTHIA 6.2: Physics and manual},
       LU-TP 01-21, [hep-ph/0108264].
 %%CITATION = HEP-PH 0108264;%%
   \bibitem{HERWIG}
     G.~Corcella et al., \textit{Herwig 6.3 release note},
     CAVENDISH-HEP 01-08, CERN-TH 2001-173, DAMTP 2001-61,
     [hep-ph/0107071].
 %%CITATION = HEP-PH 0107071;%%
   \bibitem{Ginzburg/Telnov/etal:1983:gamma-collider}
     I.~F.~Ginzburg, G.~L.~Kotkin, V.~G.~Serbo and V.~I.~Telnov,
     Nucl.{} Instrum.{} Meth.{}  \textbf{205} (1983) 47.
 %%CITATION = NUIMA,205,47;%%
   \bibitem{VEGAS}
     G.~P. Lepage, J. Comp.{} Phys.{} {\bf 27},  192  (1978);
     G.~P. Lepage, Technical Report No.~CLNS-80/447, Cornell (1980).
   \bibitem{VAMP}
     T. Ohl, Comput.{} Phys.{} Commun.{} \textbf{120} (1999) 13
     [hep-ph/9806432];
 %%CITATION = HEP-PH 9806432;%%
     T. Ohl, \textit{Electroweak Gauge Bosons at Future
       Electron-Positron Colliders}, Darmstadt University of Technology,
       1999, IKDA 99/11, LC-REV-1999-005 [hep-ph/9911437].
 %%CITATION = HEP-PH 9911437;%%
   \bibitem{Telnov:2001:priv}
     V. Telnov, 2001 (private communication).
   \bibitem{O'Caml}
     Xavier Leroy, \textit{The Objective Caml System, Release 3.02,
       Documentation and User's Guide}, Technical Report, INRIA, 2001,
     \texttt{http://pauillac.inria.fr/ocaml/}.
   \bibitem{Ginzburg/Telnov/etal:1984:gamma-collider}
     I.~F.~Ginzburg, G.~L.~Kotkin, S.~L.~Panfil, V.~G.~Serbo and V.~I.~Telnov,
     Nucl.{} Instrum.{} Meth.{} A \textbf{219} (1984) 5.
 %%CITATION = NUIMA,A219,5;%%
   \bibitem{Chen/etal:1995:CAIN}
     P.~Chen, G.~Horton-Smith, T.~Ohgaki, A.~W.~Weidemann and K.~Yokoya,
     Nucl.{} Instrum.{} Meth.{} \textbf{A355} (1995) 107.
 %%CITATION = NUIMA,A355,107;%%
   \bibitem{PDG}
     D.~E.~Groom {\it et al.}  [Particle Data Group Collaboration],
       \textit{Review of particle physics},
       Eur.{} Phys.{} J.{} \textbf{C15} (2000) 1.
 %%CITATION = EPHJA,C15,1;%%
   \bibitem{Knu97}
     D.E.~Knuth, \textit{The Art of Computer Programming, Vol.~2}, (3rd
     ed.), Addison-Wesley, Reading, MA, 1997.
   \bibitem{Mar96}
     George Marsaglia, \textit{The Marsaglia Random Number CD-ROM}, FSU,
     Dept.~of Statistics and SCRI, 1996.
   \bibitem{Jadach:2000:FOAM}
     S.~Jadach,
     % ``Foam: Multi-Dimensional General Purpose Monte Carlo Generator
     % With Self-Adapting Symplectic Grid,''
     Comput.{} Phys.{} Commun.{} \textbf{130} (2000) 244
     [arXiv:physics/9910004].
 %%CITATION = PHYS-ICS 9910004;%%
 \end{thebibliography}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % Local Variables:
 % mode:noweb
 % noweb-doc-mode:latex-mode
 % noweb-code-mode:fortran-mode
 % indent-tabs-mode:nil
 % page-delimiter:"^%%%.*\n"
 % End:
Index: trunk/circe2/src/events_lexer.mll
===================================================================
--- trunk/circe2/src/events_lexer.mll	(revision 8897)
+++ trunk/circe2/src/events_lexer.mll	(revision 8898)
@@ -1,73 +1,73 @@
 (* events_lexer.mll -- *)
 (* Copyright (C) 2022 by Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
    Circe2 is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    Circe2 is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  *)  
 
 {
   (* Fortran allows ['d'] and ['D'] as exponent starter, but
      O'Caml's [float_of_string] doesn't accept it.  *)
 
   let normalize_ascii_floats orig =
     let normalized = Bytes.of_string orig in
     for i = 0 to Bytes.length normalized - 1 do
       let c = Bytes.get normalized i in
       if c = 'd' || c = 'D' then
         Bytes.set normalized i 'E'
     done;
     Bytes.to_string normalized
 }
 
 let digit = [ '0' - '9' ]
 let exp_e = [ 'e' 'E' ]
 let exp_d = [ 'd' 'D' ]
 let white = [ ' ' '\t' '\r' ]
 
 rule token = parse
     white        { token lexbuf }     (* skip blanks *)
   | ['+''-']? digit+
-    ( '.' digit* ( exp_e digit+ )? | exp_e digit+ )
+    ( '.' digit* ( exp_e '-'? digit+ )? | exp_e '-'? digit+ )
                  { Some (float_of_string (Lexing.lexeme lexbuf)) }
   | ['+''-']? digit+
-    ( '.' digit* ( exp_d digit+ )? | exp_d digit+ )
+    ( '.' digit* ( exp_d '-'? digit+ )? | exp_d '-'? digit+ )
                  { Some (float_of_string (normalize_ascii_floats (Lexing.lexeme lexbuf))) }
   | ['+''-']? digit+
                  { Some (float_of_string (Lexing.lexeme lexbuf)) }
   | _            { failwith (Lexing.lexeme lexbuf) }
   | eof          { None }
 
 {
   (* Not used by circe2, just for illustration and testing. *)
 
   let float_list_of_string s =
     let lexbuf = Lexing.from_string s in
     let rec collect xs_rev =
       match token lexbuf with
       | None -> List.rev xs_rev
       | Some x -> collect (x :: xs_rev) in
     try
       collect []
     with
     | Failure c ->
        invalid_arg ("invalid token '" ^ c ^ "' in \"" ^ s ^ "\"")
 
   let float_array_of_string a s =
     let lexbuf = Lexing.from_string s in
     try
       for i = 0 to Array.length a - 1 do
         match token lexbuf with
         | None -> invalid_arg ("not enough floats in \"" ^ s ^ "\"")
         | Some x -> a.(i) <- x
       done
     with
     | Failure c ->
        invalid_arg ("invalid token '" ^ c ^ "' in \"" ^ s ^ "\"")
 }
Index: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	(revision 8897)
+++ trunk/ChangeLog	(revision 8898)
@@ -1,2406 +1,2409 @@
 ChangeLog -- Summary of changes to the WHIZARD package
 
 Use git log/svn log to see detailed changes.
 
 	Version 3.1.2.1
 
+2023-10-01
+	CIRCE2: add 'null' maps for regions with not enough statistics
+
 2023-09-25
 	Minimal compiler versions: OCaml 4.08, gfortran 9.1.0
 
 2023-06-01
 	Common folder 'contrib' for external codes shipped with WHIZARD
 
 2023-05-28
 	Bug fix UFO interface:workaround for case-sensitive parameters
 
 2023-05-05
 	Update of meson and baryon listings in SM hadrons model
 
 2023-03-28
 	Workaround for Intel oneAPI 2022/23 regression(s)
 
 ##################################################################
 
 2023-03-21
 	RELEASE: version 3.1.2
 
 2023-03-21
 	Bug fix in cyclic build dependence of WHIZARD core
 
 2023-03-11
 	Resolve minor inconsistency in manual for NLO real partition
 
 ##################################################################
 
 2023-03-10
 	RELEASE: version 3.1.1
 
 2023-03-09
 	Bug fix in UFO file parser
 	Small bug fix in NLO EW infrastructure
 
 2023-03-01
 	Bug fix: numerical mapping stability for peaked PDFs
 
 2023-02-28
 	Bug fix UFO interface: avoid too long ME code lines
 
 2023-02-22
 	Infrastructure for calculation of kinematic MT2 variable
 
 2023-02-17
 	Bug fix UFO interface: correct parentheses in rational functions
 
 ##################################################################
 
 2022-12-14
 	RELEASE: version 3.1.0
 
 2022-12-12
 	Bug fix Pythia8 interface: production vertices, shower history
 	O'Mega support for epsilon tensor color structures
 
 2023-01-27
 	Support for loop-induced processes
 
 2022-11-30
 	O'Mega support for general SU(N) color representations
 
 2022-11-07
 	Modernize configure checks for Python versions v3.10+
 
 2022-10-21
         General POWHEG matching
           with optional NLO real phase space partitioning
 
 2022-09-26
 	Bug fix: accept negative scale values in SLHA block header
 
 2022-08-08
 	Numerical stability of testsuite for Apple M1 processors
 
 2022-08-07
 	Technically allow for muons as CIRCE2 beam spectra
 
 2022-06-22
         POWHEG matching for Drell-Yan and similar processes
 
 2022-06-12
 	Add unit tests for Lorentz and phase-space modules
 
 2022-05-09
 	Massive eikonals: Numeric robustness at ultrahigh energies
 
 2022-04-20
 	Bug fix for VAMP2 event generation with indefinite samples
 
 ##################################################################
 
 2022-04-06
 	RELEASE: version 3.0.3
 
 2022-04-05
 	POWHEG matching for single flavor hadron collisions
 
 2022-03-31
 	NLO EW processes with massless leptons and jets (i.e.
 	   jet clustering and photon recombination) supported
 	NLO EW for massive initial leptons validated
 
 2022-03-27
 	Complete implementation/validation of NLL electron PDFs
 
 2022-02-22
 	Bug fix: correct normalization for CIRCE2+EPA+polarization
 
 2022-02-21
 	WHIZARD core now uses Fortran modules and submodules
 
 2022-01-27
 	Infrastructure for POWHEG matching for hadron collisions
 
 2021-12-16
 	Event files can be written/read also for decay processes
 	Implementation of running QED coupling alpha
 
 2021-12-10
 	Independent variations of renormalization/factorization scale
 
 ##################################################################
 
 2021-11-23
 	RELEASE: version 3.0.2
 
 2021-11-19
 	Support for a wide class of mixed NLO QCD/EW processes
 
 2021-11-18
 	Add pp processes for NLO EW corrections to testsuite
 
 2021-11-11
 	Output numerically critical values with LCIO 2.17+ as double
 
 2021-11-05
 	Minor refactoring on phase space points and kinematics
 
 2021-10-21
 	NLO (QCD) differential distributions supported for full
 	  lepton collider setup: polarization, QED ISR, beamstrahlung
 
 2021-10-15
 	SINDARIN now has a sum and product function of expressions,
 	SINDARIN supports observables defined on full (sub)events
 	First application: transverse mass
 	Bug fix: 2HDM did not allow H+, H- as external particles
 
 2021-10-14
 	CT18 PDFs included (NLO, NNLO)
 
 2021-09-30
 	Bug fix: keep non-recombined photons in the event record
 
 2021-09-13
 	Modular NLO event generation with real partition
 
 2021-08-20
 	Bug fix: correctly reading in NLO fixed order events
 
 2021-08-06
         Generalize optional partitioning of the NLO real phase space
 
 ##################################################################
 
 2021-07-08
 	RELEASE: version 3.0.1
 
 2021-07-06
 	MPI parallelization now comes with two incarnations:
 	- standard MPI parallelization ("simple", default)
 	- MPI with load balancer ("load")
 
 2021-07-05
 	Bug fix for C++17 default compilers w/ HepMC3/ROOT interface
 
 2021-07-02
 	Improvement for POWHEG matching:
 	- implement massless recoil case
 	- enable reading in existing POWHEG grids
 	- support kinematic cuts at generator level
 
 2021-07-01
 	Distinguish different cases of photons in NLO EW corrections
 
 2021-06-21
 	Option to keep negative PDF entries or set them zero
 
 2021-05-31
 	Full LCIO MC production files can be properly recasted
 
 2021-05-24
         Use defaults for UFO models without propagators.py
 
 2021-05-21
 	Bug fix: prevent invalid code for UFO models containing hyphens
 
 2021-05-20
 	UFO files with scientific notation float constants allowed
 	UFO files: max. n-arity of vertices bound by process multiplicity
 
 ##################################################################
 
 2021-04-27
 	RELEASE: version 3.0.0
 
 2021-04-20
 	Minimal required OCaml version is now 4.05.0.
 	Bug fix for tau polarization from stau decays
 
 2021-04-19
 	NLO EW splitting functions and collinear remnants completed
 	Photon recombination implemented
 
 2021-04-14
 	Bug fix for vertices/status codes with HepMC2/3 event format
 
 2021-04-08
 	Correct Lorentz statistics for UFO model with Majorana fermions
 
 2021-04-06
 	Bug fix for rare script failure in system_dependencies.f90.in
 	Kappa factor for quartic Higgs coupling in SM_ac(_CKM) model
 
 2021-04-04
 	Support for UFO extensions in SMEFTSim 3.0
 
 2021-02-25
 	Enable VAMP and VAMP2 channel equivalences for NLO integrations
 
 2021-02-04
 	Bug fix if user does not set a prefix at configuration
 
 2020-12-10
 	Generalize NLO calculations to non-CMS lab frames
 
 2020-12-08
 	Bug fix in expanded p-wave form factor for top threshold
 
 2020-12-06
 	Patch for macOS Big Sur shared library handling due to libtool;
 	   the patch also demands gcc/gfortran 11.0/10.3/9.4/8.5
 
 2020-12-04
 	O'Mega only inserts non-vanishing couplings from UFO models
 
 2020-11-21
 	Bug fix for fractional hypercharges in UFO models
 
 2020-11-11
 	Enable PYTHIA6 settings for eh collisions (enable-pythia6_eh)
 
 2020-11-09
 	Correct flavor assignment for NLO fixed-order events
 
 2020-11-05
 	Bug fix for ISR handler not working with unstable particles
 
 2020-10-08
 	Bug fix in LHAPDF interface for photon PDFs
 
 2020-10-07
 	Bug fix for structure function setup with asymmetric beams
 
 2020-10-02
 	Python/Cython layer for WHIZARD API
 
 2020-09-30
 	Allow mismatches of Python and name attributes in UFO models
 
 2020-09-26
 	Support for negative PDG particles from certain UFO models
 
 2020-09-24
 	Allow for QNUMBERS blocks in BSM SLHA files
 
 2020-09-22
 	Full support for compilation with clang(++) on Darwin/macOS
 	More documentation in the manual
 	Minor clean-ups
 
 2020-09-16
 	Bug fix enables reading LCIO events with LCIO v2.15+
 
 ##################################################################
 
 2020-09-16
 	RELEASE: version 2.8.5
 
 2020-09-11
 	Bug fix for H->tau tau transverse polarization with PYTHIA6
 	   (thanks to Junping Tian / Akiya Miyamoto)
 
 2020-09-09
 	Fix a long standing bug (since 2.0) in the calculation of color
 	factors when particles of different color were combined in a
 	particle class.  NB: O'Mega never produced a wrong number,
 	it only declared all processes as invalid.
 
 2020-09-08
 	Enable Openloops matrix element equivalences for optimization
 
 2020-09-02
 	Compatibility fix for PYTHIA v8.301+ interface
 
 2020-09-01
 	Support exclusive jet clustering in ee for Fastjet interface
 
 ##################################################################
 
 2020-08-30
 	RELEASE: version 3.0.0_beta
 
 2020-08-27
 	Major revision of NLO distributions and events for
 	   processes with structure functions:
 	- Use parton momenta/flavors (instead of beams) for events
 	- Bug fix for Lorentz boosts and Lorentz frames of momenta
 	- Bug fix: apply cuts to virtual NLO component in correct frame
 	- Correctly assign ISR radiation momenta in data structures
 	- Refactoring on quantum numbers for NLO event data structures
 	- Functional tests for hadron collider NLO distributions
 	- many minor bug fixes regarding NLO hadron collider physics
 
 2020-08-11
 	Bug fix for linking problem with OpenMPI
 
 2020-08-07
 	New WHIZARD API: WHIZARD can be externally linked as a
 	  library, added examples for Fortran, C, C++ programs
 
 ##################################################################
 
 2020-07-08
 	RELEASE: version 2.8.4
 
 2020-07-07
 	Bug fix: steering of UFO Majorana models from WHIZARD
 
 ##################################################################
 
 2020-07-06
 	Combined integration also for hadron collider processes at NLO
 
 2020-07-05
 	Bug fix: correctly steer e+e- FastJet clustering algorithms
 	Major revision of NLO differential distributions and events:
 	- Correctly assign quantum numbers to NLO fixed-order events
 	- Correctly assign weights to NLO fixed-order events for
 	     combined simulation
 	- Cut all NLO fixed-order subevents in event groups individually
 	- Only allow "sigma" normalization for NLO fixed-order events
 	- Use correct PDF setup for NLO counter events
 	- Several technical fixes and updates of the NLO testsuite
 
 ##################################################################
 
 2020-07-03
 	RELEASE: version 2.8.3
 
 2020-07-02
 	Feature-complete UFO implementation for Majorana fermions
 
 2020-06-22
 	Running width scheme supported for O'Mega matrix elements
 
 2020-06-20
 	Adding H-s-s coupling to SM_Higgs(_CKM) models
 
 2020-06-17
 	Completion of ILC 2->6 fermion extended test suite
 
 2020-06-15
 	Bug fix: PYTHIA6/Tauola, correctly assign tau spins for stau decays
 
 2020-06-09
 	Bug fix: correctly update calls for additional VAMP/2 iterations
 	Bug fix: correct assignment for tau spins from PYTHIA6 interface
 
 2020-06-04
 	Bug fix: cascades2 tree merge with empty subtree(s)
 
 2020-05-31
 	Switch $epa_mode for different EPA implementations
 
 2020-05-26
 	Bug fix: spin information transferred for resonance histories
 
 2020-04-13
 	HepMC: correct weighted events for non-xsec event normalizations
 
 2020-04-04
 	Improved HepMC3 interface: HepMC3 Root/RootTree interface
 
 2020-03-24
 	ISR: Fix on-shell kinematics for events with ?isr_handler=true
 	   (set ?isr_handler_keep_mass=false for old behavior)
 
 2020-03-11
 	Beam masses are correctly passed to hard matrix element for CIRCE2
 	EPA with polarized beams: double-counting corrected
 
 ##################################################################
 
 2020-03-03
 	RELEASE: version 3.0.0_alpha
 
 2020-02-25
 	Bug fix: Scale and alphas can be retrieved from internal event format to
 	   external formats
 
 2020-02-17
 	Bug fix: ?keep_failed_events now forces output of actual event data
 	Bug fix: particle-set reconstruction (rescanning events w/o radiation)
 
 2020-01-28
 	Bug fix for left-over EPA parameter epa_e_max (replaced by epa_q_max)
 
 2020-01-23
 	Bug fix for real components of NLO QCD 2->1 processes
 
 2020-01-22
         Bug fix: correct random number sequencing during parallel MPI event
 	   generation with rng_stream
 
 2020-01-21
 	Consistent distribution of events during parallel MPI event generation
 
 2020-01-20
 	Bug fix for configure setup for automake v1.16+
 
 2020-01-18
 	General SLHA parameter files for UFO models supported
 
 2020-01-08
 	Bug fix: correctly register RECOLA processes with flavor sums
 
 2019-12-19
 	Support for UFO customized propagators
 	O'Mega unit tests for fermion-number violating interactions
 
 2019-12-10
 	For distribution building: check for graphviz/dot
 	   version 2.40 or newer
 
 2019-11-21
 	Bug fix: alternate setups now work correctly
 	Infrastructure for accessing alpha_QED event-by-event
 	Guard against tiny numbers that break ASCII event output
 	Enable inverse hyperbolic functions as SINDARIN observables
 	Remove old compiler bug workarounds
 
 2019-11-20
 	Allow quoted -e argument, implemented -f option
 
 2019-11-19
 	Bug fix: resonance histories now work also with UFO models
 	Fix in numerical precision of ASCII VAMP2 grids
 
 2019-11-06
 	Add squared matrix elements to the LCIO event header
 
 2019-11-05
 	Do not include RNG state in MD5 sum for CIRCE1/2
 
 2019-11-04
 	Full CIRCE2 ILC 250 and 500 GeV beam spectra added
 	Minor update on LCIO event header information
 
 2019-10-30
 	NLO QCD for final states completed
 	When using Openloops, v2.1.1+ mandatory
 
 2019-10-25
 	Binary grid files for VAMP2 integrator
 
 ##################################################################
 
 2019-10-24
 	RELEASE: version 2.8.2
 
 2019-10-20
 	Bug fix for HepMC linker flags
 
 2019-10-19
 	Support for spin-2 particles from UFO files
 
 2019-09-27
 	LCIO event format allows rescan and alternate weights
 
 2019-09-24
 	Compatibility fix for OCaml v4.08.0+
 
 ##################################################################
 
 2019-09-21
 	RELEASE: version 2.8.1
 
 2019-09-19
 	Carriage return characters in UFO models can be parsed
 	Mathematica symbols in UFO models possible
 	Unused/undefined parameters in UFO models handled
 
 2019-09-13
 	New extended NLO test suite for ee and pp processes
 
 2019-09-09
 	Photon isolation (separation of perturbative and fragmentation
 	   part a la Frixione)
 
 2019-09-05
 	Major progress on NLO QCD for hadron collisions:
 	- correctly assign flavor structures for alpha regions
 	- fix crossing of particles for initial state splittings
 	- correct assignment for PDF factors for real subtractions
 	- fix kinematics for collinear splittings
 	- bug fix for integrated virtual subtraction terms
 
 2019-09-03
 	b and c jet selection in cuts and analysis
 
 2019-08-27
 	Support for Intel MPI
 
 2019-08-20
 	Complete (preliminary) HepMC3 support (incl.
 	   backwards HepMC2 write/read mode)
 
 2019-08-08
 	Bug fix: handle carriage returns in UFO files (non-Unix OS)
 
 ##################################################################
 
 2019-08-07
 	RELEASE: version 2.8.0
 
 2019-07-31
 	Complete WHIZARD UFO interface:
 	- general Lorentz structures
 	- matrix element support for general color factors
 	- missing features: Majorana fermions and SLHA
 
 2019-07-20
 	Make WHIZARD compatible with OCaml 4.08.0+
 
 2019-07-19
 	Fix version testing for LHAPDF 6.2.3 and newer
 	Minimal required OCaml version is now 4.02.3.
 
 2019-04-18
 	Correctly generate ordered FKS tuples for alpha regions
 	   from all possible underlying Born processes
 
 2019-04-08
 	Extended O'Mega/Recola matrix element test suite
 
 2019-03-29
 	Correct identical particle symmetry factors for FKS subtraction
 
 2019-03-28
 	Correct assertion of spin-correlated matrix
 	   elements for hadron collisions
 
 2019-03-27
 	Bug fix for cut-off parameter delta_i for
 	   collinear plus/minus regions
 
 ##################################################################
 
 2019-03-27
 	RELEASE: version 2.7.1
 
 2019-02-19
 	Further infrastructure for HepMC3 interface (v3.01.00)
 
 2019-02-07
 	Explicit configure option for using debugging options
 	Bug fix for performance by removing unnecessary debug operations
 
 2019-01-29
 	Bug fix for DGLAP remnants with cut-off parameter delta_i
 
 2019-01-24
 	Radiative decay neu2 -> neu1 A added to MSSM_Hgg model
 
 ##################################################################
 
 2019-01-21
 	RELEASE: version 2.7.0
 
 2018-12-18
 	Support RECOLA for integrated und unintegrated subtractions
 
 2018-12-11
 	FCNC top-up sector in model SM_top_anom
 
 2018-12-05
 	Use libtirpc instead of SunRPC on Arch Linux etc.
 
 2018-11-30
 	Display rescaling factor for weighted event samples with cuts
 
 2018-11-29
 	Reintroduce check against different masses in flavor sums
 	Bug fix for wrong couplings in the Littlest Higgs model(s)
 
 2018-11-22
 	Bug fix for rescanning events with beam structure
 
 2018-11-09
 	Major refactoring of internal process data
 
 2018-11-02
 	PYTHIA8 interface
 
 2018-10-29
         Flat phase space parametrization with RAMBO (on diet) implemented
 
 2018-10-17
 	Revise extended test suite
 
 2018-09-27
 	Process container for RECOLA processes
 
 2018-09-15
 	Fixes by M. Berggren for PYTHIA6 interface
 
 2018-09-14
 	First fixes after HepForge modernization
 
 ##################################################################
 
 2018-08-23
 	RELEASE: version 2.6.4
 
 2018-08-09
 	Infrastructure to check colored subevents
 
 2018-07-10
 	Infrastructure for running WHIZARD in batch mode
 
 2018-07-04
 	MPI available from distribution tarball
 
 2018-06-03
 	Support Intel Fortran Compiler under MAC OS X
 
 2018-05-07
 	FKS slicing parameter delta_i (initial state) implementend
 
 2018-05-03
 	Refactor structure function assignment for NLO
 
 2018-05-02
 	FKS slicing parameter xi_cut, delta_0 implemented
 
 2018-04-20
 	Workspace subdirectory for process integration (grid/phs files)
 	Packing/unpacking of files at job end/start
 	Exporting integration results from scan loops
 
 2018-04-13
 	Extended QCD NLO test suite
 
 2018-04-09
 	Bug fix for Higgs Singlet Extension model
 
 2018-04-06
 	Workspace subdirectory for process generation and compilation
 	--job-id option for creating job-specific names
 
 2018-03-20
 	Bug fix for color flow matching in hadron collisions
 	   with identical initial state quarks
 
 2018-03-08
 	Structure functions quantum numbers correctly assigned for NLO
 
 2018-02-24
 	Configure setup includes 'pgfortran' and 'flang'
 
 2018-02-21
 	Include spin-correlated matrix elements in interactions
 
 2018-02-15
 	Separate module for QED ISR structure functions
 
 ##################################################################
 
 2018-02-10
 	RELEASE: version 2.6.3
 
 2018-02-08
 	Improvements in memory management for PS generation
 
 2018-01-31
 	Partial refactoring: quantum number assigment NLO
 	Initial-state QCD splittings for hadron collisions
 
 2018-01-25
 	Bug fix for weighted events with VAMP2
 
 2018-01-17
 	Generalized interface for Recola versions 1.3+  and 2.1+
 
 2018-01-15
 	Channel equivalences also for VAMP2 integrator
 
 2018-01-12
 	Fix for OCaml compiler 4.06 (and newer)
 
 2017-12-19
 	RECOLA matrix elements with flavor sums can be integrated
 
 2017-12-18
 	Bug fix for segmentation fault in empty resonance histories
 
 2017-12-16
 	Fixing a bug in PYTHIA6 PYHEPC routine by omitting CMShowers
 	  from transferral between PYTHIA and WHIZARD event records
 
 2017-12-15
 	Event index for multiple processes in event file correct
 
 ##################################################################
 
 2017-12-13
 	RELEASE: version 2.6.2
 
 2017-12-07
 	User can set offset in event numbers
 
 2017-11-29
 	Possibility to have more than one RECOLA process in one file
 
 2017-11-23
 	Transversal/mixed (and unitarized) dim-8 operators
 
 2017-11-16
 	epa_q_max replaces epa_e_max (trivial factor 2)
 
 2017-11-15
 	O'Mega matrix element compilation silent now
 
 2017-11-14
 	Complete expanded P-wave form factor for top threshold
 
 2017-11-10
 	Incoming particles can be accessed in SINDARIN
 
 2017-11-08
 	Improved handling of resonance insertion, additional parameters
 
 2017-11-04
 	Added Higgs-electron coupling (SM_Higgs)
 
 ##################################################################
 
 2017-11-03
 	RELEASE: version 2.6.1
 
 2017-10-20
 	More than 5 NLO components possible at same time
 
 2017-10-19
 	Gaussian cutoff for shower resonance matching
 
 2017-10-12
 	Alternative (more efficient) method to generate
 	   phase space file
 
 2017-10-11
 	Bug fix for shower resonance histories for processes
 	   with multiple components
 
 2017-09-25
 	Bug fix for process libraries in shower resonance histories
 
 2017-09-21
 	Correctly generate pT distribution for EPA remnants
 
 2017-09-20
 	Set branching ratios for unstable particles also by hand
 
 2017-09-14
 	Correctly generate pT distribution for ISR photons
 
 ##################################################################
 
 2017-09-08
 	RELEASE: version 2.6.0
 
 2017-09-05
 	Bug fix for initial state NLO QCD flavor structures
 	Real and virtual NLO QCD hadron collider processes
 	   work with internal interactions
 
 2017-09-04
 	Fully validated MPI integration and event generation
 
 2017-09-01
 	Resonance histories for shower: full support
 	Bug fix in O'Mega model constraints
 	O'Mega allows to output a parsable form of the DAG
 
 2017-08-24
 	Resonance histories in events for transferral
 	   to parton shower (e.g. in ee -> jjjj)
 
 2017-08-01
 	Alpha version of HepMC v3 interface
 	   (not yet really functional)
 
 2017-07-31
 	Beta version for RECOLA OLP support
 
 2017-07-06
 	Radiation generator fix for LHC processes
 
 2017-06-30
 	Fix bug for NLO with structure
 	   functions and/or polarization
 
 2017-06-23
 	Collinear limit for QED corrections works
 
 2017-06-17
 	POWHEG grids generated already during integration
 
 2017-06-12
 	Soft limit for QED corrections works
 
 2017-05-16
 	Beta version of full MPI parallelization (VAMP2)
 	Check consistency of POWHEG grid files
 	Logfile config-summary.log for configure summary
 
 2017-05-12
 	Allow polarization in top threshold
 
 2017-05-09
 	Minimal demand automake 1.12.2
 	Silent rules for make procedures
 
 2017-05-07
 	Major fix for POWHEG damping
 	Correctly initialize FKS ISR phasespace
 
 ##################################################################
 
 2017-05-06
 	RELEASE: version 2.5.0
 
 2017-05-05
 	Full UFO support (SM-like models)
 	Fixed-beam ISR FKS phase space
 
 2017-04-26
 	QED splittings in radiation generator
 
 2017-04-10
 	Retire deprecated O'Mega vertex cache files
 
 ##################################################################
 
 2017-03-24
 	RELEASE: version 2.4.1
 
 2017-03-16
 	Distinguish resonance charge in phase space channels
 	Keep track of resonance histories in phase space
 	Complex mass scheme default for OpenLoops amplitudes
 
 2017-03-13
 	Fix helicities for polarized OpenLoops calculations
 
 2017-03-09
 	Possibility to advance RNG state in rng_stream
 
 2017-03-04
 	General setup for partitioning real emission
 	   phase space
 
 2017-03-06
 	Bug fix on rescan command for converting event files
 
 2017-02-27
 	Alternative multi-channel VEGAS implementation
 	   VAMP2: serial backbone for MPI setup
 	Smoothstep top threshold matching
 
 2017-02-25
 	Single-beam structure function with
 	   s-channel mapping supported
 	Safeguard against invalid process libraries
 
 2017-02-16
 	Radiation generator for photon emission
 
 2017-02-10
 	Fixes for NLO QCD processes (color correlations)
 
 2017-01-16
 	LCIO variable takes precedence over LCIO_DIR
 
 2017-01-13
 	Alternative random number generator
 	   rng_stream (cf. L'Ecuyer et al.)
 
 2017-01-01
 	Fix for multi-flavor BLHA tree
 	   matrix elements
 
 2016-12-31
 	Grid path option for VAMP grids
 
 2016-12-28
 	Alpha version of Recola OLP support
 
 2016-12-27
 	Dalitz plots for FKS phase space
 
 2016-12-14
 	NLO multi-flavor events possible
 
 2016-12-09
 	LCIO event header information added
 
 2016-12-02
 	Alpha version of RECOLA interface
 	Bug fix for generator status in LCIO
 
 ##################################################################
 
 2016-11-28
 	RELEASE: version 2.4.0
 
 2016-11-24
 	Bug fix for OpenLoops interface: EW scheme
 	   is set by WHIZARD
 	Bug fixes for top threshold implementation
 
 2016-11-11
 	Refactoring of dispatching
 
 2016-10-18
 	Bug fix for LCIO output
 
 2016-10-10
 	First implementation for collinear soft terms
 
 2016-10-06
 	First full WHIZARD models from UFO files
 
 2016-10-05
 	WHIZARD does not support legacy gcc 4.7.4 any longer
 
 2016-09-30
 	Major refactoring of process core and NLO components
 
 2016-09-23
 	WHIZARD homogeneous entity: discarding subconfigures
 	  for CIRCE1/2, O'Mega, VAMP subpackages; these are
 	  reconstructable by script projectors
 
 2016-09-06
 	Introduce main configure summary
 
 2016-08-26
 	Fix memory leak in event generation
 
 ##################################################################
 
 2016-08-25
 	RELEASE: version 2.3.1
 
 2016-08-19
 	Bug fix for EW-scheme dependence of gluino propagators
 
 2016-08-01
 	Beta version of complex mass scheme support
 
 2016-07-26
 	Fix bug in POWHEG damping for the matching
 
 ##################################################################
 
 2016-07-21
 	RELEASE: version 2.3.0
 
 2016-07-20
 	UFO file support (alpha version) in O'Mega
 
 2016-07-13
 	New (more) stable of WHIZARD GUI
 	Support for EW schemes for OpenLoops
 	Factorized NLO top decays for threshold model
 
 2016-06-15
 	Passing factorization scale to PYTHIA6
 	Adding charge and neutral observables
 
 2016-06-14
 	Correcting angular distribution/tweaked kinematics in
 	   non-collinear structure functions splittings
 
 2016-05-10
 	Include (Fortran) TAUOLA/PHOTOS for tau decays via PYTHIA6
 	   (backwards validation of LC CDR/TDR samples)
 
 2016-04-27
 	Within OpenLoops virtuals: support for Collier library
 
 2016-04-25
 	O'Mega vertex tables only loaded at first usage
 
 2016-04-21
 	New CJ15 PDF parameterizations added
 
 2016-04-21
 	Support for hadron collisions at NLO QCD
 
 2016-04-05
 	Support for different (parameter) schemes in model files
 
 2016-03-31
 	Correct transferral of lifetime/vertex from PYTHIA/TAUOLA
 	  into the event record
 
 2016-03-21
 	New internal implementation of polarization
 	  via Bloch vectors, remove pointer constructions
 
 2016-03-13
 	Extension of cascade syntax for processes:
 	  exclude propagators/vertices etc. possible
 
 2016-02-24
 	Full support for OpenLoops QCD NLO matrix
 	  elements, inclusion in test suite
 
 2016-02-12
 	Substantial progress on QCD NLO support
 
 2016-02-02
 	Automated resonance mapping for FKS subtraction
 
 2015-12-17
 	New BSM model WZW for diphoton resonances
 
 ##################################################################
 
 2015-11-22
 	RELEASE: version 2.2.8
 
 2015-11-21
 	Bug fix for fixed-order NLO events
 
 2015-11-20
 	Anomalous FCNC top-charm vertices
 
 2015-11-19
 	StdHEP output via HEPEVT/HEPEV4 supported
 
 2015-11-18
 	Full set of electroweak dim-6 operators included
 
 2015-10-22
 	Polarized one-loop amplitudes supported
 
 2015-10-21
 	Fixes for event formats for showered events
 
 2015-10-14
 	Callback mechanism for event output
 
 2015-09-22
 	Bypass matrix elements in pure event sample rescans
 	StdHep frozen final version v5.06.01 included internally
 
 2015-09-21
 	configure option --with-precision to
 	  demand 64bit, 80bit, or 128bit Fortran
 	  and bind C precision types
 
 2015-09-07
 	More extensive tests of NLO
 	   infrastructure and POWHEG matching
 
 2015-09-01
 	NLO decay infrastructure
 	User-defined squared matrix elements
 	Inclusive FastJet algorithm plugin
 	Numerical improvement for small boosts
 
 ##################################################################
 
 2015-08-11
 	RELEASE: version 2.2.7
 
 2015-08-10
 	Infrastructure for damped POWHEG
 	Massive emitters in POWHEG
 	Born matrix elements via BLHA
 	GoSam filters via SINDARIN
 	Minor running coupling bug fixes
 	Fixed-order NLO events
 
 2015-08-06
 	CT14 PDFs included (LO, NLO, NNLL)
 
 2015-07-07
 	Revalidation of ILC WHIZARD-PYTHIA event chain
 	Extended test suite for showered events
 	Alpha version of massive FSR for POWHEG
 
 2015-06-09
 	Fix memory leak in interaction for long cascades
 	Catch mismatch between beam definition and CIRCE2 spectrum
 
 2015-06-08
 	Automated POWHEG matching: beta version
 	Infrastructure for GKS matching
 	Alpha version of fixed-order NLO events
 	CIRCE2 polarization averaged spectra with
 	   explicitly polarized beams
 
 2015-05-12
 	Abstract matching type: OO structure for matching/merging
 
 2015-05-07
 	Bug fix in event record WHIZARD-PYTHIA6 transferral
 	Gaussian beam spectra for lepton colliders
 
 ##################################################################
 
 2015-05-02
 	RELEASE: version 2.2.6
 
 2015-05-01
 	Models for (unitarized) tensor resonances in VBS
 
 2015-04-28
 	Bug fix in channel weights for event generation.
 
 2015-04-18
 	Improved event record transfer WHIZARD/PYTHIA6
 
 2015-03-19
 	POWHEG matching: alpha version
 
 ##################################################################
 
 2015-02-27
 	RELEASE: version 2.2.5
 
 2015-02-26
 	Abstract types for quantum numbers
 
 2015-02-25
 	Read-in of StdHEP events, self-tests
 
 2015-02-22
 	Bug fix for mother-daughter relations in
 	   showered/hadronized events
 
 2015-02-20
 	Projection on polarization in intermediate states
 
 2015-02-13
 	Correct treatment of beam remnants in
 	   event formats (also LC remnants)
 
 ##################################################################
 
 2015-02-06
 	RELEASE: version 2.2.4
 
 2015-02-06
 	Bug fix in event output
 
 2015-02-05
 	LCIO event format supported
 
 2015-01-30
 	Including state matrices in WHIZARD's internal IO
 	Versioning for WHIZARD's internal IO
 	Libtool update from 2.4.3 to 2.4.5
 	LCIO event output (beta version)
 
 2015-01-27
 	Progress on NLO integration
 	Fixing a bug for multiple processes in a single
 	   event file when using beam event files
 
 2015-01-19
 	Bug fix for spin correlations evaluated in the rest
 	   frame of the mother particle
 
 2015-01-17
 	Regression fix for statically linked processes
 	   from SARAH and FeynRules
 
 2015-01-10
 	NLO: massive FKS emitters supported (experimental)
 
 2015-01-06
 	MMHT2014 PDF sets included
 
 2015-01-05
 	Handling mass degeneracies in auto_decays
 
 2014-12-19
 	Fixing bug in rescan of event files
 
 ##################################################################
 
 2014-11-30
 	RELEASE: version 2.2.3
 
 2014-11-29
 	Beta version of LO continuum/NLL-threshold
 	matched top threshold model for e+e- physics
 
 2014-11-28
 	More internal refactoring: disentanglement of module
 	   dependencies
 
 2014-11-21
 	OVM: O'Mega Virtual Machine, bytecode instructions
 	   instead of compiled Fortran code
 
 2014-11-01
 	Higgs Singlet extension model included
 
 2014-10-18
 	Internal restructuring of code; half-way
 	  WHIZARD main code file disassembled
 
 2014-07-09
 	Alpha version of NLO infrastructure
 
 ##################################################################
 
 2014-07-06
 	RELEASE: version 2.2.2
 
 2014-07-05
 	CIRCE2: correlated LC beam spectra and
 	  GuineaPig Interface to LC machine parameters
 
 2014-07-01
 	Reading LHEF for decayed/factorized/showered/
 	   hadronized events
 
 2014-06-25
 	Configure support for GoSAM/Ninja/Form/QGraf
 
 2014-06-22
 	LHAPDF6 interface
 
 2014-06-18
 	Module for automatic generation of
 	  radiation and loop infrastructure code
 
 2014-06-11
 	Improved internal directory structure
 
 ##################################################################
 
 2014-06-03
 	RELEASE: version 2.2.1
 
 2014-05-30
 	Extensions of internal PDG arrays
 
 2014-05-26
 	FastJet interface
 
 2014-05-24
 	CJ12 PDFs included
 
 2014-05-20
 	Regression fix for external models (via SARAH
 	    or FeynRules)
 
 ##################################################################
 
 2014-05-18
 	RELEASE: version 2.2.0
 
 2014-04-11
 	Multiple components: inclusive process definitions,
 	   syntax: process A + B + ...
 
 2014-03-13
 	Improved PS mappings for e+e- ISR
 	ILC TDR and CLIC spectra included in CIRCE1
 
 2014-02-23
 	New models: AltH w\ Higgs for exclusion purposes,
 	  SM_rx for Dim 6-/Dim-8 operators, SSC for
 	  general strong interactions (w/ Higgs), and
 	  NoH_rx (w\ Higgs)
 
 2014-02-14
 	Improved s-channel mapping, new on-shell
 	  production mapping (e.g. Drell-Yan)
 
 2014-02-03
 	PRE-RELEASE: version 2.2.0_beta
 
 2014-01-26
 	O'Mega: Feynman diagram generation possible (again)
 
 2013-12-16
 	HOPPET interface for b parton matching
 
 2013-11-15
 	PRE-RELEASE: version 2.2.0_alpha-4
 
 2013-10-27
 	LHEF standards 1.0/2.0/3.0 implemented
 
 2013-10-15
 	PRE-RELEASE: version 2.2.0_alpha-3
 
 2013-10-02
 	PRE-RELEASE: version 2.2.0_alpha-2
 
 2013-09-25
 	PRE-RELEASE: version 2.2.0_alpha-1
 
 2013-09-12
 	PRE-RELEASE: version 2.2.0_alpha
 
 2013-09-03
 	General 2HDM implemented
 
 2013-08-18
 	Rescanning/recalculating events
 
 2013-06-07
 	Reconstruction of complete event
 	  from 4-momenta possible
 
 2013-05-06
 	Process library stacks
 
 2013-05-02
 	Process stacks
 
 2013-04-29
 	Single-particle phase space module
 
 2013-04-26
 	Abstract interface for random
 	  number generator
 
 2013-04-24
 	More object-orientation on modules
 	Midpoint-rule integrator
 
 2013-04-05
 	Object-oriented integration and
 	  event generation
 
 2013-03-12
 	Processes recasted object-oriented:
 	  MEs, scales, structure functions
 	First infrastructure for general Lorentz
 	  structures
 
 2013-01-17
 	Object-orientated reworking of library and
 	   process core, more variable internal structure,
 	   unit tests
 
 2012-12-14
 	Update Pythia version to 6.4.27
 
 2012-12-04
 	Fix the phase in HAZ vertices
 
 2012-11-21
 	First O'Mega unit tests, some infrastructure
 
 2012-11-13
 	Bug fix in anom. HVV Lorentz structures
 
 ##################################################################
 
 2012-09-18
 	RELEASE: version 2.1.1
 
 2012-09-11
 	Model MSSM_Hgg with Hgg and HAA vertices
 
 2012-09-10
 	First version of implementation of multiple
 	   interactions in WHIZARD
 
 2012-09-05
 	Infrastructure for internal CKKW matching
 
 2012-09-02
 	C, C++, Python API
 
 2012-07-19
 	Fixing particle numbering in HepMC format
 
 ##################################################################
 
 2012-06-15
 	RELEASE: version 2.1.0
 
 2012-06-14
 	Analytical and kT-ordered shower officially
 	  released
 	PYTHIA interface officially released
 
 2012-05-09
 	Intrisince PDFs can be used for showering
 
 2012-05-04
 	Anomalous Higgs couplings a la hep-ph/9902321
 
 ##################################################################
 
 2012-03-19
 	RELEASE: version 2.0.7
 
 2012-03-15
 	Run IDs are available now
 	More event variables in analysis
 	Modified raw event format (compatibility mode exists)
 
 2012-03-12
 	Bug fix in decay-integration order
 	MLM matching steered completely internally now
 
 2012-03-09
 	Special phase space mapping for narrow resonances
 	  decaying to 4-particle final states with far off-shell
 	  intermediate states
 	Running alphas from PDF collaborations with
 	  builtin PDFs
 
 2012-02-16
 	Bug fix in cascades decay infrastructure
 
 2012-02-04
 	WHIZARD documentation compatible with TeXLive 2011
 
 2012-02-01
 	Bug fix in FeynRules interface with --prefix flag
 
 2012-01-29
 	Bug fix with name clash of O'Mega variable names
 
 2012-01-27
 	Update internal PYTHIA to version 6.4.26
 	Bug fix in LHEF output
 
 2012-01-21
 	Catching stricter automake 1.11.2 rules
 
 2011-12-23
 	Bug fix in decay cascade setup
 
 2011-12-20
 	Bug fix in helicity selection rules
 
 2011-12-16
 	Accuracy goal reimplemented
 
 2011-12-14
 	WHIZARD compatible with TeXLive 2011
 
 2011-12-09
 	Option --user-target added
 
 ##################################################################
 
 2011-12-07
 	RELEASE: version 2.0.6
 
 2011-12-07
 	Bug fixes in SM_top_anom
 	Added missing entries to HepMC format
 
 2011-12-06
 	Allow to pass options to O'Mega
 	Bug fix for HEPEVT block for showered/hadronized events
 
 2011-12-01
 	Reenabled user plug-in for external code for
 	   cuts, structure functions, routines etc.
 
 2011-11-29
 	Changed model SM_Higgs for Higgs phenomenology
 
 2011-11-25
 	Supporting a Y, (B-L) Z' model
 
 2011-11-23
 	Make WHIZARD compatible for MAC OS X Lion/XCode 4
 
 2011-09-25
 	WHIZARD paper published: Eur.Phys.J. C71 (2011) 1742
 
 2011-08-16
 	Model SM_QCD: QCD with one EW insertion
 
 2011-07-19
 	Explicit output channel for dvips avoids printing
 
 2011-07-10
 	Test suite for WHIZARD unit tests
 
 2011-07-01
 	Commands for matrix element tests
 	More OpenMP parallelization of kinematics
 	Added unit tests
 
 2011-06-23
 	Conversion of CIRCE2 from F77 to F90, major
 	  clean-up
 
 2011-06-14
 	Conversion of CIRCE1 from F77 to F90
 
 2011-06-10
 	OpenMP parallelization of channel kinematics
 		(by Matthias Trudewind)
 
 2011-05-31
 	RELEASE: version 1.97
 
 2011-05-24
 	Minor bug fixes: update grids and elsif statement.
 
 ##################################################################
 
 2011-05-10
 	RELEASE: version 2.0.5
 
 2011-05-09
 	Fixed bug in final state flavor sums
 	Minor improvements on phase-space setup
 
 2011-05-05
 	Minor bug fixes
 
 2011-04-15
 	WHIZARD as a precompiled 64-bit binary available
 
 2011-04-06
 	Wall clock instead of cpu time for time estimates
 
 2011-04-05
 	Major improvement on the phase space setup
 
 2011-04-02
 	OpenMP parallelization for helicity loop in O'Mega
 	   matrix elements
 
 2011-03-31
 	Tools for relocating WHIZARD and use in batch
 	environments
 
 2011-03-29
 	Completely static builds possible, profiling options
 
 2011-03-28
 	Visualization of integration history
 
 2011-03-27
 	Fixed broken K-matrix implementation
 
 2011-03-23
 	Including the GAMELAN manual in the distribution
 
 2011-01-26
 	WHIZARD analysis can handle hadronized event files
 
 2011-01-17
 	MSTW2008 and CT10 PDF sets included
 
 2010-12-23
 	Inclusion of NMSSM with Hgg couplings
 
 2010-12-21
 	Advanced options for integration passes
 
 2010-11-16
 	WHIZARD supports CTEQ6 and possibly other PDFs
 	directly; data files included in the distribution
 
 ##################################################################
 
 2010-10-26
 	RELEASE: version 2.0.4
 
 2010-10-06
 	Bug fix in MSSM implementation
 
 2010-10-01
 	Update to libtool 2.4
 
 2010-09-29
 	Support for anomalous top couplings (form factors etc.)
 	Bug fix for running gauge Yukawa SUSY couplings
 
 2010-09-28
 	RELEASE: version 1.96
 
 2010-09-21
 	Beam remnants and pT spectra for lepton collider re-enabled
 	Restructuring subevt class
 
 2010-09-16
 	Shower and matching are disabled by default
 	PYTHIA as a conditional on these two options
 
 2010-09-14
 	Possibility to read in beam spectra re-enabled (e.g. Guinea
 	   Pig)
 
 2010-09-13
 	Energy scan as (pseudo-) structure functions re-implemented
 
 2010-09-10
 	CIRCE2 included again in WHIZARD 2 and validated
 
 2010-09-02
 	Re-implementation of asymmetric beam energies and collision
 	  angles, e-p collisions work, inclusion of a HERA DIS test
 	  case
 
 ##################################################################
 
 2010-10-18
 	RELEASE: version 2.0.3
 
 2010-08-08
 	Bug in CP-violating anomalous triple TGCs fixed
 
 2010-08-06
 	Solving backwards compatibility problem with O'Caml 3.12.0
 
 2010-07-12
 	Conserved quantum numbers speed up O'Mega code generation
 
 2010-07-07
 	Attaching full ISR/FSR parton shower and MPI/ISR
 	   module
 	Added SM model containing Hgg, HAA, HAZ vertices
 
 2010-07-02
 	Matching output available as LHEF and STDHEP
 
 2010-06-30
 	Various bug fixes, missing files, typos
 
 2010-06-26
 	CIRCE1 completely re-enabled
 	Chaining structure functions supported
 
 2010-06-25
 	Partial support for conserved quantum numbers in
 	   O'Mega
 
 2010-06-21
 	Major upgrade of the graphics package: error bars,
 	   smarter SINDARIN steering, documentation, and all that...
 
 2010-06-17
 	MLM matching with PYTHIA shower included
 
 2010-06-16
 	Added full CIRCE1 and CIRCE2 versions including
 	full documentation and miscellanea to the trunk
 
 2010-06-12
 	User file management supported, improved variable
 	and command structure
 
 2010-05-24
 	Improved handling of variables in local command lists
 
 2010-05-20
 	PYTHIA interface re-enabled
 
 2010-05-19
 	ASCII file formats for interfacing ROOT and gnuplot in
 	   data analysis
 
 ##################################################################
 
 2010-05-18
 	RELEASE: version 2.0.2
 
 2010-05-14
 	Reimplementation of visualization of phase space
 	   channels
 	Minor bug fixes
 
 2010-05-12
 	Improved phase space - elimination of redundancies
 
 2010-05-08
 	Interface for polarization completed: polarized beams etc.
 
 2010-05-06
 	Full quantum numbers appear in process log
 	Integration results are usable as user variables
 	Communication with external programs
 
 2010-05-05
 	Split module commands into commands, integration,
 	   simulation modules
 
 2010-05-04
 	FSR+ISR for the first time connected to the WHIZARD 2 core
 
 ##################################################################
 
 2010-04-25
 	RELEASE: version 2.0.1
 
 2010-04-23
 	Automatic compile and integrate if simulate is called
 	Minor bug fixes in O'Mega
 
 2010-04-21
 	Checkpointing for event generation
 	Flush statements to use WHIZARD inside a pipe
 
 2010-04-20
 	Reimplementation of signal handling in WGIZARD 2.0
 
 2010-04-19
 	VAMP is now a separately configurable and installable unit of
 	   WHIZARD, included VAMP self-checks
 	Support again compilation in quadruple precision
 
 2010-04-06
 	Allow for logarithmic plots in GAMELAN, reimplement the
 	   possibility to set the number of bins
 
 2010-04-15
 	Improvement on time estimates for event generation
 
 ##################################################################
 
 2010-04-12
 	RELEASE: version 2.0.0
 
 2010-04-09
 	Per default, the code for the amplitudes is subdivided to allow
 	  faster compiler optimization
 	More advanced and unified and straightforward command language
 	  syntax
 	Final bug fixes
 
 2010-04-07
 	Improvement on SINDARIN syntax; printf, sprintf function
 	  thorugh a C interface
 
 2010-04-05
 	Colorizing DAGs instead of model vertices: speed boost
 	  in colored code generation
 
 2010-03-31
 	Generalized options for normalization of weighted and
 	  unweighted events
 	Grid and weight histories added again to log files
 	Weights can be used in analyses
 
 2010-03-28
 	Cascade decays completely implemented including color and
 	   spin correlations
 
 2010-03-07
 	Added new WHIZARD header with logo
 
 2010-03-05
 	Removed conflict in O'Mega amplitudes between flavour sums
 	   and cascades
 	StdHEP interface re-implemented
 
 2010-03-03
 	RELEASE: version 2.0.0rc3
 	Several bug fixes for preventing abuse in input files
 	OpenMP support for amplitudes
 	Reimplementation of WHIZARD 1 HEPEVT ASCII event formats
 	FeynRules interface successfully passed MSSM test
 
 2010-02-26
 	Eliminating ghost gluons from multi-gluon amplitudes
 
 2010-02-25
 	RELEASE: version 1.95
 	HEPEVT format from WHIZARD 1 re-implemented in WHIZARD 2
 
 2010-02-23
 	Running alpha_s implemented in the FeynRules interface
 
 2010-02-19
 	MSSM (semi-) automatized self-tests finalized
 
 2010-02-17
 	RELEASE: version 1.94
 
 2010-02-16
 	Closed memory corruption in WHIZARD 1
 	Fixed problems of old MadGraph and CompHep drivers
 	   with modern compilers
 	Uncolored vertex selection rules for colored amplitudes in
 	   O'Mega
 
 2010-02-15
 	Infrastructure for color correlation computation in O'Mega
 	   finished
 	Forbidden processes are warned about, but treated as non-fatal
 
 2010-02-14
 	Color correlation computation in O'Mega finalized
 
 2010-02-10
 	Improving phase space mappings for identical particles in
 	initial and final states
 	Introduction of more extended multi-line error message
 
 2010-02-08
 	First O'Caml code for computation of color correlations in
 	O'Mega
 
 2010-02-07
 	First MLM matching with e+ e- -> jets
 
 ##################################################################
 
 2010-02-06
 	RELEASE: version 2.0.0rc2
 
 2010-02-05
 	Reconsidered the Makefile structure and more extended tests
 	Catch a crash between WHIZARD and O'Mega for forbidden processes
 	Tensor products of arbitrary color structures in jet definitions
 
 2010-02-04
 	Color correlation computation in O'Mega finalized
 
 ##################################################################
 
 2010-02-03
 	RELEASE: version 2.0.0rc1
 
 ##################################################################
 
 2010-01-31
 	Reimplemented numerical helicity selection rules
 	Phase space functionality of version 1 restored and improved
 
 2009-12-05
 	NMSSM validated with FeynRules in WHIZARD 1 (Felix Braam)
 
 2009-12-04
 	RELEASE: version 2.0.0alpha
 
 ##################################################################
 
 2009-04-16
 	RELEASE: version 1.93
 
 2009-04-15
 	Clean-up of Makefiles and configure scripts
 	Reconfiguration of BSM model implementation
 	extended supersymmetric models
 
 2008-12-23
 	New model NMSSM	(Felix Braam)
 	SLHA2 added
 	Bug in LHAPDF interface fixed
 
 2008-08-16
 	Bug fixed in K matrix implementation
 	Gravitino option in the MSSM added
 
 2008-03-20
 	Improved color and flavor sums
 
 ##################################################################
 
 2008-03-12
 	RELEASE: version 1.92
 	LHEF (Les Houches Event File) format added
 	Fortran 2003 command-line interface (if supported by the compiler)
 	Automated interface to colored models
 	More bug fixes and workarounds for compiler compatibility
 
 ##################################################################
 
 2008-03-06
 	RELEASE: version 1.91
 	New model K-matrix (resonances and anom. couplings in WW scattering)
 	EWA spectrum
 	Energy-scan pseudo spectrum
 	Preliminary parton shower module (only from final-state quarks)
 	Cleanup and improvements of configure process
 	Improvements for O'Mega parameter files
 	Quadruple precision works again
 	More plotting options: lines, symbols, errors
 	Documentation with PDF bookmarks enabled
 	Various bug fixes
 
 2007-11-29
 	New model UED
 
 ##################################################################
 
 2007-11-23
 	RELEASE: version 1.90
 	O'Mega now part of the WHIZARD tree
 	Madgraph/CompHEP disabled by default (but still usable)
 	Support for LHAPDF (preliminary)
 	Added new models: SMZprime, SM_km, Template
 	Improved compiler recognition and compatibility
 	Minor bug fixes
 
 ##################################################################
 
 2006-06-15
 	RELEASE: version 1.51
 	Support for anomaly-type Higgs couplings (to gluon and photon/Z)
 	Support for spin 3/2 and spin 2
 	New models: Little Higgs (4 versions), toy models for extra dimensions
           and gravitinos
 	Fixes to the whizard.nw source documentation to run through LaTeX
 	Intel 9.0 bug workaround (deallocation of some arrays)
 
 2006-05-15
 	O'Mega RELEASE: version 0.11
 	merged JRR's O'Mega extensions
 
 ##################################################################
 
 2006-02-07
 	RELEASE: version 1.50
         To avoid confusion: Mention outdated manual example in BUGS file
         O'Mega becomes part of the WHIZARD generator
 
 2006-02-02   [bug fix update]
 	Bug fix: spurious error when writing event files for weighted events
 	Bug fix: 'r' option for omega produced garbage for some particle names
 	Workaround for ifort90 bug (crash when compiling whizard_event)
 	Workaround for ifort90 bug (crash when compiling hepevt_common)
 
 2006-01-27
 	Added process definition files for MSSM 2->2 processes
 	Included beam recoil for EPA (T.Barklow)
 	Updated STDHEP byte counts (for STDHEP 5.04.02)
 	Fixed STDHEP compatibility (avoid linking of incomplete .so libs)
 	Fixed issue with comphep requiring Xlibs on Opteron
 	Fixed issue with ifort 8.x on Opteron (compiling 'signal' interface)
 	Fixed color-flow code: was broken for omega with option 'c' and 'w'
 	Workaround hacks for g95 compatibility
 
 2005-11-07
 	O'Mega RELEASE: version 0.10
 	O'Mega, merged JRR's and WK's color hack for WHiZard
         O'Mega, EXPERIMENTAL: cache fusion tables (required for colors
 	  a la JRR/WK)
         O'Mega, make JRR's MSSM official
 
 ##################################################################
 
 2005-10-25
 	RELEASE: version 1.43
 	Minor fixes in MSSM couplings (Higgs/3rd gen squarks).
 	  This should be final, since the MSSM results agree now completely
           with Madgraph and Sherpa
 	User-defined lower and upper limits for split event file count
 	Allow for counters (events, bytes) exceeding $2^{31}$
 	Revised checksum treatment and implementation (now MD5)
         Bug fix: missing process energy scale in raw event file
 
 ##################################################################
 
 2005-09-30
 	RELEASE: version 1.42
 	Graphical display of integration history ('make history')
 	Allow for switching off signals even if supported (configure option)
 
 2005-09-29
 	Revised phase space generation code, in particular for flavor sums
 	Negative cut and histogram codes use initial beams instead of
 	  initial parton momenta.  This allows for computing, e.g., E_miss
 	Support constant-width and zero-width options for O'Mega
 	Width options now denoted by w:X (X=f,c,z).  f option obsolescent
 	Bug fix: colorized code: flipped indices could screw up result
 	Bug fix: O'Mega with 'c' and 'w:f' option together (still some problem)
 	Bug fix: dvips on systems where dvips defaults to lpr
 	Bug fix: integer overflow if too many events are requested
 
 2005-07-29
 	Allow for 2 -> 1 processes (if structure functions are on)
 
 2005-07-26
 	Fixed and expanded the 'test' matrix element:
 	  Unit matrix element with option 'u' / default: normalized phase space
 
 ##################################################################
 
 2005-07-15
 	RELEASE: version 1.41
 	Bug fix: no result for particle decay processes with width=0
 	Bug fix: line breaks in O'Mega files with color decomposition
 
 2005-06-02
 	New self-tests (make test-QED / test-QCD / test-SM)
 	  check lists of 2->2 processes
 	Bug fix: HELAS calling convention for wwwwxx and jwwwxx (4W-Vertex)
 
 2005-05-25
 	Revised Makefile structure
 	Eliminated obsolete references to ISAJET/SUSY (superseded by SLHA)
 
 2005-05-19
 	Support for color in O'Mega (using color flow decomposition)
 	New model QCD
 	Parameter file changes that correspond to replaced SM module in O'Mega
 	Bug fixes in MSSM (O'Mega) parameter file
 
 2005-05-18
 	New event file formats, useful for LHC applications:
           ATHENA and Les Houches Accord (external fragmentation)
         Naive (i.e., leading 1/N) color factor now implemented both for
           incoming and outgoing partons
 
 2005-01-26
 	include missing HELAS files for bundle
 	pgf90 compatibility issues [note: still internal error in pgf90]
 
 ##################################################################
 
 2004-12-13
 	RELEASE: version 1.40
 	compatibility fix: preprocessor marks in helas code now commented out
 	minor bug fix: format string in madgraph source
 
 2004-12-03
 	support for arbitray beam energies and directions
 	allow for pT kick in structure functions
 	bug fix: rounding error could result in zero cross section
 	  (compiler-dependent)
 
 2004-10-07
 	simulate decay processes
 	list fraction (of total width/cross section) instead of efficiency
           in process summary
 	new cut/analysis parameters AA, AAD, CTA: absolute polar angle
 
 2004-10-04
 	Replaced Madgraph I by Madgraph II.  Main improvement: model no
           longer hardcoded
 	introduced parameter reset_seed_each_process (useful for debugging)
         bug fix: color initialization for some processes was undefined
 
 2004-09-21
 	don't compile unix_args module if it is not required
 
 ##################################################################
 
 2004-09-20
 	RELEASE: version 1.30
 	g95 compatibility issues resolved
 	some (irrelevant) memory leaks closed
 	removed obsolete warning in circe1
 	manual update (essentially) finished
 
 2004-08-03
 	O'Mega RELEASE: version 0.9
 	O'Mega, src/trie.mli, src/trie.ml: make interface compatible with
           the O'Caml 3.08 library (remains compatible with older
           versions).  Implementation of unused functions still
           incomplete.
 
 2004-07-26
 	minor fixes and improvements in make process
 
 2004-06-29
 	workarounds for new Intel compiler bugs ...
 	no rebuild of madgraph/comphep executables after 'make clean'
 	bug fix in phase space routine:
           wrong energy for massive initial particles
         bug fix in (new) model interface: name checks for antiparticles
         pre-run checks for comphep improved
         ww-strong model file extended
         Model files particle name fixes, chep SM vertices included
 
 2004-06-22
 	O'Mega RELEASE: version 0.8
 	O'Mega MSSM: sign of W+/W-/A and W+/W-/Z couplings
 
 2004-05-05
 	Fixed bug in PDFLIB interface: p+pbar was initialized as p+p (ThO)
 	NAG compiler: set number of continuation lines to 200 as default
 	Extended format for cross section summary; appears now in whizard.out
 	Fixed 'bundle' feature
 
 2004-04-28
 	Fixed compatibility with revised O'Mega SM_ac model
 	Fixed problem with x=0 or x=1 when calling PDFLIB (ThO)
 	Fixed bug in comphep module: Vtb was overlooked
 
 ##################################################################
 
 2004-04-15
 	RELEASE: version 1.28
         Fixed bug: Color factor was missing for O'Mega processes with
           four quarks and more
         Manual partially updated
 
 2004-04-08
 	Support for grid files in binary format
 	New default value show_histories=F (reduce output file size)
 	Revised phase space switches: removed annihilation_lines,
 	  removed s_channel_resonance, changed meaning of
 	  extra_off_shell_lines, added show_deleted_channels
 	Bug fixed which lead to omission of some phase space channels
 	Color flow guessed only if requested by guess_color_flow
 
 2004-03-10
 	New model interface: Only one model name specified in whizard.prc
         All model-dependent files reside in conf/models (modellib removed)
 
 2004-03-03
 	Support for input/output in SUSY Les Houches Accord format
 	Split event files if requested
 	Support for overall time limit
 	Support for CIRCE and CIRCE2 generator mode
 	Support for reading beam events from file
 
 2004-02-05
 	Fixed compiler problems with Intel Fortran 7.1 and 8.0
 	Support for catching signals
 
 ##################################################################
 
 2003-08-06
 	RELEASE: version 1.27
 	User-defined PDF libraries as an alternative to the standard PDFLIB
 
 2003-07-23
 	Revised phase space module: improved mappings for massless particles,
 	  equivalences of phase space channels are exploited
 	Improved mapping for PDF (hadron colliders)
 	Madgraph module: increased max number of color flows from 250 to 1000
 
 ##################################################################
 
 2003-06-23
 	RELEASE: version 1.26
 	CIRCE2 support
 	Fixed problem with 'TC' integer kind [Intel compiler complained]
 
 2003-05-28
 	Support for drawing histograms of grids
 	Bug fixes for MSSM definitions
 
 ##################################################################
 
 2003-05-22
 	RELEASE: version 1.25
 	Experimental MSSM support with ISAJET interface
 	Improved capabilities of generating/analyzing weighted events
 	Optional drawing phase space diagrams using FeynMF
 
 ##################################################################
 
 2003-01-31
 	RELEASE: version 1.24
 	A few more fixes and workarounds (Intel and Lahey compiler)
 
 2003-01-15
 	Fixes and workarounds needed for WHIZARD to run with Intel compiler
 	Command-line option interface for the Lahey compiler
 
 	Bug fix: problem with reading whizard.phs
 
 ##################################################################
 
 2002-12-10
 	RELEASE: version 1.23
 
 	Command-line options (on some systems)
 
 	Allow for initial particles in the event record, ordered:
           [beams, initials] - [remnants] - outgoing partons
 
 	Support for PYTHIA 6.2: Les Houches external process interface
 	String pythia_parameters can be up to 1000 characters long
 	Select color flow states in (internal) analysis
 	Bug fix in color flow content of raw event files
 
 	Support for transversal polarization of fermion beams
 	Cut codes: PHI now for absolute azimuthal angle, DPHI for distance
 	'Test' matrix elements optionally respect polarization
 
 	User-defined code can be inserted for spectra, structure functions
           and fragmentation
 
 	Time limits can be specified for adaptation and simulation
 	User-defined file names and file directory
         Initial weights in input file no longer supported
 
         Bug fix in MadGraph (wave function counter could overflow)
 
 	Bug fix: Gamelan (graphical analysis) was not built if noweb absent
 
 ##################################################################
 
 2002-03-16
 	RELEASE: version 1.22
 	Allow for beam remnants in the event record
 
 2002-03-01
         Handling of aliases in whizard.prc fixed (aliases are whole tokens)
 
 2002-02-28
 	Optimized phase space handling routines
 	  (total execution time reduced by 20-60%, depending on process)
 
 ##################################################################
 
 2002-02-26
 	RELEASE: version 1.21
 	Fixed ISR formula (ISR was underestimated in previous versions).
           New version includes ISR in leading-log approximation up to
           third order.  Parameter ISR_sqrts renamed to ISR_scale.
 
 ##################################################################
 
 2002-02-19
 	RELEASE: version 1.20
 	New process-generating method 'test' (dummy matrix element)
 	Compatibility with autoconf 2.50 and current O'Mega version
 
 2002-02-05
 	Prevent integration channels from being dropped (optionally)
 	New internal mapping for structure functions improves performance
 	Old whizard.phx file deleted after recompiling (could cause trouble)
 
 2002-01-24
 	Support for user-defined cuts and matrix element reweighting
 	STDHEP output now written by write_events_format=20 (was 3)
 
 2002-01-16
 	Improved structure function handling; small changes in user interface:
           new parameter structured_beams in &process_input
           parameter fixed_energy in &beam_input removed
 	Support for multiple initial states
 	Eta-phi (cone) cut possible (hadron collider applications)
 	Fixed bug: Whizard library was not always recompiled when necessary
 	Fixed bug: Default cuts were insufficient in some cases
 	Fixed bug: Unusable phase space mappings generated in some cases
 
 2001-12-06
 	Reorganized document source
 
 2001-12-05
 	Preliminary CIRCE2 support (no functionality yet)
 
 2001-11-27
 	Intel compiler support (does not yet work because of compiler bugs)
 	New cut and analysis mode cos-theta* and related
 	Fixed circular jetset_interface dependency warning
 	Some broadcast routines removed (parallel support disabled anyway)
 	Minor shifts in cleanup targets (Makefiles)
         Modified library search, check for pdflib8*
 
 2001-08-06
 	Fixed bug: I/O unit number could be undefined when reading phase space
 	Fixed bug: Unitialized variable could cause segfault when
                    event generation was disabled
 	Fixed bug: Undefined subroutine in CIRCE replacement module
 	Enabled feature: TGCs in O'Mega (not yet CompHEP!) matrix elements
 		   (CompHEP model sm-GF #5, O'Mega model SM_ac)
 	Fixed portability issue: Makefile did rely on PWD environment variable
 	Fixed portability issue: PYTHIA library search ambiguity resolved
 
 2001-08-01
 	Default whizard.prc and whizard.in depend on activated modules
 	Fixed bug: TEX=latex was not properly enabled when making plots
 
 2001-07-20
 	Fixed output settings in PERL script calls
 	Cache enabled in various configure checks
 
 2001-07-13
 	Support for multiple processes in a single WHIZARD run.  The
           integrations are kept separate, but the generated events are mixed
 	The whizard.evx format has changed (incompatible), including now
 	  the color flow information for PYTHIA fragmentation
 	Output files are now process-specific, except for the event file
 	Phase space file whizard.phs (if present) is used only as input,
 	  program-generated phase space is now in whizard.phx
 
 2001-07-10
 	Bug fix: Undefined parameters in parameters_SM_ac.f90 removed
 
 2001-07-04
 	Bug fix: Compiler options for the case OMEGA is disabled
 	Small inconsistencies in whizard.out format fixed
 
 2001-07-01
 	Workaround for missing PDFLIB dummy routines in PYTHIA library
 
 ##################################################################
 
 2001-06-30
 	RELEASE: version 1.13
 	Default path /cern/pro/lib in configure script
 
 2001-06-20
 	New fragmentation option: Interface for PYTHIA with full color flow
           information, beam remnants etc.
 
 2001-06-18
 	Severe bug fixed in madgraph interface: 3-gluon coupling was missing
 	Enabled color flow information in madgraph
 
 2001-06-11
 	VAMP interface module rewritten
 	Revised output format: Multiple VAMP iterations count as one WHIZARD
           iteration in integration passes 1 and 3
 	Improved message and error handling
 	Bug fix in VAMP: handle exceptional cases in rebinning_weights
 
 2001-05-31
 	new parameters for grid adaptation: accuracy_goal and efficiency_goal
 
 ##################################################################
 
 2001-05-29
 	RELEASE: version 1.12
 	bug fixes (compilation problems): deleted/modified unused functions
 
 2001-05-16
 	diagram selection improved and documented
 
 2001-05-06
         allow for disabling packages during configuration
 
 2001-05-03
 	slight changes in whizard.out format; manual extended
 
 ##################################################################
 
 2001-04-20
 	RELEASE: version 1.11
 	fixed some configuration and compilation problems (PDFLIB etc.)
 
 2001-04-18
 	linked PDFLIB: support for quark/gluon structure functions
 
 2001-04-05
 	parameter interface written by PERL script
 	SM_ac model file: fixed error in continuation line
 
 2001-03-13
 	O'Mega, O'Caml 3.01: incompatible changes
 	O'Mega, src/trie.mli: add covariance annotation to T.t
 	  This breaks O'Caml 3.00, but is required for O'Caml 3.01.
 	O'Mega, many instances: replace `sig include Module.T end' by
 	  `Module.T', since the bug is fixed in O'Caml 3.01
 
 2001-02-28
 	O'Mega, src/model.mli:
             new field Model.vertices required for model functors, will
 	    retire Model.fuse2, Model.fuse3, Model.fusen soon.
 
 ##################################################################
 
 2001-03-27
 	RELEASE: version 1.10
 	reorganized the modules as libraries
 	linked PYTHIA: support for parton fragmentation
 
 2000-12-14
 	fixed some configuration problems (if noweb etc. are absent)
 
 ##################################################################
 
 2000-12-01
 	RELEASE of first public version: version 1.00beta