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/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 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 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/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 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/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 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/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 3.1.2.1' @ <<[[implicit none]]>>= implicit none @ <<[[circe2.f90]]>>= ! circe2.f90 -- correlated beam spectra for linear colliders <> <> module circe2 use kinds implicit none private <<[[circe2]] parameters>> <<[[circe2]] declarations>> contains <<[[circe2]] implementation>> end module circe2 @ <>= !----------------------------------------------------------------------- @ 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: <>= ! Copyright (C) 2001-2023 by Thorsten Ohl ! ! 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 <> <> call circe2_generate_channel (c2s%ch(ic), rng, y) end subroutine circe2_generate_ph <> @ <<[[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) <> <<$[[ib]] \leftarrow [[i]]$>> <<$[[x]]\in[ [[x(ib-1)]], [[x(ib)]] ]$>> y = circe2_map (ch%d, x, ib) <> end subroutine circe2_generate_channel <> @ <<[[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. <>= 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 @ <>= 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. <>= 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} <>= if (ch%triang) then y(2) = y(1) * y(2) <> end if @ <>= 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 <> @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \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 <> 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 <> @ <<[[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 <> circe2_distribution_channel = & ch%val(ib(1),ib(2)) * product (circe2_jacobian (ch%d, y, ib)) <> end function circe2_distribution_channel <> @ 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} <>= 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 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 <> 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 <> @ <>= 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 <> @ <>= 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 <> <> if (lun < 0) then write (*, '(A)') 'circe2_load: no free unit' ierror = ESIZE return end if loaded = 0 <> if (ierror .gt. 0) then write (*, '(2A)') 'circe2_load: ', <> end if prefix = index (design, '*') - 1 do <> if (buffer(8:15) == 'FORMAT#1') then read (lun, *) read (lun, *) fdesgn, froots <> if (match .and. abs (froots - roots) <= 1) then <> loaded = loaded + 1 else <> cycle end if else write (*, '(2A)') 'circe2_load: invalid format: ', buffer(8:72) ierror = EFORMT return end if <> end do end subroutine circe2_load <> @ <>= 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 @ <>= read (lun, *) read (lun, *) nc, fpolsp allocate (c2s%ch(nc), c2s%cwgt(0:nc)) <> 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 <> <> <> <> end subroutine circe2_load_channel @ @ <>= 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 @ <>= integer :: ic, nc @ <>= read (lun, *) read (lun, *) ch%pid(1), ch%pol(1), ch%pid(2), ch%pol(2), ch%lumi <> @ <>= 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 @ <>= read (lun, *) read (lun, *) nb, ch%triang @ <>= 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} <>= 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}) <>= 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 @ <>= @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Auxiliary Code For Reading Files} <>= 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 @ <>= integer :: status @ The outer [[do]] loop is never repeated! <>= 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: do read (lun, *) buffer if (buffer(1:6) == 'ECRIC2') then exit skip_data end if end do skip_data @ <>= read (lun, '(A)') buffer if (buffer(1:6) /= 'ECRIC2') then write (*, '(A)') 'circe2_load: invalid file' ierror = EFORMT return end if @ <>= 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 @ <>= 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 <> 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 <> end program circe2_generate_program @ <>= call get_command_argument (1, value = filename, status = status) if (status /= 0) filename = "" @ <>= 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 @ <>= 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 @ <>= 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 +@ +<>= +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 +@ +<>= +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 @ <>= -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 @ <>= 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 <> <> 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 <> 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 <> <> else if (buffer(1:5) == 'pid1,') then read (lun, *) pid1, hel1, pid2, hel2, lumi <> end if end do lines end if close (unit = lun) end if end do files end program circe2_ls <> @ <>= 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 (*, '(4X,4(A5,2X),A)') & 'pid#1', 'hel#1', 'pid#2', 'hel#2', 'luminosity / (10^32cm^-2sec^-1)' @ <>= 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>= 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 <> <> do <> call rng%generate (u) if (w > u) exit end do end subroutine generate_beta @ %def generate_beta @ In fact, this algorithm works for~$0>= if (a >= 1 .or. b <= 1) then x = -1 print *, 'ERROR: beta-distribution expects a<1>= <> 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 \end{cases} \end{align} The beauty of the algorithm is that we can use a single uniform deviate~$u$ for both intervals: <>= 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 \end{cases} \end{align} We start with~$u_{\text{min}}$. For efficiency, we handle the most common cases (small~$x_{\text{min}}$) first: <>= 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: <>= 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. <>= 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>= 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 <>= 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 <> end function results_ok @ gfortran doesn't have the intrinsic [[ieee_arithmetic]] module yet \ldots <>= 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} <
>= 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]]>>= <
> @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \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/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/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 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 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/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 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/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 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/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 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 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/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