Index: /tags/V1_0/Cosmo/SimLSS/Makefile
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/Makefile	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/Makefile	(revision 3382)
@@ -0,0 +1,241 @@
+include $(SOPHYABASE)/include/sophyamake.inc
+#include ../BuildMgr/sophyamake.inc
+
+OBJ = ${CMVPROG}/obj/
+EXE = ${CMVPROG}/exe/
+LIB = ${CMVPROG}/lib/
+MACH = $(shell echo `uname`)
+ifeq ($(MACH),OSF1)
+CXXREP = -ptr $(OBJ)/CmvBAO_cxxrep/
+endif
+
+MYEXTINC = ${EXTLIBDIR}/Include
+#MYLIB = $(SOPHYAEXTSLBLIST) -L$(LIB) -lcmvsimbao -lfftw3 -lm
+MYLIB = $(SOPHYAEXTSLBLIST) -L$(LIB) -lcmvsimbao -lfftw3_threads -lfftw3 -lm
+
+#--------------------------------------------------------------------------
+# ---- Les programmes de simulation
+PROGS = \
+       $(EXE)cmvtuniv $(EXE)cmvtransf $(EXE)cmvtgrowth $(EXE)cmvtstpk \
+       $(EXE)cmvtstsch $(EXE)cmvtstblack $(EXE)cmvtvarspec \
+       $(EXE)cmvdefsurv $(EXE)cmvobserv3d $(EXE)cmvtintfun \
+       $(EXE)cmvconcherr $(EXE)cmvtinterp $(EXE)cmvtstagn $(EXE)cmvschdist
+#$(EXE)cmvtluc
+ 
+PROGSOBJ = \
+          $(OBJ)cmvtuniv.o $(OBJ)cmvtransf.o $(OBJ)cmvtgrowth.o $(OBJ)cmvtstpk.o \
+          $(OBJ)cmvtstsch.o $(OBJ)cmvtstblack.o $(OBJ)cmvtvarspec.o $(OBJ)cmvdefsurv.o \
+          $(OBJ)cmvobserv3d.o $(OBJ)cmvtintfun.o $(OBJ)cmvtinterp.o \
+          $(OBJ)cmvconcherr.o $(OBJ)cmvtluc.o $(OBJ)cmvtstagn.o $(OBJ)cmvschdist.o
+ 
+LIBROBJ = \
+          $(OBJ)cosmocalc.o $(OBJ)pkspectrum.o $(OBJ)schechter.o \
+          $(OBJ)planckspectra.o $(OBJ)geneutils.o $(OBJ)agnjackson.o \
+          $(OBJ)genefluct3d.o
+
+LIBR = $(LIB)libcmvsimbao.a
+
+#--------------------------------------------------------------------------
+# ---- Les programmes de test
+PROGSTEST = \
+        $(EXE)cmvtluc $(EXE)cmvchkwhu $(EXE)hu_sigma8
+
+PROGSTESTOBJ = \
+        $(OBJ)hu_tf_fit.o $(OBJ)hu_power.o \
+        $(OBJ)cmvtluc.o $(OBJ)cmvchkwhu.o $(OBJ)hu_sigma8.o
+
+#--------------------------------------------------------------------------
+#---- Les programmes utilisant des librairies non standard SOPHYA
+SPROGS = \
+       $(EXE)cmvfitpk
+
+SPROGSOBJ = \
+       $(OBJ)cmvfitpk.o
+
+#----
+all: lib prog
+
+lib: $(LIBR)
+
+prog: $(PROGS)
+
+progtest: $(PROGSTEST)
+
+sprog: $(SPROGS)
+
+allprog: all progtest sprog
+
+clean:
+	rm -f *.o
+	rm -f $(PROGS) $(PROGSOBJ)
+	rm -f $(LIBR) $(LIBROBJ)
+	rm -rf $(OBJ)/CmvBAO_cxxrep/
+	rm -f $(PROGSTEST) $(PROGSTESTOBJ)
+	rm -f $(SPROGS) $(SPROGSOBJ)
+
+##############################################################################
+$(LIB)libcmvsimbao.a : $(LIBROBJ)
+	$(AR) $(ARFLAGS) $@ $? 
+
+$(OBJ)cosmocalc.o: cosmocalc.cc cosmocalc.h constcosmo.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cosmocalc.cc
+$(OBJ)schechter.o: schechter.cc schechter.h constcosmo.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ schechter.cc
+$(OBJ)planckspectra.o: planckspectra.cc planckspectra.h constcosmo.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ planckspectra.cc
+$(OBJ)pkspectrum.o: pkspectrum.cc pkspectrum.h constcosmo.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ pkspectrum.cc
+$(OBJ)geneutils.o: geneutils.cc geneutils.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ geneutils.cc
+$(OBJ)agnjackson.o: agnjackson.cc agnjackson.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ agnjackson.cc
+$(OBJ)genefluct3d.o: genefluct3d.cc genefluct3d.h
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ genefluct3d.cc
+
+##############################################################################
+cmvtuniv: $(EXE)cmvtuniv
+	echo $@ " done"
+$(EXE)cmvtuniv: $(OBJ)cmvtuniv.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtuniv.o $(MYLIB) 
+$(OBJ)cmvtuniv.o: cmvtuniv.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtuniv.cc
+
+##############################################################################
+cmvtransf: $(EXE)cmvtransf
+	echo $@ " done"
+$(EXE)cmvtransf: $(OBJ)cmvtransf.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtransf.o $(MYLIB) 
+$(OBJ)cmvtransf.o: cmvtransf.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtransf.cc
+
+##############################################################################
+cmvtgrowth: $(EXE)cmvtgrowth
+	echo $@ " done"
+$(EXE)cmvtgrowth: $(OBJ)cmvtgrowth.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtgrowth.o $(MYLIB) 
+$(OBJ)cmvtgrowth.o: cmvtgrowth.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtgrowth.cc
+
+##############################################################################
+cmvtstpk: $(EXE)cmvtstpk
+	echo $@ " done"
+$(EXE)cmvtstpk: $(OBJ)cmvtstpk.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtstpk.o $(MYLIB) 
+$(OBJ)cmvtstpk.o: cmvtstpk.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtstpk.cc
+
+##############################################################################
+cmvtstsch: $(EXE)cmvtstsch
+	echo $@ " done"
+$(EXE)cmvtstsch: $(OBJ)cmvtstsch.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtstsch.o $(MYLIB) 
+$(OBJ)cmvtstsch.o: cmvtstsch.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtstsch.cc
+
+##############################################################################
+cmvtstblack: $(EXE)cmvtstblack
+	echo $@ " done"
+$(EXE)cmvtstblack: $(OBJ)cmvtstblack.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtstblack.o $(MYLIB) 
+$(OBJ)cmvtstblack.o: cmvtstblack.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtstblack.cc
+
+##############################################################################
+cmvtvarspec: $(EXE)cmvtvarspec
+	echo $@ " done"
+$(EXE)cmvtvarspec: $(OBJ)cmvtvarspec.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtvarspec.o $(MYLIB) 
+$(OBJ)cmvtvarspec.o: cmvtvarspec.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtvarspec.cc
+
+##############################################################################
+cmvdefsurv: $(EXE)cmvdefsurv
+	echo $@ " done"
+$(EXE)cmvdefsurv: $(OBJ)cmvdefsurv.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvdefsurv.o $(MYLIB) 
+$(OBJ)cmvdefsurv.o: cmvdefsurv.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvdefsurv.cc
+
+##############################################################################
+cmvobserv3d: $(EXE)cmvobserv3d
+	echo $@ " done"
+$(EXE)cmvobserv3d: $(OBJ)cmvobserv3d.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvobserv3d.o $(MYLIB) 
+$(OBJ)cmvobserv3d.o: cmvobserv3d.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvobserv3d.cc
+
+##############################################################################
+cmvtintfun: $(EXE)cmvtintfun
+	echo $@ " done"
+$(EXE)cmvtintfun: $(OBJ)cmvtintfun.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtintfun.o $(MYLIB) 
+$(OBJ)cmvtintfun.o: cmvtintfun.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtintfun.cc
+
+##############################################################################
+cmvconcherr: $(EXE)cmvconcherr
+	echo $@ " done"
+$(EXE)cmvconcherr: $(OBJ)cmvconcherr.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvconcherr.o $(MYLIB) 
+$(OBJ)cmvconcherr.o: cmvconcherr.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvconcherr.cc
+
+##############################################################################
+cmvtinterp: $(EXE)cmvtinterp
+	echo $@ " done"
+$(EXE)cmvtinterp: $(OBJ)cmvtinterp.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtinterp.o $(MYLIB) 
+$(OBJ)cmvtinterp.o: cmvtinterp.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtinterp.cc
+
+##############################################################################
+cmvtstagn: $(EXE)cmvtstagn
+	echo $@ " done"
+$(EXE)cmvtstagn: $(OBJ)cmvtstagn.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtstagn.o $(MYLIB) 
+$(OBJ)cmvtstagn.o: cmvtstagn.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtstagn.cc
+
+##############################################################################
+cmvschdist: $(EXE)cmvschdist
+	echo $@ " done"
+$(EXE)cmvschdist: $(OBJ)cmvschdist.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvschdist.o $(MYLIB) 
+$(OBJ)cmvschdist.o: cmvschdist.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvschdist.cc
+
+
+##############################################################################
+cmvchkwhu: $(EXE)cmvchkwhu
+	echo $@ " done"
+$(EXE)cmvchkwhu: $(OBJ)cmvchkwhu.o $(OBJ)hu_tf_fit.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvchkwhu.o $(OBJ)hu_tf_fit.o $(MYLIB) 
+$(OBJ)cmvchkwhu.o: cmvchkwhu.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvchkwhu.cc
+$(OBJ)hu_tf_fit.o: hu_tf_fit.c hu_tf_fit.h
+	$(CCOMPILE) -o $@ hu_tf_fit.c
+
+hu_sigma8: $(EXE)hu_sigma8
+	echo $@ " done"
+$(EXE)hu_sigma8: $(OBJ)hu_sigma8.o $(OBJ)hu_power.o
+	$(CLINK) -o $@ $(OBJ)hu_sigma8.o $(OBJ)hu_power.o -lc -lm
+$(OBJ)hu_sigma8.o: hu_sigma8.c
+	$(CCOMPILE) -o $@ hu_sigma8.c
+$(OBJ)hu_power.o: hu_power.c hu_power.h
+	$(CCOMPILE) -o $@ hu_power.c
+
+##############################################################################
+cmvtluc: $(EXE)cmvtluc
+	echo $@ " done"
+$(EXE)cmvtluc: $(OBJ)cmvtluc.o
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtluc.o $(SOPHYASLBLIST) -L$(SOPHYALIBP) -lLUC
+$(OBJ)cmvtluc.o: cmvtluc.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtluc.cc
+
+##############################################################################
+cmvfitpk: $(EXE)cmvfitpk
+	echo $@ " done"
+$(EXE)cmvfitpk: $(OBJ)cmvfitpk.o $(LIBR)
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvfitpk.o $(MYLIB) -lMinuit2Base
+$(OBJ)cmvfitpk.o: cmvfitpk.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvfitpk.cc
Index: /tags/V1_0/Cosmo/SimLSS/Makeprog
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/Makeprog	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/Makeprog	(revision 3382)
@@ -0,0 +1,24 @@
+# make -f Makeprog 
+include $(SOPHYABASE)/include/sophyamake.inc
+
+LIB = ${CMVPROG}/lib/
+
+MYINC = -I${EXTLIBDIR}/Include -I${HOME}/Sophya/SimLSS
+MYLIB = $(SOPHYAEXTSLBLIST) -L${CMVPROG}/lib -lcmvsimbao -lfftw3_threads -lfftw3 -lm
+
+#---- Les programmes utilitaires de calcul de cartes
+myprog = cmvtest
+
+#----
+
+all: $(myprog)
+
+clean:
+	rm -f $(myprog).o $(myprog)
+
+##############################################################################
+$(myprog): $(myprog).o
+	$(CXXLINK) $(CXXREP) -o $@ $(myprog).o $(MYLIB) 
+$(myprog).o: $(myprog).cc
+	$(CXXCOMPILE) $(CXXREP) $(MYINC) -o $@ $(myprog).cc
+
Index: /tags/V1_0/Cosmo/SimLSS/agnjackson.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/agnjackson.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/agnjackson.cc	(revision 3382)
@@ -0,0 +1,98 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <vector>
+
+#include "pexceptions.h"
+
+#include "histos.h"
+#include "srandgen.h"
+
+#include "geneutils.h"
+#include "agnjackson.h"
+
+namespace SOPHYA {
+
+AGNJackson::AGNJackson(void)
+  : nobjang_(0.) , fluxang_(0.) , dndls_(NULL), tirls_(NULL)
+{
+
+  //--- Les valeurs lues sur la courbe de Jackson (from JIM)
+  const int nval = 10;
+  // log10(S en Jy)
+  double x[nval] = {-7.,-6.,-5.,-4.,-3.,-2.,-1.,0.,1.,2.};
+  // S^2.5*dN/dS (en Jy^1.5 /sr)
+  double y[nval] = {0.0035,0.14,0.95,2.5,7.,50.,260.,300.,150.,100.};
+
+  if(sizeof(x)!=sizeof(y) || sizeof(y)!=8*nval) {
+    cout<<"AGNJackson::AGNJackson_Error: incompatible x,y,nval sizes"<<endl;
+    throw SzMismatchError("AGNJackson::AGNJackson_Error: incompatible x,y,nval sizes");
+  }
+
+  xjack_.resize(0); yjack_.resize(0);
+  for(int i=0;i<nval;i++)
+    {xjack_.push_back(x[i]); yjack_.push_back(y[i]);}
+
+  // On cree l'histo: dndls = dN/dlog10(S) en fct de  log10(S en Jy)
+  int nbin = nval*20;
+  double xmin = x[0], xmax=x[nval-1];
+  dndls_ = new Histo(xmin,xmax,nbin);
+  dndls_->Zero();
+
+  // On remplit les histos
+  // yjack_ = S^2.5 * dN/dS (en Jy^1.5 /sr) en fct de xjack_ = log10(S en Jy)
+  // dndls: dN/dlog10(S)  (en 1/log10(Jy)/sr) en fct de log10(S en Jy)
+  //   avec dN/dlog10(S) = dN/dS * dS/dlog10(S)
+  //                     = (S^2.5*dN/dS)*S^(-2.5) * (ln(10)*S)
+  // On va interpoler en log(dN/dlog10(S)) versus log10(S)
+  vector<double> Y;
+  for(int i=0;i<nval;i++) {
+    double v = yjack_[i]*pow(10.,-1.5*xjack_[i])*M_LN10;
+    Y.push_back(log(v));
+  }
+  for(int i=0;i<nbin;i++) {
+    double lf = dndls_->BinCenter(i);
+    // Interpolation lineaire (parabolic not OK!)
+    double v = InterpTab(lf,xjack_,Y,1);
+    (*dndls_)(i) = exp(v);
+  }
+
+  // On remplit la fonction de tirage
+  tirls_ = new FunRan(*dndls_,true);
+
+  // On calcul le nombre moyen d'AGN et le flux moyen par sr
+  // ATTENTION: dn/dlog10(S) en fct de log10(s)
+  nobjang_ = fluxang_ = 0.;
+  for(int i=0;i<nbin;i++) {
+    double lf = dndls_->BinCenter(i);
+    nobjang_ += (*dndls_)(i);
+    fluxang_ += (*dndls_)(i)*pow(10.,lf);
+  }
+  nobjang_ *= dndls_->BinWidth();
+  fluxang_ *= dndls_->BinWidth();
+
+}
+
+AGNJackson::~AGNJackson(void)
+{
+  if(dndls_!=NULL) delete dndls_;
+  if(tirls_!=NULL) delete tirls_;
+}
+
+void AGNJackson::Print(void)
+{
+  cout<<"AGNJackson::Print: nobj="<<nobjang_
+      <<" /sr, flux="<<fluxang_<<" Jy/sr"<<endl;
+  dndls_->Show();
+}
+
+void AGNJackson::OrigJack(vector<double>& xjack,vector<double>& yjack)
+{
+  xjack = xjack_;
+  yjack = yjack_;
+}
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/agnjackson.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/agnjackson.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/agnjackson.h	(revision 3382)
@@ -0,0 +1,39 @@
+#ifndef AGNJACKSON_SEEN
+#define AGNJACKSON_SEEN
+
+#include "machdefs.h"
+#include <math.h>
+#include "genericfunc.h"
+#include "histos.h"
+#include "perandom.h"
+
+namespace SOPHYA {
+
+//----------------------------------------------------
+// C.A.Jackson (New Astronomy Review 40 (2004) 1187-1193)
+class AGNJackson {
+public:
+  AGNJackson(void);
+  virtual ~AGNJackson(void);
+
+  Histo& dNdlS(void) {return *dndls_;}
+  FunRan& TirL10S(void) {return *tirls_;}
+  double NObjAng(void) {return nobjang_;}
+  double FluxAng(void) {return fluxang_;}
+  double L10FluxJY(void) {return tirls_->Random();}
+  double FluxJY(void) {return pow(10.,L10FluxJY());}
+  void Print(void);
+
+  void OrigJack(vector<double>& xjack,vector<double>& yjack);
+
+protected:
+  vector<double> xjack_,yjack_;
+  double nobjang_,fluxang_;
+  Histo *dndls_;
+  FunRan *tirls_;
+
+};
+
+}  // Fin namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/cmvchkwhu.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvchkwhu.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvchkwhu.cc	(revision 3382)
@@ -0,0 +1,151 @@
+// Check cmv / Wayne Hu coding of the transfert functions
+// ATTENTION: ne pas appeler hu_power.c ici car il ecrase les initialisations de hu_tf_fit.c
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "ntuple.h"
+
+#include "constcosmo.h"
+#include "pkspectrum.h"
+#include "hu_tf_fit.h"
+
+int main(int narg,char *arg[])
+{
+ double k1 = 1e-6, k2 = 10.; int_4 npt = 10000;
+ double h100 = 0.71, Om0 = 0.267804, Ob0 = 0.0444356, tcmb = T_CMB_Par;
+
+ cout<<"k1="<<k1<<"  k2="<<k2<<" npt="<<npt<<endl;
+ cout<<"h100="<<h100<<" Om0="<<Om0<<" Ob0="<<Ob0<<" Tcmb="<<tcmb<<endl;
+ cout<<"Om0*h^2="<<Om0*h100*h100<<" Ob0*h^2="<<Ob0*h100*h100<<endl;
+ double fbaryon = Ob0/Om0;
+ cout<<"fbaryon="<<fbaryon<<endl;
+
+ cout<<endl<<"TFset_parameters"<<endl;
+ TFset_parameters(Om0*h100*h100,fbaryon,tcmb);
+ TFprint_parameters();
+ double soundfithu = TFsound_horizon_fit(Om0,fbaryon,h100)/h100;
+ cout<<"TFsound_horizon_fit = "<<soundfithu<<" Mpc"<<endl;
+
+ cout<<endl<<"TransfertEisenstein with baryon"<<endl;
+ TransfertEisenstein Tfull(h100,Om0-Ob0,Ob0,tcmb,false,1);
+
+ cout<<endl<<"TransfertEisenstein with baryon without oscillation approx.2"<<endl;
+ TransfertEisenstein Tnowig(h100,Om0-Ob0,Ob0,tcmb,false,1);
+ Tnowig.SetNoOscEnv(2);
+
+ cout<<endl<<"TransfertEisenstein without baryon"<<endl;
+ TransfertEisenstein Tnob(h100,Om0,0.,tcmb,true,1);
+
+ cout<<endl<<"Compare kpeak"<<endl;
+ double kpeak = Tfull.KPeak();
+ double kpeakhu = TFk_peak(Om0,fbaryon,h100)*h100;
+ cout<<"kpeak = "<<kpeak<<" "<<kpeakhu<<"  Mpc^-1  -> diff "<<kpeak-kpeakhu<<endl;
+
+ const int n = 11;
+ char *vname[n] = {"k","tf","tfnw","tfnb","tfc","tfb"
+                  ,"hutf","hutfnw","hutfnb","hutfc","hutfb"};
+ NTuple nt(n,vname);
+ double xnt[n];
+
+ double kmax[5]={0,0,0,0,0};
+ double tmax[5]={0.,0.,0.,0.,0.};
+ double lnk1 = log10(k1), lnk2=log10(k2), dlnk=(lnk2-lnk1)/npt;
+ for(double lnk=lnk1;lnk<lnk2+dlnk/2.;lnk+=dlnk) {
+   double k = pow(10.,lnk);
+   //if(fabs(lnk-log10(0.0186209))>1e-5) continue;
+   Tfull.SetReturnPart(TransfertEisenstein::ALL); double tf = Tfull(k);
+   double tfnw = Tnowig(k);
+   double tfnb = Tnob(k);
+   Tfull.SetReturnPart(TransfertEisenstein::CDM); double tfc = Tfull(k);
+   Tfull.SetReturnPart(TransfertEisenstein::BARYON); double tfb = Tfull(k);
+   double hutfc, hutfb;
+   double hutf = TFfit_onek(k,&hutfb,&hutfc); 
+   double hutfnw = TFnowiggles(Om0,fbaryon,h100,tcmb,k/h100);
+   double hutfnb = TFzerobaryon(Om0,h100,tcmb,k/h100);
+
+
+   if(fabs(tf-hutf)>tmax[0])     {kmax[0]=k; tmax[0]=fabs(tf-hutf);}
+   if(fabs(tfnw-hutfnw)>tmax[1]) {kmax[1]=k; tmax[1]=fabs(tfnw-hutfnw);}
+   if(fabs(tfnb-hutfnb)>tmax[2]) {kmax[2]=k; tmax[2]=fabs(tfnb-hutfnb);}
+   if(fabs(tfc-hutfc)>tmax[3])   {kmax[3]=k; tmax[3]=fabs(tfc-hutfc);}
+   if(fabs(tfb-hutfb)>tmax[4])   {kmax[4]=k; tmax[4]=fabs(tfb-hutfb);}
+
+   xnt[0]=k;
+   xnt[1]=tf; xnt[2]=tfnw; xnt[3]=tfnb; xnt[4]=tfc; xnt[5]=tfb;
+   xnt[6]=hutf; xnt[7]=hutfnw; xnt[8]=hutfnb; xnt[9]=hutfc; xnt[10]=hutfb;
+   nt.Fill(xnt);
+ }
+
+ cout<<"Maximum difference for:"<<endl;
+ cout<<"tf:   "<<tmax[0]<<"  for k="<<kmax[0]<<endl;
+ cout<<"tfnw: "<<tmax[1]<<"  for k="<<kmax[1]<<endl;
+ cout<<"tfnb: "<<tmax[2]<<"  for k="<<kmax[2]<<endl;
+ cout<<"tfc:  "<<tmax[3]<<"  for k="<<kmax[3]<<endl;
+ cout<<"tfb:  "<<tmax[4]<<"  for k="<<kmax[4]<<endl;
+
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvchkwhu.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+
+ return 0;
+}
+
+/*
+openppf cmvchkwhu.ppf
+
+set k k
+set k log10(k)
+
+######################
+zone 3 1
+n/plot nt.tf%$k ! ! "nsta connectpoints"
+n/plot nt.hutf%$k ! ! "nsta connectpoints red same"
+n/plot nt.tfc%$k ! ! "nsta connectpoints"
+n/plot nt.hutfc%$k ! ! "nsta connectpoints red same"
+n/plot nt.tfb%$k ! ! "nsta connectpoints"
+n/plot nt.hutfb%$k ! ! "nsta connectpoints red same"
+zone 2 1
+n/plot nt.tfnw%$k ! ! "nsta connectpoints"
+n/plot nt.hutfnw%$k ! ! "nsta connectpoints red same"
+n/plot nt.tfnb%$k ! ! "nsta connectpoints"
+n/plot nt.hutfnb%$k ! ! "nsta connectpoints red same"
+
+######################
+zone 3 1
+n/plot nt.tf-hutf%$k ! ! "nsta connectpoints"
+n/plot nt.tfc-hutfc%$k ! ! "nsta connectpoints"
+n/plot nt.tfb-hutfb%$k ! ! "nsta connectpoints"
+zone 2 1
+n/plot nt.tfnw-hutfnw%$k ! ! "nsta connectpoints"
+n/plot nt.tfnb-hutfnb%$k ! ! "nsta connectpoints"
+
+zone 3 1
+n/plot nt.(tf-hutf)/hutf%$k ! ! "nsta connectpoints"
+n/plot nt.(tfc-hutfc)/hutfc%$k ! ! "nsta connectpoints"
+n/plot nt.(tfb-hutfb)/hutfb%$k ! ! "nsta connectpoints"
+zone 2 1
+n/plot nt.(tfnw-hutfnw)/hutfnw%$k ! ! "nsta connectpoints"
+n/plot nt.(tfnb-hutfnb)/hutfnb%$k ! ! "nsta connectpoints"
+
+######################
+zone
+n/plot nt.tf%$k ! ! "nsta connectpoints"
+n/plot nt.tfnw%$k ! ! "nsta connectpoints red same"
+n/plot nt.tfnb%$k ! ! "nsta connectpoints blue same"
+
+zone
+n/plot nt.tf/tfnw%$k tfnw>0. ! "nsta connectpoints"
+n/plot nt.hutf/hutfnw%$k hutfnw>0. ! "nsta connectpoints same blue"
+addline -1000 1 1000 1 "red"
+
+zone
+n/plot nt.tf/tfnb%$k tfnb>0. ! "nsta connectpoints"
+n/plot nt.hutf/hutfnb%$k hutfnb>0. ! "nsta connectpoints same blue"
+addline -1000 1 1000 1 "red"
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvconcherr.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvconcherr.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvconcherr.cc	(revision 3382)
@@ -0,0 +1,381 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "histerr.h"
+#include "hist2err.h"
+#include "fitshisterr.h"
+
+int ObjectType(string nameh,string nameppf);
+int ConcatHistoErr(string nameh,vector<string> ppfname,int wrtyp=2,bool do_cov=false);
+int ConcatHisto2DErr(string nameh,vector<string> ppfname,int wrtyp=2,int ibinkt=-1,int ibinkz=-1);
+void usage(void);
+void usage(void)
+{
+cout
+<<"cmvconcherr -w wtyp -n name_histoerr file1.ppf file2.ppf ..."<<endl
+<<"  name_histoerr: object name"<<endl
+<<"  wtyp: bit0 write ASCII, bit1 write PPF, bit2 write FITS (all=7)"<<endl
+<<"  -C : compute covariance for 1D spectrum"<<endl
+<<"  -Z ibinKt : compute covariance of line Pk(ibinKt,.) along Kz for 2D"<<endl
+<<"  -T ibinKz : compute covariance of line Pk(.,ibinKz) along Kt for 2D"<<endl
+<<endl;
+}
+
+
+//---------------------------------------------------------------
+int main(int narg,char *arg[])
+{
+ // "hpkgen"  "hpkgenfb"  "hpkgenf"  "hpkrecb"  "hpkrec"
+ // "hpkgen2" "hpkgenfb2" "hpkgenf2" "hpkrecb2" "hpkrec2"
+ string nameh = "";
+ vector<string> ppfname;
+ int Write_Type = 2;
+ bool Do_Cov = false;
+ int ibinKt=-1, ibinKz=-1;
+
+ // --- Decodage arguments
+ char c;
+ while((c = getopt(narg,arg,"hCn:w:Z:T:")) != -1) {
+  switch (c) {
+  case 'n' :
+    nameh = optarg;
+    break;
+  case 'w' :
+    sscanf(optarg,"%d",&Write_Type);
+    break;
+  case 'C' :
+    Do_Cov = true;
+    break;
+  case 'Z' :
+    sscanf(optarg,"%d",&ibinKt);
+    break;
+  case 'T' :
+    sscanf(optarg,"%d",&ibinKz);
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+ if(nameh.size()<=0 || optind>=narg) {usage(); return -1;}
+ for (int i=optind;i<narg;i++) ppfname.push_back(arg[i]);
+ cout<<"nameh = "<<nameh
+     <<" , number of file to be read = "<<ppfname.size()
+     <<" , write_type="<<Write_Type<<" , cov="<<Do_Cov<<endl;
+
+ // --- Quel type d'objet ?
+ int obtyp = ObjectType(nameh,ppfname[0]);
+
+ // --- lecture et moyenne des HistoErr ou Histo2DErr
+ int nread=0;
+ if(obtyp==1) nread = ConcatHistoErr(nameh,ppfname,Write_Type,Do_Cov);
+ else if(obtyp==2) nread = ConcatHisto2DErr(nameh,ppfname,Write_Type,ibinKt,ibinKz);
+ else {
+   cout<<"Type of object "<<nameh<<" not decoded"<<endl;
+   return -1;
+ }
+ cout<<"Number of file read: "<<nread<<endl;
+ return 0;
+}
+
+//---------------------------------------------------------------
+int ObjectType(string nameh,string nameppf)
+// retourne: 1 si HistoErr
+//           2 si Histo2DErr,
+//           0 si autre objet
+//          -1 si il n'y a pas d'objet de nom "nameh"
+{
+ PInPersist pis(nameppf.c_str());
+
+ bool found_tag = pis.GotoNameTag(nameh.c_str());
+ if(!found_tag) return -1;
+
+ PPersist *pps = pis.ReadObject();
+ AnyDataObj *obj = pps->DataObj();
+ cout<<"Object type read from input PPF file : "<<typeid(*obj).name()<< endl;
+
+ HistoErr *herr = dynamic_cast<HistoErr *>(obj);
+ if(herr) return 1;
+
+ Histo2DErr *herr2 = dynamic_cast<Histo2DErr *>(obj);
+ if(herr2) return 2;
+
+ return 0;
+}
+
+//---------------------------------------------------------------
+int ConcatHistoErr(string nameh,vector<string> ppfname,int wrtyp,bool do_cov)
+{
+ if(ppfname.size()<=0) return 0;
+
+ HistoErr *herrconc = NULL;
+ TVector<r_8> Tsum; TMatrix<r_8> Tsum2;
+ int nherr=0, nread=0, itest=0;
+ double sum=0., sum2=0., nsum=0;
+ for (unsigned int ifile=0;ifile<ppfname.size();ifile++) {
+   PInPersist pis(ppfname[ifile].c_str());
+   HistoErr herr;
+   pis.GetObject(herr,nameh);
+   cout<<ifile<<" : "<<ppfname[ifile]<<"  nbin="<<herr.NBins()<<endl;
+
+   if(ifile==0) { 
+     herrconc = new HistoErr(herr.XMin(),herr.XMax(),herr.NBins());
+     nherr = herr.NBins();
+     itest = int(herrconc->NBins()/5.+0.5);
+     if(do_cov) {Tsum.ReSize(nherr); Tsum=0.; Tsum2.ReSize(nherr,nherr); Tsum2=0.;}
+   } else if(nherr!=herr.NBins()) {
+     cout<<"BAD NUMBER OF BINS"<<endl;
+     continue;
+   }
+
+   if(herr.NMean()!=1) cout<<"ATTENTION: file="<<ppfname[ifile]
+                           <<" nmean="<<herr.NMean()<<endl;
+   nread++;
+   for(int i=0;i<nherr;i++) herrconc->AddBin(i,herr(i));
+   sum+=herr(itest); sum2+=herr(itest)*herr(itest); nsum++;
+
+   if(do_cov) {
+     for(int i=0;i<nherr;i++) {
+       Tsum(i) += herr(i);
+       for(int j=0;j<nherr;j++) Tsum2(i,j) += herr(i)*herr(j);
+     }
+   }
+
+ }
+ herrconc->ToVariance();
+ if(nsum>0) {sum/=nsum; sum2/=nsum; sum2-=sum*sum;}
+ cout<<"Test bin "<<itest<<" mean="<<sum<<" sigma^2="<<sum2<<"  nsum="<<nsum<<endl;
+ cout<<"         "<<" mean="<<(*herrconc)(itest)
+                  <<" sigma^2="<<herrconc->Error2(itest)<<endl;
+
+ // --- Covariance
+ if(do_cov && nread>1) {
+   Tsum /= nread;
+   Tsum2 /= nread;
+   for(int i=0;i<nherr;i++)
+     for(int j=0;j<nherr;j++) Tsum2(i,j) -= Tsum(i)*Tsum(j);
+ }
+
+ // --- ecriture
+ if(wrtyp&1) {   // ecriture ASCII
+   string asname = "cmvconcherr.data";
+   herrconc->WriteASCII(asname);
+ }
+ if(wrtyp&2 || do_cov) {   // ecriture PPF
+   string tagobs = "cmvconcherr.ppf";
+   POutPersist posobs(tagobs);
+   tagobs = "herrconc"; posobs.PutObject(*herrconc,tagobs);
+   if(do_cov) {
+     tagobs = "mean"; posobs.PutObject(Tsum,tagobs);
+     tagobs = "cov"; posobs.PutObject(Tsum2,tagobs);
+   }
+ }
+ if(wrtyp&4) {   // ecriture FITS
+   FitsInOutFile fio("!cmvconcherr.fits",FitsInOutFile::Fits_Create);
+   fio << *herrconc;
+ }
+
+ delete herrconc;
+
+ return nread;
+}
+
+//---------------------------------------------------------------
+int ConcatHisto2DErr(string nameh,vector<string> ppfname,int wrtyp,int ibinkt,int ibinkz)
+{
+ if(ppfname.size()<=0) return 0;
+
+ Histo2DErr *herrconc = NULL;
+ TVector<r_8> Tsum_kz; TMatrix<r_8> Tsum2_kz;
+ TVector<r_8> Tsum_kt; TMatrix<r_8> Tsum2_kt;
+ int nherrx=0, nherry=0, nread=0, itestx=0, itesty=0;
+ double sum=0., sum2=0., nsum=0;
+ for (unsigned int ifile=0;ifile<ppfname.size();ifile++) {
+   PInPersist pis(ppfname[ifile].c_str());
+   Histo2DErr herr;
+   pis.GetObject(herr,nameh);
+   cout<<ifile<<" : "<<ppfname[ifile]<<"  nbin="
+       <<herr.NBinX()<<","<<herr.NBinY()<<endl;
+
+   if(ifile==0) { 
+     herrconc = new Histo2DErr(herr.XMin(),herr.XMax(),herr.NBinX()
+                              ,herr.YMin(),herr.YMax(),herr.NBinY());
+     nherrx = herr.NBinX(); nherry = herr.NBinY();
+     itestx = int(herrconc->NBinX()/5.+0.5);
+     itesty = int(herrconc->NBinY()/5.+0.5);
+     if(ibinkt>=0) { // matrix de covariance pour une ligne Kz
+       if(ibinkt>=nherrx) ibinkt = nherrx-1;
+       Tsum_kz.ReSize(nherry); Tsum_kz=0.;
+       Tsum2_kz.ReSize(nherry,nherry); Tsum2_kz=0.;
+     }
+     if(ibinkz>=0) { // matrix de covariance pour une ligne Kt
+       if(ibinkz>=nherry) ibinkz = nherry-1;
+       Tsum_kt.ReSize(nherrx); Tsum_kt=0.;
+       Tsum2_kt.ReSize(nherrx,nherrx); Tsum2_kt=0.;
+     }
+   } else if(nherrx!=herr.NBinX() || nherry!=herr.NBinY()) {
+     cout<<"BAD NUMBER OF BINS"<<endl;
+     continue;
+   }
+
+   if(herr.NMean()!=1) cout<<"ATTENTION: file="<<ppfname[ifile]
+                           <<" nmean="<<herr.NMean()<<endl;
+   nread++;
+   for(int i=0;i<nherrx;i++)
+     for(int j=0;j<nherry;j++) herrconc->AddBin(i,j,herr(i,j));
+   sum+=herr(itestx,itesty); sum2+=herr(itestx,itesty)*herr(itestx,itesty); nsum++;
+
+   if(ibinkt>=0) {
+     for(int i=0;i<Tsum_kz.Size();i++) {
+       Tsum_kz(i) += herr(ibinkt,i);
+       for(int j=0;j<Tsum_kz.Size();j++) Tsum2_kz(i,j) += herr(ibinkt,i)*herr(ibinkt,j);
+     }
+   }
+
+   if(ibinkz>=0) {
+     for(int i=0;i<Tsum_kt.Size();i++) {
+       Tsum_kt(i) += herr(i,ibinkz);
+       for(int j=0;j<Tsum_kt.Size();j++) Tsum2_kt(i,j) += herr(i,ibinkz)*herr(j,ibinkz);
+     }
+   }
+
+ }
+ herrconc->ToVariance();
+ if(nsum>0) {sum/=nsum; sum2/=nsum; sum2-=sum*sum;}
+ cout<<"Test bin "<<itestx<<","<<itesty
+     <<" mean="<<sum<<" sigma^2="<<sum2<<"  nsum="<<nsum<<endl;
+ cout<<"         "<<" mean="<<(*herrconc)(itestx,itesty)
+                  <<" sigma^2="<<herrconc->Error2(itestx,itesty)<<endl;
+
+ // --- Covariance
+ if(ibinkt>=0 && nread>1) {
+   Tsum_kz /= nread;
+   Tsum2_kz /= nread;
+   for(int i=0;i<Tsum_kz.Size();i++)
+     for(int j=0;j<Tsum_kz.Size();j++) Tsum2_kz(i,j) -= Tsum_kz(i)*Tsum_kz(j);
+ }
+ if(ibinkz>=0 && nread>1) {
+   Tsum_kt /= nread;
+   Tsum2_kt /= nread;
+   for(int i=0;i<Tsum_kt.Size();i++)
+     for(int j=0;j<Tsum_kt.Size();j++) Tsum2_kt(i,j) -= Tsum_kt(i)*Tsum_kt(j);
+ }
+
+ // --- ecriture
+ if(wrtyp&1) {   // ecriture ASCII
+   string asname = "cmvconcherr2.data";
+   herrconc->WriteASCII(asname);
+ }
+ if(wrtyp&2) {   // ecriture PPF
+   string tagobs = "cmvconcherr2.ppf";
+   POutPersist posobs(tagobs);
+   tagobs = "herrconc2"; posobs.PutObject(*herrconc,tagobs);
+   if(ibinkt>=0) {
+     char str[32];
+     sprintf(str,"kzm%d",ibinkt);
+     posobs.PutObject(Tsum_kz,str);
+     sprintf(str,"kzc%d",ibinkt);
+     posobs.PutObject(Tsum2_kz,str);
+   }
+   if(ibinkz>=0) {
+     char str[32];
+     sprintf(str,"ktm%d",ibinkz);
+     posobs.PutObject(Tsum_kt,str);
+     sprintf(str,"ktc%d",ibinkz);
+     posobs.PutObject(Tsum2_kt,str);
+   }
+ }
+ if(wrtyp&4) {   // ecriture FITS
+   FitsInOutFile fio("!cmvconcherr2.fits",FitsInOutFile::Fits_Create);
+   fio << *herrconc;
+ }
+
+ delete herrconc;
+
+ return nread;
+}
+
+/*
+####
+#### HistoErr 1D
+####
+openppf cmvconcherr.ppf
+
+c++exec int i = 700; \
+cout<<i<<" "<<herrconc.BinCenter(i)<<" "<<herrconc(i)<<" "<<herrconc.Error2(i)<<" "<<herrconc.NEntBin(i)<<endl;
+
+zone 2 2
+disp herrconc "hbincont err"
+disp herrconc "hbinerr"
+disp herrconc "hbinent"
+
+zone
+n/plot herrconc.val%log10(x) x>0 ! "connectpoints"
+n/plot herrconc.val-sqrt(err2)%log10(x) x>0&&err2>0 ! "connectpoints same red"
+n/plot herrconc.val+sqrt(err2)%log10(x) x>0&&err2>0 ! "connectpoints same red"
+
+n/plot herrconc.sqrt(err2)%log10(x) x>0&&err2>0 ! "connectpoints same red"
+n/plot herrconc.sqrt(err2)/val%log10(x) x>0&&err2>0&&val>0 ! "connectpoints"
+
+disp mean
+imag cov
+
+del cor
+c++exec \
+TMatrix<r_8> cor(cov,false); cor = 0.; \
+for(int i=0;i<cor.NRows();i++) { \
+  for(int j=0;j<cor.NCols();j++) { \
+    double v = cov(i,i)*cov(j,j); \
+    if(v<=0.) continue; \
+    cor(i,j) = cov(i,j)/sqrt(v); \
+} } \
+KeepObj(cor); \
+cout<<"Matrice cor cree "<<endl;
+
+imag cor
+n/plot cor.val%c r==500 ! "connectpoints"
+
+####
+#### Histo2DErr 2D
+####
+openppf cmvconcherr2.ppf
+
+zone 2 2
+imag herrconc2 "hbincont"
+imag herrconc2 "hbinerr"
+imag herrconc2 "hbinent"
+
+zone
+
+set mean kzm140
+set cov kzc140
+
+set mean ktm32
+set cov ktc32
+
+n/plot $mean.val%n ! ! "connectpoints"
+disp $cov
+n/plot $cov.val%c r==32 ! "connectpoints"
+
+set cor ${cov}cor
+del $cor
+c++exec \
+TMatrix<r_8> $cor($cov,false); $cor = 0.; \
+for(int i=0;i<$cor.NRows();i++) { \
+  for(int j=0;j<$cor.NCols();j++) { \
+    double v = $cov(i,i)*$cov(j,j); \
+    if(v<=0.) continue; \
+    $cor(i,j) = $cov(i,j)/sqrt(v); \
+} } \
+KeepObj($cor); \
+cout<<"Matrice cor cree "<<endl;
+
+disp $cor
+n/plot $cor.val%c r==32 ! "connectpoints"
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvdefsurv.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvdefsurv.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvdefsurv.cc	(revision 3382)
@@ -0,0 +1,869 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "constcosmo.h"
+#include "cosmocalc.h"
+#include "geneutils.h"
+#include "schechter.h"
+#include "pkspectrum.h"
+#include "planckspectra.h"
+
+/* --- Check Peterson at al. astro-ph/0606104 v1  (pb facteur sqrt(2) sur S/N !)
+cmvdefsurv -U 0.75,0.3,0.7,-1,1 -V 300 -z 0.0025,0.2,Z -x 1,90,A -O 400000,6000 -N 75 -M 6.156e9 -F 3 -2 1.5
+ --- */
+
+//-----------------------------------------------------------------------------------------------------------
+inline double rad2deg(double trad) {return trad/M_PI*180.;}
+inline double rad2min(double trad) {return trad/M_PI*180.*60.;}
+inline double rad2sec(double trad) {return trad/M_PI*180.*3600.;}
+inline double deg2rad(double tdeg) {return tdeg*M_PI/180.;}
+inline double min2rad(double tmin) {return tmin*M_PI/(180.*60.);}
+inline double sec2rad(double tsec) {return tsec*M_PI/(180.*3600.);}
+
+inline double sr2deg2(double asr) {return asr*pow(rad2deg(1.),2.);}
+inline double sr2min2(double asr) {return asr*pow(rad2min(1.),2.);}
+inline double deg22sr(double adeg) {return adeg*pow(deg2rad(1.),2.);}
+inline double min22sr(double amin) {return amin*pow(min2rad(1.),2.);}
+
+double LargeurDoppler(double v /* km/s */, double nu);
+double DzFrV(double v /* km/s */, double zred);
+double DNuFrDz(double dzred,double nu_at_0,double zred);
+double DzFrDNu(double dnu_at_0,double nu_at_0,double zred);
+double DzFrDNuApprox(double dnu_at_0,double nu_at_0,double zred);
+double ZFrLos(double loscom /* Mpc com */,CosmoCalc& univ);
+double AngsolEqTelescope(double nu /* GHz */,double telsurf /* m^2 */);
+void usage(void);
+
+void usage(void) {
+  cout<<"cmvdefsurv [options] -x dx,txlarg[,unit_x] -y dy,tylarg[,unit_y] -z dz,tzlarg[,unit_z] redshift"<<endl
+      <<"----------------"<<endl
+      <<" -x dx,txlarg[,unit_x] : resolution et largeur dans le plan transverse selon X"<<endl
+      <<" -y dy,tylarg[,unit_y] : idem selon Y, si <=0 meme que X"<<endl
+      <<" -z dz,tzlarg[,unit_z] : resolution et largeur sur la ligne de visee"<<endl
+      <<"-- Unites pour X-Y:"<<endl
+      <<"   \'A\' : en angles (pour X-Y)  : resolution=ArcMin, largeur=Degre (defaut)"<<endl
+      <<"   \'Z\' : en redshift (pour Z)  : resolution et largeur en redshift (defaut)"<<endl
+      <<"   \'F\' : en frequence (pour Z) : resolution et largeur MHz"<<endl
+      <<"   \'M\' : en longeur comobile (pour X-Y-Z) : resolution et largeur Mpc"<<endl
+      <<"----------------"<<endl
+      <<" -K k,dk,pk : k(Mpc^-1) dk(Mpc^-1) pk(a z=0 en Mpc^-3) pour estimer la variance cosmique"<<endl
+      <<"----------------"<<endl
+      <<" -O surf,tobs,eta : surface effective (m^2), temps d\'observation (s), efficacite d\'ouverture"<<endl
+      <<" -N Tsys : temperature du system (K)"<<endl
+      <<" -L lobearea,freqlob : angle solide du lobe d\'observation en arcmin^2 (def= celle du pixel)"<<endl
+      <<"                       pour la frequence freqlob en MHz"<<endl
+      <<"            Si freqlob<=0 : la frequence de reference est celle du redshift etudie (def)"<<endl
+      <<" -2 : two polarisations measured"<<endl
+      <<" -M  : masse de HI de reference (MSol), si <=0 mean schechter in pixel"<<endl
+      <<" -F  : HI flux factor to be applied for our redshift"<<endl
+      <<" -V Vrot : largeur en vitesse (km/s) pour l\'elargissement doppler (def=300km/s)"<<endl
+      <<"----------------"<<endl
+      <<" -S Tsynch,indnu : temperature (K) synch a 408 Mhz, index d\'evolution"<<endl
+      <<"                   (indnu==0 no evolution with freq.)"<<endl
+      <<"----------------"<<endl
+      <<" -U h100,om0,ol0,w0,or0,flat : cosmology"<<endl
+      <<"----------------"<<endl
+      <<" -A <log10(S_agn)> : moyenne du flux AGN en Jy dans le pixel"<<endl
+      <<" redshift : redshift moyen du survey"<<endl
+      <<endl;
+}
+
+//-------------------------------------------------------------------------------------------
+int main(int narg,char *arg[])
+{
+ // --- 
+ // --- Valeurs fixes ou par defaut
+ // --- 
+
+ //-- WMAP
+ unsigned short flat = 0;
+ double h100=0.71, om0=0.267804, or0=7.9e-05*0., ol0=0.73,w0=-1.;
+
+ //-- Schechter HIMASS
+ double h75 = h100 / 0.75;
+ double nstar = 0.006*pow(h75,3.);  //
+ double mstar = pow(10.,9.8);  // MSol
+ double alpha = -1.37;
+ cout<<"nstar= "<<nstar<<"  mstar="<<mstar<<"  alpha="<<alpha<<endl;
+
+ double hifactor = 1.;
+ double vrot = 300.; // largeur en vitesse (km/s) pour elargissement doppler
+
+ //-- CMB , Synchrotron et AGN
+ double tcmb = T_CMB_Par;
+ // a 408 MHz (Haslam) + evol index a -2.6
+ double Tsynch408=60., nuhaslam=0.408, indnu = -2.6;
+ double lflux_agn = -3.;
+
+ //-- Appareillage
+ bool ya2polar = false;
+ double facpolar = 0.5; // si on mesure les 2 polars -> 1.0
+ double Tsys=75.;
+ double tobs = 6000., surftot = 400000., eta_eff  = 1.;
+ // taille du lobe d'observation en arcmin pour la frequence
+ double lobearea0 = -1., lobefreq0 = -1.;
+
+ //-- Variance cosmique (default = standard SDSSII)
+ double kcosm = 0.05, dkcosm = -1., pkcosm = 40000.;
+
+ // --- Pour taille du survey
+ double dx=0., dy=-1., dz=0., txlarg=0., tylarg=-1., tzlarg=0.;
+ int nx=0, ny=0, nz=0;
+ char unit_x = 'A', unit_y = 'A', unit_z = 'Z';
+ double redshift0 = 0.;
+ double mhiref = -1.; // reference Mass en HI (def integ schechter)
+
+ // --- 
+ // --- Decodage arguments
+ // --- 
+ char c;
+  while((c = getopt(narg,arg,"h2x:y:z:N:S:O:M:F:V:U:L:A:K:")) != -1) {
+  switch (c) {
+  case 'x' :
+    sscanf(optarg,"%lf,%lf,%c",&dx,&txlarg,&unit_x);
+    break;
+  case 'y' :
+    sscanf(optarg,"%lf,%lf,%c",&dy,&tylarg,&unit_y);
+    break;
+  case 'z' :
+    sscanf(optarg,"%lf,%lf,%c",&dz,&tzlarg,&unit_z);
+    break;
+  case 'O' :
+    sscanf(optarg,"%lf,%lf,%lf",&surftot,&tobs,&eta_eff);
+    break;
+  case 'L' :
+    sscanf(optarg,"%lf,%lf",&lobearea0,&lobefreq0);
+    break;
+  case 'N' :
+    sscanf(optarg,"%lf",&Tsys);
+    break;
+  case 'S' :
+    sscanf(optarg,"%lf,%lf",&Tsynch408,&indnu);
+    break;
+  case 'M' :
+    sscanf(optarg,"%lf",&mhiref);
+    break;
+  case 'F' :
+    sscanf(optarg,"%lf",&hifactor);
+    break;
+  case 'V' :
+    sscanf(optarg,"%lf",&vrot);
+    break;
+  case 'U' :
+    sscanf(optarg,"%lf,%lf,%lf,%lf,%hu",&h100,&om0,&ol0,&w0,&flat);
+    break;
+  case '2' :
+    ya2polar = true;
+    facpolar = 1.0;
+    break;
+  case 'A' :
+    sscanf(optarg,"%lf",&lflux_agn);
+    break;
+  case 'K' :
+    sscanf(optarg,"%lf,%lf,%lf",&kcosm,&dkcosm,&pkcosm);
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ } 
+ if(optind>=narg) {usage(); return -1;}
+ sscanf(arg[optind],"%lf",&redshift0);
+ if(redshift0<=0.) {cout<<"Redshift "<<redshift0<<" should be >0"<<endl; return -2;}
+
+ // --- 
+ // --- Initialisation de la Cosmologie
+ // --- 
+ CosmoCalc univ(flat,true,2.*redshift0);
+ double perc=0.01,dzinc=redshift0/100.,dzmax=dzinc*10.; unsigned short glorder=4;
+ univ.SetInteg(perc,dzinc,dzmax,glorder);
+ univ.SetDynParam(h100,om0,or0,ol0,w0);
+
+ GrowthFactor growth(om0,ol0);
+
+ // --- 
+ // --- Mise en forme dans les unites appropriees
+ // --- 
+ // ATTENTION: le cube de simulation est en Mpc avec des pixels de taille comobile fixe
+ cout<<"\n>>>>\n>>>> Geometrie\n>>>>"<<endl;
+ if(dy<=0. || tylarg<=0.) {dy=dx; tylarg=txlarg; unit_y=unit_x;}
+ cout<<"X values: resolution="<<dx<<" largeur="<<txlarg<<" unite="<<unit_x<<endl;
+ if(unit_x == 'A') {
+   nx = int(txlarg*60./dx+0.5);
+   dx = min2rad(dx)*univ.Dtrcom(redshift0);
+   txlarg = dx*nx;
+ } else if(unit_x == 'M') {
+   nx = int(txlarg/dx+0.5);
+   txlarg = dx*nx;
+ } else {
+   cout<<"Unknown unit_x = "<<unit_x<<endl; return -2;
+ }
+ cout<<"Y values: resolution="<<dy<<" largeur="<<tylarg<<" unite="<<unit_y<<endl;
+ if(unit_y == 'A') {
+   ny = int(tylarg*60./dy+0.5);
+   dy = min2rad(dy)*univ.Dtrcom(redshift0);
+   tylarg = dy*ny;
+ } else if(unit_y == 'M') {
+   ny = int(tylarg/dy+0.5);
+   tylarg = dy*ny;
+ } else {
+   cout<<"Unknown unit_y = "<<unit_y<<endl; return -2;
+ }
+ cout<<"Z values: resolution="<<dz<<" largeur="<<tzlarg<<" unite="<<unit_z<<endl;
+ if(unit_z == 'Z') {
+   nz = int(tzlarg/dz+0.5);
+   dz = dz*univ.Dhubble()/univ.E(redshift0);
+   tzlarg = dz*nz;
+ } else if(unit_z == 'M') {
+   nz = int(tzlarg/dz+0.5);
+   tzlarg = dz*nz;
+ } else if(unit_z == 'F') { // unite en MHz
+   nz = int(tzlarg/dz+0.5);
+   dz = DzFrDNu(dz,Fr_HyperFin_Par*1.e3,redshift0);  //dzred
+   dz = dz*univ.Dhubble()/univ.E(redshift0);
+   tzlarg = dz*nz;
+ } else {
+   cout<<"Unknown unit_z = "<<unit_z<<endl; return -2;
+ }
+
+ // --- 
+ // --- Calcul des valeurs au centre du cube et aux faces limites av/ar
+ // --- 
+ cout<<"\n>>>>\n>>>> Cosmologie generale\n>>>>"<<endl;
+ double adtx[3], adty[3], atxlarg[3], atylarg[3];
+ double loscom[3], redshift[3], unplusz[3], dred[3], growthfac[3], rhocz[3];
+ double dang[3], dtrcom[3], dlum[3], dloscom[3], dlosdz[3];
+ double nuhiz[3], lambdahiz[3], dnuhiz[3];
+ double angsol_pix[3], angsol_tot[3];
+
+ redshift[0] = redshift0;
+ loscom[0] = univ.Dloscom(redshift0);
+ loscom[1] = loscom[0]-tzlarg/2.;
+ loscom[2] = loscom[0]+tzlarg/2.;
+ //if(loscom[1]<=0.) {cout<<"Lower distance limit "<<loscom[1]<<" should be >0"<<endl; return -3;}
+ for(int i=0;i<3;i++) {
+   double l = loscom[i]; if(l<=0.) l = dz/2.;
+   redshift[i]  = ZFrLos(l,univ);
+   unplusz[i]   = 1. + redshift[i];
+   growthfac[i] = growth(redshift[i]);
+   rhocz[i]     = univ.Rhoc(redshift[i])*GCm3toMsolMpc3_Cst;;
+   dang[i]      = univ.Dang(redshift[i]);
+   dtrcom[i]    = univ.Dtrcom(redshift[i]);
+   dlum[i]      = univ.Dlum(redshift[i]);
+   dloscom[i]   = univ.Dloscom(redshift[i]);
+   dlosdz[i]    = univ.Dhubble()/univ.E(redshift[i]);
+   dred[i]      = dz/dlosdz[i];
+   adtx[i]      = dx/dtrcom[i];
+   atxlarg[i]   = adtx[i]*nx;
+   adty[i]      = dy/dtrcom[i];
+   atylarg[i]   = adty[i]*ny;
+   nuhiz[i]     = Fr_HyperFin_Par / unplusz[i];  // GHz
+   lambdahiz[i] = SpeedOfLight_Cst*1000./(nuhiz[i]*1.e9);  // m
+   dnuhiz[i]    = DNuFrDz(dred[i],Fr_HyperFin_Par,redshift[i]);  // GHz
+   angsol_pix[i] = AngSol(adtx[i]/2.,adty[i]/2.,M_PI/2.);
+   angsol_tot[i] = AngSol(atxlarg[i]/2.,atylarg[i]/2.,M_PI/2.);
+ }
+ 
+
+ cout<<"--- Cosmology for z = "<<0.<<endl;
+ univ.Print(0.);
+ double rhoc0 = univ.Rhoc(0.)*GCm3toMsolMpc3_Cst;
+
+ for(int i=0;i<3;i++) {
+   cout<<"\n--- Cosmology for z = "<<redshift[i]<<endl;
+   univ.Print(redshift[i]);
+ }
+
+ cout<<endl;
+ cout<<"Facteur de croissance lineaire = "<<growthfac[0]
+     <<" in ["<<growthfac[1]<<","<<growthfac[2]<<"]"<<endl;
+ cout<<"                       1/(1+z) = "<<1./(1.+redshift[0])
+     <<" in ["<<1./(1.+redshift[1])<<","<<1./(1.+redshift[2])<<"]"<<endl;
+ cout<<"Facteur de croissance lineaire^2 = "<<growthfac[0]*growthfac[0]
+     <<" in ["<<growthfac[1]*growthfac[1]<<","<<growthfac[2]*growthfac[2]<<"]"<<endl;
+
+ cout<<"Rho_c (z=0) =  "<<rhoc0<<", a z="<<0<<": "<<rhoc0<<" Msol/Mpc^3"<<endl;
+ cout<<"Rho_c a z = "<<rhocz[0]
+     <<" Msol/Mpc^3 in ["<<rhocz[1]<<","<<rhocz[2]<<"]"<<endl;
+
+ cout<<endl;
+ cout<<"dang= "<<dang[0]<<" Mpc in ["<<dang[1]<<","<<dang[2]<<"]"<<endl;
+ cout<<"dtrcom= "<<dtrcom[0]<<" Mpc com in ["<<dtrcom[1]<<","<<dtrcom[2]<<"]"<<endl;
+ cout<<"dlum= "<<dlum[0]<<" Mpc in ["<<dlum[1]<<","<<dlum[2]<<"]"<<endl;
+ cout<<"dloscom= "<<dloscom[0]<<" Mpc com in ["<<dloscom[1]<<","<<dloscom[2]<<"]"<<endl;
+ cout<<"dz=1 -> dlosdz= "<<dlosdz[0]<<" Mpc com in ["<<dlosdz[1]<<","<<dlosdz[2]<<"]"<<endl;
+ cout<<"1 Mpc los com -> dz = "<<1./dlosdz[0]<<" in ["<<1./dlosdz[1]<<","<<1./dlosdz[2]<<"]"<<endl;
+
+ cout<<endl;
+ for(int i=0;i<3;i++) {
+   cout<<"...Redshift="<<redshift[i]<<endl;
+   cout<<"1\" -> "<<dang[i]*sec2rad(1.)<<" Mpc = "<<dtrcom[i]*sec2rad(1.)<<" Mpc com"<<endl;
+   cout<<"1\' -> "<<dang[i]*min2rad(1.)<<" Mpc = "<<dtrcom[i]*min2rad(1.)<<" Mpc com"<<endl;
+   cout<<"1d -> "<<dang[i]*deg2rad(1.)<<" Mpc = "<<dtrcom[i]*deg2rad(1.)<<" Mpc com"<<endl;
+   cout<<"1 Mpc transv com -> "<<rad2sec(1./dtrcom[i])<<"\" = "
+       <<rad2min(1./dtrcom[i])<<" \' = "<<rad2deg(1./dtrcom[i])<<" d"<<endl;
+   cout<<"dz=1 -> dlosdz= "<<dlosdz[i]<<" Mpc com"<<endl;
+   cout<<"1 Mpc los com -> dz = "<<1./dlosdz[0]<<endl;
+ }
+
+ // --- 
+ // --- Cosmolographie Transverse
+ // --- 
+ cout<<"\n>>>>\n>>>> Cosmologie & Geometrie transverse\n>>>>"<<endl;
+
+ cout<<"dx = "<<dx<<", txlarg = "<<txlarg<<" Mpc (com), nx="<<nx<<endl;
+ cout<<"adtx = "<<adtx[0]<<" rd in ["<<adtx[1]<<","<<adtx[2]<<"]"<<endl;
+ cout<<"     = "<<rad2min(adtx[0])<<"\' in ["<<rad2min(adtx[1])<<","<<rad2min(adtx[2])<<"]"<<endl;
+ cout<<"atxlarg = "<<atxlarg[0]<<" rd in ["<<atxlarg[1]<<","<<atxlarg[2]<<"]"<<endl;
+ cout<<"          "<<rad2deg(atxlarg[0])<<" d in ["<<rad2deg(atxlarg[1])<<","<<rad2deg(atxlarg[2])<<"]"<<endl;
+
+ if(fabs(dx-dy)>1.e-20 && fabs(txlarg-tylarg)>1.e-20) {
+   cout<<"\ndy = "<<dy<<", tylarg = "<<tylarg<<" Mpc (com), ny="<<ny<<endl;
+   cout<<"adty = "<<adty[0]<<" rd in ["<<adty[1]<<","<<adty[2]<<"]"<<endl;
+   cout<<"     = "<<rad2min(adty[0])<<"\' in ["<<rad2min(adty[1])<<","<<rad2min(adty[2])<<"]"<<endl;
+   cout<<"atylarg = "<<atylarg[0]<<" rd in ["<<atylarg[1]<<","<<atylarg[2]<<"]"<<endl;
+   cout<<"          "<<rad2deg(atylarg[0])<<" d in ["<<rad2deg(atylarg[1])<<","<<rad2deg(atylarg[2])<<"]"<<endl;
+ }
+
+ // --- 
+ // --- Cosmolographie Line of sight
+ // --- 
+ cout<<"\n>>>>\n>>>> Cosmologie & Geometrie ligne de visee\n>>>>"<<endl;
+ cout<<"dz = "<<dz<<", tzlarg = "<<tzlarg<<" Mpc (com), nz="<<nz<<endl;
+ cout<<"Redshift = "<<redshift[0]<<" in ["<<redshift[1]<<","<<redshift[2]<<"]"<<endl;
+ cout<<"dred = "<<dred[0]<<" in ["<<dred[1]<<","<<dred[2]<<"]"<<endl;
+ cout<<"nu HI = "<<nuhiz[0]<<" GHz in ["<<nuhiz[1]<<","<<nuhiz[2]<<"]"<<endl;
+ cout<<"lambda HI = "<<lambdahiz[0]<<" m in ["<<lambdahiz[1]<<","<<lambdahiz[2]<<"]"<<endl;
+ cout<<"dnu HI= "<<dnuhiz[0]*1e3<<" MHz in ["<<dnuhiz[1]*1e3<<","<<dnuhiz[2]*1e3<<"]"<<endl;
+
+ // --- 
+ // --- Volume
+ // --- 
+ cout<<"\n>>>>\n>>>> Volumes\n>>>>"<<endl;
+ double Npix = (double)nx*(double)ny*(double)nz;
+ double vol_pixel = dx*dy*dz;
+ double vol_survey = vol_pixel*Npix;
+ cout<<"Npix total = "<<Npix<<" -> "<<Npix*sizeof(double)/1.e6<<" Mo"<<endl;
+ cout<<"Volume pixel = "<<vol_pixel<<" Mpc^3 com"<<endl;
+ cout<<"Volume total = "<<vol_survey<<" Mpc^3 com = "<<vol_survey/1.e9<<" Gpc^3"<<endl;
+
+ double vol = univ.Vol4Pi(redshift[1],redshift[2])/(4.*M_PI)*angsol_tot[0];
+ cout<<"Calcul avec angsol et redshift: vol = "<<vol<<" Mpc^3 = "<<vol/1.e9<<" Gpc^3"<<endl
+     <<"       -> pixel volume comoving = vol/Npix = "<<vol/Npix<<" Mpc^3"<<endl;
+
+ // --- 
+ // --- Angles solides
+ // --- 
+ cout<<"\n>>>>\n>>>> Angles solides\n>>>>"<<endl;
+ cout<<"Pixel solid angle = "<<angsol_pix[0]<<" sr ("<<angsol_pix[0]/(4.*M_PI)<<" *4Pi)"
+     <<" in ["<<angsol_pix[1]<<","<<angsol_pix[2]<<"]"<<endl;
+ cout<<"                  = "<<sr2min2(angsol_pix[0])<<"\'^2"
+     <<" in ["<<sr2min2(angsol_pix[1])<<","<<sr2min2(angsol_pix[2])<<"]"<<endl;
+ cout<<"Total solid angle = "<<angsol_tot[0]<<" sr ("<<angsol_tot[0]/(4.*M_PI)<<" *4Pi)"
+     <<" in ["<<angsol_tot[1]<<","<<angsol_tot[2]<<"]"<<endl;
+
+ // --- 
+ // --- Fourier space: k = omega = 2*Pi*Nu = 2*Pi*C/Lambda
+ // --- 
+ cout<<"\n>>>>\n>>>> Geometrie dans l'espace de Fourier\n>>>>"<<endl;
+ cout<<"Array size: nx = "<<nx<<",  ny = "<<ny<<",  nz = "<<nz<<endl;
+ double dk_x = 2.*M_PI/(nx*dx), knyq_x = M_PI/dx;
+ double dk_y = 2.*M_PI/(nx*dy), knyq_y = M_PI/dy;
+ double dk_z = 2.*M_PI/(nz*dz), knyq_z = M_PI/dz;
+ cout<<"Transverse:"<<endl
+     <<"  Resolution: dk_x = "<<dk_x<<" Mpc^-1  (2Pi/dk_x="<<2.*M_PI/dk_x<<" Mpc)"<<endl
+     <<"              dk_y = "<<dk_y<<" Mpc^-1  (2Pi/dk_y="<<2.*M_PI/dk_y<<" Mpc)"<<endl
+     <<"  Nyquist:    kx = "<<knyq_x<<" Mpc^-1  (2Pi/knyq_x="<<2.*M_PI/knyq_x<<" Mpc)"<<endl
+     <<"              ky = "<<knyq_y<<" Mpc^-1  (2Pi/knyq_y="<<2.*M_PI/knyq_y<<" Mpc)"<<endl;
+ cout<<"Line of sight:"<<endl
+     <<"  Resolution: dk_z = "<<dk_z<<" Mpc^-1  (2Pi/dk_z="<<2.*M_PI/dk_z<<" Mpc)"<<endl
+     <<"  Nyquist:    kz = "<<knyq_z<<" Mpc^-1  (2Pi/knyq_z="<<2.*M_PI/knyq_z<<" Mpc)"<<endl;
+
+ // --- 
+ // --- Variance cosmique
+ // --- 
+ //                      cosmique                    poisson
+ // (sigma/P)^2 = 2*(2Pi)^3 / (4Pi k^2 dk Vsurvey) * [(1+n*P)/(n*P)]^2
+ // nombre de mode = 1/2 * Vsurvey/(2Pi)^3 * 4Pi*k^2*dk
+ if(kcosm>0. && pkcosm>0.) {
+   double pk = pkcosm*pow(growthfac[0],2.);
+   cout<<"\n>>>>\n>>>> variance cosmique pour k="<<kcosm<<" Mpc^-1, pk(z=0)="
+       <<pkcosm<<", pk(z="<<redshift[0]<<")="<<pk<<"\n>>>>"<<endl;
+   for(int i=0;i<3;i++) {  // la correction de variance du au bruit de poisson
+     double v = 1.1; if(i==1) v=1.5; if(i==2) v=2.0;
+     double ngal = 1./(v-1.)/pk;
+     cout<<"  pour "<<ngal<<" gal/Mpc^3 on multiplie par "<<v<<" sigma/P"<<endl;
+   }
+
+   cout<<endl;
+   vector<double> dk; if(dkcosm>0.) dk.push_back(dkcosm);
+   dk.push_back(dk_x); dk.push_back(dk_y); dk.push_back(dk_z);
+   for(int i=0;i<(int)dk.size();i++) { // la variance cosmique pure
+     double vcosm = sqrt( 2.*pow(2.*M_PI,3.)/(4.*M_PI*pow(kcosm,2.)*dk[i]*vol_survey) );
+     double nmode = 0.5*vol_survey/pow(2.*M_PI,3.) * 4.*M_PI*pow(kcosm,2.)*dk[i];
+     cout<<"  pour dk = "<<dk[i]<<" Mpc^-1:  sigma/P = "<<vcosm
+         <<" , Nmode = "<<nmode<<endl;
+   }
+ }
+
+ // --- 
+ // --- Masse de HI
+ // --- 
+ cout<<"\n>>>>\n>>>> Mass HI\n>>>>"<<endl;
+ Schechter sch(nstar,mstar,alpha);
+ sch.SetOutValue(1);
+ cout<<"nstar= "<<nstar<<"  mstar="<<mstar<<"  alpha="<<alpha<<endl;
+ cout<<"mstar*sch(mstar) = "<<sch(mstar)<<" Msol/Mpc^3/Msol"<<endl;
+ int npt = 10000;
+ double lnx1=log10(1.e+6), lnx2=log10(1.e+13), dlnx=(lnx2-lnx1)/npt;
+ double masshimpc3 = IntegrateFuncLog(sch,lnx1,lnx2,0.001,dlnx,10.*dlnx,6);
+ cout<<"Mass density: "<<masshimpc3<<" Msol/Mpc^3"<<endl;
+
+ double masshipix = masshimpc3*vol_pixel;
+ double masshitot = masshimpc3*vol_survey;
+ cout<<"Pixel mass = "<<masshipix<<" Msol"<<endl
+     <<"Total mass in survey = "<<masshitot<<" Msol"<<endl;
+ cout<<"OmegaHI a z=0: "<<masshimpc3/rhoc0<<endl;
+ for(int i=0;i<3;i++)
+   cout<<"        a z="<<redshift[i]<<": "<<masshimpc3/rhocz[i]<<endl;
+ if(mhiref<=0.)  mhiref = masshipix;
+
+ sch.SetOutValue(0);
+ cout<<"\nsch(mstar) = "<<sch(mstar)<<" /Mpc^3/Msol"<<endl;
+ cout<<"Galaxy number density:"<<endl;
+ for(double x=lnx1; x<lnx2-0.5; x+=1.) {
+   double n = IntegrateFuncLog(sch,x,lnx2,0.001,dlnx,10.*dlnx,6);
+   cout<<"  m>"<<x<<" Msol: "<<n<<" /Mpc^3, "<<n*vol_pixel<<" /pixel, "
+       <<n*vol_survey<<" in survey"<<endl;
+ }
+ sch.SetOutValue(1);
+
+ // --- 
+ // --- Survey values
+ // --- 
+ cout<<"\n>>>>\n>>>> Observations\n>>>>"<<endl;
+ double surfeff = surftot * eta_eff;
+ cout<<"surf_tot="<<surftot<<" m^2, eta="<<eta_eff<<"  surf_eff="<<surfeff<<" m^2, tobs="<<tobs<<" s"<<endl;
+
+ // Angles solides pour un telescope plein
+ double angSEq[4], angEq[4];
+ for(int i=0;i<4;i++) {
+   double nu = Fr_HyperFin_Par;
+   if(i<3) nu = nuhiz[i];
+   angSEq[i] = AngsolEqTelescope(nu,surftot);
+   angEq[i] = 2.*FrAngSol(angSEq[i]);
+ }
+ cout<<"\nFor a "<<surftot<<" m^2 telescope:"<<endl
+     <<"    equivalent Omega = "<<angSEq[0]<<" sr in ["<<angSEq[1]<<","<<angSEq[2]<<"]"<<endl
+     <<"    angular diameter = "<<angEq[0]<<" rd = "<<rad2min(angEq[0])
+     <<"\' in ["<<angEq[2]<<","<<angEq[2]<<"]"<<endl;
+ cout<<"At z=0: equivalent Omega = "<<angSEq[3]<<" sr"<<endl
+     <<"        angular diameter = "<<angEq[3]<<" rd = "<<rad2min(angEq[3])<<"\'"<<endl;
+
+ // Pour une observation ou le lobe est + petit ou grand que le pixel de simulation
+ // La taille angulaire du lobe change avec la frequence donc avec le redshift
+ // La taille du lobe "lobearea0" est donnee pour une frequence de reference "lobefreq0" en MHz
+ double nlobes[3] = {1.,1.,1.};
+ // Si "lobefreq0" negatif c'est la frequence du centre du cube
+ if(lobefreq0<=0.) lobefreq0 = nuhiz[0]*1.e3;
+ // Si "lobearea0" negatif c'est la taille du pixel ramenee a lobefreq0
+ if(lobearea0<=0.) lobearea0 = sr2min2(angsol_pix[0])*pow(nuhiz[0]*1.e3/lobefreq0,2.);
+ cout<<"\n--- Lobe: angsol="<<lobearea0<<"\'^2 pour "<<lobefreq0<<" MHz"<<endl;
+ double lobearea[3];
+ for(int i=0;i<3;i++) {
+   lobearea[i] = lobearea0*pow(lobefreq0/(nuhiz[0]*1.e3),2.);
+   nlobes[i] = sr2min2(angsol_pix[i])/lobearea[i];
+ }
+ cout<<"Lobe cylindrique area "<<lobearea[0]<<"\'^2 in ["<<lobearea[1]<<","<<lobearea[2]<<"]"<<endl;
+ cout<<"Number of beams in one transversal pixel "<<nlobes[0]<<" in ["<<nlobes[1]<<","<<nlobes[2]<<"]"<<endl;
+
+ // --- 
+ // --- Signal analysis
+ // --- 
+ // --- Temperature d'antenne Ta et temperature de brillance Tb
+ // La puissance d'une source de brillance I non polarisee est:
+ // P = I * S * Omega * dNu
+ // La puissance recue pour une seule polarisation est:
+ // P = 1/2 * I * S * Omega * dNu
+ // La puissance recue pour un telescope (plein) est
+ //    en remplacant Omega = lambda^2/S
+ // P = 1/2 * I * lambda^2 * dNu
+ // En appliquant la loi de Rayleigh: I = 2*k*Tb/lambda^2
+ //   on obtient
+ // P = 1/2 * 2*k*Tb * dNu = k * Tb * dNu
+ // La temperature d'antenne est definie comme
+ // P = k * Ta * dNu
+ // Donc pour un ciel de temperature de brillance Tb
+ //   et pour une antenne qui mesure une seule polarisation
+ // on a: Ta = Tb
+
+ cout<<"\n>>>>\n>>>> Signal Analysis\n>>>>"<<endl;
+ cout<<"Facteur polar = "<<facpolar<<endl;
+
+ PlanckSpectra planck(T_CMB_Par);
+ planck.SetSpectraApprox(PlanckSpectra::RAYLEIGH);  // Rayleigh spectra
+ planck.SetSpectraVar(PlanckSpectra::NU); // frequency
+ planck.SetSpectraPower(PlanckSpectra::POWER); // output en W/....
+ planck.SetSpectraUnit(PlanckSpectra::ANGSFLUX); // radiance W/m^2/Sr/Hz
+
+ // --- 
+ // --- Signal HI
+ // --- 
+ // Power emitted by HI
+ cout<<"--- Power from HI for M = "<<mhiref<<" Msol"<<endl;
+ cout<<"Flux factor = "<<hifactor<<" at redshift = "<<redshift[0]<<endl;
+ cout<<"Luminosite = "<<hifactor*Msol2LumiHI(mhiref)<<" W"<<endl;
+
+ double fhi_ref[3], sfhi_ref[3];
+ for(int i=0;i<3;i++) {
+   fhi_ref[i] = hifactor*Msol2FluxHI(mhiref,dlum[i]);
+   sfhi_ref[i] = fhi_ref[i] / (dnuhiz[i]*1e9) / Jansky2Watt_cst;
+ }
+ cout<<"FluxHI("<<dlum[0]<<" Mpc) all polar: "<<fhi_ref[0]<<" W/m^2 = "
+     <<fhi_ref[0]/Jansky2Watt_cst<<" Jy.Hz"
+     <<" in ["<<fhi_ref[1]/Jansky2Watt_cst<<","<<fhi_ref[2]/Jansky2Watt_cst<<"]"<<endl;
+ cout<<"If spread over pixel depth ("<<dnuhiz[0]<<" GHz):"<<endl
+     <<"  flux density = "<<sfhi_ref[0]*1.e6<<" mu_Jy"
+     <<" in ["<<sfhi_ref[1]<<","<<sfhi_ref[2]<<"]"<<endl;
+
+ // Signal HI
+ double psig_2polar[3], tasig_2polar[3], ssig_2polar[3], isig_2polar[3], tsig_2polar[3];
+ double psig[3], tasig[3], ssig[3], isig[3], tsig[3];
+ double doplarge[3], dzvrot[3];
+ 
+ for(int i=0;i<3;i++) {
+   psig_2polar[i] = fhi_ref[i] * surfeff;
+   tasig_2polar[i] = psig_2polar[i] / k_Boltzman_Cst / (dnuhiz[i]*1e9);
+   ssig_2polar[i] = psig_2polar[i] / surfeff / (dnuhiz[i]*1e9) / Jansky2Watt_cst;
+   isig_2polar[i] = ssig_2polar[i] / angsol_pix[i];
+   tsig_2polar[i] = isig_2polar[i]*Jansky2Watt_cst
+                    / (2.*pow(nuhiz[i]*1e9/(SpeedOfLight_Cst*1000.),2.)*k_Boltzman_Cst);
+   psig[i] = facpolar * psig_2polar[i];
+   tasig[i] = facpolar * tasig_2polar[i];
+   ssig[i] = facpolar * ssig_2polar[i];
+   isig[i] = facpolar * isig_2polar[i];
+   tsig[i] = facpolar * tsig_2polar[i];
+   doplarge[i] = LargeurDoppler(vrot,nuhiz[i]);
+   dzvrot[i] = DzFrV(vrot,redshift[i]);
+ }
+ cout<<"\n--- Signal HI("<<mhiref<<" Msol) for Dnu="<<dnuhiz[0]<<" GHz :"<<endl
+     <<" Observation:"<<endl
+     <<"    Power="<<psig[0]<<" W in ["<<psig[1]<<","<<psig[2]<<"]"<<endl
+     <<"    Flux density = "<<ssig[0]*1.e6<<" mu_Jy in ["<<ssig[1]*1.e6<<","<<ssig[2]*1.e6<<"]"<<endl
+     <<"    Intensity = "<<isig[0]<<" Jy/sr in ["<<isig[1]<<","<<isig[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tasig[0]<<" K in ["<<tasig[1]<<","<<tasig[2]<<"]"<<endl
+     <<"    Brightness temperature = "<<tsig[0]<<" K in ["<<tsig[1]<<","<<tsig[2]<<"]"<<endl
+     <<" 2 polars:"<<endl
+     <<"    Power="<<psig_2polar[0]<<" W in ["<<psig_2polar[1]<<","<<psig_2polar[2]<<"]"<<endl
+     <<"    Flux density = "<<ssig_2polar[0]*1.e6<<" mu_Jy in ["<<ssig_2polar[1]*1.e6<<","<<ssig_2polar[2]*1.e6<<"]"<<endl
+     <<"    Intensity = "<<isig_2polar[0]<<" Jy/sr in ["<<isig_2polar[1]<<","<<isig_2polar[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tasig_2polar[0]<<" K in ["<<tasig_2polar[1]<<","<<tasig_2polar[2]<<"]"<<endl
+     <<"    Brightness temperature = "<<tsig_2polar[0]<<" K in ["<<tsig_2polar[1]<<","<<tsig_2polar[2]<<"]"<<endl;
+
+ // Elargissement doppler de la raie a 21cm: dNu = vrot/C * Nu(21cm) / (1+z)
+ cout<<"    Doppler for rotation width of "<<vrot<<" km/s"<<endl
+     <<"            width="<<doplarge[0]*1.e3<<" MHz  in ["<<doplarge[1]*1.e3<<","<<doplarge[2]*1.e3<<"]"<<endl
+     <<"            dzvrot= "<<dzvrot[0]<<" in ["<<dzvrot[1]<<","<<dzvrot[2]<<"]"<<endl;
+ if(doplarge[0]>dnuhiz[0])
+   cout<<"Warning: doppler width "<<doplarge[0]<<" GHz > "<<dnuhiz[0]<<" GHz redshift bin width"<<endl;
+
+ // --- 
+ // --- Synchrotron  (T en -2.7  -> Flux en -0.7  dans l'approximation Rayleigh)
+ // --- 
+ double tsynch[3];
+ double psynch_2polar[3], tasynch_2polar[3], ssynch_2polar[3], isynch_2polar[3];
+ double psynch[3], tasynch[3], ssynch[3], isynch[3];
+
+ for(int i=0;i<3;i++) {
+   tsynch[i] = Tsynch408;
+   if(fabs(indnu)>1.e-50) tsynch[i] *= pow(nuhiz[i]/nuhaslam,indnu);
+   planck.SetTemperature(tsynch[i]);
+   psynch_2polar[i] = planck(nuhiz[i]*1.e+9) * surfeff * angsol_pix[i] * (dnuhiz[i]*1e9);
+   tasynch_2polar[i] = psynch_2polar[i] / k_Boltzman_Cst / (dnuhiz[i]*1e9);
+   ssynch_2polar[i] = psynch_2polar[i] / surfeff / (dnuhiz[i]*1e9) / Jansky2Watt_cst;
+   isynch_2polar[i] = ssynch_2polar[i] / angsol_pix[i];
+   psynch[i] = facpolar * psynch_2polar[i];
+   tasynch[i] = facpolar * tasynch_2polar[i];
+   ssynch[i] = facpolar * ssynch_2polar[i];
+   isynch[i] = ssynch[i] / angsol_pix[i];
+ }
+ cout<<"\n--- Synchrotron: T="<<Tsynch408<<" K ("<<nuhaslam<<" GHz), "<<endl
+     <<"    tsynch="<<tsynch[0]<<" K ("<<nuhiz[0]<<" GHz) in ["<<tsynch[1]<<","<<tsynch[2]<<"]"<<endl
+     <<" Observation:"<<endl
+     <<"    Power="<<psynch[0]<<" W for pixel in ["<<psynch[1]<<","<<psynch[2]<<"]"<<endl
+     <<"    Flux density = "<<ssynch[0]<<" Jy for pixel solid angle in ["<<ssynch[1]<<","<<ssynch[2]<<"]"<<endl
+     <<"    Intensity = "<<isynch[0]<<" Jy/sr in ["<<isynch[1]<<","<<isynch[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tasynch[0]<<" K in ["<<tasynch[1]<<","<<tasynch[2]<<"]"<<endl
+     <<" 2 polars:"<<endl
+     <<"    Power="<<psynch_2polar[0]<<" W for pixel in ["<<psynch_2polar[1]<<","<<psynch_2polar[2]<<"]"<<endl
+     <<"    Flux density = "<<ssynch_2polar[0]<<" Jy for pixel solid angle in ["<<ssynch_2polar[1]<<","<<ssynch_2polar[2]<<"]"<<endl
+     <<"    Intensity = "<<isynch_2polar[0]<<" Jy/sr in ["<<isynch_2polar[1]<<","<<isynch_2polar[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tasynch_2polar[0]<<" K in ["<<tasynch_2polar[1]<<","<<tasynch_2polar[2]<<"]"<<endl;
+
+ // --- 
+ // --- CMB
+ // --- 
+ planck.SetTemperature(tcmb);
+ double pcmb_2polar[3], tacmb_2polar[3], scmb_2polar[3], icmb_2polar[3];
+ double pcmb[3], tacmb[3], scmb[3], icmb[3];
+
+ for(int i=0;i<3;i++) {
+   pcmb_2polar[i] = planck(nuhiz[i]*1.e+9) * surfeff * angsol_pix[i] * (dnuhiz[i]*1e9);
+   tacmb_2polar[i] = pcmb_2polar[i] / k_Boltzman_Cst / (dnuhiz[i]*1e9);
+   scmb_2polar[i] = pcmb_2polar[i] / surfeff / (dnuhiz[i]*1e9) / Jansky2Watt_cst;
+   icmb_2polar[i] = scmb_2polar[i] / angsol_pix[i];
+   pcmb[i] = facpolar * pcmb_2polar[i];
+   tacmb[i] = facpolar * tacmb_2polar[i];
+   scmb[i] = facpolar * scmb_2polar[i];
+   icmb[i] = scmb[i] / angsol_pix[i];
+ }
+ cout<<"\n--- CMB: T="<<tcmb<<" K"<<endl
+     <<" Observation:"<<endl
+     <<"    Power="<<pcmb[0]<<" W for pixel in ["<<pcmb[1]<<","<<pcmb[2]<<"]"<<endl
+     <<"    Flux density = "<<scmb[0]<<" Jy for pixel solid angle in ["<<scmb[1]<<","<<scmb[2]<<"]"<<endl
+     <<"    Intensity = "<<icmb[0]<<" Jy/sr in ["<<icmb[1]<<","<<icmb[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tacmb[0]<<" K in ["<<tacmb[1]<<","<<tacmb[2]<<"]"<<endl
+     <<" 2 polars:"<<endl
+     <<"    Power="<<pcmb_2polar[0]<<" W for pixel in ["<<pcmb_2polar[1]<<","<<pcmb_2polar[2]<<"]"<<endl
+     <<"    Flux density = "<<scmb_2polar[0]<<" Jy for pixel solid angle in ["<<scmb_2polar[1]<<","<<scmb_2polar[2]<<"]"<<endl
+     <<"    Intensity = "<<icmb_2polar[0]<<" Jy/sr in ["<<icmb_2polar[1]<<","<<icmb_2polar[2]<<"]"<<endl
+     <<"    Antenna temperature = "<<tacmb_2polar[0]<<" K in ["<<tacmb_2polar[1]<<","<<tacmb_2polar[2]<<"]"<<endl;
+
+ // --- 
+ // --- AGN
+ // --- 
+ double flux_agn = pow(10.,lflux_agn);
+ double mass_agn[3], flux_agn_pix[3], mass_agn_pix[3], lmass_agn_pix[3];
+ for(int i=0;i<3;i++) {
+   mass_agn[i] = FluxHI2Msol(flux_agn*Jansky2Watt_cst,dlum[i]);
+   flux_agn_pix[i] = flux_agn*(dnuhiz[i]*1e9);
+   mass_agn_pix[i] = FluxHI2Msol(flux_agn_pix[i]*Jansky2Watt_cst,dlum[i]);
+   lmass_agn_pix[i] = log10(mass_agn_pix[i]);
+ }
+ cout<<"\n--- AGN: log10(S_agn)="<<lflux_agn<<"   S_agn="<<flux_agn<<" Jy :"<<endl
+     <<"  mass_agn = "<<mass_agn[0]<<" equiv. Msol/Hz in ["<<mass_agn[1]<<","<<mass_agn[2]<<"]"<<endl
+     <<"  flux_agn_pix = "<<flux_agn_pix[0]<<" 10^-26 W/m^2 in ["<<flux_agn_pix[1]<<","<<flux_agn_pix[2]<<"]"<<endl
+     <<"  mass_agn_pix = "<<mass_agn_pix[0]<<" Msol in ["<<mass_agn_pix[1]<<","<<mass_agn_pix[2]<<"]"<<endl
+     <<"  log10(mass_agn_pix) = "<<lmass_agn_pix[0]<<"  in ["<<lmass_agn_pix[1]<<","<<lmass_agn_pix[2]<<"]"<<endl;
+
+ // =====================================================================
+ // ---
+ // --- Noise analysis
+ // ---
+ // --- Puissance du bruit pour un telescope de surface Ae et de BW dNu
+ // Par definition la puissance du bruit est:
+ //     Pb = k * Tsys * dNu  (W)
+ // Pour une source (non-polarisee) de densite de flux (totale 2 polars)
+ //     St (exprimee en Jy = 10^-26 W/m^2/Hz)
+ //     Pt = St * Ae * dNu   (puissance totale emise en W pour 2 polars)
+ //     P1 = 1/2 * St * Ae * dNu   (puissance emise en W pour une polar)
+ // la SEFD (system equivalent flux density en Jy) est definie comme
+ //   la densite de flux total (2 polars) "St" d'une source (non-polarisee)
+ //   dont la puissance P1 mesuree pour une seule polarisation
+ //   serait egale a la puissance du bruit. De P1 = Pb on deduit:
+ //   SEFD = 2 * k * Tsys / Ae    (en Jy)
+ //   la puissance du bruit est: Pb = 1/2 * SEFD * Ae * dNu  (en W)
+ // la sensibilite Slim tient compte du temps d'integration et de la BW:
+ //   le nombre de mesures independantes est "2*dNu*Tobs" donc
+ //   Slim = SEFD / sqrt(2*dNu*Tobs) =  2*k*Tsys/[Ae*sqrt(2*dNu*Tobs) (en Jy)
+ // --- Puissance du bruit pour un interferometre
+ // Ae = surface d'un telescope elementaire
+ // N  = nombre de telescopes dans l'interferometre (Atot = N*Ae)
+ // La sensibilite Slim en Jy est:
+ // Slim = 2 * k * Tsys / [ Ae * Sqrt(2*N(N-1)/2 *dnu*Tobs) ]
+ //      = 2 * k * Tsys / [ Atot/N * Sqrt(2*N(N-1)/2*dnu*Tobs) ]
+ //      = 2 * k * Tsys / [ Atot * Sqrt((N-1)/N *dnu*Tobs) ]
+ // - Interferometre a deux antennes:
+ // Slim =  2 * k * Tsys / [ Atot * Sqrt(1/2 *dnu*Tobs) ]
+ // - Interferometre a N antennes (N grand):
+ // Slim ->  2 * k * Tsys / [ Atot * Sqrt(dnu*Tobs) ]
+ //      C'est aussi la formule pour un telescope unique de surface Atot
+ // --- On ne mesure qu'une seule polarisation
+ // Ces formules sont valables si on mesure 1 polarisation:
+ // Slim est la densite de flux total "St" (2 polars) d'une source (non-polarisee)
+ //   qui donne la meme puissance que le bruit dans un detecteur qui ne
+ //   mesure qu'une seule polarisation:
+ // Le rapport S/N pour une source de densite de flux St (totale 2 polars):
+ //    S/N = St / Slim
+ // La puissance de bruit est, par definition:
+ //    Pb = 1/2 *Slim*Atot*dNu
+ //         = k*Tsys*sqrt(2*dNu/Tobs)  pour N=2
+ //         = k*Tsys*sqrt(dNu/Tobs)    pour N>>grand
+ // La densite de flux d'une source a S/N=1 est:
+ //    St = Slim
+ // La puissance d'une source a S/N=1 mesuree par un detecteur
+ //    qui ne mesure qu'une polar est:
+ //    P1_lim = 1/2 *Slim*Atot*dNu
+ // --- On mesure les 2 polarisations avec deux voies d'electronique distinctes
+ // la puissance du signal mesure est multipliee par 2
+ // la puissance du bruit est multipliee par sqrt(2)
+ // on a donc un gain d'un facteur sqrt(2) sur le rapport S/N
+ // (cela revient d'ailleur a doubler le temps de pose: Tobs -> 2*Tobs)
+ // En notant arbitrairement: Slim' = Slim / sqrt(2)
+ //    ou Slim est defini par les formules ci-dessus
+ // Le rapport S/N pour une source de densite de flux St (totale 2 polars):
+ //   (S/N)_2 = (S/N)_1 * sqrt(2) = (St / Slim) * sqrt(2) = St / Slim'
+ // La densite de flux d'une source a S/N=1 est:
+ //    St = Slim' = Slim / sqrt(2)
+ // La puissance d'une source a S/N=1 cumulee par les 2 detecteurs est:
+ //    P_lim = St*Atot*dNu = Slim'*Atot*dNu = 1/sqrt(2) *Slim*Atot*dNu
+ //          = P1_lim * sqrt(2)
+ // La puissance de bruit cumulee par les 2 detecteurs est, par definition:
+ //    Pb = P_lim = Slim'*Atot*dNu = P1_lim * sqrt(2)
+ //               = 2*k*Tsys*sqrt(dNu/Tobs)   pour N=2
+ //               = k*Tsys*sqrt(2*dNu/Tobs)   pour N>>grand
+ // =====================================================================
+
+ cout<<"\n>>>>\n>>>> Noise analysis\n>>>>"<<endl;
+ double psys[3];
+ for(int i=0;i<3;i++) psys[i] = k_Boltzman_Cst * Tsys * (dnuhiz[i]*1.e+9);
+ cout<<"Noise: T="<<Tsys<<" K"<<endl
+     <<"       P="<<psys[0]<<" W in ["<<psys[1]<<","<<psys[2]<<"]"<<endl;
+
+ cout<<"...Computation assume that noise dominate the signal."<<endl;
+ if(ya2polar)
+   cout<<"...Assuming 2 polarisations measurements with 2 different electronics."<<endl;
+
+
+ //---
+ for(unsigned short it=0;it<2;it++) {
+
+   double fac = 1.;
+   if(it==0) { // Interferometre a 2 telescopes
+     fac = 0.5;
+     cout<<"\n...Observation limits for a 2 telescope interferometer (with complex correlator)"<<endl
+         <<"   (sensitivity is given for real or complex correlator output)"<<endl;
+   } else if (it==1) { // Interferometre a N>> telescopes
+     fac = 1.;
+     cout<<"\n...Observation limits for a N (large) telescope interferometer (with complex correlator)"<<endl
+         <<"     (weak source limit sensitivity in a synthetised image)"<<endl
+         <<"     Also valid for a single dish telescope."<<endl;
+   } else continue;
+
+   double slim[3], SsN[3], smass[3], pkbruit[3];
+   for(int i=0;i<3;i++) {
+     slim[i] = 2. * k_Boltzman_Cst * Tsys / surfeff
+               / sqrt(fac*(dnuhiz[i]*1.e+9)*tobs) /Jansky2Watt_cst;
+     if(ya2polar) slim[i] /= sqrt(2.);
+     SsN[i] = ssig_2polar[i] / slim[i];  // independant de  angsol_pix*surfeff
+     smass[i] = mhiref / ssig_2polar[i] * slim[i];
+     pkbruit[i] = pow(smass[i]/mhiref,2.)*vol_pixel;
+   }
+   cout<<"for 1 lobe:"<<endl
+       <<"   Slim    = "<<slim[0]*1.e6<<" mu_Jy in ["<<slim[1]*1.e6<<","<<slim[2]*1.e6<<"]"<<endl
+       <<"   S/N     = "<<SsN[0]<<" in ["<<SsN[1]<<","<<SsN[2]<<"]"<<endl
+       <<"   Mass HI = "<<smass[0]<<" Msol in ["<<smass[1]<<","<<smass[2]<<"]"<<endl
+       <<"   Pk      = "<<pkbruit[0]<<" Mpc^3 in ["<<pkbruit[1]<<","<<pkbruit[2]<<"]"<<endl;
+
+   double slim_nl[3], SsN_nl[3], smass_nl[3], pkbruit_nl[3];
+   for(int i=0;i<3;i++) {
+     slim_nl[i] = slim[i] * sqrt(nlobes[i]);
+     SsN_nl[i] = ssig_2polar[i] / slim_nl[i];
+     smass_nl[i] = mhiref / ssig_2polar[i] * slim_nl[i];
+     pkbruit_nl[i] = pow(smass_nl[i]/mhiref,2.)*vol_pixel;
+   }
+   cout<<"for "<<nlobes[0]<<" lobes[i] in ["<<nlobes[1]<<","<<nlobes[2]<<"] :"<<endl
+       <<"   Slim    = "<<slim_nl[0]*1.e6<<" mu_Jy in ["<<slim_nl[1]*1.e6<<","<<slim_nl[2]*1.e6<<"]"<<endl
+       <<"   S/N     = "<<SsN_nl[0]<<" in ["<<SsN_nl[1]<<","<<SsN_nl[2]<<"]"<<endl
+       <<"   Mass HI = "<<smass_nl[0]<<" Msol in ["<<smass_nl[1]<<","<<smass_nl[2]<<"]"<<endl
+       <<"   Pk      = "<<pkbruit_nl[0]<<" Mpc^3 in ["<<pkbruit_nl[1]<<","<<pkbruit_nl[2]<<"]"<<endl;
+
+ }
+
+ return 0;
+ }
+
+
+//-------------------------------------------------------------------------------------------
+double LargeurDoppler(double v, double nu)
+// largeur doppler pour une vitesse v en km/s et une frequence nu
+{
+ return v / SpeedOfLight_Cst * nu;
+}
+
+double DzFrV(double v, double zred)
+// largeur en redshift pour une vitesse v en km/s au redshift zred
+{
+  return v / SpeedOfLight_Cst * (1. + zred);
+}
+
+double DNuFrDz(double dzred,double nu_at_0,double zred)
+// Largeur DNu pour une largeur en redshift "dzred" au redshift "zred"
+//    pour la frequence "nu_at_0" a z=0
+// nu =  NuHi(z=0)/(1.+z0)
+// dnu = NuHi(z=0)/(1.+z0-dz/2) - NuHi/(1.+z0+dz/2)
+//     = NuHi(z=0)*dz/[ (1+z0)^2 - (dz/2)^2 ]
+//     = NuHi(z=0)*dz/(1.+z0)^2 / [ 1 - [dz/(1+z0)/2)]^2 ]
+//     = NuHi(z=0)*dz/(1.+z0)^2 / [1 - dz/(1+z0)/2] / [1 + dz/(1+z0)/2]
+//    ~= NuHi(z=0)*dz/(1.+z0)^2   (approx. pour dz<<z0 a l'ordre (dz/z0)^2)
+{
+  double zp1 = 1.+zred;
+  return nu_at_0*dzred/(zp1*zp1)/(1.-dzred/zp1/2.)/(1.+dzred/zp1/2.);
+}
+
+double DzFrDNu(double dnu_at_0,double nu_at_0,double zred)
+// Largeur en redshift au redshift "zred" pour une largeur
+// en frequence "dnu_at_0" a la frequence "nu_at_0" a z=0
+{
+  if(dnu_at_0<=0.) return 0.;
+  double zp1 = 1.+zred;
+  double dnusnu0 = dnu_at_0/nu_at_0;
+  return 2./dnusnu0 * (sqrt(1.+(dnusnu0*zp1)*(dnusnu0*zp1)) - 1.);
+}
+double DzFrDNuApprox(double dnu_at_0,double nu_at_0,double zred)
+// idem DzFrDNu mais on utilise l'approximation: dnu=NuHi(z=0)*dz/(1.+z0)^2
+{
+  double zp1 = 1.+zred;
+  return dnu_at_0/nu_at_0 *(zp1*zp1);
+}
+
+double ZFrLos(double loscom,CosmoCalc& univ)
+// Recherche du redshift correspondant a une distance comobile
+// le long de la ligne de visee egale a "loscom" Mpc
+// et pour un univers "univ"
+{
+  double dz = univ.ZMax()/10.; if(dz<=0.) dz = 0.1;
+  double zmin=0., zmax=0.;
+  while(univ.Dloscom(zmax)<loscom) zmax += dz;
+  if(zmax==0.) return 0.;
+  for(int i=0; i<6; i++) {
+    zmin=zmax-dz; if(zmin<0.) zmin=0.;
+    dz /= 10.;
+    for(double z=zmin; z<zmax+dz; z+=dz) {
+      double d = univ.Dloscom(z);
+      if(d<loscom) continue;
+      zmax = z;
+      //cout<<"ZFrLos: z="<<zmax<<" d="<<d<<" / "<<loscom<<endl;
+      break;
+    }
+  }
+  return zmax;
+}
+
+double AngsolEqTelescope(double nu /* GHz */,double telsurf /* m^2 */)
+/*
+Calcul de l'angle solide (sr) equivalent pour un telescope
+de surface totale "telsurf" (m^2) a la frequence "nu" (GHz)
+- Soit D(t) la figure de diffraction du telescope telle que D(t=0)=1
+       (t = angle depuis l'axe optique)
+  telescope circulaire de diametre D:
+      D(t) = [2J1(Pi*D*t/l)/(Pi*D*t/l)]
+  telescope rectangulaire axb:
+      D(t) = [sin(Pi*a*t/l)/(Pi*a*t/l)]*[sin(Pi*b*t/l)/(Pi*b*t/l)]
+- On cherche l'angle solide equivalent (par ex d'un cylindre de hauteur 1)
+  Int[ D(t)^2 dOmega ] =  Int[ D(t)^2 2Pi t dt ] = Lambda^2/S
+- En conclusion, pour un ciel d'intensite uniforme I, on a:
+  P = I * S * Omega * dNu = I * S * (Lambda^2/S) * dNu
+*/
+{
+  double lambda = SpeedOfLight_Cst*1000./(nu*1.e9);
+  return lambda*lambda / telsurf;
+}
Index: /tags/V1_0/Cosmo/SimLSS/cmvfitpk.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvfitpk.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvfitpk.cc	(revision 3382)
@@ -0,0 +1,340 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "ntuple.h"
+#include "histerr.h"
+
+#include "constcosmo.h"
+#include "pkspectrum.h"
+
+#include "Minuit2/FunctionMinimum.h"
+#include "Minuit2/MnMigrad.h"
+#include "Minuit2/MnUserParameters.h"
+#include "Minuit2/MnPrint.h"
+#include "Minuit2/MnMinos.h"
+#include "Minuit2/MinosError.h"
+#include "Minuit2/FCNBase.h"
+using namespace ROOT::Minuit2;
+
+namespace ROOT { namespace Minuit2 {
+class MyFCN : public FCNBase {
+public:
+  MyFCN(HistoErr& herr,PkSpectrumZ& pk);
+  void Init(const vector<double>& par) const;
+  double Func(double x,const vector<double>& par) const;
+  double operator()(const vector<double>& par) const;
+  double Up(void) const {return 1.;}
+private:
+  HistoErr& herr_;
+  PkSpectrumZ& pk_;
+};
+} }  // namespace ROOT + Minuit2
+
+void usage(void);
+void usage(void)
+{
+cout<<"usage: cmvfitpk [-k kmin,kmax] -e conchpkrec.ppf observ3d_1.ppf observ3d_2.ppf ..."<<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ // --- Cosmography definition (WMAP)
+ double zref = 0.175;
+ double ob0 = 0.0444356;
+ double h100=0.71, om0=0.267804, ol0=0.73;
+
+ // --- Spectrum and variance definition
+ double ns = 1., as = 1.;
+ double R=8./h100, sigmaR = 1.;
+ double kmin=1e-5,kmax=1000.;
+ int npt = 10000;
+ double eps=1.e-3;
+
+ // --- les fichiers
+ double klim[2]={0.,-1.};
+ string fconc = "";
+
+ // --- les options de print/plot
+ int nprint = 3, nplot = -1;  // -1 = all
+
+ // --- Reading arguments
+ char c;
+ while((c = getopt(narg,arg,"hk:e:")) != -1) {
+  switch (c) {
+  case 'k' :
+    sscanf(optarg,"%lf,%lf",&klim[0],&klim[1]);
+    break;
+  case 'e' :
+    fconc = optarg;
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+
+ if(optind>=narg) return -2;
+
+ // --- Create spectrum
+ cout<<endl<<"\n--- Create Spectrum"<<endl;
+ InitialSpectrum pkini(ns,as);
+ bool nobaryon = false;
+ double ocdm0 = om0-ob0;
+ TransfertEisenstein tf(h100,ocdm0,ob0,T_CMB_Par,nobaryon);
+ GrowthFactor growth(om0,ol0); cout<<"...Growth="<<growth(zref)<<endl;
+ PkSpectrum0 pk0(pkini,tf);
+ PkSpectrumZ pkz(pk0,growth,zref);
+
+ // --- Compute variance and normalize spectrum
+ pkz.SetZ(0.);
+ cout<<endl<<"\n--- Compute variance for top-hat R="<<R
+     <<" at z="<<pkz.GetZ()<<endl;
+ VarianceSpectrum varpk_th(pkz,R,VarianceSpectrum::TOPHAT);
+ double kfind_th = varpk_th.FindMaximum(kmin,kmax,eps);
+ double pkmax_th = varpk_th(kfind_th);
+ cout<<"kfind_th = "<<kfind_th<<" ("<<log10(kfind_th)<<"), integrand="<<pkmax_th<<endl;
+ double k1=kmin, k2=kmax;
+ int rc = varpk_th.FindLimits(pkmax_th/1.e4,k1,k2,eps);
+ cout<<"limit_th: rc="<<rc<<" : "<<k1<<" ("<<log10(k1)<<") , "
+     <<k2<<" ("<<log10(k2)<<")"<<endl;
+
+ double ldlk = (log10(k2)-log10(k1))/npt;
+ varpk_th.SetInteg(0.01,ldlk,-1.,4);
+ double sr2 = varpk_th.Variance(k1,k2);
+ cout<<"varpk_th="<<sr2<<"  ->  sigma="<<sqrt(sr2)<<endl;
+
+ double normpkz = sigmaR*sigmaR/sr2;
+ pkz.SetScale(normpkz);
+ cout<<"Spectrum normalisation = "<<pkz.GetScale()<<endl;
+ pkz.SetZ(zref);
+
+ // --- Reading reference mean spectrum
+ cout<<endl<<"\n--- Reading spectrum form file "<<fconc<<endl;
+ HistoErr herrconc;
+ {
+ PInPersist pis(fconc.c_str());
+ pis >> PPFNameTag("herrconc") >> herrconc;
+ }
+ cout<<herrconc;
+ if(herrconc.NBins()<1) return -3;
+ double b_ini = herrconc(2*herrconc.NBins()/3);
+ cout<<"b_ini = "<<b_ini<<endl;
+ if(klim[1]<=klim[0]) klim[1] = herrconc.XMax();
+
+ // --- NTuple et ppf
+ const int npar = 7;  // Number of parameters in the fit
+ TMatrix<r_8> Cov(npar,npar); Cov = 0.;
+ POutPersist pos("cmvfitpk.ppf");
+ const int nvar = 2*npar+1;
+ char *vname[nvar] = {
+       "xi2"
+       ,"b","a","oc","ob","ol","h","n"
+       ,"eb","ea","eoc","eob","eol","eh","en"
+       };
+ NTuple nt(nvar,vname);
+ double xnt[nvar];
+
+ // ***
+ // --- Boucle sur les fichiers a fitter
+ // ***
+ int nfile=0, ncov=0;
+ for(int ifile=optind;ifile<narg;ifile++) {
+
+   // --- lecture du fichier
+   cout<<">>> Reading["<<nfile<<","<<ifile<<"]: "<<arg[ifile]<<endl;
+   HistoErr herr;
+   PInPersist pis(arg[ifile]);
+   pis >> PPFNameTag("hpkrec") >> herr;
+   if(herr.NBins()!=herrconc.NBins()) {
+     cout<<"... bad number of bins: "<<herr.NBins()<<endl;
+     continue;
+   }
+
+   // --- Mise en forme
+   unsigned int nbinok = 0;
+   for(int i=0;i<herr.NBins();i++) {
+     double k = herr.BinCenter(i);
+     if(i==0 || k<klim[0] || k>klim[1]) {herr.SetErr2(i,-1.); continue;}
+     herr.SetErr2(i,herrconc.Error2(i));
+     nbinok++;
+   }
+
+   // --- Initialisation de minuit
+    MnUserParameters upar;
+    upar.Add("B",b_ini,b_ini/100.);
+    upar.Add("A",1.,0.01);
+    upar.Add("Ocdm",ocdm0,0.001,ocdm0/2.,2.*ocdm0);
+    //upar.Fix("Ocdm");
+    upar.Add("Ob",ob0,0.001,ob0/10.,10.*ob0);
+    //upar.Fix("Ob");
+    upar.Add("Ol",ol0,0.001,0.1,2.);
+    upar.Fix("Ol");
+    upar.Add("h100",h100,0.01,10.,150.);
+    upar.Fix("h100");
+    upar.Add("ns",ns,0.001,0.7,1.5);
+    upar.Fix("ns");
+    MyFCN fcn(herr,pkz);
+    if(nbinok<upar.VariableParameters()) {
+      cout<<"... nombre de degres de liberte <0: nbinok="<<nbinok<<endl;
+      continue;
+    }
+
+   // --- Fit minuit
+   unsigned int nfcall = 1000; double tolerance = 0.05;
+   MnMigrad migrad(fcn,upar,MnStrategy(1));
+   FunctionMinimum min = migrad(nfcall,tolerance);
+   if(!min.IsValid()) {
+     cout<<"!!!!!!!!! Echec Minuit"<<endl;
+     //cout<<"minimum: "<<min<<endl;
+     continue;
+   }
+
+   MnUserParameterState ustate = min.UserState();
+   double xi2r = ustate.Fval()/(nbinok-ustate.VariableParameters());
+   vector<double> parfit  = ustate.Parameters().Params();
+   vector<double> eparfit = ustate.Parameters().Errors();
+   if(ustate.HasCovariance()) {
+     MnUserCovariance ucov = ustate.Covariance();
+     for(unsigned int i=0;i<upar.VariableParameters();i++)
+       for(unsigned int j=0;j<upar.VariableParameters();j++)
+	 Cov(ustate.ExtOfInt(i),ustate.ExtOfInt(j)) += ucov(i,j);
+     ncov++;
+   }
+
+   // --- Recuperation des informations et remplissage NTuple
+   for(int i=0;i<nvar;i++) xnt[i] = 0.;
+   xnt[0] = xi2r;
+   for(int i=0;i<npar;i++) xnt[1+i] = parfit[i];
+   for(int i=0;i<npar;i++) xnt[npar+1+i] = eparfit[i];
+   nt.Fill(xnt);
+
+   // --- stoquage des histos de plots
+   if(nfile<nplot || nplot<0) {
+     HistoErr herrf(herr); herrf.Zero();
+     HistoErr herrd(herr); herrd.Zero();
+     fcn.Init(parfit);
+     for(int i=1;i<herr.NBins();i++) {
+       double f = fcn.Func(herr.BinCenter(i),parfit);
+       herrf.SetBin(i,f,herr.Error(i),1.);
+       herrd.SetBin(i,herr(i)-f,herr.Error(i),1.);
+     }
+     char str[64];
+     sprintf(str,"h%d",nfile); pos.PutObject(herr,str);
+     sprintf(str,"hf%d",nfile); pos.PutObject(herrf,str);
+     sprintf(str,"hd%d",nfile); pos.PutObject(herrd,str);
+   }
+
+   // --- Print de debug
+   if(nfile<nprint) {
+     cout<<"minimum: "<<min<<endl;
+     for(int i=0;i<nvar;i++) cout<<"["<<i<<"] = "<<xnt[i]<<endl;
+
+     MnMinos Minos(fcn,min);
+     pair<double,double> eminos[npar];
+     for(int ip=0;ip<npar;ip++) {
+       eminos[ip].first = eminos[ip].second = 0.;
+       if(!ustate.Parameter(ip).IsFixed()) eminos[ip] = Minos(ip);
+       cout<<"Minos: "<<ip<<" err=["<<eminos[ip].first<<","<<eminos[ip].second<<"]"<<endl;
+     }
+   }
+
+   nfile++;
+ }
+
+ // --- Fin du job
+ if(nfile>0) pos.PutObject(nt,"nt");
+ if(ncov>0) {Cov /= (double)ncov; pos.PutObject(Cov,"cov");}
+
+ return 0;
+}
+
+//--------------------------------------------------
+MyFCN::MyFCN(HistoErr& herr,PkSpectrumZ& pk)
+  : herr_(herr) , pk_(pk)
+{
+}
+
+void MyFCN::Init(const vector<double>& par) const
+{
+ double A=par[1], Ocdm0=par[2], Ob0=par[3], Ol0=par[4], h100=par[5], ns=par[6];
+ pk_.GetPk0().GetPkIni().SetSlope(ns);
+ pk_.GetPk0().GetPkIni().SetNorm(A);
+ pk_.GetPk0().GetTransfert().SetParTo(h100,Ocdm0,Ob0);
+ pk_.GetGrowthFactor().SetParTo(Ocdm0+Ob0,Ol0);
+}
+
+double MyFCN::Func(double x,const vector<double>& par) const
+// par: [0]=B,  [1]=A,  [2]=Ocdm0,  [3]=Ob0,  [4]=Ol0, [5]=h100, [6]=npow
+{
+ Init(par);
+ return pk_(x) + par[0];
+}
+
+double MyFCN::operator()(const vector<double>& par) const
+{
+ Init(par);
+ double xi2 = 0.;
+ for(int i=0;i<herr_.NBins();i++) {
+   double e2 = herr_.Error2(i);
+   if(e2<=0.) continue;
+   double x = herr_.BinCenter(i);
+   double v = herr_(i);
+   double f = Func(x,par);
+   xi2 += (v-f)*(v-f)/e2;
+ }
+ return xi2;
+}
+
+/*
+openppf cmvfitpk.ppf
+
+print nt
+
+set i 0
+zone
+disp h$i "nsta hbincont err"
+disp hf$i "nsta same red"
+
+zone
+disp hd$i "nsta hbincont err red"
+disp hd$i "nsta same"
+
+zone
+n/plot nt.xi2
+
+zone
+n/plot nt.a
+n/plot nt.b
+n/plot nt.b%a ! ! "crossmarker5"
+
+n/plot nt.oc
+n/plot nt.ob
+n/plot nt.oc+ob
+n/plot nt.ob%oc ! ! "crossmarker5"
+
+n/plot nt.ea
+n/plot nt.eb
+n/plot nt.ea%eb ! ! "crossmarker5"
+
+disp cov "zoomx30"
+del cor
+c++exec \
+TMatrix<r_8> cor(cov,false); cor = 0.; \
+for(int i=0;i<cor.NRows();i++) { \
+  for(int j=0;j<cor.NCols();j++) { \
+    double v = cov(i,i)*cov(j,j); \
+    if(v<=0.) continue; \
+    cor(i,j) = cov(i,j)/sqrt(v); \
+} } \
+KeepObj(cor); \
+cout<<"Matrice cor cree "<<endl;
+
+disp cor "zoomx30"
+
+ */
Index: /tags/V1_0/Cosmo/SimLSS/cmvobserv3d.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvobserv3d.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvobserv3d.cc	(revision 3382)
@@ -0,0 +1,719 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+#include "matharr.h"
+
+#include "constcosmo.h"
+#include "cosmocalc.h"
+#include "schechter.h"
+#include "geneutils.h"
+#include "genefluct3d.h"
+
+void usage(void);
+void usage(void)
+{
+ cout<<"cmvobserv3d [...options...]"<<endl
+     <<" -a : auto init random seed (needed for multiple simul)"<<endl
+     <<" -0 : use ComputeFourier0 method (defaut: no, use normal way)"<<endl
+     <<" -G typevol: compute Pk(z=0) and apply growth factor in real space"<<endl
+     <<"             typevol=1 noise evolved with distance / observateur (def)"<<endl
+     <<"             typevol=2 noise evolved with distance to middle of Z planes"<<endl
+     <<"      (default: no, spectrum Pk(z=z_median) for all cube)"<<endl
+     <<" -F : filter spectrum by pixel shape (0=no 1=yes(default)"<<endl
+     <<" -U typ : do not poisson fluctuate with Ngal, convert directly to HI mass"<<endl
+     <<"          (typ<0 just multiply dRho/Rho by mass_by_pixel)"<<endl
+     <<" -x nx,dx : size along x axis (npix,Mpc)"<<endl
+     <<" -y ny,dy : size along y axis (npix,Mpc)"<<endl
+     <<"            if ny or dy <=0 take same value as for x"<<endl
+     <<" -z nz,dz : size along z axis (redshift axis, npix,Mpc)"<<endl
+     <<" -Z zref : redshift for the center of the simulation cube"<<endl
+     <<" -s snoise,typevol : gaussian noise sigma in equivalent Msol"<<endl
+     <<"           typevol=0 no evolution (def)"<<endl
+     <<"           typevol=1 noise evolved with distance / observateur"<<endl
+     <<"           typevol=2 noise evolved with distance to middle of Z planes"<<endl
+     <<" -2 : compute also 2D spectrum (default: no)"<<endl
+     <<" -N scalemass: facteur d\'unite pour la masse (default: -1)"<<endl
+     <<"               ex: si on veut unites 10^8 Msol -> scalemass=1.e-8"<<endl
+     <<"               si <0 alors facteur=-scalemass*Mpix"<<endl
+     <<" -M schmin,schmax,nsch : min,max mass and nb points for schechter HI"<<endl
+     <<"                         If nsch<0 alors no,bre de points par decade"<<endl
+     <<" -Q naleagal : use quick method for turning ngal to mass"<<endl
+     <<" -R schmassdist.ppf : read mass distribution for trials from file"<<endl
+     <<"               instead of computing it (ONLY if \"-Q\" option is activated)"<<endl
+     <<" -8 sigmaR,R : normalisation du spectre de puissance, R en Mpc"<<endl
+     <<"               (default sigmaR=1, R=8/h100 Mpc)"<<endl
+     <<" -W : write cube in FITS format (complex cube is coded as real cube)"<<endl
+     <<" -P : write cube in PPF format"<<endl
+     <<" -S : write cube slices in PPF format"<<endl
+     <<" -V : compute variance from real space (for check, default: no)"<<endl
+     <<" -T nth : nombre de threads (si compil multi-thread, default: 0)"<<endl
+     <<endl;
+     ////<<" -A <log10(S_agn in Jy at 1.4 GHz)>,sigma,powlaw :"<<endl
+     ////<<"    AGN mean and sigma gaussian equiv. distrib. for solid angle of centeral pixel"<<endl
+     ////<<"    powlaw: apply S_agn evolution as (Nu/1.4)^powlaw"<<endl
+}
+
+int main(int narg,char *arg[])
+{
+ InitTim();
+
+ //-----------------------------------------------------------------
+ // *** Survey definition
+ long nx=360, ny=-1, nz=64; double dx=1., dy=-1., dz=-1.;
+ //long nx=1000, ny=-1, nz=128; double dx=3., dy=-1., dz=6.;
+ //long nx=1200, ny=-1, nz=128; double dx=1., dy=-1., dz=3;
+
+ // *** Cosmography definition   (WMAP)
+ unsigned short flat = 0;
+ double ob0 = 0.0444356;
+ double h100=0.71, om0=0.267804, or0=7.9e-05, ol0=0.73,w0=-1.;
+ double zref = 0.5;
+ double perc=0.01,dzinc=-1.,dzmax=-1.; unsigned short glorder=4;
+
+ // *** Spectrum and variance definition
+ double ns = 1., as = 1.;
+ double R=8./h100, Rg=R/sqrt(5.);
+ double sigmaR = 1.;
+
+ double kmin=1e-5,kmax=1000.;
+ int npt = 10000;
+ double lkmin=log10(kmin), lkmax=log10(kmax);
+ double eps=1.e-3;
+
+ // *** Schechter mass function definition
+ double h75 = h100 / 0.75;
+ double nstar = 0.006*pow(h75,3.);
+ double mstar = pow(10.,9.8);  // MSol
+ double alpha = -1.37;
+
+ double schmin=1.e7, schmax=1.e13;
+ int schnpt = -100;
+ bool use_schmassdist = false;
+ long naleagal = 100000;
+ bool recompute_schmassdist = true;
+ string schmassdistfile = "";
+ bool no_poisson = false;
+ int no_poisson_type = 1;
+
+ double scalemass = -1.;
+
+ // *** Niveau de bruit
+ double snoise= 0.;   // en equivalent MSol
+ int noise_evol = 0;
+
+ //// *** AGN
+ ////bool do_agn = false;
+ ////double lfjy_agn=-99., lsigma_agn=0.;   // en Jy
+ ////double powlaw_agn = 0.;
+
+ // *** type de generation
+ bool computefourier0=false;
+ int use_growth_factor = 0;
+ unsigned short nthread=0;
+ int filter_by_pixel = 1;
+
+ // *** What to do
+ bool comp2dspec = false;
+ bool wfits = false;
+ bool wppf = false;
+ bool wslice = false;
+ bool compvarreal = false;
+
+ // --- Decodage arguments
+ if(narg>0) {
+   cout<<"\n--- Arguments: "<<endl;
+   for(int i=0;i<narg;i++) cout<<arg[i]<<" ";
+   cout<<endl;
+ }
+
+ char c;
+ while((c = getopt(narg,arg,"ha0PWSV2U:G:F:x:y:z:s:Z:M:A:T:N:Q:R:8:")) != -1) {
+  int nth = 0;
+  switch (c) {
+  case 'a' :
+    Auto_Ini_Ranf(5);
+    break;
+  case '0' :
+    computefourier0 = true;
+    break;
+  case 'G' :
+    sscanf(optarg,"%d",&use_growth_factor);
+    break;
+  case 'U' :
+    no_poisson = true;
+    sscanf(optarg,"%d",&no_poisson_type);
+    break;
+  case 'F' :
+    sscanf(optarg,"%d",&filter_by_pixel);
+    break;
+  case 'x' :
+    sscanf(optarg,"%ld,%lf",&nx,&dx);
+    break;
+  case 'y' :
+    sscanf(optarg,"%ld,%lf",&ny,&dy);
+    break;
+  case 'z' :
+    sscanf(optarg,"%ld,%lf",&nz,&dz);
+    break;
+  case 's' :
+    sscanf(optarg,"%lf,%d",&snoise,&noise_evol);
+    break;
+  case 'Z' :
+    sscanf(optarg,"%lf",&zref);
+    break;
+  case '2' :
+    comp2dspec = true;
+    break;
+  case 'N' :
+    sscanf(optarg,"%lf",&scalemass);
+    if(scalemass==0.) scalemass = 1.;
+    break;
+  case 'M' :
+    sscanf(optarg,"%lf,%lf,%d",&schmin,&schmax,&schnpt);
+    break;
+  case 'Q' :
+    use_schmassdist = true;
+    sscanf(optarg,"%ld",&naleagal);
+    break;
+  case 'R' :
+    schmassdistfile = optarg;
+    break;
+    ////  case 'A' :
+    ////do_agn = true;
+    ////sscanf(optarg,"%lf,%lf,%lf",&lfjy_agn,&lsigma_agn,&powlaw_agn);
+    ////break;
+  case '8' :
+    sscanf(optarg,"%lf,%lf",&sigmaR,&R);
+    break;
+  case 'V' :
+    compvarreal = true;
+    break;
+  case 'W' :
+    wfits = true;
+    break;
+  case 'P' :
+    wppf = true;
+    break;
+  case 'S' :
+    wslice = true;
+    break;
+  case 'T' :
+    sscanf(optarg,"%d",&nth);
+    nthread = (nth<1)? 0: nth;
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+
+ double lschmin=log10(schmin), lschmax=log10(schmax);
+ if(schnpt<=0) {  // alors c'est un nombre de points par decade
+   schnpt = long( (-schnpt)*(lschmax-lschmin+1.) + 0.5 );
+   if(schnpt<=2) schnpt = 1000;
+ }
+ if(naleagal<=2) naleagal = 100000;
+
+ cout<<"zref="<<zref<<endl;
+ cout<<"nx="<<nx<<" dx="<<dx<<" ny="<<ny<<" dy="<<dy<<" nz="<<nz<<" dz="<<dz<<endl;
+ cout<<"kmin="<<kmin<<" ("<<lkmin<<"), kmax="<<kmax<<" ("<<lkmax<<") Mpc^-1"
+     <<", npt="<<npt<<endl;
+ cout<<"Filter by pixel = "<<filter_by_pixel<<endl;
+ cout<<"R="<<R<<" Rg="<<Rg<<" Mpc, sigmaR="<<sigmaR<<endl;
+ cout<<"Use_growth_factor = "<<use_growth_factor<<endl;
+ cout<<"nstar= "<<nstar<<"  mstar="<<mstar<<"  alpha="<<alpha<<endl;
+ cout<<"schmin="<<schmin<<" ("<<lschmin
+     <<"), schmax="<<schmax<<" ("<<lschmax<<") Msol"
+     <<", schnpt="<<schnpt<<endl;
+ if(no_poisson) cout<<"No poisson fluctuation, direct conversion to HI mass, typ="
+                    <<no_poisson_type<<endl;
+ cout<<"snoise="<<snoise<<" equivalent Msol, evolution="<<noise_evol<<endl;
+ cout<<"scalemass="<<scalemass<<endl;
+ ////if(do_agn)
+ ////  cout<<"AGN: <log10(Jy)>="<<lfjy_agn<<" , sigma="<<lsigma_agn
+ ////      <<" , powlaw="<<powlaw_agn<<endl;
+
+ string tagobs = "cmvobserv3d.ppf";
+ POutPersist posobs(tagobs);
+
+ //-----------------------------------------------------------------
+ cout<<endl<<"\n--- Create Cosmology"<<endl;
+
+ CosmoCalc univ(flat,true,zref+1.);
+ univ.SetInteg(perc,dzinc,dzmax,glorder);
+ univ.SetDynParam(h100,om0,or0,ol0,w0);
+ univ.PrtInteg();
+ univ.Print();
+ double loscomref = univ.Dloscom(zref);
+ cout<<"\nzref = "<<zref<<" -> dloscom = "<<loscomref<<" Mpc"<<endl;
+ univ.Print(zref);
+
+ //-----------------------------------------------------------------
+ cout<<endl<<"\n--- Create Spectrum"<<endl;
+
+ InitialSpectrum pkini(ns,as);
+
+ TransfertEisenstein tf(h100,om0-ob0,ob0,T_CMB_Par,false);
+ //tf.SetNoOscEnv(2);
+
+ GrowthFactor growth(om0,ol0);
+ // GrowthFactor growth(1.,0.); // D(z) = 1/(1+z)
+ double growth_at_z = growth(zref);
+ cout<<"...Growth factor at z="<<zref<<" = "<<growth_at_z<<endl;
+
+ PkSpectrum0 pk0(pkini,tf);
+
+ PkSpectrumZ pkz(pk0,growth,zref);
+
+ //-----------------------------------------------------------------
+ pkz.SetZ(0.);
+ cout<<endl<<"\n--- Compute variance for top-hat R="<<R
+     <<" at z="<<pkz.GetZ()<<endl;
+ VarianceSpectrum varpk_th(pkz,R,VarianceSpectrum::TOPHAT);
+ double kfind_th = varpk_th.FindMaximum(kmin,kmax,eps);
+ double pkmax_th = varpk_th(kfind_th);
+ cout<<"kfind_th = "<<kfind_th<<" ("<<log10(kfind_th)<<"), integrand="<<pkmax_th<<endl;
+ double k1=kmin, k2=kmax;
+ int rc = varpk_th.FindLimits(pkmax_th/1.e4,k1,k2,eps);
+ cout<<"limit_th: rc="<<rc<<" : "<<k1<<" ("<<log10(k1)<<") , "
+     <<k2<<" ("<<log10(k2)<<")"<<endl;
+
+ double ldlk = (log10(k2)-log10(k1))/npt;
+ varpk_th.SetInteg(0.01,ldlk,-1.,4);
+ double sr2 = varpk_th.Variance(k1,k2);
+ cout<<"varpk_th="<<sr2<<"  ->  sigma="<<sqrt(sr2)<<endl;
+
+ double normpkz = sigmaR*sigmaR/sr2;
+ pkz.SetScale(normpkz);
+ cout<<"Spectrum normalisation = "<<pkz.GetScale()<<endl;
+
+ {
+ Histo hpkz0(lkmin,lkmax,npt); hpkz0.ReCenterBin();
+ FuncToHisto(pkz,hpkz0,true);
+ tagobs = "hpkz0"; posobs.PutObject(hpkz0,tagobs);
+ }
+
+ pkz.SetZ(zref);
+
+ {
+ Histo hpkz(lkmin,lkmax,npt); hpkz.ReCenterBin();
+ FuncToHisto(pkz,hpkz,true);
+ tagobs = "hpkz"; posobs.PutObject(hpkz,tagobs);
+ }
+
+ //-----------------------------------------------------------------
+ cout<<endl<<"\n--- Compute variance for Pk at z="<<pkz.GetZ()<<endl;
+ VarianceSpectrum varpk_int(pkz,R,VarianceSpectrum::NOFILTER);
+
+ double kfind_int = varpk_int.FindMaximum(kmin,kmax,eps);
+ double pkmax_int = varpk_int(kfind_int);
+ cout<<"kfind_int = "<<kfind_int<<" ("<<log10(kfind_int)<<"), integrand="<<pkmax_int<<endl;
+ double k1int=kmin, k2int=kmax;
+ int rcint = varpk_int.FindLimits(pkmax_int/1.e4,k1int,k2int,eps);
+ cout<<"limit_int: rc="<<rcint<<" : "<<k1int<<" ("<<log10(k1int)<<") , "
+     <<k2int<<" ("<<log10(k2int)<<")"<<endl;
+
+ double ldlkint = (log10(k2int)-log10(k1int))/npt;
+ varpk_int.SetInteg(0.01,ldlkint,-1.,4);
+ double sr2int = varpk_int.Variance(k1int,k2int);
+ cout<<"varpk_int="<<sr2int<<"  ->  sigma="<<sqrt(sr2int)<<endl;
+ 
+ //-----------------------------------------------------------------
+ cout<<endl<<"\n--- Create mass function, compute number/mass density, init mass trials"<<endl;
+
+ Schechter sch(nstar,mstar,alpha);
+ sch.Print();
+
+ sch.SetOutValue(0);
+ cout<<"sch(mstar) = "<<sch(mstar)<<" /Mpc^3/Msol"<<endl;
+ double ngal_by_mpc3 = sch.Integrate(schmin,schmax,schnpt);
+ cout<<"Galaxy density number = "<<ngal_by_mpc3<<" /Mpc^3 between limits"<<endl;
+
+ sch.SetOutValue(1);
+ cout<<"mstar*sch(mstar) = "<<sch(mstar)<<" Msol/Mpc^3/Msol"<<endl;
+ double mass_by_mpc3 = sch.Integrate(schmin,schmax,schnpt);
+ cout<<"Galaxy mass density= "<<mass_by_mpc3<<" Msol/Mpc^3 between limits"<<endl;
+ cout<<"Omega_HI at z=0 is "<<mass_by_mpc3/(univ.Rhoc(0.)*GCm3toMsolMpc3_Cst)<<endl
+     <<"         at z="<<zref<<" is "<<mass_by_mpc3/(univ.Rhoc(zref)*GCm3toMsolMpc3_Cst)<<endl;
+
+ SchechterMassDist schmdist(sch,schmin,schmax,schnpt);
+ if(use_schmassdist && schmassdistfile.size()>0) {
+   cout<<"\nSchechterMassDist read from "<<schmassdistfile<<endl;
+   schmdist.ReadPPF(schmassdistfile);
+   bool compsch = IsCompatible(sch,schmdist.GetSchechter());
+   double m1,m2; schmdist.GetMassLim(m1,m2);
+   if( !compsch || fabs(m1-schmin)>1e-4*schmin || fabs(m2-schmax)>1e-4*schmax) {
+     cout<<"FATAL_ERROR: INCONSISTENT SchechterMassDist file / Schechter or limits"<<endl;
+     cout<<"Schechter:"<<endl; sch.Print();
+     cout<<"schmin="<<schmin<<" schmax="<<schmax<<endl;
+     cout<<"SchechterMassDist:"<<endl; schmdist.Print();
+     return -10;
+   }
+   recompute_schmassdist = false;
+ }
+ schmdist.Print();
+ Histo hmdndm = schmdist.GetHmDnDm();
+ FunRan tirhmdndm = schmdist.GetTmDnDm();
+ {
+ tagobs = "hmdndm"; posobs.PutObject(hmdndm,tagobs);
+ Histo hdum1(tirhmdndm);
+ tagobs = "tirhmdndm"; posobs.PutObject(hdum1,tagobs);
+ }
+
+ PrtTim(">>>> End of definition");
+
+ //-----------------------------------------------------------------
+ // FFTW3 (p26): faster if sizes 2^a 3^b 5^c 7^d 11^e 13^f  with e+f=0 ou 1
+ cout<<endl<<"\n--- Initialisation de GeneFluct3D"<<endl;
+
+ GeneFluct3D fluct3d(nx,ny,nz,dx,dy,dz,nthread,2);
+ fluct3d.SetObservator(zref,-nz/2.);
+ fluct3d.SetCosmology(univ);
+ fluct3d.SetGrowthFactor(growth);
+ fluct3d.LosComRedshift(0.001,-1);
+ TArray< complex<r_8> >& pkgen = fluct3d.GetComplexArray();
+ TArray<r_8>& rgen = fluct3d.GetRealArray();
+ cout<<endl; fluct3d.Print();
+ cout<<"\nMean number of galaxies per pixel = "<<ngal_by_mpc3*fluct3d.GetDVol()<<endl;
+ double mass_by_pixel = mass_by_mpc3 * fluct3d.GetDVol();
+ cout<<"Mean mass per pixel = "<<mass_by_pixel<<endl;
+
+ double dkmin = fluct3d.GetKincMin();
+ double knyqmax = fluct3d.GetKmax();
+ long nherr = long(knyqmax/dkmin+0.5);
+ cout<<"\nFor HistoErr: d="<<dkmin<<" max="<<knyqmax<<" n="<<nherr<<endl;
+
+ double dktmin = fluct3d.GetKTincMin();
+ double ktnyqmax = fluct3d.GetKTmax();
+ long nherrt = long(ktnyqmax/dktmin+0.5);
+ double dkzmin = fluct3d.GetKinc()[2];
+ double kznyqmax = fluct3d.GetKnyq()[2];
+ long nherrz = long(kznyqmax/dkzmin+0.5);
+ cout<<"For Histo2DErr: d="<<dktmin<<","<<dkzmin
+     <<" max="<<ktnyqmax<<","<<kznyqmax<<" n="<<nherrt<<","<<nherrz<<endl;
+
+ //-----------------------------------------------------------------
+ cout<<"\n--- Computing spectra variance up to Kmax at z="<<pkz.GetZ()<<endl;
+ // En fait on travaille sur un cube inscrit dans la sphere de rayon kmax:
+ // sphere: Vs = 4Pi/3 k^3 , cube inscrit (cote k*sqrt(2)): Vc = (k*sqrt(2))^3
+ // Vc/Vs = 0.675   ->  keff = kmax * (0.675)^(1/3) = kmax * 0.877
+ double knyqmax_mod = 0.877*knyqmax;
+ ldlkint = (log10(knyqmax_mod)-log10(k1int))/npt;
+ varpk_int.SetInteg(0.01,ldlkint,-1.,4);
+ double sr2int_kmax = varpk_int.Variance(k1int,knyqmax_mod);
+ cout<<"varpk_int(<"<<knyqmax_mod<<")="<<sr2int_kmax<<"  ->  sigma="<<sqrt(sr2int_kmax)<<endl;
+
+ PrtTim(">>>> End Initialisation de GeneFluct3D");
+
+ //-----------------------------------------------------------------
+ cout<<"\n--- Computing a realization in Fourier space"<<endl;
+ if(use_growth_factor>0) pkz.SetZ(0.); else pkz.SetZ(zref);
+ cout<<"Power spectrum set at redshift: "<<pkz.GetZ()<<endl;
+ if(computefourier0) fluct3d.ComputeFourier0(pkz);
+   else              fluct3d.ComputeFourier(pkz);
+ PrtTim(">>>> End Computing a realization in Fourier space");
+
+ cout<<"\n--- Checking realization spectra"<<endl;
+ HistoErr hpkgen(0.,knyqmax,nherr);
+ hpkgen.ReCenterBin(); hpkgen.Zero();
+ hpkgen.Show();
+ fluct3d.ComputeSpectrum(hpkgen);
+ {
+ tagobs = "hpkgen"; posobs.PutObject(hpkgen,tagobs);
+ }
+ PrtTim(">>>> End Checking realization spectra");
+
+ if(comp2dspec) {
+   cout<<"\n--- Checking realization 2D spectra"<<endl;
+   Histo2DErr hpkgen2(0.,ktnyqmax,nherrt,0.,kznyqmax,nherrz);
+   hpkgen2.ReCenterBin(); hpkgen2.Zero();
+   hpkgen2.Show();
+   fluct3d.ComputeSpectrum2D(hpkgen2);
+   {
+   tagobs = "hpkgen2"; posobs.PutObject(hpkgen2,tagobs);
+   }
+   PrtTim(">>>> End Checking realization 2D spectra");
+ }
+
+ if(filter_by_pixel!=0) {
+   cout<<"\n--- Computing convolution by pixel shape"<<endl;
+   fluct3d.FilterByPixel();
+   PrtTim(">>>> End Computing convolution by pixel shape");
+
+   cout<<"\n--- Checking realization spectra after pixel shape convol."<<endl;
+   HistoErr hpkgenfb(0.,knyqmax,nherr);
+   hpkgenfb.ReCenterBin(); hpkgenfb.Zero();
+   hpkgenfb.Show();
+   fluct3d.ComputeSpectrum(hpkgenfb);
+   {
+   tagobs = "hpkgenfb"; posobs.PutObject(hpkgenfb,tagobs);
+   }
+   PrtTim(">>>> End Checking realization spectra");
+
+   cout<<"\n--- Checking realization spectra after pixel shape convol. with pixel correc."<<endl;
+   HistoErr hpkgenf(hpkgenfb); hpkgenf.Zero();
+   fluct3d.ComputeSpectrum(hpkgenf,0.,filter_by_pixel);
+   {
+   tagobs = "hpkgenf"; posobs.PutObject(hpkgenf,tagobs);
+   }
+   PrtTim(">>>> End Checking realization spectra with pixel correc.");
+
+   if(comp2dspec) {
+     cout<<"\n--- Checking realization 2D spectra after pixel shape convol."<<endl;
+     Histo2DErr hpkgenfb2(0.,ktnyqmax,nherrt,0.,kznyqmax,nherrz);
+     hpkgenfb2.ReCenterBin(); hpkgenfb2.Zero();
+     hpkgenfb2.Show();
+     fluct3d.ComputeSpectrum2D(hpkgenfb2);
+     {
+     tagobs = "hpkgenfb2"; posobs.PutObject(hpkgenfb2,tagobs);
+     }
+     PrtTim(">>>> End Checking realization 2D spectra");
+
+     cout<<"\n--- Checking realization 2D spectra after pixel shape convol. with pixel correc."<<endl;
+     Histo2DErr hpkgenf2(hpkgenfb2); hpkgenf2.Zero();
+     fluct3d.ComputeSpectrum2D(hpkgenf2,0.,filter_by_pixel);
+     {
+     tagobs = "hpkgenf2"; posobs.PutObject(hpkgenf2,tagobs);
+     }
+     PrtTim(">>>> End Checking realization 2D spectra with pixel correc.");
+   }
+ }
+
+ if(wfits) {
+   fluct3d.WriteFits("!cmvobserv3d_k0.fits");
+   PrtTim(">>>> End WriteFits");
+ }
+ if(wppf) {
+   fluct3d.WritePPF("cmvobserv3d_k0.ppf",false);
+   PrtTim(">>>> End WritePPF");
+ }
+
+ //-----------------------------------------------------------------
+ cout<<"\n--- Computing a realization in real space"<<endl;
+ fluct3d.ComputeReal();
+ double rmin,rmax; fluct3d.MinMax(rmin,rmax);
+ cout<<"rgen.Min = "<<rmin<<" , Max="<<rmax<<endl;
+ PrtTim(">>>> End Computing a realization in real space");
+
+ if(use_growth_factor>0) {
+   cout<<"\n--- Apply Growth factor"<<endl;
+   cout<<"...D(z=0)="<<growth(0.)<<"  D(z="<<zref<<")="<<growth(zref)<<endl;
+   fluct3d.ApplyGrowthFactor(use_growth_factor);
+   fluct3d.MinMax(rmin,rmax);
+   cout<<"rgen.Min = "<<rmin<<" , Max="<<rmax<<endl;
+   PrtTim(">>>> End Applying growth factor");
+ }
+
+ int_8 nm;
+ double rmref,rs2ref;
+ cout<<"\n--- Computing reference variance in real space"<<endl;
+ nm = fluct3d.MeanSigma2(rmref,rs2ref);
+ cout<<" rs2ref= "<<rs2ref<<" , rmref="<<rmref<<" ("<<nm<<")"<<endl;
+ PrtTim(">>>> End Computing reference variance in real space");
+
+ if(wfits) {
+   fluct3d.WriteFits("!cmvobserv3d_r0.fits");
+   PrtTim(">>>> End WriteFits");
+ }
+ if(wppf) {
+   fluct3d.WritePPF("cmvobserv3d_r0.ppf",true);
+   PrtTim(">>>> End WritePPF");
+ }
+ if(wslice) {
+   fluct3d.WriteSlicePPF("cmvobserv3d_s_r0.ppf");
+   PrtTim(">>>> End WriteSlicePPF");
+ }
+
+ cout<<"\n--- Check mean and variance in real space"<<endl;
+ fluct3d.NumberOfBad(-1.,1e+200);
+ double rm,rs2;
+ nm = fluct3d.MeanSigma2(rm,rs2);
+ PrtTim(">>>> End Check mean and variance in real space");
+
+ if(compvarreal) {
+   cout<<"\n--- Check variance sigmaR in real space"<<endl;
+   double varr;
+   fluct3d.VarianceFrReal(R,varr);
+   cout<<"...Computed variance = "<<varr
+       <<" , Theorical variance at (z=0) = "<<pow(sigmaR,2.)
+       <<" , at (z="<<zref<<") = "<<pow(sigmaR*growth_at_z,2.)<<endl;
+   PrtTim(">>>> End Check variance sigmaR in real space");
+ }
+
+ //-----------------------------------------------------------------
+ if(no_poisson) {
+   cout<<"\n--- Converting !!!DIRECTLY!!! mass into HI mass: mass per pixel ="
+       <<mass_by_pixel<<endl;
+   if(no_poisson_type<0) {
+     cout<<"!!!WARNING!!! dRho/Rho is just multiplied by "<<mass_by_pixel<<endl;
+     fluct3d.ScaleOffset(mass_by_pixel);
+   } else {
+     rm = fluct3d.TurnFluct2MeanNumber(mass_by_mpc3); // ici on doit donner Msol/Mpc^3
+   }
+ } else {
+   cout<<"\n--- Converting mass into galaxy number: gal per pixel ="
+       <<ngal_by_mpc3*fluct3d.GetDVol()<<endl;
+   rm = fluct3d.TurnFluct2MeanNumber(ngal_by_mpc3); // ici on doit donner Ngal/Mpc^3
+ }
+ nm = fluct3d.MeanSigma2(rm,rs2,0.,1e200);
+ nm = fluct3d.MeanSigma2(rm,rs2);
+ if(rm>0.) cout<<"normalised sigma(dM/M) is "<<sqrt(rs2)/rm<<endl;
+ PrtTim(">>>> End Converting mass into galaxy number or mass");
+
+ if( !no_poisson ) {
+
+   cout<<"\n--- Apply poisson on galaxy number"<<endl;
+   fluct3d.ApplyPoisson();
+     nm = fluct3d.MeanSigma2(rm,rs2,0.,1e200);
+     nm = fluct3d.MeanSigma2(rm,rs2);
+   double xgalmin,xgalmax; fluct3d.MinMax(xgalmin,xgalmax,0.1,1.e50);
+   PrtTim(">>>> End Apply poisson on galaxy number");
+   if(wslice) {
+     fluct3d.WriteSlicePPF("cmvobserv3d_s_rn.ppf");
+     PrtTim(">>>> End WriteSlicePPF");
+   }
+
+   cout<<"\n--- Convert Galaxy number to HI mass"<<endl;
+   double mhi = 0.;
+   if(use_schmassdist) {
+     if(recompute_schmassdist) {
+       int ngalmax = int(xgalmax+0.5);
+       schmdist.SetNgalLim(ngalmax,1,naleagal);
+       PrtTim(">>>> End creating tabulated histograms for trials");
+     }
+     mhi = fluct3d.TurnNGal2MassQuick(schmdist);
+     schmdist.PrintStatus();
+   } else {
+     mhi = fluct3d.TurnNGal2Mass(tirhmdndm,true);
+   }
+   cout<<mhi<<" MSol in survey / "<<mass_by_mpc3*fluct3d.GetVol()<<endl;
+     nm = fluct3d.MeanSigma2(rm,rs2,0.,1e200);
+     cout<<"Equivalent: "<<rm*nm/fluct3d.NPix()<<" Msol / pixels"<<endl;
+     nm = fluct3d.MeanSigma2(rm,rs2);
+   PrtTim(">>>> End Convert Galaxy number to HI mass");
+
+ }
+
+ //-----------------------------------------------------------------
+ if(wfits) {
+   fluct3d.WriteFits("!cmvobserv3d_r.fits");
+   PrtTim(">>>> End WriteFits");
+ }
+ if(wppf) {
+   fluct3d.WritePPF("cmvobserv3d_r.ppf",true);
+   PrtTim(">>>> End WritePPF");
+ }
+ if(wslice) {
+   fluct3d.WriteSlicePPF("cmvobserv3d_s_r.ppf");
+   PrtTim(">>>> End WriteSlicePPF");
+ }
+
+ //-----------------------------------------------------------------
+ ////if(do_agn) {
+ ////  cout<<"\n--- Add AGN: <log10(S Jy)>="<<lfjy_agn<<" , sigma="<<lsigma_agn
+ ////      <<" , powlaw="<<powlaw_agn<<endl;
+ ////  fluct3d.AddAGN(lfjy_agn,lsigma_agn,powlaw_agn);
+ ////    nm = fluct3d.MeanSigma2(rm,rs2);
+ ////   PrtTim(">>>> End Add AGN");
+ ////}
+
+ //-----------------------------------------------------------------
+ double snoisesave = 0.;
+ if(snoise>0.) {
+   cout<<"\n--- Add noise to HI Flux snoise="<<snoise<<", evolution="<<noise_evol<<endl;
+   fluct3d.AddNoise2Real(snoise,noise_evol);
+   snoisesave = snoise;
+     nm = fluct3d.MeanSigma2(rm,rs2);
+   PrtTim(">>>> End Add noise");
+ }
+
+ //-----------------------------------------------------------------
+ if(scalemass!=0. && scalemass!=1.) {  // Si scalemass==0 pas de normalisation
+   if(scalemass<0.) scalemass = 1. / (-scalemass * mass_by_pixel);
+   cout<<"\n--- Scale cube scale="<<scalemass<<endl;
+   fluct3d.ScaleOffset(scalemass);
+   snoisesave *= scalemass;
+     nm = fluct3d.MeanSigma2(rm,rs2);
+   PrtTim(">>>> End Scale cube");
+ }
+
+ //----------------------------------------------------------------- 
+ if(wfits) {
+   fluct3d.WriteFits("!cmvobserv3d_rf.fits");
+   PrtTim(">>>> End WriteFits");
+ }
+ if(wppf) {
+   fluct3d.WritePPF("cmvobserv3d_rf.ppf",true);
+   PrtTim(">>>> End WritePPF");
+ }
+ if(wslice) {
+   fluct3d.WriteSlicePPF("cmvobserv3d_s_rf.ppf");
+   PrtTim(">>>> End WriteSlicePPF");
+ }
+
+ //-----------------------------------------------------------------
+ // -- NE PAS FAIRE CA SI ON VEUT CONTINUER LA SIMULATION -> d_rho/rho ecrase
+ 
+ cout<<endl<<"\n--- ReComputing spectrum from real space"<<endl;
+ fluct3d.ReComputeFourier();
+ PrtTim(">>>> End ReComputing spectrum");
+
+ if(wfits) {
+   fluct3d.WriteFits("!cmvobserv3d_k.fits");
+   PrtTim(">>>> End WriteFits");
+ }
+ if(wppf) {
+   fluct3d.WritePPF("cmvobserv3d_k.ppf",false);
+   PrtTim(">>>> End WritePPF");
+ }
+
+ cout<<endl<<"\n--- Computing final spectrum"<<endl;
+ HistoErr hpkrecb(0.,knyqmax,nherr); hpkrecb.Zero();
+ hpkrecb.ReCenterBin();
+ hpkrecb.Show();
+ fluct3d.ComputeSpectrum(hpkrecb);
+ {
+ tagobs = "hpkrecb"; posobs.PutObject(hpkrecb,tagobs);
+ }
+ PrtTim(">>>> End Computing final spectrum");
+
+ cout<<endl<<"\n--- Computing final spectrum with pixel deconv."<<endl;
+ HistoErr hpkrec(hpkrecb); hpkrec.Zero();
+ fluct3d.ComputeSpectrum(hpkrec,snoisesave,filter_by_pixel);
+ {
+ tagobs = "hpkrec"; posobs.PutObject(hpkrec,tagobs);
+ }
+ PrtTim(">>>> End Computing final spectrum with pixel deconv.");
+
+ if(comp2dspec) {
+   cout<<"\n--- Computing final 2D spectrum"<<endl;
+   Histo2DErr hpkrecb2(0.,ktnyqmax,nherrt,0.,kznyqmax,nherrz);
+   hpkrecb2.ReCenterBin(); hpkrecb2.Zero();
+   hpkrecb2.Show();
+   fluct3d.ComputeSpectrum2D(hpkrecb2);
+   {
+   tagobs = "hpkrecb2"; posobs.PutObject(hpkrecb2,tagobs);
+   }
+   PrtTim(">>>> End Computing final 2D spectrum");
+
+   cout<<"\n--- Computing final 2D spectrum with pixel deconv."<<endl;
+   Histo2DErr hpkrec2(hpkrecb2); hpkrec2.Zero();
+   fluct3d.ComputeSpectrum2D(hpkrec2,snoisesave,filter_by_pixel);
+   {
+   tagobs = "hpkrec2"; posobs.PutObject(hpkrec2,tagobs);
+   }
+   PrtTim(">>>> End Computing final 2D spectrum with pixel deconv.");
+
+ }
+
+ PrtTim(">>>> End Of Job");
+ return 0;
+}
+
Index: /tags/V1_0/Cosmo/SimLSS/cmvschdist.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvschdist.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvschdist.cc	(revision 3382)
@@ -0,0 +1,255 @@
+/* Distributions de masse pour n=1,2,3,... tirages */
+#include "sopnamsp.h"
+#include "machdefs.h"
+// Pour faire les histogrammes des distributions de masses
+//  pour ntirages:
+// ex: on a un pixel qui a N galaxies, quelle est la distribution
+//     statistique de masse dans un tel pixel ?
+// > cmvschdist -a -v -m 1e+7,1e+13 -n -100 -r 200 -N 100000
+// compare with:
+// > cmvschdist -a -v -m 1e+7,1e+13 -n -100 -r 200 -N 100000 -0
+// Fabriquer un fichier pour la prod
+// > cmvschdist -a -m 1e+7,1e+13 -n -100 -r 2000 -N 5000000 -W schdist_2000.ppf
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "histos.h"
+#include "ntuple.h"
+#include "srandgen.h"
+#include "perandom.h"
+
+#include "geneutils.h"
+#include "cosmocalc.h"
+#include "schechter.h"
+
+#include <vector>
+
+void usage(void);
+void usage(void)
+{
+ cout<<"cmvschdist -m xmin,xmax -a -0 -n nbin -r ngmax,ngmin -N nalea "
+     <<"-R readfile.ppf -W writefile.ppf"<<endl
+     <<"  -m xmin,xmax : limites en masse"<<endl
+     <<"  -n nbin : nombre de bins (si <0 alors nb par decade)"<<endl
+     <<"  -r ngmax,ngmin : distribution pour tirage de ngmin a ngmax galaxies"<<endl
+     <<"  -N nalea : nombre de tirages aleatoires"<<endl
+     <<"  -v : back verification of random trials"<<endl
+     <<"  -0 : only use ngal=1 histogram"<<endl
+     <<"  -a : init auto de l\'aleatoire"<<endl
+     <<"  -R readfile.ppf : read SchechterMassDist from ppf file"<<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ double h75 = 0.71 / 0.75;
+ double nstar = 0.006*pow(h75,3.);  //  
+ double mstar = pow(10.,9.8);  // MSol
+ double alpha = -1.37;
+ cout<<"h75= "<<h75<<" nstar= "<<nstar<<"  mstar="<<mstar<<"  alpha="<<alpha<<endl;
+
+ double xmin=1.e7, xmax=1.e13;
+ int npt = -100;
+ int ngmax = 200, ngmin = 1;
+ bool useonly1 = false;
+ unsigned long long nalea = 10000;
+ bool verif = false;
+ bool readfrppf = false;
+ string namefrppf = "";
+ string nametoppf = "";
+
+ char c;
+ while((c = getopt(narg,arg,"h0avm:N:n:r:R:W:")) != -1) {
+   switch (c) {
+   case 'm' :
+     sscanf(optarg,"%lf,%lf",&xmin,&xmax);
+     if(xmin<=0.) xmin=1e6;
+     if(xmax<=0.) xmax=xmin;
+     if(xmin>xmax) xmax=10.*xmin;
+     break;
+   case 'r' :
+     sscanf(optarg,"%d,%d",&ngmax,&ngmin);
+     if(ngmin<=0) ngmin=1;
+     if(ngmax<=0) ngmax=ngmin;
+     if(ngmin>ngmax) ngmin=ngmax;
+     break;
+   case 'n' :
+     sscanf(optarg,"%d",&npt);
+     if(npt<=0) npt = -100;
+     break;
+   case 'N' :
+     sscanf(optarg,"%llu",&nalea);
+     if(nalea<=0) nalea=10000;
+     break;
+   case 'v' :
+     verif = true;
+     break;
+   case '0' :
+     useonly1 = true;
+     break;
+   case 'R' :
+     readfrppf = true;
+     namefrppf = optarg;
+     break;
+   case 'W' :
+     nametoppf = optarg;
+     break;
+   case 'a' :
+     Auto_Ini_Ranf(5);
+     break;
+   case 'h' :
+   default :
+     usage(); return -1;
+   }
+ }
+
+ double lnx1=log10(xmin), lnx2=log10(xmax);
+ cout<<"xmin="<<xmin<<" ("<<lnx1<<") xmax="<<xmax<<" ("<<lnx2<<")"<<endl;
+ cout<<"npt="<<npt<<",  nalea="<<nalea<<endl;
+ cout<<"useonly1="<<useonly1<<" ngmin="<<ngmin<<" ngmax="<<ngmax<<endl;
+ cout<<"verif="<<verif<<endl;
+ if(readfrppf) cout<<"SchechterMassDist will be read from file "<<namefrppf<<endl;
+ if(nametoppf.size()>0) cout<<"SchechterMassDist will be written to file "<<nametoppf<<endl;
+
+
+ //-------m*dn/dm
+ cout<<"> Schechter m*dn/dm nstar="<<nstar<<" mstar="<<mstar<<" alpha="<<alpha<<endl;
+ Schechter sch(nstar,mstar,alpha);
+
+ //------- Construct Mass Distribution
+ cout<<"> Creating  Mass Distribution"<<endl;
+ SchechterMassDist schdmass(sch,xmin,xmax,npt);
+ if(readfrppf) {
+   cout<<"> Mass Distribution read from "<<namefrppf<<endl;
+   schdmass.ReadPPF(namefrppf);
+ }
+ Histo hmdndm = schdmass.GetHmDnDm();
+ FunRan tirhmdndm = schdmass.GetTmDnDm();
+
+ //------- Random
+ InitTim();
+ if(!useonly1 && !readfrppf) {
+   cout<<"> Creating "<<ngmax-ngmin+1<<" histos and filling with  "<<nalea<<" trials"<<endl;
+   schdmass.SetNgalLim(ngmax,ngmin,nalea);
+   PrtTim("End of filling histos for trials");
+ }
+ schdmass.Print();
+
+ //------- Generation des histos de verif
+ vector<Histo> vthisto; vector<string> vthname;
+ if(verif) {
+   cout<<"> Creating "<<ngmax-ngmin+1<<" Histos for back-verif"<<endl;
+   for(int i=ngmin;i<=ngmax;i++) {
+     Histo h(hmdndm); h.Zero();
+     vthisto.push_back(h);
+     char str[32]; sprintf(str,"th%d",i);
+     vthname.push_back(string(str));
+   }
+   cout<<"   "<<vthisto.size()<<" Histos created"<<endl;
+   vthisto[20].Show();
+
+   cout<<"> Checking tirage"<<endl;
+   int lpmod = nalea/20; if(lpmod<=0) lpmod=1;
+   for(unsigned long long ia=0;ia<nalea;ia++) {
+     if(ia%lpmod==0) cout<<"...filling tirage "<<ia<<endl;
+     for(unsigned int i=0;i<vthisto.size();i++) {
+       int ng = ngmin+i;
+       double v = schdmass.TirMass(ng)/(double)ng;
+       vthisto[i].Add(log10(v));
+     }
+   }
+   schdmass.PrintStatus();
+   PrtTim("End Random loop back-tirage");
+ }
+
+ //------- Ecritures ppf
+ if(nametoppf.size()>0) {
+   cout<<"Ecriture de l\'objet SchechterMassDist dans "<<nametoppf<<endl;
+   schdmass.WritePPF(nametoppf);
+ }
+
+ cout<<"Ecriture pour verification"<<endl;
+ string tag = "cmvschdist.ppf";
+ POutPersist pos(tag);
+ {
+ cout<<"  writing hmdndm tirhmdndm"<<endl;
+ tag = "hmdndm"; pos.PutObject(hmdndm,tag);
+ Histo hdum(tirhmdndm);
+ tag = "tirhmdndm"; pos.PutObject(hdum,tag);
+ }
+ if(schdmass.GetNgalLim()>0) {
+   cout<<"  writing h t"<<endl;
+   for(int i=0;i<schdmass.GetNgalLim();i++) {
+     int ng = schdmass.NGalFrIndex(i);
+     if(ng<=0) continue;
+     char str[32];
+     sprintf(str,"h%d",ng);
+     Histo hdum = schdmass.GetHisto(i);
+     tag = str; pos.PutObject(hdum,tag);
+     sprintf(str,"t%d",ng);
+     Histo hdum2(schdmass.GetFunRan(i));
+     tag = str; pos.PutObject(hdum2,tag);
+   }
+ }
+ if(vthisto.size()>0) {
+  cout<<"  writing th"<<endl;
+  for(unsigned int i=0;i<vthisto.size();i++)
+     if(vthisto[i].NEntries()>0) pos.PutObject(vthisto[i],vthname[i]);
+ }
+
+ PrtTim("End of Job");
+
+ return 0;
+}
+
+/*
+delobjs *
+openppf cmvschdist.ppf
+
+set n 70
+echo ${h70.vmax}
+
+set h h$n
+set t t$n
+set th th$n
+
+disp tirhmdndm
+disp $t "same red"
+
+disp $h
+disp $th "same red"
+
+n/plot $h.val%x ! ! "connectpoints"
+n/plot $th.val%x ! ! "nsta connectpoints same red"
+
+n/plot $h.log10(val)%x val>0. ! "connectpoints"
+n/plot $th.log10(val)%x val>0. ! "nsta connectpoints same red"
+
+n/plot $h.val%pow(10.,x) ! ! "connectpoints"
+n/plot $th.val%pow(10.,x) ! ! "nsta connectpoints same red"
+
+c++exec \
+for(int i=0;i<$h.NBins();i++) \
+  if($h(i)>0.) { \
+  cout<<i<<" m="<<$h.BinCenter(i)<<" ("<<pow(10.,$h.BinCenter(i))<<") h="<<$h(i)<<endl; \
+  break; \
+} \
+for(int i=$h.NBins()-1;i>=0;i--) \
+  if($h(i)>0.) { \
+  cout<<i<<" m="<<$h.BinCenter(i)<<" ("<<pow(10.,$h.BinCenter(i))<<") h="<<$h(i)<<endl; \
+  break; \
+}
+
+# Compare evolution
+disp h2000               
+disp h1000 "same red"        
+disp h500 "same blue"        
+disp h200 "same green"     
+disp h100 "same red"
+disp h50 "same blue"
+disp h10 "same green"
+disp h1 "same yellow"
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtgrowth.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtgrowth.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtgrowth.cc	(revision 3382)
@@ -0,0 +1,63 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "cosmocalc.h"
+#include "pkspectrum.h"
+
+void usage(void);
+void usage(void) {cout<<"cmvtgrowth z1,z2,dz [Omatter0,Lambda0]"<<endl;}
+
+void tstprint(CosmoCalc& univ,double z1,double z2,double dz);
+void tstspeed(CosmoCalc& univ,double z1,double z2,double dz);
+void tstntuple(CosmoCalc& univ,double z1,double z2,double dz);
+
+int main(int narg,char *arg[])
+{
+
+ double z1=0., z2=10., dz=1.;
+ if(narg>1) sscanf(arg[1],"%lf,%lf,%lf",&z1,&z2,&dz);
+ cout<<"z1="<<z1<<"  z2="<<z2<<"  dz="<<dz<<endl;
+
+ double om0=0.267804, ol0=0.73;
+ if(narg>2) sscanf(arg[2],"%lf,%lf",&om0,&ol0);
+ cout<<"Om0="<<om0<<"  Ol0="<<ol0<<endl;
+
+ GrowthFactor growth(om0,ol0);
+ cout<<"D1(z=0) = "<<growth(0.)<<endl;
+
+ const int n = 2;
+ char *vname[n] = {"z","d1"};
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   xnt[0]  = z;
+   xnt[1]  = growth(z);
+   nt.Fill(xnt);
+ }
+
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtgrowth.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+
+ return 0;
+}
+
+
+/*
+openppf cmvtgrowth.ppf
+
+set cut 1
+set cut z<5
+
+n/plot nt.d1%z $cut ! "nsta connectpoints"
+n/plot nt.1./(1.+z)%z $cut ! "nsta connectpoints red same"
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtinterp.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtinterp.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtinterp.cc	(revision 3382)
@@ -0,0 +1,163 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "cosmocalc.h"
+#include "geneutils.h"
+
+int main(int narg,char *arg[])
+{
+ double zmax = 2.5;
+ unsigned short flat = 0;
+ // -- WMAP
+ double h100=0.71, om0=0.267804, or0=7.9e-05, ol0=0.73,w0=-1.;
+ // -- ouvert matter only
+ //double h100=0.71, om0=0.3, or0=0., ol0=0.,w0=-1.;
+ // -- plat matter only
+ //double h100=0.71, om0=1., or0=0., ol0=0.,w0=-1.; flat = 1;
+ // -- plat lambda only
+ //double h100=0.71, om0=0., or0=0., ol0=1.,w0=-1.; flat = 2;
+
+ // --- la cosmologie
+ double perc=0.01,dzinc=-1.,dzmax=5.; unsigned short glorder=4;
+ cout<<" perc="<<perc<<" dzinc="<<dzinc<<" dzmax="<<dzmax<<" glorder="<<glorder<<endl;
+ CosmoCalc univ(flat,true,zmax);
+ univ.SetInteg(perc,dzinc,dzmax,glorder);
+ univ.SetDynParam(h100,om0,or0,ol0,w0);
+ univ.Print();
+
+ // --- Remplissage de Dloscom en fct de z
+ int_4 lmod=10 , nzfin = lmod*100;
+ cout<<"Remplissage de loscom vs z: nzfin="<<nzfin<<" , lmod="<<lmod<<endl;
+ vector<double> zfin, dlcfin;
+ vector<double> zgros, dlcgros;
+ for(int_4 i=0;i<=nzfin;i++) {
+   double z = i*zmax/(nzfin-1.);
+   double loscom = univ.Dloscom(z); // pour test:  loscom = z*(z+4);
+   zfin.push_back(z); dlcfin.push_back(loscom);
+   if(i%lmod==0) { // ATTENTION il faut etre equidistant en z !
+     zgros.push_back(z);
+     dlcgros.push_back(loscom);
+   }
+ }
+ nzfin = zfin.size();
+ printf("Fin: z(%d) : [%f,%f]  -> loscom : [%f,%f]\n"
+       ,nzfin,zfin[0],zfin[nzfin-1],dlcfin[0],dlcfin[nzfin-1]);
+ int_4 nzgros = zgros.size();
+ printf("Gros: z(%d) : [%f,%f]  -> loscom : [%f,%f]\n"
+       ,nzgros,zgros[0],zgros[nzgros-1],dlcgros[0],dlcgros[nzgros-1]);
+
+ // --- Check interpolation en z
+ cout<<"Check interpolation en z"<<endl;
+ InterpFunc interpgros(zgros[0],zgros[nzgros-1],dlcgros);
+ double xnt[10];
+ vector<string> noms;
+ noms.push_back("z"); noms.push_back("d");
+ noms.push_back("d0"); noms.push_back("d1"); noms.push_back("d2");
+ NTuple ntg(noms);
+ for(int_4 i=0;i<nzfin;i++) {
+   unsigned short ok;
+   double z = zfin[i];
+   xnt[0] = z;
+   xnt[1] = dlcfin[i];
+   xnt[2] = interpgros(z);
+   xnt[3] = interpgros.Linear(z,ok);
+   xnt[4] = interpgros.Parab(z,ok);
+   ntg.Fill(xnt);
+ }
+
+ // --- Check interpolation en los avec inversion
+ cout<<"Check interpolation en los avec inversion"<<endl;
+ InverseFunc invfun(zgros,dlcgros);
+ vector<double> zbackl;
+ invfun.ComputeLinear(nzfin,zbackl);
+ vector<double> zbackp;
+ invfun.ComputeParab(nzfin,zbackp);
+ printf("YMin=%f , YMax=%f\n",invfun.YMin(),invfun.YMax());
+ printf("Linear ZBack: z(%d) : [%f,%f]\n"
+       ,zbackl.size(),zbackl[0],zbackl[zbackl.size()-1]);
+ printf("Parab ZBack: z(%d) : [%f,%f]\n"
+       ,zbackp.size(),zbackp[0],zbackp[zbackp.size()-1]);
+
+ InterpFunc interpinvl(invfun.YMin(),invfun.YMax(),zbackl);
+ InterpFunc interpinvp(invfun.YMin(),invfun.YMax(),zbackp);
+
+ noms.resize(0);
+ noms.push_back("z"); noms.push_back("d");
+ noms.push_back("zl"); noms.push_back("zp");
+ NTuple ntinv(noms);
+ for(int_4 i=0;i<nzfin;i++) {
+   double z = zfin[i];
+   double d = dlcfin[i];
+   unsigned short ok;
+   xnt[0] = z;
+   xnt[1] = d;
+   xnt[2] = interpinvl.Parab(d,ok);
+   xnt[3] = interpinvp.Parab(d,ok);
+   ntinv.Fill(xnt);
+ }
+
+ // --- Write PPF
+ string tag = "cmvtinterp.ppf";
+ cout<<"Write PPF : "<<tag<<endl;
+ POutPersist pos(tag);
+ tag = "ntg"; pos.PutObject(ntg,tag);
+ tag = "ntinv"; pos.PutObject(ntinv,tag);
+
+ return 0;
+}
+
+/*
+openppf cmvtinterp.ppf
+
+#### Check interpolation
+n/plot ntg.d%z ! ! "nsta connectpoints"
+n/plot ntg.d0%z ! ! "nsta connectpoints same green"
+n/plot ntg.d1%z ! ! "nsta connectpoints same blue"
+n/plot ntg.d2%z ! ! "nsta connectpoints same red"
+
+n/plot ntg.d0-d%z ! ! "nsta connectpoints green"
+n/plot ntg.d1-d%z ! ! "nsta connectpoints same blue"
+n/plot ntg.d2-d%z ! ! "nsta connectpoints same red"
+addline 0 0 1000 0
+
+n/plot ntg.d0-d%d ! ! "nsta connectpoints green"
+n/plot ntg.d1-d%d ! ! "nsta connectpoints same blue"
+n/plot ntg.d2-d%d ! ! "nsta connectpoints same red"
+addline 0 0 1000 0
+
+n/plot ntg.(d0-d)/d%d fabs(d)>1e-13 ! "nsta connectpoints green"
+n/plot ntg.(d1-d)/d%d fabs(d)>1e-13 ! "nsta connectpoints same blue"
+n/plot ntg.(d2-d)/d%d fabs(d)>1e-13 ! "nsta connectpoints same red"
+addline 0 0 1000 0
+
+#### Check inversion
+n/plot ntinv.d%_nl ! ! "connectpoints"
+
+n/plot ntinv.z%d ! ! "nsta connectpoints"
+n/plot ntg.z%d ! ! "nsta connectpoints same red"
+
+n/plot ntinv.z%d ! ! "nsta connectpoints"
+n/plot ntinv.zl%d ! ! "nsta connectpoints same blue"
+n/plot ntinv.zp%d ! ! "nsta connectpoints same red"
+
+n/plot ntinv.zl-z%d ! ! "nsta connectpoints blue"
+n/plot ntinv.zp-z%d ! ! "nsta connectpoints same red"
+addline 0 0 10000 0
+
+n/plot ntinv.zl-z%z ! ! "nsta connectpoints blue"
+n/plot ntinv.zp-z%z ! ! "nsta connectpoints same red"
+addline 0 0 10000 0
+
+n/plot ntinv.(zl-z)/z%z z>0 ! "nsta connectpoints blue"
+n/plot ntinv.(zp-z)/z%z z>0 ! "nsta connectpoints same red"
+addline 0 0 10000 0
+
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtintfun.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtintfun.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtintfun.cc	(revision 3382)
@@ -0,0 +1,61 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "geneutils.h"
+
+// cmvtintfun [n] [xmin,xmax,npt]
+
+class MyFunc : public GenericFunc {
+public:
+  MyFunc(double n) {n_=n;}
+  virtual ~MyFunc(void) {};
+  virtual double operator() (double x)
+          {return (n_>=0.) ? pow(x,n_) : exp(n_*x);}
+  double integ(double xmin,double xmax) {
+    return (n_>=0.) ? (pow(xmax,n_+1.)-pow(xmin,n_+1.))/(n_+1.)
+                    : (exp(n_*xmax)-exp(n_*xmin))/n_;
+  }
+protected:
+  double n_;
+};
+
+
+int main(int narg,char *arg[])
+{
+
+  double n=3.;
+  if(narg>1) sscanf(arg[1],"%lf",&n);
+  double xmin=1., xmax=10.;
+  int npt = 100;
+  if(narg>2) sscanf(arg[2],"%lf,%lf,%d",&xmin,&xmax,&npt);
+
+  double lxmin=log10(xmin), lxmax=log10(xmax);
+  double perc=0.01;
+  double dxinc=(xmax-xmin)/npt, dxmax=-1.;
+  double dlxinc=(lxmax-lxmin)/npt, dlxmax=-1.;
+  unsigned short glorder=4;
+
+  if(narg>1) sscanf(arg[1],"%lf",&n);
+  if(narg>2) sscanf(arg[2],"%lf,%lf,%d",&xmin,&xmax,&npt);
+  cout<<"n="<<n<<" xmin="<<xmin<<" xmax="<<xmax<<" npt="<<npt<<endl;
+
+  MyFunc myfunc(n);
+
+  double integ = IntegrateFunc(myfunc,xmin,xmax,perc,dxinc,dxmax,glorder);
+  cout<<"IntegrateFunc() = "<<integ<<endl;
+
+  double integlog = IntegrateFuncLog(myfunc,lxmin,lxmax,perc,dlxinc,dlxmax,glorder);
+  cout<<"IntegrateFuncLog() = "<<integlog<<endl;
+
+  cout<<"Integrate() = "<<myfunc.integ(xmin,xmax)<<endl;
+
+ return 0;
+}
Index: /tags/V1_0/Cosmo/SimLSS/cmvtluc.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtluc.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtluc.cc	(revision 3382)
@@ -0,0 +1,103 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "luc.h"
+
+void usage(void);
+void usage(void)
+{
+  cout<<"cmvtuniv z1,z2,dz"<<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ // -- WMAP
+ double h100=0.71, om0=0.267804, or0=7.9e-05, ol0=0.73,w0=-1., ob0=0.045, oph0=5e-5;
+ // -- ouvert matter only
+ //double h100=0.71, om0=0.3, or0=0., ol0=0.,w0=-1., ob0=0.045, oph0=5e-5;
+ // -- plat matter only
+ //double h100=0.71, om0=1., or0=0., ol0=0.,w0=-1., ob0=0.045, oph0=5e-5;
+
+ double z1=0., z2=10., dz=1.;
+ if(narg>1) sscanf(arg[1],"%lf,%lf,%lf",&z1,&z2,&dz);
+
+ SimpleUniverse univ;
+ univ.SetPrtDbgLevel(1);
+
+ univ.Seth(h100);
+ univ.SetOmegaMatter(om0);
+ univ.SetOmegaLambda(ol0);
+ //univ.SetDarkEnergy(ol0,w0);
+ univ.SetOmegaRadiation(or0);
+ univ.SetOmegaBaryon(ob0);
+ univ.SetOmegaPhoton(oph0);
+
+ //univ.SetFlatUniverse_OmegaMatter();
+ //univ.SetFlatUniverse_OmegaLambda();
+
+ /*
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   univ.SetEmissionRedShift(z,0.001);
+   cout<<endl;
+   univ.Print();
+ }
+ */
+
+ /**/
+ double norm = univ.HubbleLengthMpc(); // 1.;
+ double norm3 = pow(norm,3.);
+ const int n = 11;
+ char *vname[n] = {
+   "z","hz","om","or","ol","ok","ot",
+   "da","dl","dvc","vc0"
+ };
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   univ.SetEmissionRedShift(z,0.001);
+   xnt[0]  = univ.ZE();
+   xnt[1]  = univ.HZE();
+   xnt[2]  = univ.OmegaMatterZE();
+   xnt[3]  = univ.OmegaRadiationZE();
+   xnt[4]  = 0.; //univ.OmegaLambdaZE()+univ.OmegaDarkZE();
+   xnt[5]  = univ.OmegaCurvZE();
+   xnt[6]  = 0.; //univ.OmegaTotalZE();
+   xnt[7]  = univ.AngularDiameterDistanceMpc()/norm;
+   xnt[8]  = univ.LuminosityDistanceMpc()/norm;
+   if(xnt[8]<0.) cout<<xnt[8]<<endl;
+   xnt[9]  = 0.; //univ.dVolZE()/norm3;
+   xnt[10] = 0.; //univ.Vol4PiZE()/norm3;
+   nt.Fill(xnt);
+ }
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtluc.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+ /**/
+
+ return 0;
+}
+
+
+/*
+openppf cmvtluc.ppf
+
+set cut 1
+set cut z<100.
+
+zone
+n/plot nt.hz%z $cut ! "nsta"
+
+zone
+n/plot nt.dl%z $cut ! "nsta"
+n/plot nt.da%z $cut ! "nsta same red"
+
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtransf.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtransf.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtransf.cc	(revision 3382)
@@ -0,0 +1,128 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "constcosmo.h"
+#include "pkspectrum.h"
+
+void usage(void);
+void usage(void) {
+cout
+<<"cmvtransf [options]"<<endl
+<<"  -k k1,k2,npt : k range in Mpc^-1"<<endl
+<<"  -U h100,Om0,Ob0,tcmb : cosmology"<<endl
+<<"  -F filename : read also CMBFast file"<<endl
+<<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ double k1 = 1e-6, k2 = 10.; int_4 npt = 100;
+ double h100 = 0.71, Om0 = 0.267804, Ob0 = 0.0444356, tcmb = T_CMB_Par;
+ string fcmbfast = "";
+
+ char c;
+  while((c = getopt(narg,arg,"hk:U:F:")) != -1) {
+  switch (c) {
+  case 'k' :
+    sscanf(optarg,"%d,%lf,%lf",&npt,&k1,&k2);
+    break;
+  case 'U' :
+    sscanf(optarg,"%lf,%lf,%lf,%lf",&h100,&Om0,&Ob0,&tcmb);
+    break;
+  case 'F' :
+    fcmbfast = optarg;
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+
+ if(k1<=0.) {cout<<"k1 must be >0"<<endl; return -1;}
+ if(npt<=0) npt = 1000;
+ if(k2<=k1) {k1=1.e-4; k2=1.e+2;}
+ cout<<"k1="<<k1<<"  k2="<<k2<<" npt="<<npt<<endl;
+ cout<<"h100="<<h100<<" Om0="<<Om0<<" Ob0="<<Ob0<<" Tcmb="<<tcmb<<endl;
+ cout<<"fcmbfast="<<fcmbfast<<endl;
+
+ cout<<"TransfertEisenstein with baryon"<<endl;
+ TransfertEisenstein tf(h100,Om0-Ob0,Ob0,tcmb);
+ cout<<"KPeak = "<<tf.KPeak()<<"  1/Mpc"<<endl;
+
+ cout<<endl<<"TransfertEisenstein with baryon without oscillation approx.1"<<endl;
+ TransfertEisenstein tfnosc1(h100,Om0-Ob0,Ob0,tcmb);  // No oscillation approx.1
+ tfnosc1.SetNoOscEnv(1);
+
+ cout<<endl<<"TransfertEisenstein with baryon without oscillation approx.2"<<endl;
+ TransfertEisenstein tfnosc2(h100,Om0-Ob0,Ob0,tcmb);  // No oscillation approx.2
+ tfnosc2.SetNoOscEnv(2);
+
+ cout<<endl<<"TransfertEisenstein without baryon"<<endl;
+ TransfertEisenstein tfnob(h100,Om0-Ob0,Ob0,tcmb,true);  // No baryons
+
+ TransfertTabulate tfcmbfast(h100,Om0-Ob0,Ob0);
+ bool cmbfastOK = false;
+ if(fcmbfast.size()>0) {
+   cout<<endl<<"TransfertTabulate for CMBfast"<<endl;
+   tfcmbfast.ReadCMBFast(fcmbfast);
+   tfcmbfast.SetInterpTyp(1);
+   if(tfcmbfast.NPoints()>0) cmbfastOK = true;
+ }
+
+ const int n = 6;
+ char *vname[n] = {"k","t","tnosc1","tnosc2","tnob","tcmbf"};
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(int i=0;i<n;i++) xnt[i]=0.;
+
+ double lnk1 = log10(k1), lnk2=log10(k2), dlnk=(lnk2-lnk1)/npt;
+ for(double lnk=lnk1;lnk<lnk2+dlnk/2.;lnk+=dlnk) {
+   double k = pow(10.,lnk);
+   xnt[0]  = k;
+   xnt[1]  = tf(k);
+   xnt[2]  = tfnosc1(k);
+   xnt[3]  = tfnosc2(k);
+   xnt[4]  = tfnob(k);
+   if(cmbfastOK) xnt[5]  = tfcmbfast(k);
+   nt.Fill(xnt);
+ }
+
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtransf.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+
+ return 0;
+}
+
+/*
+openppf cmvtransf.ppf
+
+set k k
+set k log10(k)
+
+# Eisenstein
+n/plot nt.t%$k ! ! "nsta connectpoints"
+n/plot nt.tnob%$k ! ! "nsta red same connectpoints"
+n/plot nt.tnosc2%$k ! ! "nsta blue same connectpoints"
+n/plot nt.tnosc1%$k ! ! "nsta green same connectpoints"
+
+n/plot nt.t/tnob%$k   tnob>0   ! "nsta red connectpoints"
+n/plot nt.t/tnosc2%$k tnosc2>0 ! "nsta blue same connectpoints"
+n/plot nt.t/tnosc1%$k tnosc1>0 ! "nsta green same connectpoints"
+
+# CMBFast
+n/plot nt.t%$k ! ! "nsta connectpoints"
+n/plot nt.tcmbf%$k ! ! "nsta red same connectpoints"
+
+n/plot nt.(tcmbf-t)%$k tcmbf>0. ! "nsta connectpoints"
+n/plot nt.(tcmbf-t)/tcmbf%$k tcmbf>0. ! "nsta connectpoints"
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtstagn.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtstagn.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtstagn.cc	(revision 3382)
@@ -0,0 +1,198 @@
+// Distribution des flux des AGN dans un pixel de taille donne
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "geneutils.h"
+#include "agnjackson.h"
+
+void usage(void);
+void usage(void)
+{
+cout<<"cmvtstagn "<<endl
+ <<" -a angsol: taille pixel (en sr si >0 ou arcmin^2 si <0)"<<endl
+ <<" -x nbin,xmin,xmax: def histo des log10(S Jy)/pixel"<<endl
+ <<"              si nbin<0 on a de <S>+xmin , <S>-xmax"<<endl
+ <<" -n npix: nombre de tirages de pixel"<<endl;
+}
+
+
+int main(int narg,char *arg[])
+{
+ double angsol = 1.;  // sr
+ double lxmin=-3.,lxmax=4.; int nbinlx = -100;
+ int npix = 100;
+
+ // --- Decodage arguments
+ char c;
+ while((c = getopt(narg,arg,"ha:x:n:")) != -1) {
+  switch (c) {
+  case 'a' :
+    sscanf(optarg,"%lf",&angsol);
+    break;
+  case 'x' :
+    sscanf(optarg,"%d,%lf,%lf",&nbinlx,&lxmin,&lxmax);
+    break;
+  case 'n' :
+    sscanf(optarg,"%d",&npix);
+    break;
+  case 'h' :
+  default :
+    usage();
+    return -1;
+  }
+ }
+
+ // --- Class de distribution d'AGN
+ double sr2amin = AngSol(M_PI/180./60./2.,M_PI/180./60./2.);
+ if(angsol<0) angsol *= -sr2amin;
+ cout<<"angsol = "<<angsol<<" sr -> "<<angsol/sr2amin<<" arcmin^2"<<endl;
+ AGNJackson agn;
+ agn.Print();
+
+ cout<<endl;
+ vector<double> xjack, yjack; agn.OrigJack(xjack,yjack);
+ Histo hdndls0 = agn.dNdlS();
+ Histo hdndls(hdndls0); hdndls *= angsol;
+ Histo htirls = agn.TirL10S();
+ double nobjang = agn.NObjAng()*angsol;
+ double fluxang = agn.FluxAng()*angsol;
+ cout<<"Nombre moyen d\'objets dans notre pixel: "<<nobjang<<endl;
+ cout<<"Flux moyen dans notre pixel: "<<fluxang<<" Jy"<<endl;
+
+ // --- Distribution sur angsol
+ // Histo du nombre d'objets / angsol
+ cout<<endl;
+ double mu = nobjang; if(mu<=0.) mu=1.;
+ double xmin = mu-5.*sqrt(mu); if(xmin<0.) xmin=0.; xmin=floor(xmin);
+ double xmax = mu+7.*sqrt(mu); xmax=floor(xmax+1.);
+ long nb = long(xmax-xmin+1.01); while(nb>250) nb /= 2;
+ // Histo du nombre d'objets/pixel
+ Histo hnobj(xmin,xmax,nb); hnobj.ReCenterBin();
+ cout<<"hnobj: "; hnobj.Show();
+ // Histo de check du tirage
+ Histo hlflux(htirls); hlflux.Zero();
+ // Histo du flux/pixel
+ if(nbinlx==0 || nbinlx==1) nbinlx = -100;
+ if(nbinlx<0) {
+   nbinlx = -nbinlx;
+   lxmin = log10(fluxang) + lxmin;
+   lxmax = log10(fluxang) + lxmax;
+   cout<<"Recomputing: lxmin="<<lxmin<<" lxmax="<<lxmax<<" nbin="<<nbinlx<<endl;
+ }
+ Histo hlfang(lxmin,lxmax,nbinlx); hlfang.Zero();
+ cout<<"hlfang: "; hlfang.Show();
+
+ // Tirage aleatoire
+ cout<<endl;
+ if(npix>1) {
+   long l = npix/10; if(l<=0) l=1;
+   cout<<"Making "<<npix<<" trials"<<endl;
+   unsigned long nzero=0, ntir=0;
+   double sumpix=0., sumpix2=0., sumn=0., sumn2=0.;
+   for(long i=0;i<npix;i++) {
+     if(i%l==0) cout<<"...trial: "<<i<<endl;
+     unsigned long n = PoissRandLimit(mu,10.);
+     hnobj.Add((double)n);
+     sumn += n; sumn2 += n*n;
+     double fsum = 0.; unsigned long nf = 0;
+     for(unsigned long j=0;j<n;j++) {
+       double f = agn.FluxJY();
+       hlflux.Add(log10(f));
+       fsum += f;
+       nf++;
+     }
+     ntir += nf;
+     if(nf==0) {
+       nzero++;
+     } else {
+       sumpix += fsum; sumpix2 += fsum*fsum;
+       hlfang.Add(log10(fsum));
+     }
+   }
+   sumn /= (double)npix;
+   sumn2 = sumn2/(double)npix - sumn*sumn;
+   sumpix /= (double)npix;
+   sumpix2 = sumpix2/(double)npix - sumpix*sumpix;
+   cout<<"Number of try: "<<ntir<<endl;
+   cout<<"Number of pixels with no flux: "<<nzero<<" / "<<npix<<endl;
+   cout<<"Mean object number/pix: "<<sumn<<" (check "<<(double)ntir/(double)npix
+       <<") s^2="<<sumn2<<" s="<<sqrt(fabs(sumn2))<<endl;
+   cout<<"Mean flux/pix: "<<sumpix<<" s^2="<<sumpix2<<" s="<<sqrt(fabs(sumpix2))<<endl;
+   // Info de l'histo des flux
+   cout<<"hlfang: "; hlfang.Show();
+   // normalisation de hlflux
+   hlflux *= hdndls.BinWidth()/hlflux.BinWidth()*hdndls.Sum()/hlflux.Sum();
+ }
+
+ // --- Ecriture sur fichier ppf
+ string tag = "cmvtstagn.ppf";
+ POutPersist pos(tag);
+
+ TVector<r_8> vxjack(xjack), vyjack(yjack);
+ tag = "xjack"; pos.PutObject(vxjack,tag);
+ tag = "yjack"; pos.PutObject(vyjack,tag);
+
+ tag = "dndls0"; pos.PutObject(hdndls0,tag);
+ tag = "dndls"; pos.PutObject(hdndls,tag);
+
+ tag = "tirls"; pos.PutObject(htirls,tag);
+ tag = "hlflux"; pos.PutObject(hlflux,tag);
+
+ tag = "nobj"; pos.PutObject(hnobj,tag);
+ tag = "hlfang"; pos.PutObject(hlfang,tag);
+
+ return 0;
+}
+
+
+/*
+openppf cmvtstagn.ppf
+
+del ntjack
+c++exec char *vname[2] = {"x","y"}; double xnt[2]; \
+NTuple ntjack(2,vname); \
+for(int i=0;i<xjack.Size();i++) \
+  {xnt[0]=xjack(i); xnt[1]=yjack(i); ntjack.Fill(xnt);} \
+KeepObj(ntjack); cout<<"OK";
+
+# Jackson initial (Jy^1.5/sr)
+n/plot ntjack.y%x ! ! "nsta connectpoints"
+vecplot xjack yjack "same red fcirclemarker7"
+
+# Check de ce qu'on a extrapole
+set yxt "y*pow(10.,-1.5*x)*M_LN10"
+n/plot dndls0.log10(val)%x ! ! "nsta connectpoints"
+n/plot ntjack.log10($yxt)%x ! ! "nsta red fcirclemarker7 same"
+
+# la pdf : histo en 1/log10(Jy)/sr
+disp dndls0 "nsta"
+n/plot ntjack.$yxt%x ! ! "nsta red fcirclemarker7 same"
+
+# la pdf : histo en 1/log10(Jy)/angsol
+disp dndls "nsta"
+
+# la pdf en flux: dn/dlog10(S)*S en microJy/log10(Jy)/sr
+n/plot dndls.val*pow(10.,x)*1e6%x ! ! "nsta connectpoints"
+
+# la fonction de tirage en 1/Jy/(angsol sr)
+disp tirls "nsta"
+
+# Check tirages
+disp dndls "nsta"
+disp hlflux "nsta same red"
+
+# Resultat: nombre d'objets (poisson) par pixel
+disp nobj
+
+# Resultat: distribution du flux par pixel
+disp hlfang
+
+ */
Index: /tags/V1_0/Cosmo/SimLSS/cmvtstblack.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtstblack.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtstblack.cc	(revision 3382)
@@ -0,0 +1,362 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "constcosmo.h"
+#include "geneutils.h"
+#include "planckspectra.h"
+
+void compute_xroot(void);
+
+// cmvtstblack [T,nutest(Hz)] [deriv 0/1]
+
+int main(int narg,char *arg[])
+{
+  //{compute_xroot(); return -41;}
+ double T = 2.718, nutest=-1.;
+ unsigned short funcderiv = 0;
+ double x0;
+
+ if(narg>1) sscanf(arg[1],"%lf,%lf",&T,&nutest);
+ if(T<=0.) T = 2.718;
+ if(narg>2) sscanf(arg[2],"%hu",&funcderiv);
+ PlanckSpectra::SpectraFunc deriv = (funcderiv==0) ? PlanckSpectra::VALUE : PlanckSpectra::DERIV;
+
+ cout<<"Temperature "<<T<<" K , deriv="<<(int)deriv<<endl;
+
+ //--------------------------------- Radiance Frequence
+ // frequence planck radiance W/..
+ PlanckSpectra pradf(T);
+ pradf.SetSpectraFunc(deriv);
+ pradf.SetSpectraVar(PlanckSpectra::NU);
+ pradf.SetSpectraApprox(PlanckSpectra::PLANCK);
+ pradf.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ pradf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phpradf(pradf);
+ phpradf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // frequence rayleigh radiance W/..
+ PlanckSpectra rradf(T);
+ rradf.SetSpectraFunc(deriv);
+ rradf.SetSpectraVar(PlanckSpectra::NU);
+ rradf.SetSpectraApprox(PlanckSpectra::RAYLEIGH);
+ rradf.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ rradf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phrradf(rradf);
+ phrradf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // frequence wien radiance W/..
+ PlanckSpectra wradf(T);
+ wradf.SetSpectraFunc(deriv);
+ wradf.SetSpectraVar(PlanckSpectra::NU);
+ wradf.SetSpectraApprox(PlanckSpectra::WIEN);
+ wradf.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ wradf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phwradf(wradf);
+ phwradf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // Check
+ if(nutest<=0.) nutest = k_Boltzman_Cst*T/h_Planck_Cst;
+ cout<<"Test for t="<<T<<" K,  nu="<<nutest<<" Hz"<<endl
+     <<"    planck = "<<pradf(nutest)<<endl
+     <<"      wien = "<<wradf(nutest)<<endl
+     <<"  rayleigh = "<<rradf(nutest)<<endl;
+
+ //--------------------------------- Densite Frequence
+ // frequence planck density W/..
+ PlanckSpectra pdensf(T);
+ pdensf.SetSpectraFunc(deriv);
+ pdensf.SetSpectraVar(PlanckSpectra::NU);
+ pdensf.SetSpectraApprox(PlanckSpectra::PLANCK);
+ pdensf.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ pdensf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phpdensf(pdensf);
+ phpdensf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // frequence rayleigh density W/..
+ PlanckSpectra rdensf(T);
+ rdensf.SetSpectraFunc(deriv);
+ rdensf.SetSpectraVar(PlanckSpectra::NU);
+ rdensf.SetSpectraApprox(PlanckSpectra::RAYLEIGH);
+ rdensf.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ rdensf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phrdensf(rdensf);
+ phrdensf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // frequence wien density W/..
+ PlanckSpectra wdensf(T);
+ wdensf.SetSpectraFunc(deriv);
+ wdensf.SetSpectraVar(PlanckSpectra::NU);
+ wdensf.SetSpectraApprox(PlanckSpectra::WIEN);
+ wdensf.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ wdensf.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phwdensf(wdensf);
+ phwdensf.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ //--------------------------------- Radiance Longeur d'onde
+ // longueur d'onde planck radiance W/..
+ PlanckSpectra pradl(T);
+ pradl.SetSpectraFunc(deriv);
+ pradl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ pradl.SetSpectraApprox(PlanckSpectra::PLANCK);
+ pradl.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ pradl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phpradl(pradl);
+ phpradl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // longueur d'onde rayleigh radiance W/..
+ PlanckSpectra rradl(T);
+ rradl.SetSpectraFunc(deriv);
+ rradl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ rradl.SetSpectraApprox(PlanckSpectra::RAYLEIGH);
+ rradl.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ rradl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phrradl(rradl);
+ phrradl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // longueur d'onde wien radiance W/..
+ PlanckSpectra wradl(T);
+ wradl.SetSpectraFunc(deriv);
+ wradl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ wradl.SetSpectraApprox(PlanckSpectra::WIEN);
+ wradl.SetSpectraUnit(PlanckSpectra::ANGSFLUX);
+ wradl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phwradl(wradl);
+ phwradl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ //--------------------------------- Densite Longeur d'onde
+ // longueur d'onde planck density W/..
+ PlanckSpectra pdensl(T);
+ pdensl.SetSpectraFunc(deriv);
+ pdensl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ pdensl.SetSpectraApprox(PlanckSpectra::PLANCK);
+ pdensl.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ pdensl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phpdensl(pdensl);
+ phpdensl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // longueur d'onde rayleigh density W/..
+ PlanckSpectra rdensl(T);
+ rdensl.SetSpectraFunc(deriv);
+ rdensl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ rdensl.SetSpectraApprox(PlanckSpectra::RAYLEIGH);
+ rdensl.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ rdensl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phrdensl(rdensl);
+ phrdensl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ // longueur d'onde wien density W/..
+ PlanckSpectra wdensl(T);
+ wdensl.SetSpectraFunc(deriv);
+ wdensl.SetSpectraVar(PlanckSpectra::LAMBDA);
+ wdensl.SetSpectraApprox(PlanckSpectra::WIEN);
+ wdensl.SetSpectraUnit(PlanckSpectra::DENSENERG);
+ wdensl.SetSpectraPower(PlanckSpectra::POWER);
+ PlanckSpectra phwdensl(wdensl);
+ phwdensl.SetSpectraPower(PlanckSpectra::PHOTON);
+
+ //--------------------------------- Le maximum des spectres de planck
+ cout<<endl;
+ double eps = 0.001;
+ x0 = pradf.WienLaw();
+ printf("Planck maximum for radiance energy: f = %e Hz  -> %e W/m^2/sr/Hz\n",x0,pradf(x0));
+ printf("                             check:   = %e\n",pradf.FindMaximum(eps));
+ x0 = phpradf.WienLaw();
+ printf("Planck maximum for radiance photon: f = %e Hz  -> %e ph/s/m^2/sr/Hz\n",x0,phpradf(x0));
+ printf("                             check:   = %e\n",phpradf.FindMaximum(eps));
+
+ x0 = pdensf.WienLaw();
+ printf("Planck maximum for density energy:  f = %e Hz  -> %e J/m^3/Hz\n",x0,pdensf(x0));
+ printf("                             check:   = %e\n",pdensf.FindMaximum(eps));
+ x0 = phpdensf.WienLaw();
+ printf("Planck maximum for density photon:  f = %e Hz  -> %e ph/m^3/Hz\n",x0,phpdensf(x0));
+ printf("                             check:   = %e\n",phpdensf.FindMaximum(eps));
+
+ x0 = pradl.WienLaw();
+ printf("Planck maximum for radiance energy: l = %e m  -> %e W/m^2/sr/m\n",x0,pradl(x0));
+ printf("                             check:   = %e\n",pradl.FindMaximum(eps));
+ x0 = phpradl.WienLaw();
+ printf("Planck maximum for radiance photon: l = %e m  -> %e ph/s/m^2/sr/m\n",x0,phpradl(x0));
+ printf("                             check:   = %e\n",phpradl.FindMaximum(eps));
+
+ x0 = pdensl.WienLaw();
+ printf("Planck maximum for density energy:  l = %e m  -> %e J/m^3/m\n",x0,pdensl(x0));
+ printf("                             check:   = %e\n",pdensl.FindMaximum(eps));
+ x0 = phpdensl.WienLaw();
+ printf("Planck maximum for density photon:  l = %e m  -> %e ph/m^3/m\n",x0,phpdensl(x0));
+ printf("                             check:   = %e\n",phpdensl.FindMaximum(eps));
+
+ //--------------------------------- La loi de Wien
+ cout<<endl;
+ x0 = wradf.WienLaw();
+ printf("Wien law for radiance energy: f = %e Hz  -> %e W/m^2/sr/Hz\n",x0,wradf(x0));
+ printf("                       check:   = %e\n",wradf.FindMaximum(eps));
+ x0 = phwradf.WienLaw();
+ printf("Wien law for radiance photon: f = %e Hz  -> %e ph/s/m^2/sr/Hz\n",x0,phwradf(x0));
+ printf("                       check:   = %e\n",phwradf.FindMaximum(eps));
+
+ x0 = wdensf.WienLaw();
+ printf("Wien law for density energy:  f = %e Hz  -> %e J/m^3/Hz\n",x0,wdensf(x0));
+ printf("                      check:    = %e\n",wdensf.FindMaximum(eps));
+ x0 = phwdensf.WienLaw();
+ printf("Wien law for density photon:  f = %e Hz  -> %e  ph/m^3/Hz\n",x0,phwdensf(x0));
+ printf("                      check:    = %e\n",phwdensf.FindMaximum(eps));
+
+ x0 = wradl.WienLaw();
+ printf("Wien law for radiance energy: l = %e m  -> %e W/m^2/sr/m\n",x0,wradl(x0));
+ printf("                       check:   = %e\n",wradl.FindMaximum(eps));
+ x0 = phwradl.WienLaw();
+ printf("Wien law for radiance photon: l = %e m  -> %e ph/s/m^2/sr/m\n",x0,phwradl(x0));
+ printf("                       check:   = %e\n",phwradl.FindMaximum(eps));
+
+ x0 = wdensl.WienLaw();
+ printf("Wien law for density energy:  l = %e m  -> %e J/m^3/m\n",x0,wdensl(x0));
+ printf("                      check:    = %e\n",wdensl.FindMaximum(eps));
+ x0 = phwdensl.WienLaw();
+ printf("Wien law for density photon:  l = %e m  -> %e ph/m^3/m\n",x0,phwdensl(x0));
+ printf("                      check:    = %e\n",phwdensl.FindMaximum(eps));
+
+ //--------------------------------- Densite totale d'energie
+ cout<<endl;
+ cout<<"Densite totale d'energie: "<<pdensf.PlanckEnergie()<<" J/m^3"<<endl;
+ if(! deriv) {
+   double x1,x2,perc,dxinc;
+   x0 = pdensf.WienLaw(); x1=x0/100.; x2=x0*100.; perc=0.1; dxinc=x0/1000.;
+   cout<<"   check by integration: "<<IntegrateFunc(pdensf,x1,x2,perc,dxinc)<<" J/m^3"<<endl;
+   x1=log10(x0/100.); x2=log10(x0*100.); perc=0.1; dxinc=(x2-x1)/100.;
+   cout<<"   check by integration: "<<IntegrateFuncLog(pdensf,x1,x2,perc,dxinc)<<" J/m^3"<<endl;
+
+   x0 = pdensl.WienLaw(); x1=x0/100.; x2=x0*100.; perc=0.1; dxinc=x0/1000.;
+   cout<<"   check by integration: "<<IntegrateFunc(pdensl,x1,x2,perc,dxinc)<<" J/m^3"<<endl;
+   x1=log10(x0/100.); x2=log10(x0*100.); perc=0.1; dxinc=(x2-x1)/100.;
+   cout<<"   check by integration: "<<IntegrateFuncLog(pdensl,x1,x2,perc,dxinc)<<" J/m^3"<<endl;
+ }
+
+ //--------------------------------- Densite totale de photons
+ cout<<endl;
+ cout<<"Densite totale de photons: "<<pdensf.PlanckPhoton()<<" ph/m^3"<<endl;
+ if(! deriv) {
+   double x1,x2,perc,dxinc;
+   x0 = phpdensf.WienLaw(); x1=x0/100.; x2=x0*100.; perc=0.1; dxinc=x0/1000.;
+   cout<<"   check by integration: "<<IntegrateFunc(phpdensf,x1,x2,perc,dxinc)<<" ph/m^3"<<endl;
+   x1=log10(x0/100.); x2=log10(x0*100.); perc=0.1; dxinc=(x2-x1)/100.;
+   cout<<"   check by integration: "<<IntegrateFuncLog(phpdensf,x1,x2,perc,dxinc)<<" ph/m^3"<<endl;
+
+   x0 = phpdensl.WienLaw(); x1=x0/100.; x2=x0*100.; perc=0.1; dxinc=x0/1000.;
+   cout<<"   check by integration: "<<IntegrateFunc(phpdensl,x1,x2,perc,dxinc)<<" ph/m^3"<<endl;
+   x1=log10(x0/100.); x2=log10(x0*100.); perc=0.1; dxinc=(x2-x1)/100.;
+   cout<<"   check by integration: "<<IntegrateFuncLog(phpdensl,x1,x2,perc,dxinc)<<" ph/m^3"<<endl;
+ }
+
+ //--------------------------------- NTuple
+ cout<<endl;
+ int npt = 1000;
+ double frac = 10000.;
+ x0 = wradf.WienLaw();
+ double xmin = x0/frac, xmax = x0*frac;
+ cout<<"xmin="<<xmin<<" Hz,  xmax="<<xmax<<" Hz"<<endl;
+ double lnx1 = log10(xmin), lnx2 = log10(xmax), dlnx = (lnx2-lnx1)/npt;
+ cout<<"lnx1="<<lnx1<<",  lnx2="<<lnx2<<", dlnx="<<dlnx<<endl;
+
+ const int n = 14;
+ char *vname[n] = {"f","l","prf","prl","pdf","pdl","rrf","rrl","rdf","rdl","wrf","wrl","wdf","wdl"};
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(double lx=lnx1;lx<lnx2+dlnx/2.;lx+=dlnx) {
+   double f = pow(10.,lx);
+   double l = wradf.F2L(f);
+   xnt[0] = f;
+   xnt[1] = l;
+   xnt[2] = pradf(f);
+   xnt[3] = pradl(l);
+   xnt[4] = pdensf(f);
+   xnt[5] = pdensl(l);
+   xnt[6] = rradf(f);
+   xnt[7] = rradl(l);
+   xnt[8] = rdensf(f);
+   xnt[9] = rdensl(l);
+   xnt[10] = wradf(f);
+   xnt[11] = wradl(l);
+   xnt[12] = wdensf(f);
+   xnt[13] = wdensl(l);
+   nt.Fill(xnt);
+ }
+
+ cout<<"\n>>>> Ecriture"<<endl;
+ string tag = "cmvtstblack.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+
+ return 0;
+}
+
+//---------------------------------------
+void compute_xroot(void)
+// Pour calculer les x qui donnent le maximum de f(x) pour:
+// f(x) = x^n * exp(-x)
+// ou
+// f(x) = x^n / (exp(x)-1)
+// ou
+// f(x) = x^n * exp(x) / (exp(x)-1)^2
+{
+  double n = 3.;
+  cout<<"n="<<n<<endl;
+  int npt=10;
+  double xmin=0.1,xmax=10., dx=(xmax-xmin)/npt;
+  for(int itry=0;itry<100;itry++) {
+    double x0=xmin, v0=-1e10;
+    for(double x=xmin;x<xmax+dx/2.; x+=dx) {
+      double f = pow(x,n) * exp(-x);  // Wien ou dWein/dT
+      //double f = pow(x,n) / (exp(x)-1);  // Planck
+      //double f = pow(x,n)  * exp(x) / ((exp(x)-1)*(exp(x)-1));  // dPlanck/dT
+      if(f>v0) {v0=f; x0=x;}
+    }
+    printf("x0 = %.18f , v0=%.18f , dx=%e\n",x0,v0,dx);
+    xmin = x0-dx; xmax = x0+dx; dx=(xmax-xmin)/npt;
+    if(dx<1e-15) break;
+  }
+}
+
+
+/*
+openppf cmvtstblack.ppf
+
+# Energie
+set fac 1.
+# Photon
+set fac (6.6260693e-34*f)
+
+n/plot nt.log10(f)%log10(l)
+
+# radiance frequence
+n/plot nt.prf/${fac}%log10(f) ! ! "nsta connectpoints"
+n/plot nt.rrf/${fac}%log10(f) ! ! "nsta connectpoints red same"
+n/plot nt.wrf/${fac}%log10(f) ! ! "nsta connectpoints blue same"
+
+# radiance longeur d'onde
+n/plot nt.prl/${fac}%log10(l) ! ! "nsta connectpoints"
+n/plot nt.rrl/${fac}%log10(l) ! ! "nsta connectpoints red same"
+n/plot nt.wrl/${fac}%log10(l) ! ! "nsta connectpoints blue same"
+
+# densite frequence
+n/plot nt.pdf/${fac}%log10(f) ! ! "nsta connectpoints"
+n/plot nt.rdf/${fac}%log10(f) ! ! "nsta connectpoints red same"
+n/plot nt.wdf/${fac}%log10(f) ! ! "nsta connectpoints blue same"
+
+# densite longeur d'onde
+n/plot nt.pdl/${fac}%log10(l) ! ! "nsta connectpoints"
+n/plot nt.rdl/${fac}%log10(l) ! ! "nsta connectpoints red same"
+n/plot nt.wdl/${fac}%log10(l) ! ! "nsta connectpoints blue same"
+
+# Check:  p(l)dl = p(f)df avec dl = c/f^2 df = l^2/c df
+n/plot nt.prf%log10(f) ! ! "nsta connectpoints"
+n/plot nt.prl*2.998e8/(f*f)%log10(f) ! ! "nsta connectpoints red same"
+
+ */
Index: /tags/V1_0/Cosmo/SimLSS/cmvtstpk.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtstpk.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtstpk.cc	(revision 3382)
@@ -0,0 +1,248 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "histos.h"
+#include "tvector.h"
+#include "ntuple.h"
+#include "perandom.h"
+
+#include "constcosmo.h"
+#include "pkspectrum.h"
+#include "geneutils.h"
+
+void usage(void);
+void usage(void) {
+ cout<<"cmvtstpk [options] z_redshift"<<endl
+     <<" -H h100 -B Ob0 -M Om0 -L Ol0,w0"<<endl
+     <<" -k npt,lkmin,lkmax : les valeurs sont en log10"<<endl
+     <<" -s scale : on multiplie pkz par scale"<<endl
+     <<" -w : write spectra on ASCII file"<<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ // -- WMAP
+ double h100=0.71, Om0=0.267804, Ob0 = 0.0444356, Ol0=0.73,w0=-1.;
+
+ double ns = 1., as = 1.;
+ int npt = 10000;
+ double lkmin = -3., lkmax=2.;
+ double scale = 1.;
+ bool wrascii = false;
+
+ char c;
+  while((c = getopt(narg,arg,"hwk:s:H:M:B:L:")) != -1) {
+  switch (c) {
+  case 'H' :
+    sscanf(optarg,"%lf",&h100);
+    break;
+  case 'M' :
+    sscanf(optarg,"%lf",&Om0);
+    break;
+  case 'B' :
+    sscanf(optarg,"%lf",&Ob0);
+    break;
+  case 'L' :
+    sscanf(optarg,"%lf,%lf",&Ol0,&w0);
+    break;
+  case 'k' :
+    sscanf(optarg,"%d,%lf,%lf",&npt,&lkmin,&lkmax);
+    if(npt<=0) npt=1000;
+    if(lkmax<lkmin) {lkmin=-4.; lkmax=2.;}
+    break;
+  case 's' :
+    sscanf(optarg,"%lf",&scale);
+    break;
+  case 'w' :
+    wrascii = true;
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+ double dlk=(lkmax-lkmin)/npt;
+
+ // Fill z value into list
+ double zval = 0.;
+ if(optind<narg) zval = atof(arg[optind]);
+
+ cout<<"h100="<<h100<<" Om0="<<Om0<<" Ob0="<<Ob0<<" Ol0="<<Ol0<<" w0="<<w0<<endl;
+ cout<<"lkmin="<<lkmin<<" lkmax="<<lkmax<<" npt="<<npt<<" dlk="<<dlk<<endl;
+ cout<<"scale="<<scale<<endl;
+ cout<<"zval="<<zval<<endl;
+
+ //--------------------------
+ InitialSpectrum pkini(ns,as);
+
+ TransfertEisenstein tf(h100,Om0-Ob0,Ob0,T_CMB_Par,false);
+ cout<<"kpeak="<<tf.KPeak()<<endl;
+ TransfertEisenstein tfnosc2(tf); tfnosc2.SetNoOscEnv(2);
+ TransfertEisenstein tfnosc1(tf); tfnosc1.SetNoOscEnv(1);
+ TransfertEisenstein tfnob(h100,Om0,0.,T_CMB_Par,true);
+
+ GrowthFactor d1(Om0,Ol0);
+ cout<<"GrowthFactor: "<<d1(zval)<<endl;
+
+ PkSpectrum0 pk0(pkini,tf);
+ PkSpectrum0 pk0nosc2(pkini,tfnosc2);
+ PkSpectrum0 pk0nosc1(pkini,tfnosc1);
+ PkSpectrum0 pk0nob(pkini,tfnob);
+
+ PkSpectrumZ pkz(pk0,d1,zval);
+ PkSpectrumZ pkznosc2(pk0nosc2,d1,zval);
+ PkSpectrumZ pkznosc1(pk0nosc1,d1,zval);
+ PkSpectrumZ pkznob(pk0nob,d1,zval);
+
+ //--------------------------
+ Histo hd1(0.,20.,10000); hd1.ReCenterBin();
+ FuncToHisto(d1,hd1,false);
+
+ Histo hpkz(lkmin,lkmax,npt); hpkz.ReCenterBin();
+ FuncToHisto(pkz,hpkz,true);
+ TVector<r_8> vpkz(npt);
+ FuncToVec(pkz,vpkz,lkmin,lkmax,true);
+
+ FunRan talea(hpkz,true);
+ Histo halea(hpkz); halea.Zero();
+ int nalea = 100000;
+ for(int i=0;i<nalea;i++) halea.Add(talea.Random());
+ halea *= hpkz.Sum()/halea.Sum();
+
+ //--------------------------
+ const int n = 14;
+ char *vname[n] = {
+   "k","pkini",
+   "tf","pk0","pk",
+   "tfnosc2","pk0nosc2","pknosc2",
+   "tfnosc1","pk0nosc1","pknosc1",
+   "tfnob","pk0nob","pknob"
+ };
+ NTuple nt(n,vname);
+ double xnt[n];
+
+ for(double lk=lkmin;lk<lkmax+dlk/2.;lk+=dlk) {
+   double k = pow(10.,lk);
+   xnt[0] = k;
+   xnt[1] = pkini(k);
+   xnt[2] = tf(k);
+   xnt[3] = pk0(k);
+   xnt[4] = pkz(k,zval);
+   xnt[5] = tfnosc2(k);
+   xnt[6] = pk0nosc2(k);
+   xnt[7] = pkznosc2(k,zval);
+   xnt[8] = tfnosc1(k);
+   xnt[9] = pk0nosc1(k);
+   xnt[10] = pkznosc1(k,zval);
+   xnt[11] = tfnob(k);
+   xnt[12] = pk0nob(k);
+   xnt[13] = pkznob(k,zval);
+   nt.Fill(xnt);
+ }
+
+ //--------------------------
+ if(wrascii) {
+   cout<<">>>> ASCII"<<endl;
+   FILE * fdata = fopen("cmvtstpk.data","w");
+   fprintf(fdata,"# z= %g : k(Mpc^-1) pkini, tf pk0 pkz, tfnosc2 pk0nosc2 pkznosc2, ",zval);
+   fprintf(fdata,"tfnosc1 pk0nosc1 pkznosc1, tfnob pk0nob pkznob\n");
+   for(double lk=lkmin;lk<lkmax+dlk/2.;lk+=dlk) {
+     double k = pow(10.,lk);
+     fprintf(fdata,"%e %e %e %e %e %e %e %e %e %e %e %e %e %e\n",
+	     k,pkini(k),
+	     tf(k),pk0(k),scale*pkz(k,zval),
+	     tfnosc2(k),pk0nosc2(k),scale*pkznosc2(k,zval),
+	     tfnosc1(k),pk0nosc1(k),scale*pkznosc1(k,zval),
+	     tfnob(k),pk0nob(k),scale*pkznob(k,zval));
+   }
+   fclose(fdata);
+ }
+
+ //--------------------------
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtstpk.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+ tag = "hd1"; pos.PutObject(hd1,tag);
+ tag = "hpkz"; pos.PutObject(hpkz,tag);
+ tag = "vpkz"; pos.PutObject(vpkz,tag);
+ tag = "halea"; pos.PutObject(halea,tag);
+ return 0;
+}
+
+/*
+openppf cmvtstpk.ppf
+
+#### growth-factor
+zone
+n/plot hd1.val%x ! ! "nsta connectpoints"
+
+#### Spectre initial
+zone
+n/plot nt.log10(pkini)%log10(k) pkini>0. ! "nsta connectpoints"
+
+#### Gestion des abscisses
+set xk log10(k)
+set xk k
+
+#### fct de transfert
+zone
+n/plot nt.tf%$xk ! ! "nsta connectpoints"
+n/plot nt.tfnosc2%$xk ! ! "nsta connectpoints same red"
+n/plot nt.tfnosc1%$xk ! ! "nsta connectpoints same blue"
+n/plot nt.tfnob%$xk ! ! "nsta connectpoints same green"
+
+n/plot nt.tf/tfnosc2%$xk ! ! "nsta connectpoints red"
+n/plot nt.tf/tfnosc1%$xk ! ! "nsta connectpoints same blue"
+n/plot nt.tf/tfnob%$xk ! ! "nsta connectpoints same green"
+addline -10 1 10 1
+
+#### Spectre a z=0
+zone
+n/plot nt.pk0%$xk ! ! "nsta connectpoints"
+n/plot nt.pk0nosc2%$xk ! ! "nsta connectpoints same red"
+n/plot nt.pk0nosc1%$xk ! ! "nsta connectpoints same blue"
+n/plot nt.pk0nob%$xk ! ! "nsta connectpoints same green"
+
+# Check
+zone 2 2
+n/plot nt.pk0/pkini-tf*tf%$xk pkini>0 ! "nsta crossmarker3"
+n/plot nt.pk0nosc2/pkini-tfnosc2*tfnosc2%$xk pkini>0 ! "nsta crossmarker3"
+n/plot nt.pk0nosc1/pkini-tfnosc1*tfnosc1%$xk pkini>0 ! "nsta crossmarker3"
+n/plot nt.pk0nob/pkini-tfnob*tfnob%$xk pkini>0 ! "nsta crossmarker3"
+
+#### Spectre a z
+zone
+n/plot nt.pk%$xk ! ! "nsta connectpoints"
+n/plot nt.pknosc2%$xk ! ! "nsta connectpoints same red"
+n/plot nt.pknosc1%$xk ! ! "nsta connectpoints same blue"
+n/plot nt.pknob%$xk ! ! "nsta connectpoints same green"
+
+n/plot nt.pk/pknosc2%$xk ! ! "nsta connectpoints red"
+n/plot nt.pk/pknosc1%$xk ! ! "nsta connectpoints same blue"
+n/plot nt.pk/pknob%$xk ! ! "nsta connectpoints same green"
+addline -10 1 10 1
+
+#### Le spectre version Delta^2
+set D2 k*k*k*pk/(2*M_PI*M_PI)
+n/plot nt.$D2%$xk  !  ! "nsta crossmarker3 connectpoints"
+
+#### Test des transferts dans Histo et TVector
+zone 1 2
+n/plot nt.pk%log10(k) ! ! "nsta crossmarker3"
+disp hpkz "same red"
+
+disp vpkz
+c++exec cout<<hpkz(0)<<" =?= "<<vpkz(0)<<endl;
+
+zone
+disp hpkz
+disp halea "same red"
+
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtstsch.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtstsch.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtstsch.cc	(revision 3382)
@@ -0,0 +1,241 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "histos.h"
+#include "ntuple.h"
+#include "srandgen.h"
+#include "perandom.h"
+
+#include "geneutils.h"
+#include "cosmocalc.h"
+#include "schechter.h"
+
+void usage(void);
+void usage(void)
+{
+ cout<<"cmvtstsch -m xmin,xmax -a -i perc,dlxinc,dlxmax,glorder -n nbin -N nalea"<<endl
+     <<"  xmin,xmax : limites en masse"<<endl
+     <<"  perc : see IntegrateFunc"<<endl
+     <<"  dlnx : see IntegrateFunc"<<endl
+     <<"         si <0 nombre de point dlx = (log10(xmax)-log10(xmin))/(-dlx)"<<endl
+     <<"  dlxmax : see IntegrateFunc, si <0 -dlxmax*dlx, si ==0 no check"<<endl
+     <<"  glorder : odre gauss-legendre"<<endl
+     <<"  nbin : nombre de bins"<<endl
+     <<"  nalea : nombre de tirages aleatoires"<<endl
+     <<"  -a : init auto de l\'aleatoire"<<endl;
+}
+
+
+int main(int narg,char *arg[])
+{
+ double h75 = 0.71 / 0.75;
+ double nstar = 0.006*pow(h75,3.);  //  
+ double mstar = pow(10.,9.8);  // MSol
+ double alpha = -1.37;
+ cout<<"h75= "<<h75<<" nstar= "<<nstar<<"  mstar="<<mstar<<"  alpha="<<alpha<<endl;
+
+ double xmin=1e6, xmax=1e12;
+ double perc=0.01,dlxinc=-1000.,dlxmax=0.; unsigned short glorder=4;
+ int npt = 1000;
+ int nalea = 100000;
+
+ char c;
+ while((c = getopt(narg,arg,"ham:i:n:N:")) != -1) {
+   switch (c) {
+   case 'm' :
+     sscanf(optarg,"%lf,%lf",&xmin,&xmax);
+     break;
+   case 'i' :
+     int ig;
+     sscanf(optarg,"%lf,%lf,%lf,%u",&perc,&dlxinc,&dlxmax,&ig);
+     if(perc<=0.) perc = 0.01;
+     glorder = (ig<=0) ? 4: ig;
+     break;
+   case 'n' :
+     sscanf(optarg,"%d",&npt);
+     if(npt<=0) npt = 1000;
+     break;
+   case 'N' :
+     sscanf(optarg,"%d",&nalea);
+     break;
+   case 'a' :
+     Auto_Ini_Ranf(5);
+     break;
+   case 'h' :
+   default :
+     usage(); return -1;
+   }
+ }
+
+ double lnx1=log10(xmin), lnx2=log10(xmax), dlnx = (lnx2-lnx1)/npt;
+ cout<<"xmin="<<xmin<<" ("<<lnx1<<") xmax="<<xmax<<" ("<<lnx2<<"), dlnx="<<dlnx<<endl;
+
+ if(dlxinc<0.) dlxinc=(lnx2-lnx1)/(-dlxinc);
+ if(dlxmax<0.) dlxmax *= -dlxinc; else if(dlxmax==0.) dlxmax=-1.;
+ cout<<"perc="<<perc<<" dlxinc="<<dlxinc<<" dlxmax="<<dlxmax<<" glorder="<<glorder<<endl;
+
+ cout<<"npt="<<npt<<",  nalea="<<nalea<<endl;
+
+ Schechter sch(nstar,mstar,alpha);
+
+ InitTim();
+
+ //-------dn/dm
+ cout<<endl;
+ cout<<"sch(mstar) = "<<sch(mstar)<<" /Mpc^3/Msol"<<endl;
+ sch.SetOutValue(0);
+ cout<<"......"<<endl;
+ for(double lnx=lnx1-3.;lnx<=lnx2-1.;lnx+=1.) {
+   double num = sch.Integrate(pow(10.,lnx),pow(10.,lnx2),npt);
+   double numc = IntegrateFuncLog(sch,lnx,lnx2,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx<<","<<lnx2<<"] integrated number = "<<num<<" Mpc^-3 , check: "<<numc<<endl;
+ }
+ cout<<"......"<<endl;
+ for(double lnx=lnx1+1.;lnx<=lnx2+3.;lnx+=1.) {
+   double num = sch.Integrate(pow(10.,lnx1),pow(10.,lnx),npt);
+   double numc = IntegrateFuncLog(sch,lnx1,lnx,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx1<<","<<lnx<<"] integrated number = "<<num<<" Mpc^-3 , check: "<<numc<<endl;
+ }
+ cout<<"......"<<endl;
+ for(double lnx=lnx1-3.;lnx<=lnx2+3.;lnx+=1.) {
+   double num = sch.Integrate(pow(10.,lnx),pow(10.,lnx+1.),npt);
+   double numc = IntegrateFuncLog(sch,lnx,lnx+1.,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx<<","<<lnx+1.<<"] integrated number = "<<num<<" Mpc^-3 , check: "<<numc<<endl;
+ }
+ Histo hdndm(lnx1,lnx2,npt); hdndm.ReCenterBin();
+ FuncToHisto(sch,hdndm,true);
+
+ //-------m*dn/dm
+ cout<<endl;
+ sch.SetOutValue(1);
+ cout<<"mstar*sch(mstar) = "<<sch(mstar)<<" Msol/Mpc^3/Msol"<<endl;
+ cout<<"......"<<endl;
+ for(double lnx=lnx1-3.;lnx<=lnx2-1.;lnx+=1.) {
+   double sum = sch.Integrate(pow(10.,lnx),pow(10.,lnx2),npt);
+   double sumc = IntegrateFuncLog(sch,lnx,lnx2,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx<<","<<lnx2<<"] integrated mass = "<<sum<<" Msol.Mpc^-3 , check: "<<sumc<<endl;
+ }
+ cout<<"......"<<endl;
+ for(double lnx=lnx1+1.;lnx<=lnx2+3.;lnx+=1.) {
+   double sum = sch.Integrate(pow(10.,lnx1),pow(10.,lnx),npt);
+   double sumc = IntegrateFuncLog(sch,lnx1,lnx,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx1<<","<<lnx<<"] integrated mass = "<<sum<<" Msol.Mpc^-3 , check: "<<sumc<<endl;
+ }
+ cout<<"......"<<endl;
+ for(double lnx=lnx1-3.;lnx<=lnx2+3.;lnx+=1.) {
+   double sum = sch.Integrate(pow(10.,lnx),pow(10.,lnx+1.),npt);
+   double sumc = IntegrateFuncLog(sch,lnx,lnx+1.,perc,dlxinc,dlxmax,glorder);
+   cout<<"["<<lnx<<","<<lnx+1.<<"] integrated mass = "<<sum<<" Msol.Mpc^-3 , check: "<<sumc<<endl;
+ }
+ Histo hmdndm(lnx1,lnx2,npt); hmdndm.ReCenterBin();
+ FuncToHisto(sch,hmdndm,true);
+
+ //------- Le flux HI pour M=mstar a 1 Gpc
+ cout<<endl;
+ double d = 1000.;
+ double f = Msol2FluxHI(mstar,d);
+ cout<<"FluxHI: d="<<d<<" Mpc:"<<"  M= "<<mstar<<" Msol  "
+     <<"-> Flux= "<<f<<" W/m^2"<<endl;
+ cout<<"Check... MassHI: d="<<d<<" Mpc:"<<"  f= "<<f<<" W/m^2  "
+     <<"-> Mass= "<<FluxHI2Msol(f,d)<<" Msol"<<endl;
+
+ //------- Random
+ Histo hdna(hdndm); hdna.Zero();
+ Histo hmdna(hmdndm); hmdna.Zero();
+ FunRan tirhdndm = FunRan(hdndm,true);
+ FunRan tirhmdndm = FunRan(hmdndm,true);
+ if(nalea>0) {
+   double summ=0.;
+   PrtTim("--- avant tirage aleatoire");
+   for(int i=0;i<nalea;i++) {
+     double a = tirhdndm.RandomInterp();
+     hdna.Add(a);
+     a = tirhmdndm.RandomInterp();
+     summ += pow(10.,a);
+     hmdna.Add(a);
+   }
+   cout<<"Tirgae aleatoire: <m>="<<summ/(double)nalea<<endl;
+   hdna *= hdndm.Sum()/hdna.Sum();
+   hmdna *= hmdndm.Sum()/hmdna.Sum();
+   PrtTim("--- apres tirage aleatoire");
+ }
+
+ //-------
+ const int n = 3;
+ char *vname[n] = {"m","f","mf"};
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(double lx=lnx1;lx<lnx2+dlnx/2.;lx+=dlnx) {
+   double x = pow(10.,lx);
+   xnt[0]  = x;
+   sch.SetOutValue(0);
+   xnt[1]  = sch(x);
+   sch.SetOutValue(1);
+   xnt[2]  = sch(x);
+   nt.Fill(xnt);
+ }
+
+ cout<<"Ecriture"<<endl;
+ string tag = "cmvtstsch.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+ tag = "hdndm"; pos.PutObject(hdndm,tag);
+ tag = "hmdndm"; pos.PutObject(hmdndm,tag);
+ tag = "hdna"; pos.PutObject(hdna,tag);
+ tag = "hmdna"; pos.PutObject(hmdna,tag);
+ Histo hdum1(tirhdndm);
+ tag = "tirhdndm"; pos.PutObject(hdum1,tag);
+ Histo hdum2(tirhmdndm);
+ tag = "tirhmdndm"; pos.PutObject(hdum2,tag);
+
+ return 0;
+}
+
+/*
+openppf cmvtstsch.ppf
+
+#--- la fonction de masse numerique
+zone 2 2
+n/plot nt.f%m ! ! "nsta crossmarker3"
+n/plot nt.f%log10(m) ! ! "nsta crossmarker3"
+n/plot nt.log10(f)%log10(m) f>0. ! "nsta crossmarker3"
+
+# ce qu'on integre (en log10)
+n/plot nt.m*f%log10(m) ! ! "nsta crossmarker3"
+
+#--- la fonction de masse
+zone 2 2
+n/plot nt.mf%m ! ! "nsta crossmarker3"
+n/plot nt.mf%log10(m) f>0. ! "nsta crossmarker3"
+n/plot nt.log10(mf)%log10(m) mf>0. ! "nsta crossmarker3"
+
+# ce qu'on integre (en log10)
+n/plot nt.m*mf%log10(m) ! ! "nsta crossmarker3"
+
+#--- Check histos
+zone 2 1
+disp hdndm "red"
+n/plot nt.f%log10(m) ! ! "nsta crossmarker3 same"
+
+disp hmdndm "red"
+n/plot nt.m*f%log10(m) ! ! "nsta crossmarker3 same"
+
+#--- Check tirage aleatoire
+zone 2 1
+disp hdndm
+disp hdna "same red"
+
+disp hmdndm
+disp hmdna "same red"
+
+zone
+disp tirhdndm
+disp tirhmdndm "same red"
+
+ */
Index: /tags/V1_0/Cosmo/SimLSS/cmvtuniv.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtuniv.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtuniv.cc	(revision 3382)
@@ -0,0 +1,307 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "cosmocalc.h"
+#include "geneutils.h"
+
+void tstprint(CosmoCalc& univ,double z1,double z2,double dz);
+void tstprint(CosmoCalc& univ1,CosmoCalc& univ2,double z1,double z2,double dz);
+void tstspeed(CosmoCalc& univ,double z1,double z2,double dz);
+void tstntuple(CosmoCalc& univ,double z1,double z2,double dz);
+void tstinterp(CosmoCalc& univ,double z1,double z2,double dz);
+
+const double deg2rad = M_PI/180.;
+
+void usage(void);
+void usage(void) {
+ cout
+ <<"cmvtuniv [options] z1,z2"<<endl
+ <<"  -D dz"<<endl
+ <<"  -U h100,om0,or0,ol0,w0"<<endl
+ <<"  -F flat(0,1,2)"<<endl
+ <<"  -I perc,dzinc,dzmax,glorder"<<endl
+ <<" --- What has to be done:"<<endl
+ <<"  -W 1/2/3/4/5"<<endl
+ <<"     1 : print info from z1 to z2 by step dz"<<endl
+ <<"     2 : compare with/without spline from z1 to z2 by step dz"<<endl
+ <<"     3 : test speed from z1 to z2 by step dz"<<endl
+ <<"     4 : fill ntuple with infos from z1 to z2 by step dz"<<endl
+ <<"     5 : test interpolation loscom from z1 to z2 by step dz"<<endl
+ <<endl;
+}
+
+int main(int narg,char *arg[])
+{
+ unsigned short flat = 0;
+ // -- WMAP
+ double h100=0.71, om0=0.267804, or0=7.9e-05, ol0=0.73,w0=-1.;
+ // -- ouvert matter only
+ //double h100=0.71, om0=0.3, or0=0., ol0=0.,w0=-1.;
+ // -- plat matter only
+ //double h100=0.71, om0=1., or0=0., ol0=0.,w0=-1.; flat = 1;
+ // -- plat lambda only
+ //double h100=0.71, om0=0., or0=0., ol0=1.,w0=-1.; flat = 2;
+
+ // -- parametre d'integration
+ double perc=0.01,dzinc=-1.,dzmax=-1.;
+ unsigned short glorder=4;
+ // -- redshift
+ double z1=0., z2=-1., dz=-1.;
+ // -- Work to be done
+ int todo = 1;
+
+ InitTim();
+
+ // Read arguments
+ char c;
+ while ((c = getopt(narg, arg, "hD:U:F:I:W:")) != -1) {
+  switch (c) {
+  case 'D' :
+    sscanf(optarg,"%lf",&dz);
+    break;
+  case 'U' :
+    sscanf(optarg,"%lf,%lf,%lf,%lf,%lf",&h100,&om0,&or0,&ol0,&w0);
+    break;
+  case 'F' :
+    sscanf(optarg,"%hu",&flat);
+    break;
+  case 'I' :
+    sscanf(optarg,"%lf,%lf,%lf,%hu",&perc,&dzinc,&dzmax,&glorder);
+    break;
+  case 'W' :
+    sscanf(optarg,"%d",&todo);
+    break;
+  case 'h' :
+  default:
+    usage();
+    return -1;
+  }
+}
+ if(optind<narg) sscanf(arg[optind],"%lf,%lf",&z1,&z2);
+
+ if(z1<0.) z1 = 0.;
+ if(z2<=z1) z2 = z1+1.;
+ if(dz<=0.) dz = 10.*(z2-z1);
+ cout<<"z1="<<z1<<"  z2="<<z2<<"  dz="<<dz<<endl;
+ cout<<"perc="<<perc<<" dzinc="<<dzinc<<" dzmax="<<dzmax<<" glorder="<<glorder<<endl;
+ cout<<"h100="<<h100<<" om0="<<om0<<" or0="<<or0<<" ol0="<<ol0<<" w0="<<w0<<" flat="<<flat<<endl;
+ cout<<"todo ="<<todo<<endl;
+
+ CosmoCalc univ1(flat,true,z2);
+ univ1.SetInteg(perc,dzinc,dzmax,glorder);
+ univ1.SetDynParam(h100,om0,or0,ol0,w0);
+ univ1.PrtInteg();
+ univ1.Print();
+ cout<<endl;
+
+ if(todo==1)  tstprint(univ1,z1,z2,dz);
+ else if(todo==2) {
+   CosmoCalc univ2(flat,false,z2);
+   univ2.SetInteg(perc,dzinc,dzmax,glorder);
+   univ2.SetDynParam(h100,om0,or0,ol0,w0);
+   univ2.PrtInteg();
+   univ2.Print();
+   tstprint(univ1,univ2,z1,z2,dz);
+ }
+ else if(todo==3) tstspeed(univ1,z1,z2,dz);
+ else if(todo==4) tstntuple(univ1,z1,z2,dz);
+ else if(todo==5)tstinterp(univ1,z1,z2,dz);
+ else cout<<"Unknown job to be done !!!!!  todo="<<todo<<endl;
+
+ return 0;
+}
+
+/* ----------------------------------------------------- */
+void tstprint(CosmoCalc& univ,double z1,double z2,double dz)
+{
+ if(dz>z2-z1) dz = z2-z1;
+ cout<<"\nTSTPRINT(): z1="<<z1<<" z2="<<z2<<" dz="<<dz<<endl;
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   cout<<"-- z = "<<z<<endl;
+   univ.Print(z);
+   cout<<"Volume comoving in [z,z+"<<dz<<"] for 4Pi sr: "
+       <<univ.Vol4Pi(z,z+dz)<<" Mpc^3"<<endl;
+   double dang = univ.Dang(z);
+   double a = deg2rad/3600.;
+   cout<<"1\" -> "<<dang*a<<" Mpc = "<<dang*a*(1.+z)<<" Mpc com"<<endl;
+   a = deg2rad/60.;
+   cout<<"1\' -> "<<dang*a<<" Mpc = "<<dang*a*(1.+z)<<" Mpc com"<<endl;
+   a = deg2rad;
+   cout<<"1d -> "<<dang*a<<" Mpc = "<<dang*a*(1.+z)<<" Mpc com"<<endl;
+   double dloscom = univ.Dhubble() / univ.E(z);
+   cout<<"dz=1 -> "<<dloscom<<" Mpc com"<<endl;
+ }
+
+}
+
+/* ----------------------------------------------------- */
+void tstprint(CosmoCalc& univ1,CosmoCalc& univ2,double z1,double z2,double dz)
+{
+ if(dz>z2-z1) dz = z2-z1;
+ cout<<"\nTSTPRINT(): z1="<<z1<<" z2="<<z2<<" dz="<<dz<<endl;
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   cout<<endl<<"--spline: z = "<<z<<endl;
+   univ1.Print(z);
+   cout<<"Volume comoving in [z,z+dz] for 4Pi sr: "
+       <<univ1.Vol4Pi(z,z+dz)<<" Mpc^3"<<endl;
+   cout<<"--integ: z = "<<z<<endl;
+   univ2.Print(z);
+   cout<<"Volume comoving in [z,z+dz] for 4Pi sr: "
+       <<univ2.Vol4Pi(z,z+dz)<<" Mpc^3"<<endl;
+ }
+}
+
+/* ----------------------------------------------------- */
+void tstspeed(CosmoCalc& univ,double z1,double z2,double dz)
+{
+ if(dz>z2-z1) dz = z2-z1;
+ cout<<"\nTSTSPEED(): z1="<<z1<<" z2="<<z2<<" dz="<<dz<<endl;
+ double sum = 0.;
+ int_4 n=0;
+ PrtTim("-- Beginning");
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   sum += univ.Dang(z);
+   n++;
+ }
+ if(n>0) cout<<"n="<<n<<" ...dum="<<sum/n<<endl;
+ PrtTim("-- Ending");
+}
+
+/* ----------------------------------------------------- */
+void tstntuple(CosmoCalc& univ,double z1,double z2,double dz)
+{
+ if(dz>z2-z1) dz = z2-z1;
+ cout<<"\nTSTNTUPLE(): z1="<<z1<<" z2="<<z2<<" dz="<<dz<<endl;
+ double norm =  univ.Dhubble();  // 1.
+ double norm3 = pow(norm,3.);
+ const int n = 15;
+ char *vname[n] = {
+   "z","hz","om","or","ol","ok","ot","ob",
+   "dtc","dlc","da","dl",
+   "dvc","vc0","vcdz"
+ };
+ NTuple nt(n,vname);
+ double xnt[n];
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   xnt[0]  = z;
+   xnt[1]  = univ.H(z);
+   xnt[2]  = univ.Omatter(z);
+   xnt[3]  = univ.Orelat(z);
+   xnt[4]  = univ.Olambda(z);
+   xnt[5]  = univ.Ocurv(z);
+   xnt[6]  = univ.Otot(z);
+   xnt[7]  = univ.Obaryon(z);
+   xnt[8]  = univ.Dtrcom(z)/norm;
+   xnt[9]  = univ.Dloscom(z)/norm;
+   xnt[10] = univ.Dang(z)/norm;
+   xnt[11] = univ.Dlum(z)/norm;
+   xnt[12] = univ.dVol(z)/norm3;
+   xnt[13] = univ.Vol4Pi(z)/norm3;
+   xnt[14] = univ.Vol4Pi(z,z+dz)/norm3;
+   nt.Fill(xnt);
+ }
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtuniv_nt.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+}
+
+
+/*
+openppf cmvtuniv_nt.ppf
+
+set cut 1
+set cut z<100.
+set cut z<10.
+
+zone
+n/plot nt.hz%z $cut ! "nsta connectpoints"
+
+zone
+n/plot nt.dl%z $cut ! "nsta connectpoints"
+n/plot nt.da%z $cut ! "nsta connectpoints same red"
+n/plot nt.dtc%z $cut ! "nsta connectpoints same blue"
+n/plot nt.dlc%z $cut ! "nsta connectpoints same green"
+
+zone 2 2
+n/plot nt.dvc%z $cut ! "nsta connectpoints"
+n/plot nt.vc0%z $cut ! "nsta connectpoints"
+n/plot nt.vcdz%z $cut ! "nsta connectpoints"
+
+zone
+n/plot nt.ot%z $cut ! "nsta connectpoints"
+n/plot nt.om%z $cut ! "nsta connectpoints same blue"
+n/plot nt.or%z $cut ! "nsta connectpoints same red"
+n/plot nt.ol%z $cut ! "nsta connectpoints same green"
+n/plot nt.ok%z $cut ! "nsta connectpoints same orange"
+
+ */
+
+/* ----------------------------------------------------- */
+void tstinterp(CosmoCalc& univ,double z1,double z2,double dz)
+{
+ if(dz>z2-z1) dz = z2-z1;
+ cout<<"\nTSTINTERP(): z1="<<z1<<" z2="<<z2<<" dz="<<dz<<endl;
+ // On remplit les donnes completes
+ vector<double> Z,D;
+ for(double z=z1;z<z2+dz/2.;z+=dz) {
+   Z.push_back(z);
+   D.push_back(univ.Dloscom(z));
+ }
+ // On remplit un sous tableau
+ int ninc = 5;
+ vector<double> Dinterp;
+ double zmin = Z[0], zmax = Z[0];
+ for(unsigned int i=0;i<Z.size();i+=ninc) {
+   Dinterp.push_back(D[i]);
+   zmax = Z[i];
+ }
+ InterpFunc interp(zmin,zmax,Dinterp);
+ unsigned short ok;
+
+ const int n = 8;
+ char *vname[n] = {"z","d","di","dl","dp","zi","zl","zp"};
+ NTuple nt(n,vname);
+ double xnt[n];
+   
+ for(unsigned int i=0;i<Z.size();i++) {
+   if(Z[i]>zmax) break;
+   xnt[0] = Z[i];
+   xnt[1] = D[i];
+   xnt[2] = interp(Z[i]);
+   xnt[3] = interp.Linear(Z[i],ok);
+   xnt[4] = interp.Parab(Z[i],ok);
+   xnt[5] = xnt[6] = xnt[7] = 0.;
+   nt.Fill(xnt);
+ }
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtuniv_int.ppf";
+ POutPersist pos(tag);
+ tag = "nt"; pos.PutObject(nt,tag);
+}
+
+/*
+openppf cmvtuniv_int.ppf
+
+n/plot nt.d%z ! ! "nsta connectpoints"
+n/plot nt.di%z ! ! "nsta connectpoints same green"
+n/plot nt.dl%z ! ! "nsta connectpoints same red"
+n/plot nt.dp%z ! ! "nsta connectpoints same blue"
+
+n/plot nt.di-d%z ! ! "nsta connectpoints green"
+n/plot nt.dl-d%z ! ! "nsta connectpoints same red"
+n/plot nt.dp-d%z ! ! "nsta connectpoints same blue"
+
+n/plot nt.(di-d)/d%z d>0 ! "nsta connectpoints green"
+n/plot nt.(dl-d)/d%z d>0 ! "nsta connectpoints same red"
+n/plot nt.(dp-d)/d%z d>0 ! "nsta connectpoints same blue"
+
+*/
Index: /tags/V1_0/Cosmo/SimLSS/cmvtvarspec.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cmvtvarspec.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cmvtvarspec.cc	(revision 3382)
@@ -0,0 +1,197 @@
+#include "sopnamsp.h"
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include "timing.h"
+#include "ntuple.h"
+
+#include "constcosmo.h"
+#include "pkspectrum.h"
+
+void usage(void);
+void usage(void)
+{
+  cout<<"cmvtvarspec -z zref -R R -n as,ns -k kmin,kmax -i eps,npt,fracmax"<<endl;
+}
+
+
+int main(int narg,char *arg[])
+{
+ double ob0 = 0.0444356;
+ // -- WMAP
+ double h100=0.71, om0=0.267804, ol0=0.73;
+ // -- ouvert matter only
+ //double h100=0.71, om0=0.3, ol0=0.;
+ // -- plat matter only
+ //double h100=0.71, om0=1., ol0=0.;
+
+ double ns = 1., as = 1.;
+
+ double zref = 0.5;
+ double R=8./h100;
+
+ double kmin=1e-5,kmax=1000.;
+ int npt = 10000;
+ double eps=1.e-3, fracmax=1e-4;
+
+ char c;
+ while((c = getopt(narg,arg,"hz:R:n:k:i:")) != -1) {
+  switch (c) {
+  case 'z' :
+    sscanf(optarg,"%lf",&zref);
+    break;
+  case 'R' :
+    sscanf(optarg,"%lf",&R);
+    if(R<0.) R = -R/h100;
+    break;
+  case 'n' :
+    sscanf(optarg,"%lf,%lf",&as,&ns);
+    break;
+  case 'k' :
+    sscanf(optarg,"%lf,%lf",&kmin,&kmax);
+    break;
+  case 'i' :
+    sscanf(optarg,"%lf,%d,%lf",&eps,&npt,&fracmax);
+    break;
+  case 'h' :
+  default :
+    usage(); return -1;
+  }
+ }
+
+ double Rg=R/sqrt(5.);
+ double lkmin=log10(kmin), lkmax=log10(kmax), dlk=(lkmax-lkmin)/npt;
+
+ cout<<"zref="<<zref<<endl;
+ cout<<"as="<<as<<" ns="<<ns<<endl;
+ cout<<"R="<<R<<", Rg="<<Rg<<endl;
+ cout<<"kmin="<<kmin<<" ("<<lkmin<<"), kmax="<<kmax<<" ("<<lkmax<<")"
+     <<", dlk="<<dlk<<" npt="<<npt<<endl;
+ cout<<"eps="<<eps<<"  fracmax="<<fracmax<<endl;
+
+ //-----------------------------------------------------------------
+ InitialSpectrum pkini(ns,as);
+
+ TransfertEisenstein tf(h100,om0-ob0,ob0,T_CMB_Par,false);
+ //tf.SetNoOscEnv(2);
+
+ GrowthFactor d1(om0,ol0);
+
+ PkSpectrum0 pk0(pkini,tf);
+
+ PkSpectrumZ pkz(pk0,d1,zref);
+
+ //-----------------------------------------------------------------
+ double k1,k2;
+ int rc = 0;
+ //----
+ cout<<endl<<"Filtrage top_hat"<<endl;
+ VarianceSpectrum varpk_th(pkz,R,VarianceSpectrum::TOPHAT);
+ double kfind_th = varpk_th.FindMaximum(kmin,kmax,eps);
+ double pkmax_th = varpk_th(kfind_th);
+ cout<<"kfind_th = "<<kfind_th<<" ("<<log10(kfind_th)<<"), integrand="<<pkmax_th<<endl;
+ k1=kmin, k2=kmax;
+ rc = varpk_th.FindLimits(pkmax_th*fracmax,k1,k2,eps);
+ cout<<"limit_th: rc="<<rc<<" : "<<k1<<" ("<<log10(k1)<<") , "<<k2<<" ("<<log10(k2)<<")"<<endl;
+
+ varpk_th.SetInteg(0.01,dlk,-1.,4);
+ cout<<"varpk_th="<<varpk_th.Variance(k1,k2)<<endl;
+
+ //----
+ cout<<endl<<"Filtrage gaussien"<<endl;
+ VarianceSpectrum varpk_ga(pkz,Rg,VarianceSpectrum::GAUSSIAN);
+ double kfind_ga = varpk_ga.FindMaximum(kmin,kmax,eps);
+ double pkmax_ga = varpk_ga(kfind_ga);
+ cout<<"kfind_ga = "<<kfind_ga<<" -> "<<log10(kfind_ga)<<", integrand="<<pkmax_ga<<endl;
+ k1=kmin, k2=kmax;
+ rc = varpk_ga.FindLimits(pkmax_ga*fracmax,k1,k2,eps);
+ cout<<"limit_ga: rc="<<rc<<" : "<<k1<<" ("<<log10(k1)<<") , "<<k2<<" ("<<log10(k2)<<")"<<endl;
+
+ varpk_ga.SetInteg(0.01,dlk,-1.,4);
+ cout<<"varpk_ga="<<varpk_ga.Variance(k1,k2)<<endl;
+ 
+ //----
+  cout<<endl<<"Filtrage 1 (integrale du spectre)"<<endl;
+ VarianceSpectrum varpk_int(pkz,Rg,VarianceSpectrum::NOFILTER);
+ double kfind_int = varpk_int.FindMaximum(kmin,kmax,eps);
+ double pkmax_int = varpk_int(kfind_int);
+ cout<<"kfind_int = "<<kfind_int<<" -> "<<log10(kfind_int)<<", integrand="<<pkmax_int<<endl;
+ k1=kmin, k2=kmax;
+ rc = varpk_int.FindLimits(pkmax_int*fracmax,k1,k2,eps);
+ cout<<"limit_int: rc="<<rc<<" : "<<k1<<" ("<<log10(k1)<<") , "<<k2<<" ("<<log10(k2)<<")"<<endl;
+
+ varpk_int.SetInteg(0.01,dlk,-1.,4);
+ cout<<"varpk_int="<<varpk_int.Variance(k1,k2)<<endl;
+ 
+//-----------------------------------------------------------------
+ const int n = 2;
+ char *vname[n] = {"k","pk"};
+ NTuple nt(n,vname);
+ double xnt[n];
+
+ for(double lk=lkmin;lk<lkmax+dlk/2.;lk+=dlk) {
+   double k = pow(10.,lk);
+   xnt[0] = k;
+   xnt[1] = pkz(k);
+   nt.Fill(xnt);
+ }
+
+ cout<<">>>> Ecriture"<<endl;
+ string tag = "cmvtvarspec.ppf"; POutPersist pos(tag); tag = "nt"; pos.PutObject(nt,tag);
+
+ return 0;
+}
+
+/*
+openppf cmvtvarspec.ppf
+
+#### Spectre a z
+n/plot nt.pk%log10(k) ! ! "nsta crossmarker3"
+
+# L'approximation pour j1(x) (top-hat) et la gaussienne equivalente
+set l1 1e-6
+set l2 10
+set j1sx pow(3*(sin(x)-x*cos(x))/(x*x*x),2.)
+set j1sxa3 (1.-x*x/5.)
+set j1sxa5 (1.-x*x/5.*(1.-3.*x*x/35.))
+set j1sxa7 (1.-x*x/5.*(1.-3.*x*x/35.*(1.-4.*x*x/81.)))
+func $j1sx    $l1 $l2 1000
+func $j1sxa3  $l1 $l2 1000 "red same"
+func $j1sxa5  $l1 $l2 1000 "blue same"
+func $j1sxa7  $l1 $l2 1000 "orange same"
+set gauss  pow(exp(-(x/sqrt(5.))*(x/sqrt(5.))/2.),2.)
+func $gauss  $l1 $l2 1000 "green same"
+
+func $j1sx-$j1sxa3  $l1 $l2 1000 "red"
+func $j1sx-$j1sxa5  $l1 $l2 1000 "blue same"
+func $j1sx-$j1sxa7  $l1 $l2 1000 "orange same"
+func $j1sx-$gauss  $l1 $l2 1000 "green same"
+addline $l1 0 $l2 0
+
+# la fonction "Pk" a integrer
+zone
+set D (k*k*pk/(2.*M_PI*M_PI))
+n/plot nt.$D%log10(k) ! ! "nsta crossmarker3"
+
+# La fonction a integrer en dk lineaire (top-hat et gaussien)
+set R 10
+set RG ($R/sqrt(5.))
+set x (k*$R)
+set j1sx pow(3*(sin($x)-$x*cos($x))/($x*$x*$x),2.)
+set y (k*$RG)
+set gauss  pow(exp(-$y*$y/2.),2.)
+
+n/plot nt.$D*$j1sx%log10(k) ! ! "nsta crossmarker3"
+n/plot nt.$D*$gauss%log10(k) ! ! "nsta crossmarker3 same red"
+
+# La fonction a integrer en d(log(x)) (top-hat et gaussien)
+# c'est ce que fait Variance()
+n/plot nt.k*$D*$j1sx%log10(k) ! ! "nsta crossmarker3"
+n/plot nt.k*$D*$gauss%log10(k) ! ! "nsta crossmarker3 same red"
+n/plot nt.k*$D%log10(k) ! ! "nsta crossmarker3 same blue"
+
+*/
Index: /tags/V1_0/Cosmo/SimLSS/constcosmo.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/constcosmo.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/constcosmo.h	(revision 3382)
@@ -0,0 +1,26 @@
+#ifndef CONSTCOSMO_SEEN
+#define CONSTCOSMO_SEEN
+
+static const double SpeedOfLight_Cst = 299792.458; // speed of light "km/sec"
+static const double G_Newton_Cst = 6.6742e-11; // G_N in SI units "m^3 / kg /s^2"
+static const double h_Planck_Cst = 6.6260693e-34;   // Planck constant SI units "J s"
+static const double k_Boltzman_Cst = 1.3806503e-23;  // Boltzman constant SI "J / K"
+//            Sigma = 2*PI^5*K^4/(15.*C^2*H^3) = PI^2*K^4/(60.*Hbar^3*C2)
+static const double StefBoltz_Cst = 5.670400e-8; // constante de Stefan-Boltzman in "W/m^2/K^4"
+static const double Zeta_3_Cst = 1.2020569031595942854; // Zeta(3)
+
+static const double YeartoSec_Cst = 31556925.2; // 1 year into seconds
+static const double MpctoMeters_Cst = 3.0856e+22; // 1 Mpc into meters
+static const double LightYear_Cst = 9.46073042e+15; // 1 Light-Year into "m"
+static const double Jansky2Watt_cst = 1.e-26;  // 1 Jansky into "Watt/m^2/Hz == J/m^2"
+static const double SolarMass_Cst = 1.98844e+33; // 1 Solar mass into "g"
+//                  GCm3toMsolMpc3_Cst = (MpctoMeters_Cst*100)^3 / SolarMass_Cst
+static const double GCm3toMsolMpc3_Cst = 1.477428208143872e+40; // 1 g/cm^3 into 1 Msol/Mpc^3
+static const double ProtonMass_Cst = 1.67262171e-24; // 1 "proton mass" in "g"
+static const double Deg2Rad_Cst = (M_PI/180.); // 1 deg into rad
+
+static const double T_CMB_Par = 2.725;  // temperature du CMB en "K"
+static const double T_NU_Par = 1.9;  // temperature des neutrinos en "K"
+static const double Fr_HyperFin_Par = 1.420405751786;  // frequence de la raie hyperfine HI en "GHz"
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/cosmocalc.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cosmocalc.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cosmocalc.cc	(revision 3382)
@@ -0,0 +1,459 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "pexceptions.h"
+#include "cspline.h"
+
+#include "constcosmo.h"
+#include "cosmocalc.h"
+#include "geneutils.h"
+
+namespace SOPHYA {
+
+///////////////////////////////////////////////////////////
+//*********************** CosmoCalc *********************//
+///////////////////////////////////////////////////////////
+
+//----------------------------------------------------------
+// flat = 0 : no compute Otot from other
+//      = 1 : change Omatter to get Otot=1
+//      = 2 : change Olambda to get Otot=1
+//      = 3 : change Orelat to get Otot=1
+// usespline = "true" : compute integrale then use spline to extrapolate
+//           = "false" : compute integrale everytime
+// zmax : maximum redshift(only if usespline=true)
+         
+CosmoCalc::CosmoCalc(unsigned short flat,bool usespline,double zmax)
+  : _flat(flat),
+    _zold(-1.) , _integval(0.),
+    _usespline(usespline), _computespl(true), _zmax(zmax), _spline(NULL),
+    _nspl(0), _xspl(NULL), _yspl(NULL)
+{
+  if(_usespline && _zmax<=0.) {
+    cout<<"CosmoCalc::CosmoCalc: Error bad _zmax value    zmax="<< _zmax<<endl;
+    throw ParmError("CosmoCalc::UseSpline: Error bad _zmax value");
+  }
+  DefaultParam();
+  SetInteg();
+}
+
+CosmoCalc::CosmoCalc(CosmoCalc& univ)
+  : _spline(NULL), _xspl(NULL), _yspl(NULL)
+{
+  Clone(univ);
+  if(_usespline && _zmax<=0.) {
+    cout<<"CosmoCalc::CosmoCalc: Error bad _zmax value    zmax="<< _zmax<<endl;
+    throw ParmError("CosmoCalc::UseSpline: Error bad _zmax value");
+  }
+}
+
+CosmoCalc::~CosmoCalc(void)
+{
+  if(_spline != NULL) delete _spline; _spline = NULL;
+  if(_xspl != NULL) delete [] _xspl; _xspl = NULL;
+  if(_yspl != NULL) delete [] _yspl; _yspl = NULL;
+}
+
+void CosmoCalc::Clone(CosmoCalc& univ)
+{
+ _flat = univ._flat;
+ _h100 = univ._h100;
+ _H0 = univ._H0;
+ _Olambda0 = univ._Olambda0;
+ _W0 = univ._W0;
+ _Omatter0 = univ._Omatter0;
+ _Obaryon0 = univ._Obaryon0;
+ _Orelat0 = univ._Orelat0;
+ _Otot0 = univ._Otot0;
+ _Ocurv0 = univ._Ocurv0;
+ _Dhubble = univ._Dhubble;
+
+ _dperc = univ._dperc;
+ _dzinc = univ._dzinc;
+ _dzmax = univ._dzmax;
+ _glorder = univ._glorder;
+ if(_xgausl.size()>0) {
+   _xgausl.resize(0); _wgausl.resize(0);
+   for(int i=0;i<(int)_xgausl.size();i++) {
+     _xgausl.push_back(univ._xgausl[i]);
+     _wgausl.push_back(univ._wgausl[i]);
+   }
+ }
+
+ _zold = -1.;
+ _integval = -1.;
+
+ _usespline = univ._usespline;
+ _computespl = true;
+ _zmax = univ._zmax;
+ _nspl = 0;
+ if(_spline) delete _spline; _spline = NULL;
+ if(_xspl) delete [] _xspl; _xspl = NULL;
+ if(_yspl) delete [] _yspl; _yspl = NULL;
+}
+
+//----------------------------------------------------------
+// On va couper l'intervalle entre [0,zmax]:
+// On parcourt [0,zmax] par pas de dzinc
+// et on cree un intervalle
+//     - si la fonction varie de plus de "dperc"
+//     - ou si l'increment en z est superieur a "dzmax"
+void CosmoCalc::SetInteg(double dperc,double dzinc,double dzmax,unsigned short order)
+{
+  _dperc = dperc; _dzinc = dzinc; _dzmax = dzmax;
+
+  if(_dperc<=0.) _dperc = 0.01;
+
+  if(_dzinc<=0.) _dzinc = _zmax/100.;
+  if(_dzinc>=_zmax/2.) _dzinc = _zmax/2.; // Protection against big dzinc
+
+  if(_dzmax<=0.) _dzmax = _zmax;
+  if(_dzmax<_dzinc) _dzmax = _dzinc;
+
+  _glorder = order;
+  if(_glorder<=1) _glorder = 4;
+  Compute_GaussLeg(_glorder,_xgausl,_wgausl,0.,1.);
+
+  _computespl=true;
+}
+
+
+void CosmoCalc::PrtInteg(void)
+{
+ printf("CosmoCalc::PrtInteg: dperc=%g dzinc=%g dzmax=%g glorder=%hu\n",_dperc,_dzinc,_dzmax,_glorder);
+}
+
+void CosmoCalc::SetObaryon0(double v)
+{
+  _Obaryon0 = v;
+  if(_Obaryon0<0.) {
+    cout<<"CosmoCalc::SetObaryon0: Error bad _Obaryon0 value: "<<_Obaryon0<<endl;
+    throw ParmError("CosmoCalc::SetObaryon0: Error bad _Obaryon0 value");
+  }
+}
+
+void CosmoCalc::SetDynParam(double h100,double om0,double or0,double ol0,double w0)
+{
+  _computespl=true;
+
+  _h100 = h100;
+  _H0 = 100. * _h100 ;
+  _Dhubble = SpeedOfLight_Cst / _H0;
+
+  _Omatter0 = om0;
+  _Orelat0 = or0;
+  _Olambda0 = ol0;
+  _W0 = w0;
+  _Otot0 = _Olambda0 + _Omatter0 + _Orelat0;
+  _Ocurv0 = 1. - _Otot0;
+  if( _h100<0. || _Omatter0<0. || _Orelat0<0. || _Olambda0<0. ) {
+    cout<<"CosmoCalc::SetDynParam: Error bad parameter value"<<endl;
+    throw ParmError("CosmoCalc::SetDynParam: Error bad parameter value");
+  }
+  if(_flat==0) return;
+
+  _Otot0 = 1.; _Ocurv0 = 0.;
+  if(_flat==1) {
+    _Omatter0 = _Otot0 - _Olambda0 - _Orelat0;
+    if( _Omatter0<0. ) {
+      cout<<"CosmoCalc::SetDynParam: Error bad _Omatter0 value: "<<_Omatter0<<endl;
+      throw ParmError("CosmoCalc::SetDynParam: Error bad _Omatter0 value");
+    }
+    return;
+  }
+
+  //--
+  if(_flat==2) {
+    _Olambda0 = _Otot0 - _Omatter0 - _Orelat0;
+    if( _Olambda0<0. ) {
+      cout<<"CosmoCalc::SetDynParam: Error bad _Olambda0 value: "<<_Olambda0<<endl;
+      throw ParmError("CosmoCalc::SetDynParam: Error bad _Olambda0 value");
+    }
+    return;
+  }
+
+  //--
+  if(_flat==3) {
+    _Orelat0 = _Otot0 - _Omatter0 - _Olambda0;
+    if( _Orelat0<0. ) {
+      cout<<"CosmoCalc::SetDynParam: Error bad _Orelat0 value: "<<_Orelat0<<endl;
+      throw ParmError("CosmoCalc::SetDynParam: Error bad _Orelat0 value");
+    }
+    return;
+  }
+
+  cout<<"CosmoCalc::SetDynParam: Error bad _flat value: "<<_flat<<endl;
+  throw ParmError("CosmoCalc::SetDynParam: Error bad _flat value");
+
+}
+
+void CosmoCalc::DefaultParam(void)
+{
+  _computespl=true;
+
+  double h100 = 0.71;
+  double ol0 = 0.73, w0 = -1.;
+  double om0 = 0.135/(h100*h100);
+  // Relat = photons (2.725 K) + neutrinos (1.9 K)
+  double or0 = 2.47e-5 * (1. + 21./8.*pow(T_NU_Par/T_CMB_Par,4.)) / (h100*h100);
+  SetDynParam(h100,om0,or0,ol0,w0);
+  _Obaryon0 = 0.0224/(h100*h100);
+
+  return;
+}
+
+//----------------------------------------------------------
+void CosmoCalc::Print(double z)
+{
+  if(z<0.) z = 0.;
+
+  printf("CosmoCalc::Print(spl=%d,zmax=%g,flat=%u)  for z=%g\n",int(_usespline),ZMax(),Flat(),z);
+  printf("h100=%g H0=%g Dhub=%g  H(z)=%g  Rhoc=%g g/cm^3 =%g Msol/Mpc^3\n"
+        ,h100(),H0(),Dhubble(),H(z),Rhoc(z),Rhoc(z)*GCm3toMsolMpc3_Cst);
+  printf("Olambda=%g  W0=%g\n",Olambda(z),_W0);
+  printf("Omatter=%g  Obaryon=%g\n",Omatter(z),Obaryon(z));
+  printf("Orelat=%g\n",Orelat(z));
+  printf("Otot=%g  Ocurv=%g\n",Otot(z),Ocurv(z));
+  if(z <= 0.) return;
+  printf("Distance comoving: los=%g Mpc, transv=%g Mpc\n",Dloscom(z),Dtrcom(z));
+  printf("Distance: angular=%g Mpc, lum=%g Mpc\n",Dang(z),Dlum(z));
+  printf("Volume comoving element: %g Mpc^3/sr/dz=1\n",dVol(z));
+  printf("Volume comoving in [0,z] for 4Pi sr: %g Mpc^3\n",Vol4Pi(z));
+
+}
+//----------------------------------------------------------
+double CosmoCalc::Olambda(double z)
+{
+  double v = _Olambda0;
+  if(_W0 != -1.) v *= pow((1.+z),3.*(1+_W0));
+  return v / E2(z);
+}
+
+double CosmoCalc::Omatter(double z)
+{
+  return _Omatter0 * (1.+z)*(1.+z)*(1.+z) /E2(z);
+}
+
+double CosmoCalc::Obaryon(double z)
+{
+  return _Obaryon0 * (1.+z)*(1.+z)*(1.+z) /E2(z);
+}
+
+double CosmoCalc::Orelat(double z)
+{
+  double z2 = (1.+z)*(1.+z);
+  return _Orelat0 * z2*z2 /E2(z);
+}
+
+double CosmoCalc::Ocurv(double z)
+{
+  return _Ocurv0 * (1.+z)*(1.+z) /E2(z);
+}
+
+double CosmoCalc::Otot(double z)
+{
+  return Olambda(z)+Omatter(z)+Orelat(z);
+}
+
+double CosmoCalc::Rhoc(double z)
+// Densite critique au redshift "z"  en "g/cm^3"
+{
+  double h2 = H(z) / MpctoMeters_Cst;  h2 *= h2;
+  return 3.* h2 / (8.*M_PI*G_Newton_Cst) * 1000.;
+}
+
+//----------------------------------------------------------
+double CosmoCalc::Dloscom(double z)     /* Mpc comobile */
+{
+  return _Dhubble * NInteg(z);
+}
+
+double CosmoCalc::Dtrcom(double z)     /* Mpc comobile */
+{
+  double v = NInteg(z);  // Zero curvature
+
+  if(_flat) return _Dhubble * v;
+
+  if(_Ocurv0>0.) {  // hyperbolique
+    double s = sqrt(_Ocurv0);
+    v = sinh(s*v)/s;
+  } else if(_Ocurv0<0.) {  // spherique
+    double s = sqrt(-_Ocurv0);
+    v = sin(s*v)/s;
+  }
+
+  return _Dhubble * v;
+
+}
+
+double CosmoCalc::Dang(double z)     /* Mpc */
+{
+  return Dtrcom(z) / (1.+z);
+}
+
+double CosmoCalc::Dlum(double z)     /* Mpc */
+{
+  return (1.+z) * Dtrcom(z);
+}
+
+double CosmoCalc::dVol(double z)     /* Mpc^3/ sr / unite z */
+{
+  double d = Dtrcom(z);
+  return _Dhubble * d*d / E(z);
+}
+
+//----------------------------------------------------------
+double CosmoCalc::Vol4Pi(double z)  /* Mpc^3 pour 4Pi sr entre [0,z] */
+  // --- on pose x = dm/dh = (1+z)*da/dh, s = sqrt(|Ok|)
+  // Ok=0 : V(z)/dh^3 = (4*Pi/3) * x^3
+  // Ok>0 : V(z)/dh^3 = (4*Pi/(2*Ok)) * (x*sqrt(1+Ok*x^2) - 1/s * asinh(s*x))
+  // Ok<0 : V(z)/dh^3 = (4*Pi/(2*Ok)) * (x*sqrt(1+Ok*x^2) - 1/s * asin(s*x) )
+  // --- on pose y = s*x  (y>0)
+  // Ok>0 : V(z)/dh^3 = (4*Pi/(2*Ok*s)) * (y*sqrt(1+y^2) - asinh(y))
+  // Ok<0 : V(z)/dh^3 = (4*Pi/(2*Ok*s)) * (y*sqrt(1-y^2) - asin(y) )
+  // --- a petit "z" on a pour "y -> 0+" en faisant le DL
+  // Ok>0 : V(z)/dh^3 =  4*Pi*y^3 / (3*Ok*s) * (1 - 3*y^2/10) + O(y^7)
+  // Ok<0 : V(z)/dh^3 = -4*Pi*y^3 / (3*Ok*s) * (1 + 3*y^2/10) + O(y^7)
+  //                          (remarque: Ok^(3/2) = s*Ok)
+{
+  double v,x = Dtrcom(z)/_Dhubble;
+
+  if(_flat) {
+    v = 4.*M_PI/3. * x*x*x;
+  } else if(_Ocurv0>0.) {
+    double s = sqrt(_Ocurv0), y = s*x, y2 = y*y;
+    if(y<1e-6) {
+      v = 1. - 3.*y2/10.;
+      v *= 4.*M_PI*y*y2 / (3.*_Ocurv0*s);
+    } else {
+      v = y*sqrt(1.+y2) - asinh(y);
+      v *= 4.*M_PI/(2.*_Ocurv0*s);
+    }
+  } else if (_Ocurv0<0.) {
+    double s = sqrt(-_Ocurv0), y = s*x, y2 = y*y;
+    if(y<1e-6) {
+      v = 1. + 3.*y2/10.;
+      v *= -4.*M_PI*y*y2 / (3.*_Ocurv0*s);
+    } else {
+      v = y*sqrt(1.-y2) - asin(y);
+      v *= 4.*M_PI/(2.*_Ocurv0*s);
+    }
+  } else {
+    v = 4.*M_PI/3. * x*x*x;
+  }
+
+  return v * _Dhubble*_Dhubble*_Dhubble;
+}
+
+double CosmoCalc::Vol4Pi(double z1,double z2)  /* Mpc^3 pour 4Pi sr entre [z1,z2] */
+{
+  return Vol4Pi(z2) - Vol4Pi(z1);
+}
+
+double CosmoCalc::E2(double z) const
+{
+  z += 1.;
+  double oldum = _Olambda0;
+
+  if(oldum>0. && _W0!=-1.) oldum *= pow(z,3.*(1.+_W0));
+
+  return oldum + z*z*(_Ocurv0 + z*(_Omatter0+z*_Orelat0));
+}
+
+//----------------------------------------------------------
+double CosmoCalc::NInteg(double z)
+{
+  if(z<0.) {
+    cout<<"CosmoCalc::NInteg: Error bad z value  z="<<z<<endl;
+    throw ParmError("CosmoCalc::NInteg: Error bad z value");
+  }
+
+  // On utilise le spline
+  if(_usespline) {
+    if( (!_computespl) && (z==_zold) ) return _integval;
+    if(z>_zmax) {_zmax = z+_dzmax; _computespl = true;}
+    if(_computespl) Init_Spline();
+    _integval = _spline->CSplineInt(z);
+    _zold = z;
+    return _integval;
+  }
+
+  // On calcule l'integrale
+  if(z != _zold) {
+    _integval = IntegrateFunc(*this,0.,z,_dperc,_dzinc,_dzmax,_glorder);
+    _zold = z;
+  }
+  return _integval;
+
+}
+
+int_4 CosmoCalc::Init_Spline(void)
+{
+  if(_spline!=NULL)
+    {delete _spline; delete [] _xspl; delete [] _yspl;}
+
+  //-- Look for intervalles and integrate
+  vector<double> x,y;
+  x.push_back(0.); y.push_back(0.);
+  double zbas=0., fbas = Integrand(zbas);
+  for(double z=_dzinc;;z+=_dzinc) {
+    double f = Integrand(z);
+    //cout<<fbas<<","<<f<<"  :  "<<fabs(f-fbas)<<" >? "<<_dperc*fabs(fbas)<<endl;
+    if( z>_zmax || z-zbas>_dzmax || fabs(f-fbas)>_dperc*fabs(fbas) ) {
+      double sum=0.,  dz=z-zbas;
+      for(unsigned short i=0;i<_glorder;i++) sum += _wgausl[i]*Integrand(zbas+_xgausl[i]*dz);
+      x.push_back(z); y.push_back(sum*dz);
+      //cout<<"...set... "<<zbas<<","<<z<<"  ,  "<<fbas<<","<<f<<endl;
+      zbas = z;  fbas = f;
+      if( z>_zmax ) break;
+    }
+  }
+
+  //-- Protection car il faut au moins 4 points pour un spline cubique
+  if(x.size()<4) {
+    x.resize(0); y.resize(0);
+    x.push_back(0.); y.push_back(0.);
+    for(int i=1;i<4;i++) {
+      x.push_back(i*_zmax/3.);
+      double sum=0., dz=x[i]-x[i-1];
+      for(unsigned short i=0;i<_glorder;i++) sum += _wgausl[i]*Integrand(x[i-1]+_xgausl[i]*dz);
+      y.push_back(sum*dz);
+    }
+  }
+
+  //-- Fill spline
+  _nspl = x.size();
+  _xspl = new double[_nspl];
+  _yspl = new double[_nspl];
+  for(int i=0;i<_nspl;i++) {
+    _xspl[i] = x[i];
+    _yspl[i] = y[i];
+    if(i!=0) _yspl[i] += _yspl[i-1];
+  }
+
+#if 1
+  cout<<"CosmoCalc::Init_Spline called: (zmax="<<_zmax<<") _nspl="<<_nspl<<endl;
+  int n = (_nspl>5)? 5: _nspl;
+  cout<<_nspl<<"...";
+  for(int i=0;i<n;i++) cout<<_xspl[i]<<" ("<<_yspl[i]<<") ";
+  cout<<"\n... ";
+  n = (_nspl<5)? 0: _nspl-5;
+  for(int i=n;i<_nspl;i++) cout<<_xspl[i]<<" ("<<_yspl[i]<<") ";
+  cout<<endl;
+#endif
+
+  double yp1 = Integrand(_xspl[0]);
+  double ypn = Integrand(_xspl[_nspl-1]);
+  _spline = new CSpline(_nspl,_xspl,_yspl,yp1,ypn,CSpline::NoNatural,false);
+  _spline->ComputeCSpline();
+  _computespl = false;
+
+  return _nspl;
+}
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/cosmocalc.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/cosmocalc.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/cosmocalc.h	(revision 3382)
@@ -0,0 +1,100 @@
+#ifndef COSMOCALC_SEEN
+#define COSMOCALC_SEEN
+
+#include "machdefs.h"
+#include <vector>
+
+#include "genericfunc.h"
+
+namespace SOPHYA {
+
+  class CSpline;
+
+//-----------------------------------------------------------------------------------
+class CosmoCalc : public GenericFunc {
+public:
+  CosmoCalc(unsigned short flat=0,bool usespline=false,double zmax=0.);
+  CosmoCalc(CosmoCalc& univ);
+  virtual ~CosmoCalc(void);
+
+  unsigned short Flat(void) { return _flat;}
+
+  double ZMax(void) { return _zmax;}
+  void SetInteg(double dperc=-1.,double dzinc=-1.,double dzmax=-1.,unsigned short order=4);
+  void PrtInteg(void);
+
+  void SetDynParam(double h100,double om0,double or0,double ol0,double w0=-1.);
+  void SetObaryon0(double v);
+  void DefaultParam(void);
+
+  inline double h100(void) {return _h100;}
+  inline double H0(void) {return _H0;}
+  inline double Dhubble(void) {return _Dhubble;}
+  inline double Olambda0(void) {return _Olambda0;}
+  inline double W0(void) {return _W0;}
+  inline double Omatter0(void) {return _Omatter0;}
+  inline double Obaryon0(void) {return _Obaryon0;}
+  inline double Orelat0(void) {return _Orelat0;}
+  inline double Ocurv0(void) {return _Ocurv0;}
+  inline double Otot0(void) {return _Otot0;}
+  double Rhoc(double z);
+
+  inline double H(double z) {return _H0 * E(z);}
+  double Olambda(double z);
+  double Omatter(double z);
+  double Obaryon(double z);
+  double Orelat(double z);
+  double Ocurv(double z);
+  double Otot(double z);
+
+  double Dtrcom(double z);
+  double Dloscom(double z);
+  double Dang(double z);
+  double Dlum(double z);
+
+  double dVol(double z);
+  double Vol4Pi(double z);
+  double Vol4Pi(double z1,double z2);
+
+  void Print(double z=0.);
+
+  double E2(double z) const;
+  inline double E(double z) const {return sqrt(E2(z));}
+
+  double NInteg(double z);
+  inline double Integrand(double z) const {return 1./E(z);}
+
+  virtual double operator() (double z) {return Integrand(z);}
+protected:
+  int_4 Init_Spline(void);
+  void Clone(CosmoCalc& univ);
+
+  // La cosmology
+  unsigned short _flat;
+  double _h100, _H0;  /* km/s/Mpc */
+  double _Olambda0,_W0;
+  double _Omatter0,_Obaryon0;
+  double _Orelat0;
+  double _Otot0,_Ocurv0;
+  double _Dhubble;  /* Mpc */
+
+  // Parametres d'integration
+  double _dperc,_dzinc,_dzmax;
+  unsigned short _glorder;
+  vector<double> _xgausl, _wgausl;
+
+  // Pour le calcul direct
+  double _zold,_integval;
+
+  // Pour les splines
+  bool _usespline,_computespl;
+  double _zmax;
+  CSpline * _spline;
+  int_4 _nspl;
+  double *_xspl, *_yspl;
+
+};
+
+} // Fin du namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/genefluct3d.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/genefluct3d.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/genefluct3d.cc	(revision 3382)
@@ -0,0 +1,1516 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "tarray.h"
+#include "pexceptions.h"
+#include "perandom.h"
+#include "srandgen.h"
+
+#include "fabtcolread.h"
+#include "fabtwriter.h"
+#include "fioarr.h"
+
+#include "arrctcast.h"
+
+#include "constcosmo.h"
+#include "geneutils.h"
+#include "schechter.h"
+
+#include "genefluct3d.h"
+
+#define WITH_FFTW_THREAD
+
+#define MODULE2(_x_) ((double)((_x_).real()*(_x_).real() + (_x_).imag()*(_x_).imag()))
+
+namespace SOPHYA {
+
+//-------------------------------------------------------
+GeneFluct3D::GeneFluct3D(long nx,long ny,long nz,double dx,double dy,double dz
+                        ,unsigned short nthread,int lp)
+{
+ init_default();
+
+ lp_ = lp;
+ nthread_ = nthread;
+
+ setsize(nx,ny,nz,dx,dy,dz);
+ setalloc();
+ setpointers(false);
+ init_fftw();
+}
+
+GeneFluct3D::GeneFluct3D(unsigned short nthread)
+{
+ init_default();
+ setsize(2,2,2,1.,1.,1.);
+ nthread_ = nthread;
+ setalloc();
+ setpointers(false);
+ init_fftw();
+}
+
+GeneFluct3D::~GeneFluct3D(void)
+{
+ delete_fftw();
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::init_default(void)
+{
+ Nx_ = Ny_ = Nz_ = 0;
+ is_set_fftw_plan = false;
+ nthread_ = 0;
+ lp_ = 0;
+ array_allocated_ = false;
+ cosmo_ = NULL;
+ growth_ = NULL;
+ redsh_ref_ = -999.;
+ kredsh_ref_ = 0.;
+ dred_ref_ = -999.;
+ loscom_ref_ = -999.;
+ dtrc_ref_ = dlum_ref_ = dang_ref_ = -999.;
+ nu_ref_ = dnu_ref_ = -999.;
+ loscom_min_ = loscom_max_ = -999.;
+ loscom2zred_min_ = loscom2zred_max_ = 0.;
+ xobs_[0] = xobs_[1] = xobs_[2] = 0.;
+ zred_.resize(0);
+ loscom_.resize(0);
+ loscom2zred_.resize(0);
+}
+
+void GeneFluct3D::setsize(long nx,long ny,long nz,double dx,double dy,double dz)
+{
+ if(lp_>1) cout<<"--- GeneFluct3D::setsize: N="<<nx<<","<<ny<<","<<nz
+                <<" D="<<dx<<","<<dy<<","<<dz<<endl;
+ if(nx<=0 || dx<=0.) {
+   char *bla = "GeneFluct3D::setsize_Error: bad value(s) for nn/dx";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+
+ // Les tailles des tableaux
+ Nx_ = nx;
+ Ny_ = ny;  if(Ny_ <= 0) Ny_ = Nx_;
+ Nz_ = nz;  if(Nz_ <= 0) Nz_ = Nx_;
+ N_.resize(0); N_.push_back(Nx_); N_.push_back(Ny_); N_.push_back(Nz_);
+ NRtot_ = Nx_*Ny_*Nz_; // nombre de pixels dans le survey
+ NCz_ =  Nz_/2 +1;
+ NTz_ = 2*NCz_;
+
+ // le pas dans l'espace (Mpc)
+ Dx_ = dx;
+ Dy_ = dy; if(Dy_ <= 0.) Dy_ = Dx_;
+ Dz_ = dz; if(Dz_ <= 0.) Dz_ = Dx_;
+ D_.resize(0); D_.push_back(Dx_); D_.push_back(Dy_); D_.push_back(Dz_);
+ dVol_ = Dx_*Dy_*Dz_;
+ Vol_ = (Nx_*Dx_)*(Ny_*Dy_)*(Nz_*Dz_);
+
+ // Le pas dans l'espace de Fourier (Mpc^-1)
+ Dkx_ = 2.*M_PI/(Nx_*Dx_);
+ Dky_ = 2.*M_PI/(Ny_*Dy_);
+ Dkz_ = 2.*M_PI/(Nz_*Dz_);
+ Dk_.resize(0); Dk_.push_back(Dkx_); Dk_.push_back(Dky_); Dk_.push_back(Dkz_);
+ Dk3_ = Dkx_*Dky_*Dkz_;
+ 
+ // La frequence de Nyquist en k (Mpc^-1)
+ Knyqx_ = M_PI/Dx_;
+ Knyqy_ = M_PI/Dy_;
+ Knyqz_ = M_PI/Dz_;
+ Knyq_.resize(0); Knyq_.push_back(Knyqx_); Knyq_.push_back(Knyqy_); Knyq_.push_back(Knyqz_);
+}
+
+void GeneFluct3D::setalloc(void)
+{
+ if(lp_>1) cout<<"--- GeneFluct3D::setalloc ---"<<endl;
+ // Dimensionnement du tableau complex<r_8>
+ // ATTENTION: TArray adresse en memoire a l'envers du C
+ //            Tarray(n1,n2,n3) == Carray[n3][n2][n1]
+ sa_size_t SzK_[3] = {NCz_,Ny_,Nx_}; // a l'envers
+ try {
+   T_.ReSize(3,SzK_);
+   array_allocated_ = true;
+   if(lp_>1) cout<<"  allocating: "<<T_.Size()*sizeof(complex<r_8>)/1.e6<<" Mo"<<endl;
+ } catch (...) {
+   cout<<"GeneFluct3D::setalloc_Error: Problem allocating T_"<<endl;
+ }
+ T_.SetMemoryMapping(BaseArray::CMemoryMapping);
+}
+
+void GeneFluct3D::setpointers(bool from_real)
+{
+ if(lp_>1) cout<<"--- GeneFluct3D::setpointers ---"<<endl;
+ if(from_real) T_ = ArrCastR2C(R_);
+   else        R_ = ArrCastC2R(T_);
+ // On remplit les pointeurs
+ fdata_ = (fftw_complex *) (&T_(0,0,0));
+ data_ = (double *) (&R_(0,0,0));
+}
+
+void GeneFluct3D::init_fftw(void)
+{
+ if( is_set_fftw_plan ) delete_fftw();
+
+ // --- Initialisation de fftw3 (attention data est sur-ecrit a l'init)
+ if(lp_>1) cout<<"--- GeneFluct3D::init_fftw ---"<<endl;
+#ifdef WITH_FFTW_THREAD
+ if(nthread_>0) {
+   cout<<"...Computing with "<<nthread_<<" threads"<<endl;
+   fftw_init_threads();
+   fftw_plan_with_nthreads(nthread_);
+ }
+#endif
+ if(lp_>1) cout<<"...forward plan"<<endl;
+ pf_ = fftw_plan_dft_r2c_3d(Nx_,Ny_,Nz_,data_,fdata_,FFTW_ESTIMATE);
+ if(lp_>1) cout<<"...backward plan"<<endl;
+ pb_ = fftw_plan_dft_c2r_3d(Nx_,Ny_,Nz_,fdata_,data_,FFTW_ESTIMATE);
+ is_set_fftw_plan = true;
+}
+
+void GeneFluct3D::delete_fftw(void)
+{
+ if( !is_set_fftw_plan ) return;
+ fftw_destroy_plan(pf_);
+ fftw_destroy_plan(pb_);
+#ifdef WITH_FFTW_THREAD
+ if(nthread_>0) fftw_cleanup_threads();
+#endif
+ is_set_fftw_plan = false;
+}
+
+void GeneFluct3D::check_array_alloc(void)
+// Pour tester si le tableau T_ est alloue
+{
+ if(array_allocated_) return;
+ char bla[90];
+ sprintf(bla,"GeneFluct3D::check_array_alloc_Error: array is not allocated");
+ cout<<bla<<endl; throw ParmError(bla);
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::SetObservator(double redshref,double kredshref)
+// L'observateur est au redshift z=0
+//               est situe sur la "perpendiculaire" a la face x,y
+//                         issue du centre de cette face
+// Il faut positionner le cube sur l'axe des z cad des redshifts:
+//     redshref  = redshift de reference
+//                 Si redshref<0 alors redshref=0
+//     kredshref = indice (en double) correspondant a ce redshift
+//                 Si kredshref<0 alors kredshref=nz/2 (milieu du cube)
+// Exemple: redshref=1.5 kredshref=250.75
+//    -> Le pixel i=nx/2 j=ny/2 k=250.75 est au redshift 1.5
+{
+ if(redshref<0.) redshref = 0.;
+ if(kredshref<0.) {
+   if(Nz_<=0) {
+     char *bla = "GeneFluct3D::SetObservator_Error: for kredsh_ref<0 define cube geometry first";
+     cout<<bla<<endl; throw ParmError(bla);
+   }
+   kredshref = Nz_/2.;
+ }
+ redsh_ref_  = redshref;
+ kredsh_ref_ = kredshref;
+ if(lp_>0)
+   cout<<"--- GeneFluct3D::SetObservator zref="<<redsh_ref_<<" kref="<<kredsh_ref_<<endl;
+}
+
+void GeneFluct3D::SetCosmology(CosmoCalc& cosmo)
+{
+ cosmo_ = &cosmo;
+ if(lp_>1) cosmo_->Print();
+}
+
+void GeneFluct3D::SetGrowthFactor(GrowthFactor& growth)
+{
+ growth_ = &growth;
+}
+
+long GeneFluct3D::LosComRedshift(double zinc,long npoints)
+// Given a position of the cube relative to the observer
+// and a cosmology
+// (SetObservator() and SetCosmology() should have been called !)
+// This routine filled:
+//   the vector "zred_" of scanned redshift (by zinc increments)
+//   the vector "loscom_" of corresponding los comoving distance
+// -- Input:
+// zinc : redshift increment for computation
+// npoints : number of points required for inverting loscom -> zred
+// 
+{
+ if(lp_>0) cout<<"--- LosComRedshift: zinc="<<zinc<<" , npoints="<<npoints<<endl;
+
+ if(cosmo_ == NULL || redsh_ref_<0.) {
+   char *bla = "GeneFluct3D::LosComRedshift_Error: set Observator and Cosmology first";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+
+ // La distance angulaire/luminosite/Dnu au pixel de reference
+ dred_ref_ = Dz_/(cosmo_->Dhubble()/cosmo_->E(redsh_ref_));
+ loscom_ref_ = cosmo_->Dloscom(redsh_ref_);
+ dtrc_ref_ = cosmo_->Dtrcom(redsh_ref_);
+ dlum_ref_ = cosmo_->Dlum(redsh_ref_);
+ dang_ref_ = cosmo_->Dang(redsh_ref_);
+ nu_ref_   = Fr_HyperFin_Par/(1.+redsh_ref_); // GHz
+ dnu_ref_  = Fr_HyperFin_Par *dred_ref_/pow(1.+redsh_ref_,2.); // GHz
+ if(lp_>0) {
+   cout<<"...reference pixel redshref="<<redsh_ref_
+       <<", dredref="<<dred_ref_
+       <<", nuref="<<nu_ref_ <<" GHz"
+       <<", dnuref="<<dnu_ref_ <<" GHz"<<endl
+       <<"   dlosc="<<loscom_ref_<<" Mpc com"
+       <<", dtrc="<<dtrc_ref_<<" Mpc com"
+       <<", dlum="<<dlum_ref_<<" Mpc"
+       <<", dang="<<dang_ref_<<" Mpc"<<endl;
+ }
+
+ // On calcule les coordonnees de l'observateur dans le repere du cube
+ // cad dans le repere ou l'origine est au centre du pixel i=j=l=0.
+ // L'observateur est sur un axe centre sur le milieu de la face Oxy
+ xobs_[0] = Nx_/2.*Dx_;
+ xobs_[1] = Ny_/2.*Dy_;
+ xobs_[2] = kredsh_ref_*Dz_ - loscom_ref_;
+
+ // L'observateur est-il dans le cube?
+ bool obs_in_cube = false;
+ if(xobs_[2]>=0. && xobs_[2]<=Nz_*Dz_) obs_in_cube = true;
+
+ // Find MINIMUM los com distance to the observer:
+ // c'est le centre de la face a k=0
+ // (ou zero si l'observateur est dans le cube)
+ loscom_min_ = 0.;
+ if(!obs_in_cube) loscom_min_ = -xobs_[2];
+
+ // TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED
+ if(loscom_min_<=1.e-50)
+   for(int i=0;i<50;i++)
+     cout<<"ATTENTION TOUTES LES PARTIES DU CODE NE MARCHENT PAS POUR UN OBSERVATEUR DANS LE CUBE"<<endl;
+ // TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED
+
+
+ // Find MAXIMUM los com distance to the observer:
+ // ou que soit positionne l'observateur, la distance
+ // maximal est sur un des coins du cube
+ loscom_max_ = 0.;
+ for(long i=0;i<=1;i++) {
+   double dx2 = DXcom(i*(Nx_-1)); dx2 *= dx2;
+   for(long j=0;j<=1;j++) {
+     double dy2 = DYcom(j*(Ny_-1)); dy2 *= dy2;
+     for(long k=0;k<=1;k++) {
+       double dz2 = DZcom(k*(Nz_-1)); dz2 *= dz2;
+       dz2 = sqrt(dx2+dy2+dz2);
+       if(dz2>loscom_max_) loscom_max_ = dz2;
+     }
+   }
+ }
+ if(lp_>0) {
+   cout<<"...zref="<<redsh_ref_<<" kzref="<<kredsh_ref_<<" losref="<<loscom_ref_<<" Mpc\n"
+       <<"   xobs="<<xobs_[0]<<" , "<<xobs_[1]<<" , "<<xobs_[2]<<" Mpc "
+       <<" in_cube="<<obs_in_cube
+       <<" loscom_min="<<loscom_min_<<" loscom_max="<<loscom_max_<<" Mpc (com)"<<endl;
+ }
+
+ // Fill the corresponding vectors for loscom and zred
+ // Be shure to have one dlc <loscom_min and one >loscom_max
+ if(zinc<=0.) zinc = 0.01;
+ for(double z=0.; ; z+=zinc) {
+   double dlc = cosmo_->Dloscom(z);
+   if(dlc<loscom_min_) {zred_.resize(0); loscom_.resize(0);}
+   zred_.push_back(z);
+   loscom_.push_back(dlc);
+   z += zinc;
+   if(dlc>loscom_max_) break; // on sort apres avoir stoque un dlc>dlcmax
+ }
+
+ if(lp_>0) {
+   long n = zred_.size();
+   cout<<"...zred/loscom tables[zinc="<<zinc<<"]: n="<<n;
+   if(n>0) cout<<" z="<<zred_[0]<<" -> d="<<loscom_[0];
+   if(n>1) cout<<" , z="<<zred_[n-1]<<" -> d="<<loscom_[n-1];
+   cout<<endl;
+ }
+
+ // Compute the parameters and tables needed for inversion loscom->zred
+ if(npoints<3) npoints = zred_.size();
+ InverseFunc invfun(zred_,loscom_);
+ invfun.ComputeParab(npoints,loscom2zred_);
+ loscom2zred_min_ = invfun.YMin();
+ loscom2zred_max_ = invfun.YMax();
+
+ if(lp_>0) {
+   long n = loscom2zred_.size();
+   cout<<"...loscom -> zred[npoints="<<npoints<<"]: n="<<n
+       <<" los_min="<<loscom2zred_min_
+       <<" los_max="<<loscom2zred_max_
+       <<" -> zred=[";
+   if(n>0) cout<<loscom2zred_[0];
+   cout<<",";
+   if(n>1) cout<<loscom2zred_[n-1];
+   cout<<"]"<<endl;
+   if(lp_>1 && n>0)
+     for(int i=0;i<n;i++)
+       if(i<2 || abs(i-n/2)<2 || i>=n-2)
+         cout<<"    i="<<i
+             <<"  d="<<loscom2zred_min_+i*(loscom2zred_max_-loscom2zred_min_)/(n-1.)
+             <<" Mpc   z="<<loscom2zred_[i]<<endl;
+ }
+
+ return zred_.size();
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::WriteFits(string cfname,int bitpix)
+{
+ cout<<"--- GeneFluct3D::WriteFits: Writing Cube to "<<cfname<<endl;
+ try {
+   FitsImg3DWriter fwrt(cfname.c_str(),bitpix,5);
+   fwrt.WriteKey("NX",Nx_," axe transverse 1");
+   fwrt.WriteKey("NY",Ny_," axe transverse 2");
+   fwrt.WriteKey("NZ",Nz_," axe longitudinal (redshift)");
+   fwrt.WriteKey("DX",Dx_," Mpc");
+   fwrt.WriteKey("DY",Dy_," Mpc");
+   fwrt.WriteKey("DZ",Dz_," Mpc");
+   fwrt.WriteKey("DKX",Dkx_," Mpc^-1");
+   fwrt.WriteKey("DKY",Dky_," Mpc^-1");
+   fwrt.WriteKey("DKZ",Dkz_," Mpc^-1");
+   fwrt.WriteKey("ZREF",redsh_ref_," reference redshift");
+   fwrt.WriteKey("KZREF",kredsh_ref_," reference redshift on z axe");
+   fwrt.Write(R_);
+ } catch (PThrowable & exc) {
+   cout<<"Exception : "<<(string)typeid(exc).name()
+       <<" - Msg= "<<exc.Msg()<<endl;
+   return;
+ } catch (...) {
+   cout<<" some other exception was caught !"<<endl;
+   return;
+ }
+}
+
+void GeneFluct3D::ReadFits(string cfname)
+{
+ cout<<"--- GeneFluct3D::ReadFits: Reading Cube from "<<cfname<<endl;
+ try {
+   FitsImg3DRead fimg(cfname.c_str(),0,5);
+   fimg.Read(R_);
+   long nx = fimg.ReadKeyL("NX");
+   long ny = fimg.ReadKeyL("NY");
+   long nz = fimg.ReadKeyL("NZ");
+   double dx = fimg.ReadKey("DX");
+   double dy = fimg.ReadKey("DY");
+   double dz = fimg.ReadKey("DZ");
+   double zref = fimg.ReadKey("ZREF");
+   double kzref = fimg.ReadKey("KZREF");
+   setsize(nx,ny,nz,dx,dy,dz);
+   setpointers(true);
+   init_fftw();
+   SetObservator(zref,kzref);
+   array_allocated_ = true;
+ } catch (PThrowable & exc) {
+   cout<<"Exception : "<<(string)typeid(exc).name()
+       <<" - Msg= "<<exc.Msg()<<endl;
+   return;
+ } catch (...) {
+   cout<<" some other exception was caught !"<<endl;
+   return;
+ }
+}
+
+void GeneFluct3D::WritePPF(string cfname,bool write_real)
+// On ecrit soit le TArray<r_8> ou le TArray<complex <r_8> >
+{
+ cout<<"--- GeneFluct3D::WritePPF: Writing Cube (real="<<write_real<<") to "<<cfname<<endl;
+ try {
+   R_.Info()["NX"] = (int_8)Nx_;
+   R_.Info()["NY"] = (int_8)Ny_;
+   R_.Info()["NZ"] = (int_8)Nz_;
+   R_.Info()["DX"] = (r_8)Dx_;
+   R_.Info()["DY"] = (r_8)Dy_;
+   R_.Info()["DZ"] = (r_8)Dz_;
+   R_.Info()["ZREF"] = (r_8)redsh_ref_;
+   R_.Info()["KZREF"] = (r_8)kredsh_ref_;
+   POutPersist pos(cfname.c_str());
+   if(write_real) pos << PPFNameTag("rgen")  << R_;
+     else         pos << PPFNameTag("pkgen") << T_;
+ } catch (PThrowable & exc) {
+   cout<<"Exception : "<<(string)typeid(exc).name()
+       <<" - Msg= "<<exc.Msg()<<endl;
+   return;
+ } catch (...) {
+   cout<<" some other exception was caught !"<<endl;
+   return;
+ }
+}
+
+void GeneFluct3D::ReadPPF(string cfname)
+{
+ cout<<"--- GeneFluct3D::ReadPPF: Reading Cube from "<<cfname<<endl;
+ try {
+   bool from_real = true;
+   PInPersist pis(cfname.c_str());
+   string name_tag_k = "pkgen";
+   bool found_tag_k = pis.GotoNameTag("pkgen");
+   if(found_tag_k) {
+     cout<<"           ...reading spectrum into TArray<complex <r_8> >"<<endl;
+     pis >> PPFNameTag("pkgen")  >> T_;
+     from_real = false;
+   } else {
+     cout<<"           ...reading space into TArray<r_8>"<<endl;
+     pis >> PPFNameTag("rgen")  >> R_;
+   }
+   setpointers(from_real);  // a mettre ici pour relire les DVInfo
+   int_8 nx = R_.Info()["NX"];
+   int_8 ny = R_.Info()["NY"];
+   int_8 nz = R_.Info()["NZ"];
+   r_8 dx = R_.Info()["DX"];
+   r_8 dy = R_.Info()["DY"];
+   r_8 dz = R_.Info()["DZ"];
+   r_8 zref = R_.Info()["ZREF"];
+   r_8 kzref = R_.Info()["KZREF"];
+   setsize(nx,ny,nz,dx,dy,dz);
+   init_fftw();
+   SetObservator(zref,kzref);
+   array_allocated_ = true;
+ } catch (PThrowable & exc) {
+   cout<<"Exception : "<<(string)typeid(exc).name()
+       <<" - Msg= "<<exc.Msg()<<endl;
+   return;
+ } catch (...) {
+   cout<<" some other exception was caught !"<<endl;
+   return;
+ }
+}
+
+void GeneFluct3D::WriteSlicePPF(string cfname)
+// On ecrit 3 tranches du cube selon chaque axe
+{
+ cout<<"--- GeneFluct3D::WriteSlicePPF: Writing Cube Slices "<<cfname<<endl;
+ try {
+
+   POutPersist pos(cfname.c_str());
+   TMatrix<r_4> S;
+   char str[16];
+   long i,j,l;
+
+   // Tranches en Z
+   for(int s=0;s<3;s++) {
+     S.ReSize(Nx_,Ny_);
+     if(s==0) l=0; else if(s==1) l=(Nz_+1)/2; else  l=Nz_-1;
+     sprintf(str,"z%ld",l);
+     for(i=0;i<Nx_;i++) for(j=0;j<Ny_;j++) S(i,j)=data_[IndexR(i,j,l)];
+     pos<<PPFNameTag(str)<<S; S.RenewObjId();
+   }
+
+   // Tranches en Y
+   for(int s=0;s<3;s++) {
+     S.ReSize(Nz_,Nx_);
+     if(s==0) j=0; else if(s==1) j=(Ny_+1)/2; else  j=Ny_-1;
+     sprintf(str,"y%ld",j);
+     for(i=0;i<Nx_;i++) for(l=0;l<Nz_;l++) S(l,i)=data_[IndexR(i,j,l)];
+     pos<<PPFNameTag(str)<<S; S.RenewObjId();
+   }
+
+   // Tranches en X
+   for(int s=0;s<3;s++) {
+     S.ReSize(Nz_,Ny_);
+     if(s==0) i=0; else if(s==1) i=(Nx_+1)/2; else  i=Nx_-1;
+     sprintf(str,"x%ld",i);
+     for(j=0;j<Ny_;j++) for(l=0;l<Nz_;l++) S(l,j)=data_[IndexR(i,j,l)];
+     pos<<PPFNameTag(str)<<S; S.RenewObjId();
+   }
+
+ } catch (PThrowable & exc) {
+   cout<<"Exception : "<<(string)typeid(exc).name()
+       <<" - Msg= "<<exc.Msg()<<endl;
+   return;
+ } catch (...) {
+   cout<<" some other exception was caught !"<<endl;
+   return;
+ }
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::Print(void)
+{
+ cout<<"GeneFluct3D(T_alloc="<<array_allocated_<<"):"<<endl;
+ cout<<"Space Size : nx="<<Nx_<<" ny="<<Ny_<<" nz="<<Nz_<<" ("<<NTz_<<")  size="
+     <<NRtot_<<endl;
+ cout<<"      Resol: dx="<<Dx_<<" dy="<<Dy_<<" dz="<<Dz_<<" Mpc"
+     <<", dVol="<<dVol_<<", Vol="<<Vol_<<" Mpc^3"<<endl;
+ cout<<"Fourier Size : nx="<<Nx_<<" ny="<<Ny_<<" nz="<<NCz_<<endl;
+ cout<<"        Resol: dkx="<<Dkx_<<" dky="<<Dky_<<" dkz="<<Dkz_<<" Mpc^-1"
+     <<", Dk3="<<Dk3_<<" Mpc^-3"<<endl;
+ cout<<"          (2Pi/k: "<<2.*M_PI/Dkx_<<" "<<2.*M_PI/Dky_<<" "<<2.*M_PI/Dkz_<<" Mpc)"<<endl;
+ cout<<"      Nyquist: kx="<<Knyqx_<<" ky="<<Knyqy_<<" kz="<<Knyqz_<<" Mpc^-1"
+     <<", Kmax="<<GetKmax()<<" Mpc^-1"<<endl;
+ cout<<"          (2Pi/k: "<<2.*M_PI/Knyqx_<<" "<<2.*M_PI/Knyqy_<<" "<<2.*M_PI/Knyqz_<<" Mpc)"<<endl;
+ cout<<"Redshift "<<redsh_ref_<<" for z axe at k="<<kredsh_ref_<<endl;
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::ComputeFourier0(GenericFunc& pk_at_z)
+// cf ComputeFourier() mais avec autre methode de realisation du spectre
+//    (attention on fait une fft pour realiser le spectre)
+{
+
+ // --- realisation d'un tableau de tirage gaussiens
+ if(lp_>0) cout<<"--- ComputeFourier0: before gaussian filling ---"<<endl;
+ // On tient compte du pb de normalisation de FFTW3
+ double sntot = sqrt((double)NRtot_);
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   data_[ip] = NorRand()/sntot;
+ }
+
+ // --- realisation d'un tableau de tirage gaussiens
+ if(lp_>0) cout<<"...before fft real ---"<<endl;
+ fftw_execute(pf_);
+
+ // --- On remplit avec une realisation
+ if(lp_>0) cout<<"...before Fourier realization filling"<<endl;
+ T_(0,0,0) = complex<r_8>(0.);  // on coupe le continue et on l'initialise
+ long lmod = Nx_/10; if(lmod<1) lmod=1;
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;  kx *= kx;
+   if(lp_>0 && i%lmod==0) cout<<"i="<<i<<" ii="<<ii<<endl;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;  ky *= ky;
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;  kz *= kz;
+       if(i==0 && j==0 && l==0) continue; // Suppression du continu
+       double k = sqrt(kx+ky+kz);
+       // cf normalisation: Peacock, Cosmology, formule 16.38 p504
+       double pk = pk_at_z(k)/Vol_;
+       // ici pas de "/2" a cause de la remarque ci-dessus
+       T_(l,j,i) *= sqrt(pk);
+     }
+   }
+ }
+
+ if(lp_>0) cout<<"...computing power"<<endl;
+ double p = compute_power_carte();
+ if(lp_>0) cout<<"Puissance dans la realisation: "<<p<<endl;
+
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::ComputeFourier(GenericFunc& pk_at_z)
+// Calcule une realisation du spectre "pk_at_z"
+// Attention: dans TArray le premier indice varie le + vite
+// Explication normalisation: see Coles & Lucchin, Cosmology, p264-265
+// FFTW3: on note N=Nx*Ny*Nz
+// f  --(FFT)-->  F = TF(f)  --(FFT^-1)-->  fb = TF^-1(F) = TF^-1(TF(f))
+// sum(f(x_i)^2) = S
+//                sum(F(nu_i)^2) = S*N
+//                                          sum(fb(x_i)^2) = S*N^2
+{
+ // --- RaZ du tableau
+ T_ = complex<r_8>(0.);
+
+ // --- On remplit avec une realisation
+ if(lp_>0) cout<<"--- ComputeFourier ---"<<endl;
+ long lmod = Nx_/10; if(lmod<1) lmod=1;
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;  kx *= kx;
+   if(lp_>0 && i%lmod==0) cout<<"i="<<i<<" ii="<<ii<<endl;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;  ky *= ky;
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;  kz *= kz;
+       if(i==0 && j==0 && l==0) continue; // Suppression du continu
+       double k = sqrt(kx+ky+kz);
+       // cf normalisation: Peacock, Cosmology, formule 16.38 p504
+       double pk = pk_at_z(k)/Vol_;
+       // Explication de la division par 2: voir perandom.cc
+       // ou egalement Coles & Lucchin, Cosmology formula 13.7.2 p279
+       T_(l,j,i) = ComplexGaussRan(sqrt(pk/2.));
+     }
+   }
+ }
+
+ manage_coefficients();   // gros effet pour les spectres que l'on utilise !
+
+ if(lp_>0) cout<<"...computing power"<<endl;
+ double p = compute_power_carte();
+ if(lp_>0) cout<<"Puissance dans la realisation: "<<p<<endl;
+
+}
+
+long GeneFluct3D::manage_coefficients(void)
+// Take into account the real and complexe conjugate coefficients
+// because we want a realization of a real data in real space
+{
+ if(lp_>1) cout<<"...managing coefficients"<<endl;
+ check_array_alloc();
+
+ // 1./ Le Continu et Nyquist sont reels
+ long nreal = 0;
+ for(long kk=0;kk<2;kk++) {
+   long k=0;  // continu
+   if(kk==1) {if(Nz_%2!=0) continue; else k = Nz_/2;}  // Nyquist
+   for(long jj=0;jj<2;jj++) {
+     long j=0;
+     if(jj==1) {if( Ny_%2!=0) continue; else j = Ny_/2;}
+     for(long ii=0;ii<2;ii++) {
+       long i=0;
+       if(ii==1) {if( Nx_%2!=0) continue; else i = Nx_/2;}
+       int_8 ip = IndexC(i,j,k);
+       //cout<<"i="<<i<<" j="<<j<<" k="<<k<<" = ("<<fdata_[ip][0]<<","<<fdata_[ip][1]<<")"<<endl;
+       fdata_[ip][1] = 0.; fdata_[ip][0] *= M_SQRT2;
+       nreal++;
+     }
+   }
+ }
+ if(lp_>1) cout<<"Number of forced real number ="<<nreal<<endl;
+
+ // 2./ Les elements complexe conjugues (tous dans le plan k=0,Nyquist)
+
+ // a./ les lignes et colonnes du continu et de nyquist
+ long nconj1 = 0;
+ for(long kk=0;kk<2;kk++) {
+   long k=0;  // continu
+   if(kk==1) {if(Nz_%2!=0) continue; else k = Nz_/2;}  // Nyquist
+   for(long jj=0;jj<2;jj++) { // selon j
+     long j=0;
+     if(jj==1) {if( Ny_%2!=0) continue; else j = Ny_/2;}
+     for(long i=1;i<(Nx_+1)/2;i++) {
+       int_8 ip = IndexC(i,j,k);
+       int_8 ip1 = IndexC(Nx_-i,j,k);
+       fdata_[ip1][0] = fdata_[ip][0]; fdata_[ip1][1] = -fdata_[ip][1];
+       nconj1++;
+     }
+   }
+   for(long ii=0;ii<2;ii++) {
+     long i=0;
+     if(ii==1) {if( Nx_%2!=0) continue; else i = Nx_/2;}
+     for(long j=1;j<(Ny_+1)/2;j++) {
+       int_8 ip = IndexC(i,j,k);
+       int_8 ip1 = IndexC(i,Ny_-j,k);
+       fdata_[ip1][0] = fdata_[ip][0]; fdata_[ip1][1] = -fdata_[ip][1];
+       nconj1++;
+     }
+   }
+ }
+ if(lp_>1) cout<<"Number of forced conjugate on cont+nyq ="<<nconj1<<endl;
+
+ // b./ les lignes et colonnes hors continu et de nyquist
+ long nconj2 = 0;
+ for(long kk=0;kk<2;kk++) {
+   long k=0;  // continu
+   if(kk==1) {if(Nz_%2!=0) continue; else k = Nz_/2;}  // Nyquist
+   for(long j=1;j<(Ny_+1)/2;j++) {
+     if(Ny_%2==0 && j==Ny_/2) continue; // on ne retraite pas nyquist en j
+     for(long i=1;i<Nx_;i++) {
+       if(Nx_%2==0 && i==Nx_/2) continue; // on ne retraite pas nyquist en i
+       int_8 ip = IndexC(i,j,k);
+       int_8 ip1 = IndexC(Nx_-i,Ny_-j,k);
+       fdata_[ip1][0] = fdata_[ip][0]; fdata_[ip1][1] = -fdata_[ip][1];
+       nconj2++;
+     }
+   }
+ }
+ if(lp_>1) cout<<"Number of forced conjugate hors cont+nyq ="<<nconj2<<endl;
+
+ if(lp_>1) cout<<"Check: ddl= "<<NRtot_<<" =?= "<<2*(Nx_*Ny_*NCz_-nconj1-nconj2)-8<<endl;
+
+ return nreal+nconj1+nconj2;
+}
+
+double GeneFluct3D::compute_power_carte(void)
+// Calcul la puissance de la realisation du spectre Pk
+{
+ check_array_alloc();
+
+ double s2 = 0.;
+ for(long l=0;l<NCz_;l++)
+   for(long j=0;j<Ny_;j++)
+     for(long i=0;i<Nx_;i++) s2 += MODULE2(T_(l,j,i));
+
+ double s20 = 0.;
+ for(long j=0;j<Ny_;j++)
+   for(long i=0;i<Nx_;i++) s20 += MODULE2(T_(0,j,i));
+
+ double s2n = 0.;
+ if(Nz_%2==0)
+   for(long j=0;j<Ny_;j++)
+     for(long i=0;i<Nx_;i++) s2n += MODULE2(T_(NCz_-1,j,i));
+
+ return 2.*s2 -s20 -s2n;
+}
+
+//-------------------------------------------------------------------
+void GeneFluct3D::FilterByPixel(void)
+// Filtrage par la fonction fenetre du pixel (parallelepipede)
+// TF = 1/(dx*dy*dz)*Int[{-dx/2,dx/2},{-dy/2,dy/2},{-dz/2,dz/2}]
+//                   e^(ik_x*x) e^(ik_y*y) e^(ik_z*z) dxdydz
+//    = 2/(k_x*dx) * sin(k_x*dx/2)  * (idem y) * (idem z)
+// Gestion divergence en 0: sin(y)/y = 1 - y^2/6*(1-y^2/20)
+//                          avec y = k_x*dx/2
+{
+ if(lp_>0) cout<<"--- FilterByPixel ---"<<endl;
+ check_array_alloc();
+
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_ *Dx_/2;
+   double pk_x = pixelfilter(kx);
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_ *Dy_/2;
+     double pk_y = pixelfilter(ky);
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_ *Dz_/2;
+       double pk_z =  pixelfilter(kz);
+       T_(l,j,i) *= pk_x*pk_y*pk_z;
+     }
+   }
+ }
+
+}
+
+//-------------------------------------------------------------------
+void GeneFluct3D::ApplyGrowthFactor(int type_evol)
+// Apply Growth to real space
+// Using the correspondance between redshift and los comoving distance
+// describe in vector "zred_" "loscom_"
+// type_evol = 1 : evolution de la puissance du bruit avec la distance a l'observateur
+//             2 : evolution de la puissance du bruit avec la distance du plan Z
+//             (tous les pixels d'un plan Z sont mis au meme redshift z que celui du milieu)
+{
+ if(lp_>0) cout<<"--- ApplyGrowthFactor: evol="<<type_evol<<endl;
+ check_array_alloc();
+
+ if(growth_ == NULL) {
+   char *bla = "GeneFluct3D::ApplyGrowthFactor_Error: set GrowthFactor first";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+ if(type_evol<1 || type_evol>2) {
+   char *bla = "GeneFluct3D::ApplyGrowthFactor_Error: bad type_evol value";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+
+ InterpFunc interpinv(loscom2zred_min_,loscom2zred_max_,loscom2zred_);
+ unsigned short ok;
+
+ //CHECK: Histo hgr(0.9*zred_[0],1.1*zred_[n-1],1000);
+ for(long i=0;i<Nx_;i++) {
+   double dx2 = DXcom(i); dx2 *= dx2;
+   for(long j=0;j<Ny_;j++) {
+     double dy2 = DYcom(j); dy2 *= dy2;
+     for(long l=0;l<Nz_;l++) {
+       double dz = DZcom(l);
+       if(type_evol==1) dz = sqrt(dx2+dy2+dz*dz);
+         else dz = fabs(dz); // tous les plans Z au meme redshift
+       double z = interpinv(dz);
+       //CHECK: hgr.Add(z);
+       double dzgr = (*growth_)(z);   // interpolation par morceau
+       //double dzgr = growth_->Linear(z,ok);  // interpolation lineaire
+       //double dzgr = growth_->Parab(z,ok);  // interpolation parabolique
+       int_8 ip = IndexR(i,j,l);
+       data_[ip] *= dzgr;
+     }
+   }
+ }
+
+ //CHECK: {POutPersist pos("applygrowth.ppf"); string tag="hgr"; pos.PutObject(hgr,tag);}
+
+}
+
+//-------------------------------------------------------------------
+void GeneFluct3D::ComputeReal(void)
+// Calcule une realisation dans l'espace reel
+{
+ if(lp_>0) cout<<"--- ComputeReal ---"<<endl;
+ check_array_alloc();
+
+ // On fait la FFT
+ fftw_execute(pb_);
+}
+
+//-------------------------------------------------------------------
+void GeneFluct3D::ReComputeFourier(void)
+{
+ if(lp_>0) cout<<"--- ReComputeFourier ---"<<endl;
+ check_array_alloc();
+
+ // On fait la FFT
+ fftw_execute(pf_);
+ // On corrige du pb de la normalisation de FFTW3
+ double v = (double)NRtot_;
+ for(long i=0;i<Nx_;i++)
+   for(long j=0;j<Ny_;j++)
+     for(long l=0;l<NCz_;l++) T_(l,j,i) /= complex<r_8>(v);
+
+}
+
+//-------------------------------------------------------------------
+int GeneFluct3D::ComputeSpectrum(HistoErr& herr)
+// Compute spectrum from "T" and fill HistoErr "herr"
+// T : dans le format standard de GeneFuct3D: T(nz,ny,nx)
+// cad T(kz,ky,kx) avec  0<kz<kz_nyq  -ky_nyq<ky<ky_nyq  -kx_nyq<kx<kx_nyq
+{
+ if(lp_>0) cout<<"--- ComputeSpectrum ---"<<endl;
+ check_array_alloc();
+
+ if(herr.NBins()<0) return -1;
+ herr.Zero();
+
+ // Attention a l'ordre
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;  kx *= kx;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;  ky *= ky;
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;
+       double k = sqrt(kx+ky+kz*kz);
+       double pk = MODULE2(T_(l,j,i));
+       herr.Add(k,pk);
+     }
+   }
+ }
+ herr.ToVariance();
+
+ // renormalize to directly compare to original spectrum
+ double norm = Vol_;
+ herr *= norm;
+
+ return 0;
+}
+
+int GeneFluct3D::ComputeSpectrum2D(Histo2DErr& herr)
+{
+ if(lp_>0) cout<<"--- ComputeSpectrum2D ---"<<endl;
+ check_array_alloc();
+
+ if(herr.NBinX()<0 || herr.NBinY()<0) return -1;
+ herr.Zero();
+
+ // Attention a l'ordre
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;  kx *= kx;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;  ky *= ky;
+     double kt = sqrt(kx+ky);
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;
+       double pk = MODULE2(T_(l,j,i));
+       herr.Add(kt,kz,pk);
+     }
+   }
+ }
+ herr.ToVariance();
+
+ // renormalize to directly compare to original spectrum
+ double norm = Vol_;
+ herr *= norm;
+
+ return 0;
+}
+
+//-------------------------------------------------------------------
+int GeneFluct3D::ComputeSpectrum(HistoErr& herr,double sigma,bool pixcor)
+// Compute spectrum from "T" and fill HistoErr "herr"
+// AVEC la soustraction du niveau de bruit et la correction par filterpixel()
+// Si on ne fait pas ca, alors on obtient un spectre non-isotrope!
+//
+// T : dans le format standard de GeneFuct3D: T(nz,ny,nx)
+// cad T(kz,ky,kx) avec  0<kz<kz_nyq  -ky_nyq<ky<ky_nyq  -kx_nyq<kx<kx_nyq
+{
+  if(lp_>0) cout<<"--- ComputeSpectrum: sigma="<<sigma<<endl;
+ check_array_alloc();
+
+ if(sigma<=0.) sigma = 0.;
+ double sigma2 = sigma*sigma / (double)NRtot_;
+
+ if(herr.NBins()<0) return -1;
+ herr.Zero();
+
+ TVector<r_8> vfz(NCz_);
+ if(pixcor)  // kz = l*Dkz_
+   for(long l=0;l<NCz_;l++) {vfz(l)=pixelfilter(l*Dkz_ *Dz_/2); vfz(l)*=vfz(l);}
+
+ // Attention a l'ordre
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;
+   double fx = (pixcor) ? pixelfilter(kx*Dx_/2): 1.;
+   kx *= kx; fx *= fx;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;
+     double fy = (pixcor) ? pixelfilter(ky*Dy_/2): 1.;
+     ky *= ky; fy *= fy;
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;
+       double k = sqrt(kx+ky+kz*kz);
+       double pk = MODULE2(T_(l,j,i)) - sigma2;
+       double fz = (pixcor) ? vfz(l): 1.;
+       double f = fx*fy*fz;
+       if(f>0.) herr.Add(k,pk/f);
+     }
+   }
+ }
+ herr.ToVariance();
+ for(int i=0;i<herr.NBins();i++) herr(i) += sigma2;
+
+ // renormalize to directly compare to original spectrum
+ double norm = Vol_;
+ herr *= norm;
+
+ return 0;
+}
+
+int GeneFluct3D::ComputeSpectrum2D(Histo2DErr& herr,double sigma,bool pixcor)
+// AVEC la soustraction du niveau de bruit et la correction par filterpixel()
+{
+ if(lp_>0) cout<<"--- ComputeSpectrum2D: sigma="<<sigma<<endl;
+ check_array_alloc();
+
+ if(sigma<=0.) sigma = 0.;
+ double sigma2 = sigma*sigma / (double)NRtot_;
+
+ if(herr.NBinX()<0 || herr.NBinY()<0) return -1;
+ herr.Zero();
+
+ TVector<r_8> vfz(NCz_);
+ if(pixcor)  // kz = l*Dkz_
+   for(long l=0;l<NCz_;l++) {vfz(l)=pixelfilter(l*Dkz_ *Dz_/2); vfz(l)*=vfz(l);}
+
+ // Attention a l'ordre
+ for(long i=0;i<Nx_;i++) {
+   long ii = (i>Nx_/2) ? Nx_-i : i;
+   double kx = ii*Dkx_;
+   double fx = (pixcor) ? pixelfilter(kx*Dx_/2) : 1.;
+   kx *= kx; fx *= fx;
+   for(long j=0;j<Ny_;j++) {
+     long jj = (j>Ny_/2) ? Ny_-j : j;
+     double ky = jj*Dky_;
+     double fy = (pixcor) ? pixelfilter(ky*Dy_/2) : 1.;
+     ky *= ky; fy *= fy;
+     double kt = sqrt(kx+ky);
+     for(long l=0;l<NCz_;l++) {
+       double kz = l*Dkz_;
+       double pk = MODULE2(T_(l,j,i)) - sigma2;
+       double fz = (pixcor) ? vfz(l): 1.;
+       double f = fx*fy*fz;
+       if(f>0.) herr.Add(kt,kz,pk/f);
+     }
+   }
+ }
+ herr.ToVariance();
+ for(int i=0;i<herr.NBinX();i++)
+    for(int j=0;j<herr.NBinY();j++) herr(i,j) += sigma2;
+
+ // renormalize to directly compare to original spectrum
+ double norm = Vol_;
+ herr *= norm;
+
+ return 0;
+}
+
+//-------------------------------------------------------
+int_8 GeneFluct3D::VarianceFrReal(double R,double& var)
+// Recompute MASS variance in spherical top-hat (rayon=R)
+// Par definition: SigmaR^2 = <(M-<M>)^2>/<M>^2
+//                 ou M = masse dans sphere de rayon R
+// --- ATTENTION: la variance calculee a une tres grande dispersion
+//  (surtout si le volume du cube est petit). Pour verifier
+//  que le sigmaR calcule par cette methode est en accord avec
+//  le sigmaR en input, il faut faire plusieurs simulations (~100)
+//  et regarder la moyenne des sigmaR reconstruits
+{
+  if(lp_>0) cout<<"--- VarianceFrReal R="<<R<<endl;
+ check_array_alloc();
+
+ long dnx = long(R/Dx_)+1; if(dnx<=0) dnx = 1;
+ long dny = long(R/Dy_)+1; if(dny<=0) dny = 1;
+ long dnz = long(R/Dz_)+1; if(dnz<=0) dnz = 1;
+ if(lp_>0) cout<<"dnx="<<dnx<<" dny="<<dny<<" dnz="<<dnz<<endl;
+
+ double sum=0., sum2=0., sn=0., r2 = R*R;
+ int_8 nsum=0;
+
+ for(long i=dnx;i<Nx_-dnx;i+=2*dnx) {
+   for(long j=dny;j<Ny_-dny;j+=2*dny) {
+     for(long l=dnz;l<Nz_-dnz;l+=2*dnz) {
+       double m=0.; int_8 n=0;
+       for(long ii=i-dnx;ii<=i+dnx;ii++) {
+         double x = (ii-i)*Dx_; x *= x;
+         for(long jj=j-dny;jj<=j+dny;jj++) {
+           double y = (jj-j)*Dy_; y *= y;
+           for(long ll=l-dnz;ll<=l+dnz;ll++) {
+             double z = (ll-l)*Dz_; z *= z;
+             if(x+y+z>r2) continue;
+             int_8 ip = IndexR(ii,jj,ll);
+             m += 1.+data_[ip];  // 1+drho/rho
+             n++;
+	   }
+	 }
+       }
+       if(n>0) {sum += m; sum2 += m*m; nsum++; sn += n;}
+       //cout<<i<<","<<j<<","<<l<<" n="<<n<<" m="<<m<<" sum="<<sum<<" sum2="<<sum2<<endl;
+     }
+   }
+ }
+
+ if(nsum<=1) {var=0.; return nsum;}
+ sum /= nsum;
+ sum2 = sum2/nsum - sum*sum;
+ sn /= nsum;
+ if(lp_>0) cout<<"...<n>="<<sn<<", nsum="<<nsum<<" <M>="<<sum<<" <(M-<M>)^2>="<<sum2<<endl;
+ var = sum2/(sum*sum);  // <dM^2>/<M>^2
+ if(lp_>0) cout<<"...sigmaR^2 = <(M-<M>)^2>/<M>^2 = "<<var
+               <<" -> sigmaR = "<<sqrt(var)<<endl;
+
+ return nsum;
+}
+
+//-------------------------------------------------------
+int_8 GeneFluct3D::NumberOfBad(double vmin,double vmax)
+// number of pixels outside of ]vmin,vmax[ extremites exclues
+//     ->  vmin and vmax are considered as bad
+{
+ check_array_alloc();
+
+ int_8 nbad = 0;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(v<=vmin || v>=vmax) nbad++;
+ }
+
+ if(lp_>0) cout<<"--- NumberOfBad "<<nbad<<" px out of ]"<<vmin<<","<<vmax
+               <<"[ i.e. frac="<<nbad/(double)NRtot_<<endl;
+ return nbad;
+}
+
+int_8 GeneFluct3D::MinMax(double& xmin,double& xmax,double vmin,double vmax)
+// Calcul des valeurs xmin et xmax dans le cube reel avec valeurs ]vmin,vmax[ extremites exclues
+{
+ bool tstval = (vmax>vmin)? true: false;
+ if(lp_>0) {
+   cout<<"--- MinMax";
+   if(tstval) cout<<"  range=]"<<vmin<<","<<vmax<<"[";
+   cout<<endl;
+ }
+ check_array_alloc();
+
+ int_8 n = 0;
+ xmin = xmax = data_[0];
+
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double x = data_[ip];
+   if(tstval && (x<=vmin || x>=vmax)) continue;
+   if(x<xmin) xmin = x;
+   if(x>xmax) xmax = x;
+   n++;
+ }
+
+ if(lp_>0) cout<<"  n="<<n<<" min="<<xmin<<" max="<<xmax<<endl;
+
+ return n;
+}
+
+int_8 GeneFluct3D::MeanSigma2(double& rm,double& rs2,double vmin,double vmax
+                             ,bool useout,double vout)
+// Calcul de mean,sigma2 dans le cube reel avec valeurs ]vmin,vmax[ extremites exclues
+// useout = false: ne pas utiliser les pixels hors limites pour calculer mean,sigma2
+//          true : utiliser les pixels hors limites pour calculer mean,sigma2
+//                 en remplacant leurs valeurs par "vout"
+{
+ bool tstval = (vmax>vmin)? true: false;
+ if(lp_>0) {
+   cout<<"--- MeanSigma2";
+   if(tstval) cout<<"  range=]"<<vmin<<","<<vmax<<"[";
+   if(useout) cout<<", useout="<<useout<<" vout="<<vout;
+   cout<<endl;
+ }
+ check_array_alloc();
+
+ int_8 n = 0;
+ rm = rs2 = 0.;
+
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(tstval) {
+     if(v<=vmin || v>=vmax) {if(useout) v=vout; else continue;}
+   }
+   rm += v;
+   rs2 += v*v;
+   n++;
+ }
+
+ if(n>1) {
+   rm /= (double)n;
+   rs2 = rs2/(double)n - rm*rm;
+ }
+
+ if(lp_>0) cout<<"  n="<<n<<" m="<<rm<<" s2="<<rs2<<" s="<<sqrt(fabs(rs2))<<endl;
+
+ return n;
+}
+
+int_8 GeneFluct3D::SetToVal(double vmin, double vmax,double val0)
+// set to "val0" if out of range ]vmin,vmax[ extremites exclues
+// cad set to "val0" if in [vmin,vmax] -> vmin and vmax are set to val0
+{
+ check_array_alloc();
+
+ int_8 nbad = 0;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(v<=vmin || v>=vmax) {data_[ip] = val0; nbad++;}
+ }
+
+ if(lp_>0) cout<<"--- SetToVal "<<nbad<<" px set to="<<val0
+               <<" because out of range=]"<<vmin<<","<<vmax<<"["<<endl;
+ return nbad;
+}
+
+void GeneFluct3D::ScaleOffset(double scalecube,double offsetcube)
+// Replace  "V"  by  "scalecube * ( V + offsetcube )"
+{
+ if(lp_>0) cout<<"--- ScaleCube scale="<<scalecube<<" offset="<<offsetcube<<endl;
+
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   data_[ip] = scalecube * ( data_[ip] + offsetcube );
+ }
+
+ return;
+}
+
+//-------------------------------------------------------
+void GeneFluct3D::TurnFluct2Mass(void)
+// d_rho/rho -> Mass  (add one!)
+{
+ if(lp_>0) cout<<"--- TurnFluct2Mass ---"<<endl;
+ check_array_alloc();
+
+
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   data_[ip] += 1.;
+ }
+}
+
+double GeneFluct3D::TurnFluct2MeanNumber(double val_by_mpc3)
+// ATTENTION: la gestion des pixels<0 proposee ici induit une perte de variance
+// sur la carte, le spectre Pk reconstruit sera plus faible!
+// L'effet sera d'autant plus grand que le nombre de pixels<0 sera grand.
+{
+ if(lp_>0) cout<<"--- TurnFluct2MeanNumber : "<<val_by_mpc3<<" quantity (gal or mass)/Mpc^3"<<endl;
+
+ // First convert dRho/Rho into 1+dRho/Rho
+ int_8  nball = 0; double sumall = 0., sumall2 = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   data_[ip] += 1.;
+   nball++; sumall += data_[ip]; sumall2 += data_[ip]*data_[ip];
+ }
+ if(nball>2) {
+   sumall /= (double)nball;
+   sumall2 = sumall2/(double)nball - sumall*sumall;
+   if(lp_>0) cout<<"1+dRho/Rho: mean="<<sumall<<" variance="<<sumall2
+                 <<" -> "<<sqrt(fabs(sumall2))<<endl;
+ }
+
+ // Find contribution for positive pixels
+ int_8  nbpos = 0; double sumpos = 0. , sumpos2 = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(data_[ip]>0.) {nbpos++; sumpos += v; sumpos2 += v*v;}
+ }
+ if(nbpos<1) {
+   cout<<"TurnFluct2MeanNumber_Error: nbpos<1"<<endl;
+   throw RangeCheckError("TurnFluct2MeanNumber_Error: nbpos<1");
+ }
+ sumpos2 = sumpos2/nball - sumpos*sumpos/(nball*nball);
+ if(lp_>0)
+   cout<<"1+dRho/Rho with v<0 set to zero: mean="<<sumpos/nball
+       <<" variance="<<sumpos2<<" -> "<<sqrt(fabs(sumpos2))<<endl;
+   cout<<"Sum of positive values: sumpos="<<sumpos
+       <<" (n(v>0) = "<<nbpos<<" frac(v>0)="<<nbpos/(double)NRtot_<<")"<<endl;
+
+ // - Mettre exactement val_by_mpc3*Vol galaxies (ou Msol) dans notre survey
+ // - Uniquement dans les pixels de masse >0.
+ // - Mise a zero des pixels <0
+ double dn = val_by_mpc3 * Vol_ / sumpos;
+ if(lp_>0) cout<<"...density move from "
+               <<val_by_mpc3*dVol_<<" to "<<dn<<" / pixel"<<endl;
+
+ double sum = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   if(data_[ip]<=0.) data_[ip] = 0.;
+   else {
+     data_[ip] *= dn;
+     sum += data_[ip];
+   }
+ }
+
+ if(lp_>0) cout<<"...quantity put into survey "<<sum<<" / "<<val_by_mpc3*Vol_<<endl;
+
+ return sum;
+}
+
+double GeneFluct3D::ApplyPoisson(void)
+// do NOT treate negative or nul mass  -> let it as it is
+{
+ if(lp_>0) cout<<"--- ApplyPoisson ---"<<endl;
+ check_array_alloc();
+
+ double sum = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(v>0.) {
+     unsigned long dn = PoissRandLimit(v,10.);
+     data_[ip] = (double)dn;
+     sum += (double)dn;
+   }
+ }
+ if(lp_>0) cout<<sum<<" galaxies put into survey"<<endl;
+
+ return sum;
+}
+
+double GeneFluct3D::TurnNGal2Mass(FunRan& massdist,bool axeslog)
+// do NOT treate negative or nul mass  -> let it as it is
+// INPUT:
+//   massdist : distribution de masse (m*dn/dm)
+//   axeslog = false : retourne la masse
+//           = true  : retourne le log10(mass)
+// RETURN la masse totale
+{
+ if(lp_>0) cout<<"--- TurnNGal2Mass ---"<<endl;
+ check_array_alloc();
+
+ double sum = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(v>0.) {
+     long ngal = long(v+0.1);
+     data_[ip] = 0.;
+     for(long i=0;i<ngal;i++) {
+       double m = massdist.RandomInterp();  // massdist.Random();
+       if(axeslog) m = pow(10.,m);
+       data_[ip] += m;
+     }
+     sum += data_[ip];
+   }
+ }
+ if(lp_>0) cout<<sum<<" MSol HI mass put into survey"<<endl;
+
+ return sum;
+}
+
+double GeneFluct3D::TurnNGal2MassQuick(SchechterMassDist& schmdist)
+// idem TurnNGal2Mass mais beaucoup plus rapide
+{
+ if(lp_>0) cout<<"--- TurnNGal2MassQuick ---"<<endl;
+ check_array_alloc();
+
+ double sum = 0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) for(long l=0;l<Nz_;l++) {
+   int_8 ip = IndexR(i,j,l);
+   double v = data_[ip];
+   if(v>0.) {
+     long ngal = long(v+0.1);
+     data_[ip] = schmdist.TirMass(ngal);
+     sum += data_[ip];
+   }
+ }
+ if(lp_>0) cout<<sum<<" MSol HI mass put into survey"<<endl;
+
+ return sum;
+}
+
+void GeneFluct3D::AddNoise2Real(double snoise,int type_evol)
+// add noise to every pixels (meme les <=0 !)
+// type_evol = 0 : pas d'evolution de la puissance du bruit
+//             1 : evolution de la puissance du bruit avec la distance a l'observateur
+//             2 : evolution de la puissance du bruit avec la distance du plan Z
+//                 (tous les plans Z sont mis au meme redshift z de leur milieu)
+{
+ if(lp_>0) cout<<"--- AddNoise2Real: snoise = "<<snoise<<" evol="<<type_evol<<endl;
+ check_array_alloc();
+
+ if(type_evol<0) type_evol = 0;
+ if(type_evol>2) {
+   char *bla = "GeneFluct3D::AddNoise2Real_Error: bad type_evol value";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+
+ vector<double> correction;
+ InterpFunc *intercor = NULL;
+
+ if(type_evol>0) {
+   // Sigma_Noise(en mass) :
+   //      Slim ~ 1/sqrt(DNu) * sqrt(nlobe)   en W/m^2Hz
+   //      Flim ~ sqrt(DNu) * sqrt(nlobe)   en W/m^2
+   //      Mlim ~ sqrt(DNu) * (Dlum)^2 * sqrt(nlobe)  en Msol
+   //                                    nlobe ~ 1/Dtrcom^2
+   //      Mlim ~ sqrt(DNu) * (Dlum)^2 / Dtrcom
+   if(cosmo_ == NULL || redsh_ref_<0.| loscom2zred_.size()<1) {
+     char *bla = "GeneFluct3D::AddNoise2Real_Error: set Observator and Cosmology first";
+     cout<<bla<<endl; throw ParmError(bla);
+   }
+   InterpFunc interpinv(loscom2zred_min_,loscom2zred_max_,loscom2zred_);
+   long nsz = loscom2zred_.size(), nszmod=((nsz>10)? nsz/10: 1);
+   for(long i=0;i<nsz;i++) {
+     double d = interpinv.X(i);
+     double zred = interpinv(d);
+     double dtrc = cosmo_->Dtrcom(zred);  // pour variation angle solide
+     double dlum = cosmo_->Dlum(zred);  // pour variation conversion mass HI
+     double dred = Dz_/(cosmo_->Dhubble()/cosmo_->E(zred));
+     double dnu  = Fr_HyperFin_Par *dred/pow(1.+zred,2.); // pour variation dNu
+     double corr = sqrt(dnu/dnu_ref_) * pow(dlum/dlum_ref_,2.) * dtrc_ref_/dtrc;
+     if(lp_>0 && (i==0 || i==nsz-1 || i%nszmod==0))
+       cout<<"i="<<i<<" d="<<d<<" red="<<zred<<" dred="<<dred<<" dnu="<<dnu
+           <<" dtrc="<<dtrc<<" dlum="<<dlum<<" -> cor="<<corr<<endl;
+     correction.push_back(corr);
+   }
+   intercor = new InterpFunc(loscom2zred_min_,loscom2zred_max_,correction);
+ } 
+
+ double corrlim[2] = {1.,1.};
+ for(long i=0;i<Nx_;i++) {
+   double dx2 = DXcom(i); dx2 *= dx2;
+   for(long j=0;j<Ny_;j++) {
+     double dy2 = DYcom(j); dy2 *= dy2;
+     for(long l=0;l<Nz_;l++) {
+       double corr = 1.;
+       if(type_evol>0) {
+         double dz = DZcom(l);
+         if(type_evol==1) dz = sqrt(dx2+dy2+dz*dz);
+           else dz = fabs(dz); // tous les plans Z au meme redshift
+         corr = (*intercor)(dz);
+         if(corr<corrlim[0]) corrlim[0]=corr; else if(corr>corrlim[1]) corrlim[1]=corr;
+       }
+       int_8 ip = IndexR(i,j,l);
+       data_[ip] += snoise*corr*NorRand();
+     }
+   }
+ }
+ if(type_evol>0)
+   cout<<"correction factor range: ["<<corrlim[0]<<","<<corrlim[1]<<"]"<<endl;
+
+ if(intercor!=NULL) delete intercor;
+}
+
+}  // Fin namespace SOPHYA
+
+
+
+
+/*********************************************************************
+void GeneFluct3D::AddAGN(double lfjy,double lsigma,double powlaw)
+// Add AGN flux into simulation:
+// --- Procedure:
+// 1. lancer "cmvdefsurv" avec les parametres du survey
+//        (au redshift de reference du survey)
+//    et recuperer l'angle solide "angsol sr" du pixel elementaire
+//    au centre du cube.
+// 2. lancer "cmvtstagn" pour cet angle solide -> cmvtstagn.ppf
+// 3. regarder l'histo "hlfang" et en deduire un equivalent gaussienne
+//    cad une moyenne <log10(S)> et un sigma "sig"
+//    Attention: la distribution n'est pas gaussienne les "mean,sigma"
+//               de l'histo ne sont pas vraiment ce que l'on veut
+// --- Limitations actuelle du code:
+// . les AGN sont supposes evoluer avec la meme loi de puissance pour tout theta,phi
+// . le flux des AGN est mis dans une colonne Oz (indice k) et pas sur la ligne de visee
+// . la distribution est approximee a une gaussienne
+// ... C'est une approximation pour un observateur loin du centre du cube
+//     et pour un cube peu epais / distance observateur 
+// --- Parametres de la routine:
+// llfy : c'est le <log10(S)> du flux depose par les AGN
+//        dans l'angle solide du pixel elementaire de reference du cube
+// lsigma : c'est le sigma de la distribution des log10(S)
+// powlaw : c'est la pente de la distribution cad que le flux "lmsol"
+//          et considere comme le flux a 1.4GHz et qu'on suppose une loi
+//             F(nu) = (1.4GHz/nu)^powlaw * F(1.4GHz)
+// - Comme on est en echelle log10():
+//   on tire log10(Msol) + X
+//   ou X est une realisation sur une gaussienne de variance "sig^2"
+//   La masse realisee est donc: Msol*10^X
+// - Pas de probleme de pixel negatif car on a une multiplication!
+{
+  if(lp_>0) cout<<"--- AddAGN: <log10(S Jy)> = "<<lfjy<<" , sigma = "<<lsigma<<endl;
+  check_array_alloc();
+
+ if(cosmo_ == NULL || redsh_ref_<0.| loscom2zred_.size()<1) {
+   char *bla = "GeneFluct3D::AddAGN_Error: set Observator and Cosmology first";
+   cout<<bla<<endl; throw ParmError(bla);
+ }
+
+ // Le flux des AGN en Jy et en mass solaire
+ double fagnref = pow(10.,lfjy)*(dnu_ref_*1.e9); // Jy.Hz = W/m^2
+ double magnref = FluxHI2Msol(fagnref*Jansky2Watt_cst,dlum_ref_); // Msol
+ if(lp_>0)
+   cout<<"Au pixel de ref: fagnref="<<fagnref
+       <<" Jy.Hz (a 1.4GHz), magnref="<<magnref<<" Msol"<<endl;
+
+ if(powlaw!=0.) {
+   // F(nu) = F(1.4GHz)*(nu GHz/1.4 Ghz)^p = F(1.4GHz)*(1/(1+z))^p , car nu = 1.4 GHz/(1+z)
+   magnref *= pow(1/(1.+redsh_ref_),powlaw);
+   if(lp_>0) cout<<" powlaw="<<powlaw<<"  -> change magnref to "<<magnref<<" Msol"<<endl;
+ }
+
+ // Les infos en fonction de l'indice "l" selon Oz
+ vector<double> correction;
+ InterpFunc interpinv(loscom2zred_min_,loscom2zred_max_,loscom2zred_);
+ long nzmod = ((Nz_>10)?Nz_/10:1);
+ for(long l=0;l<Nz_;l++) {
+   double z = fabs(DZcom(l));
+   double zred = interpinv(z);
+   double dtrc = cosmo_->Dtrcom(zred);  // pour variation angle solide
+   double dlum = cosmo_->Dlum(zred);  // pour variation conversion mass HI
+   double dred = Dz_/(cosmo_->Dhubble()/cosmo_->E(zred));
+   double dnu  = Fr_HyperFin_Par *dred/pow(1.+zred,2.); // pour variation dNu
+   // on a: Mass ~ DNu * Dlum^2 / Dtrcom^2
+   double corr = dnu/dnu_ref_*pow(dtrc_ref_/dtrc*dlum/dlum_ref_,2.);
+   // F(nu) = F(1.4GHz)*(nu GHz/1.4 Ghz)^p = F(1.4GHz)*(1/(1+z))^p , car nu = 1.4 GHz/(1+z)
+   if(powlaw!=0.) corr *= pow((1.+redsh_ref_)/(1.+zred),powlaw);
+   correction.push_back(corr);
+   if(lp_>0 && (l==0 || l==Nz_-1 || l%nzmod==0)) {
+     cout<<"l="<<l<<" z="<<z<<" red="<<zred<<" dred="<<dred<<" dnu="<<dnu
+         <<" dtrc="<<dtrc<<" dlum="<<dlum
+         <<" -> cor="<<corr<<endl;
+   }
+ }
+
+ double sum=0., sum2=0., nsum=0.;
+ for(long i=0;i<Nx_;i++) for(long j=0;j<Ny_;j++) {
+   double a = lsigma*NorRand();
+   a = magnref*pow(10.,a);
+   // On met le meme tirage le long de Oz (indice k)
+   for(long l=0;l<Nz_;l++) {
+     int_8 ip = IndexR(i,j,l);
+     data_[ip] += a*correction[l];
+   }
+   sum += a; sum2 += a*a; nsum += 1.;
+ }
+
+ if(lp_>0 && nsum>1.) {
+   sum /= nsum;
+   sum2 = sum2/nsum - sum*sum;
+   cout<<"...Mean mass="<<sum<<" Msol , s^2="<<sum2<<" s="<<sqrt(fabs(sum2))<<endl;
+ }
+ 
+}
+*********************************************************************/
Index: /tags/V1_0/Cosmo/SimLSS/genefluct3d.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/genefluct3d.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/genefluct3d.h	(revision 3382)
@@ -0,0 +1,187 @@
+#ifndef GENEFLUCT3D_SEEN
+#define GENEFLUCT3D_SEEN
+
+#include "machdefs.h"
+#include <math.h>
+#include "genericfunc.h"
+#include "tarray.h"
+#include "histerr.h"
+#include "hist2err.h"
+#include "perandom.h"
+
+#include "FFTW/fftw3.h"
+#include "FitsIO/fitsio.h"
+
+#include <vector>
+
+#include "cosmocalc.h"
+#include "pkspectrum.h"
+
+
+namespace SOPHYA {
+
+//-----------------------------------------------------------------------------------
+class GeneFluct3D {
+public:
+  GeneFluct3D(long nx,long ny,long nz,double dx,double dy,double dz,unsigned short nthread=0,int lp=0);  // Mpc
+  GeneFluct3D(unsigned short nthread=0);
+  virtual ~GeneFluct3D(void);
+
+  // Distance los comobile a l'observateur
+  void SetObservator(double redshref=0.,double kredshref=0.);
+    inline double DXcom(long i) {return i*Dx_ - xobs_[0];}
+    inline double DYcom(long j) {return j*Dy_ - xobs_[1];}
+    inline double DZcom(long k) {return k*Dz_ - xobs_[2];}
+    inline double Dcom(long i,long j,long k) {
+      double dx=DXcom(i), dy=DYcom(j), dz=DZcom(k); 
+      return sqrt(dx*dx+dy*dy+dz*dz);
+    }
+  void SetCosmology(CosmoCalc& cosmo);
+  void SetGrowthFactor(GrowthFactor& growth);
+  long LosComRedshift(double zinc=0.001,long npoints=-1);
+
+  TArray< complex<r_8> >& GetComplexArray(void) {return T_;}
+  fftw_complex* GetComplexPointer(void) {return fdata_;}
+  TArray<r_8>& GetRealArray(void) {return R_;}
+  r_8* GetRealPointer(void) {return data_;}
+
+  // Pour adressage data_[ip]
+  inline int_8 IndexR(long i,long j,long k) {return (int_8)(k+NTz_*(j+Ny_*i));}
+  // Pour adressage fdata_[ip][0-1]
+  inline int_8 IndexC(long i,long j,long k) {return (int_8)(k+NCz_*(j+Ny_*i));}
+  // On peut aussi adresser:
+  // TArray< complex<r_8> >& pk = gf3d.GetComplexArray();
+  //    pk(k,j,i) avec k=[0,NCz_[  j=[0,Ny_[   i=[0,Nx_[
+  //    pk[IndexC(i,j,k)]
+  // TArray<r_8>& rgen = gf3d.GetRealArray();
+  //    rgen(k,j,i) avec k=[0,NTz_[  j=[0,Ny_[   i=[0,Nx_[
+  //                mais seul k=[0,Nz_[ est utile
+  //    rgen[IndexR(i,j,k)]
+  // ATTENTION: TArray adresse en memoire a l'envers du C !
+  //            Tarray(n1,n2,n3) == Carray[n3][n2][n1]
+
+  vector<long> GetNpix(void) {return N_;}
+  int_8 NPix(void) {return NRtot_;}
+  long GetNx(void) {return Nx_;}
+  long GetNy(void) {return Ny_;}
+  long GetNz(void) {return Nz_;}
+
+  // Return |K_i| module relative to pixel indices
+  inline r_8 Kx(long i) {long ii=(i>Nx_/2)? Nx_-i :i; return ii*Dkx_;}
+  inline r_8 Ky(long j) {long jj=(j>Ny_/2)? Ny_-j :j; return jj*Dky_;}
+  inline r_8 Kz(long l) {return l*Dkz_;}
+
+  vector<r_8> GetDinc(void) {return D_;}
+  double GetDVol(void) {return dVol_;}
+  double GetVol(void) {return Vol_;}
+
+  vector<r_8> GetKinc(void) {return Dk_;}
+  vector<r_8> GetKnyq(void) {return Knyq_;}
+  double GetKmax(void) {return sqrt(Knyqx_*Knyqx_+Knyqy_*Knyqy_+Knyqz_*Knyqz_);}
+  double GetKTmax(void) {return sqrt(Knyqx_*Knyqx_+Knyqy_*Knyqy_);}
+  double GetKincMin(void)
+    {vector<r_8>::const_iterator it = min_element(Dk_.begin(), Dk_.end()); return *it;}
+  double GetKincMax(void)
+    {vector<r_8>::const_iterator it = max_element(Dk_.begin(), Dk_.end()); return *it;}
+  double GetKTincMin(void) {return min(Dk_[0],Dk_[1]);}
+  double GetKTincMax(void) {return max(Dk_[0],Dk_[1]);}
+
+  void ComputeFourier0(GenericFunc& pk_at_z);
+  void ComputeFourier(GenericFunc& pk_at_z);
+  void FilterByPixel(void);
+
+  void ComputeReal(void);
+  void ApplyGrowthFactor(int type_evol=1);
+
+  void ReComputeFourier(void);
+
+  int  ComputeSpectrum(HistoErr& herr);
+  int  ComputeSpectrum2D(Histo2DErr& herr);
+  int  ComputeSpectrum(HistoErr& herr,double sigma,bool pixcor);
+  int  ComputeSpectrum2D(Histo2DErr& herr,double sigma,bool pixcor);
+
+  int_8 VarianceFrReal(double R,double& var);
+  int_8 MeanSigma2(double& rm,double& rs2,double vmin=1.,double vmax=-1.
+                  ,bool useout=false,double vout=0.);
+  int_8 MinMax(double& xmin,double& xmax,double vmin=1.,double vmax=-1.);
+  int_8 NumberOfBad(double vmin=-1.e+150,double vmax=1.e+150);
+  int_8 SetToVal(double vmin, double vmax,double val0=0.);
+  void  ScaleOffset(double scalecube=1.,double offsetcube=0.);
+
+  void TurnFluct2Mass(void);
+  double TurnFluct2MeanNumber(double val_by_mpc3);
+  double ApplyPoisson(void);
+  double TurnNGal2Mass(FunRan& massdist,bool axeslog=false);
+  double TurnNGal2MassQuick(SchechterMassDist& schmdist);
+  double TurnMass2Flux(void);
+  //void AddAGN(double lfjy,double lsigma,double powlaw=0.);
+  void AddNoise2Real(double snoise,int type_evol=0);
+
+  void WriteFits(string cfname,int bitpix=FLOAT_IMG);
+  void ReadFits(string cfname);
+
+  void WritePPF(string cfname,bool write_real=true);
+  void ReadPPF(string cfname);
+  void WriteSlicePPF(string cfname);
+
+  void SetPrtLevel(int lp=0) {lp_ = lp;}
+  void Print(void);
+
+//-------------------------------------------------------------------
+
+protected:
+  void init_default(void);
+  void setsize(long nx,long ny,long nz,double dx,double dy,double dz);
+  void setalloc(void);
+  void setpointers(bool from_real);
+  void init_fftw(void);
+  void delete_fftw(void);
+  long manage_coefficients(void);
+  double compute_power_carte(void);
+  void check_array_alloc(void);
+  inline double pixelfilter(double x)
+    {return (x<0.025) ? 1.-x*x/6.*(1.-x*x/20.): sin(x)/x;}
+
+  // valeurs dans l'espace reel
+  long Nx_,Ny_,Nz_;  vector<long> N_;
+  long NCz_,NTz_;
+  int_8 NRtot_;
+
+  double Dx_,Dy_,Dz_;  vector<double> D_;
+
+  // valeurs dans l'espace des K
+  double Dkx_,Dky_,Dkz_;  vector<double> Dk_;
+  double Knyqx_,Knyqy_,Knyqz_;  vector<double> Knyq_;
+  double Dk3_;
+  double dVol_, Vol_;
+
+  // la gestion de la FFT
+  bool is_set_fftw_plan;
+  fftw_plan pf_,pb_;
+  unsigned short nthread_;
+  int lp_;
+
+  // le stockage du Cube de donnees et les pointeurs
+  bool array_allocated_;  // true if array has been allocated
+  TArray< complex<r_8> > T_;
+  fftw_complex *fdata_;
+  TArray<r_8> R_;
+  double *data_;
+
+  // l'observateur
+  CosmoCalc *cosmo_;
+  GrowthFactor *growth_;
+  double redsh_ref_,kredsh_ref_,dred_ref_;
+  double loscom_ref_,dtrc_ref_, dlum_ref_, dang_ref_;
+  double nu_ref_, dnu_ref_ ;
+  double xobs_[3];
+  double loscom_min_, loscom_max_;
+  vector<double> zred_, loscom_;
+  double loscom2zred_min_, loscom2zred_max_;
+  vector<double> loscom2zred_;
+
+};
+
+} // Fin du namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/geneutils.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/geneutils.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/geneutils.cc	(revision 3382)
@@ -0,0 +1,456 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <vector>
+
+#include "pexceptions.h"
+
+#include "histos.h"
+#include "hisprof.h"
+#include "srandgen.h"
+
+#include "geneutils.h"
+
+namespace SOPHYA {
+
+//-------------------------------------------------------------------
+// Classe d'interpolation lineaire:
+// Le vecteur y a n elements y_i tels que y_i = f(x_i)
+//   ou les x_i sont regulierement espaces
+//   et x_0=xmin et x_{n-1}=xmax   (xmax inclus!)
+InterpFunc::InterpFunc(double xmin,double xmax,vector<double>& y)
+  : _xmin(xmin), _xmax(xmax), _y(y)
+{
+  if(_xmin>=_xmax || _y.size()<=2) {  // au moins 3 points!
+   cout<<"InterpFunc::InterpFunc : bad arguments values"<<endl;
+   throw ParmError("InterpFunc::InterpFunc : bad arguments values");
+  }
+  _nm1   = _y.size()-1;
+  _dx    = (_xmax-_xmin)/(double)_nm1;
+}
+
+double InterpFunc::Linear(double x,unsigned short& ok)
+{
+  ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
+  x -= _xmin;
+  long i = long(x/_dx);  // On prend le "i" juste en dessous
+  if(i<0) i=0; else if(i>=_nm1) i=_nm1-1;
+  return _y[i] + (_y[i+1]-_y[i])/_dx*(x-i*_dx);
+}
+
+double InterpFunc::Parab(double x,unsigned short& ok)
+{
+  ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
+  x -= _xmin;
+  long i = long(x/_dx+0.5);  // On prend le "i" le + proche
+  if(i<1) i=1; else if(i>=_nm1-1) i=_nm1-2;
+  double a = (_y[i+1]-2.*_y[i]+_y[i-1])/(2.*_dx*_dx);
+  double b = (_y[i+1]-_y[i-1])/(2.*_dx);
+  return _y[i] + (x-i*_dx)*(a*(x-i*_dx)+b);
+}
+
+//-------------------------------------------------------------------
+// Classe d'inversion d'une fonction STRICTEMENT MONOTONE CROISSANTE
+//
+// - On part de deux vecteurs x,y de "Nin" elements tels que "y_i = f[x_i]"
+//   ou la fonction "f" est strictement monotone croissante:
+//          x(i) < x(i+1)   et   y(i) < y(i+1)
+// - Le but de la classe est de remplir un vecteur X de "Nout" elements
+//   tels que:    X_j = f^-1[Y_j]    avec   j=[0,Nout[
+//   avec les Y_j regulierement espaces entre ymin=y(0) , ymax=y(Nin -1)
+//   cad:     X_j = f^-1[ ymin+j*(ymax-ymin)/(Nout-1) ]
+// - La construction du vecteur X est realisee
+//   par interpolation lineaire (ComputeLinear) ou parabolique (ComputeParab)
+InverseFunc::InverseFunc(vector<double>& x,vector<double>& y)
+  : _ymin(0.) , _ymax(0.) , _x(x) , _y(y)
+{
+  uint_4 ns = _x.size();
+  if(ns<3 || _y.size()<=0 || ns!=_y.size())
+    throw ParmError("InverseFunc::InverseFunc_Error: bad array size");
+
+  // Check "x" strictement monotone croissant
+  for(uint_4 i=0;i<ns-1;i++)
+    if(_x[i+1]<=_x[i]) {
+      cout<<"InverseFunc::InverseFunc_Error: _x array not stricly growing"<<endl;
+      throw ParmError("InverseFunc::InverseFunc_Error: _x array not stricly growing");
+    }
+
+  // Check "y" monotone croissant
+  for(uint_4 i=0;i<ns-1;i++)
+    if(_y[i+1]<_y[i]) {
+      cout<<"InverseFunc::InverseFunc_Error: _y array not growing"<<endl;
+      throw ParmError("InverseFunc::InverseFunc_Error: _y array not growing");
+    }
+
+  // define limits
+  _ymin = _y[0];
+  _ymax = _y[ns-1];
+
+}
+
+InverseFunc::~InverseFunc(void)
+{
+}
+
+int InverseFunc::ComputeLinear(long nout,vector<double>& xfcty)
+// Compute table "xfcty" by linear interpolation of "x" versus "y"
+//   on "nout" points from "ymin" to "ymax":
+// xfcty[i] = interpolation of function "x" for "ymin+i*(ymax-ymin)/(nout-1)"
+{
+  if(nout<3) return -1;
+
+  xfcty.resize(nout);
+
+  long i1,i2;
+  double x;
+  for(int_4 i=0;i<nout;i++) {
+    double y = _ymin + i*(_ymax-_ymin)/(nout-1.);
+    find_in_y(y,i1,i2);
+    double dy = _y[i2]-_y[i1];
+    if(dy==0.) {
+      x = (_x[i2]+_x[i1])/2.; // la fct a inverser est plate!
+    } else {
+      x = _x[i1] + (_x[i2]-_x[i1])/dy * (y-_y[i1]);
+    }
+    xfcty[i] = x;
+  }
+
+  return 0;
+}
+
+int InverseFunc::ComputeParab(long nout,vector<double>& xfcty)
+{
+  if(nout<3) return -1;
+
+  xfcty.resize(nout);
+
+  long i1,i2,i3;
+  double x;
+  for(int_4 i=0;i<nout;i++) {
+    double y = _ymin + i*(_ymax-_ymin)/(nout-1.);
+    find_in_y(y,i1,i2);
+    // On cherche le 3ieme point selon la position de y / au 2 premiers
+    double my = (_y[i1]+_y[i2])/2.;
+    if(y<my) {i3=i2; i2=i1; i1--;} else {i3=i2+1;}
+    // Protection
+    if(i1<0) {i1++; i2++; i3++;}
+    if(i3==(long)_y.size()) {i1--; i2--; i3--;}
+    // Interpolation parabolique
+    double dy = _y[i3]-_y[i1];
+    if(dy==0.) {
+      x = (_x[i3]+_x[i1])/2.; // la fct a inverser est plate!
+    } else {
+      double X1=_x[i1]-_x[i2], X3=_x[i3]-_x[i2];
+      double Y1=_y[i1]-_y[i2], Y3=_y[i3]-_y[i2];
+      double den = Y1*Y3*dy;
+      double a = (X3*Y1-X1*Y3)/den;
+      double b = (X1*Y3*Y3-X3*Y1*Y1)/den;
+      y -= _y[i2];
+      x = (a*y+b)*y + _x[i2];
+    }
+    xfcty[i] = x;
+  }
+
+  return 0;
+}
+
+//----------------------------------------------------
+double InterpTab(double x0,vector<double>& X,vector<double>& Y,unsigned short typint)
+// Interpole in x0 the table Y = f(X)
+//           X doit etre ordonne par ordre croissant (strictement)
+// typint = 0 : nearest value
+//          1 : linear interpolation
+//          2 : parabolique interpolation
+{
+ long n = X.size();
+ if(n>(long)Y.size() || n<2)
+   throw ParmError("InterpTab_Error :  incompatible size between X and Y tables!");
+
+ if(x0<X[0] || x0>X[n-1]) return 0.;
+ if(typint>2) typint = 0;
+
+ // Recherche des indices encadrants par dichotomie
+ long k, klo=0, khi=n-1;
+ while (khi-klo > 1) {
+   k = (khi+klo) >> 1;
+   if (X[k] > x0) khi=k; else klo=k;
+ }
+
+ // Quel est le plus proche?
+ k = (x0-X[klo]<X[khi]-x0) ? klo: khi;
+
+ // On retourne le plus proche
+ if(typint==0) return Y[k];
+
+ // On retourne l'extrapolation lineaire
+ if(typint==1 || n<3)
+   return Y[klo] + (Y[khi]-Y[klo])/(X[khi]-X[klo])*(x0-X[klo]);
+
+ // On retourne l'extrapolation parabolique
+ if(k==0) k++; else if(k==n-1) k--;
+ klo = k-1; khi = k+1;
+ double x1 = X[klo]-X[k], x2 = X[khi]-X[k];
+ double y1 = Y[klo]-Y[k], y2 = Y[khi]-Y[k];
+ double den = x1*x2*(x1-x2);
+ double a = (y1*x2-y2*x1)/den;
+ double b = (y2*x1*x1-y1*x2*x2)/den;
+ x0 -= X[k];
+ return Y[k] + (a*x0+b)*x0;;
+
+}
+
+//-------------------------------------------------------------------
+int FuncToHisto(GenericFunc& func,Histo& h,bool logaxex)
+// Remplit l'histo 1D "h" avec la fonction "func"
+// INPUT:
+// logaxex = false : remplissage lineaire
+//        les abscisses "x" des bins sont remplis avec f(x)
+// logaxex = true : remplissage logarithmique (base 10)
+//        les abscisses "x" des bins sont remplis avec f(10^x)
+// RETURN:
+//       0 = OK
+//       1 = error
+{
+  if(h.NBins()<=0) return 1;
+
+  h.Zero();
+
+  for(int_4 i=0;i<h.NBins();i++) {
+    double x = h.BinCenter(i);
+    if(logaxex) x = pow(10.,x);
+    h.SetBin(i,func(x));
+  }
+
+  return 0;
+}
+
+int FuncToVec(GenericFunc& func,TVector<r_8>& v,double xmin,double xmax,bool logaxex)
+// Remplit le TVector avec la fonction "func"
+// INPUT:
+// logaxex = false : remplissage lineaire
+//        les abscisses "x" des bins sont remplis avec f(x)
+// logaxex = true : remplissage logarithmique (base 10)
+//        les abscisses "x" des bins sont remplis avec f(10^x)
+// RETURN:
+//       0 = OK
+//       1 = error
+// Remarque:
+//  v(i) = f(xmin+i*dx) avec dx = (xmax-xmin)/v.NElts()
+{
+  if(v.NElts()<=0 || xmax<=xmin) return 1;
+
+  v = 0.;
+  double dx = (xmax-xmin)/v.NElts();
+   
+  for(int_4 i=0;i<v.NElts();i++) {
+    double x = xmin + i * dx;;
+    if(logaxex) x = pow(10.,x);
+    v(i) = func(x);
+  }
+
+  return 0;
+}
+
+//-------------------------------------------------------------------
+double AngSol(double dtheta,double dphi,double theta0)
+// Retourne l'angle solide d'un "rectangle" et coordonnees spheriques
+// de DEMI-COTE "dtheta" x "dphi" et centre en "theta0"
+// Attention: Le "theta0" de l'equateur est Pi/2  (et non pas zero)
+//            Les unites des angles sont en radians
+//               theta0 in [0,Pi]
+//               dtheta in [0,Pi]
+//               dphi   in [0,2Pi]
+// Return: l'angle solide en steradian
+{
+  double theta1 = theta0-dtheta, theta2 = theta0+dtheta;
+  if(theta1<0.) theta1=0.;
+  if(theta2>M_PI) theta2=M_PI;
+
+  return   2.*dphi * (cos(theta1)-cos(theta2));
+}
+
+double AngSol(double dtheta)
+// Retourne l'angle solide d'une calotte spherique de demi-ouverture "dtheta"
+// Attention: Les unites des angles sont en radians
+//               dtheta in [0,Pi]
+// Return: l'angle solide en steradian
+// Approx pour theta petit: PI * theta^2
+{
+  return   2.*M_PI * (1.-cos(dtheta));
+}
+
+double FrAngSol(double angsol)
+// Retourne la demi-ouverture "dtheta" d'une calotte spherique d'angle solide "angsol"
+// Input: angle solide de la calotte spherique en steradians
+// Return: demi-ouverture de la calotte spherique en radians
+{
+  angsol = 1. - angsol/(2.*M_PI);
+  if(angsol<-1. || angsol>1.) return -1.;
+  return acos(angsol);
+}
+
+//-------------------------------------------------------------------
+
+static unsigned short IntegrateFunc_GlOrder = 0;
+static vector<double> IntegrateFunc_x;
+static vector<double> IntegrateFunc_w;
+
+///////////////////////////////////////////////////////////
+//************** Integration of Functions ***************//
+///////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////////////////
+double IntegrateFunc(GenericFunc& func,double xmin,double xmax
+       ,double perc,double dxinc,double dxmax,unsigned short glorder)
+// --- Integration adaptative ---
+//     Integrate[func[x], {x,xmin,xmax}]
+// ..xmin,xmax are the integration limits
+// ..dxinc is the searching increment x = xmin+i*dxinc
+//         if <0  npt = int(|dxinc|)   (si<2 alors npt=100)
+//                et dxinc = (xmax-xmin)/npt
+// ..dxmax is the maximum possible increment (if dxmax<=0 no test)
+// ---
+// Partition de [xmin,xmax] en intervalles [x(i),x(i+1)]:
+// on parcourt [xmin,xmax] par pas de "dxinc" : x(i) = xmin + i*dxinc
+// on cree un intervalle [x(i),x(i+1)]
+//     - si |f[x(i+1)] - f[x(i)]| > perc*|f[[x(i)]|
+//     - si |x(i+1)-x(i)| >= dxmax  (si dxmax>0.)
+// Dans un intervalle [x(i),x(i+1)] la fonction est integree
+//   avec une methode de gauss-legendre d'ordre "glorder"
+{
+  double signe = 1.;
+  if(xmin>xmax) {double tmp=xmax; xmax=xmin; xmin=tmp; signe=-1.;}
+
+  if(glorder==0) glorder = 4;
+  if(perc<=0.) perc=0.1;
+  if(dxinc<=0.) {int n=int(-dxinc); if(n<2) n=100; dxinc=(xmax-xmin)/n;}
+  if(glorder != IntegrateFunc_GlOrder) {
+    IntegrateFunc_GlOrder = glorder;
+    Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
+  }
+
+  // Recherche des intervalles [x(i),x(i+1)]
+  int_4 ninter = 0;
+  double sum = 0., xbas=xmin, fbas=func(xbas), fabsfbas=fabs(fbas);
+  for(double x=xmin+dxinc; x<xmax+dxinc/2.; x += dxinc) {
+    double f = func(x);
+    double dx = x-xbas;
+    bool doit = false;
+    if( x>xmax ) {doit = true; x=xmax;}
+    else if( dxmax>0. && dx>dxmax ) doit = true;
+    else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
+    if( ! doit ) continue;
+    double s = 0.;
+    for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++)
+      s += IntegrateFunc_w[i]*func(xbas+IntegrateFunc_x[i]*dx);
+    sum += s*dx;
+    xbas = x; fbas = f; fabsfbas=fabs(fbas); ninter++;
+  }
+  //cout<<"Ninter="<<ninter<<endl;
+
+  return sum*signe;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+double IntegrateFuncLog(GenericFunc& func,double lxmin,double lxmax
+         ,double perc,double dlxinc,double dlxmax,unsigned short glorder)
+// --- Integration adaptative ---
+// Idem IntegrateFunc but integrate on logarithmic (base 10) intervals:
+//    Int[ f(x) dx ] = Int[ x*f(x) dlog10(x) ] * log(10)
+// ..lxmin,lxmax are the log10() of the integration limits
+// ..dlxinc is the searching logarithmic (base 10) increment lx = lxmin+i*dlxinc
+// ..dlxmax is the maximum possible logarithmic (base 10) increment (if dlxmax<=0 no test)
+// Remarque: to be use if "x*f(x) versus log10(x)" looks like a polynomial
+//            better than "f(x) versus x"
+// ATTENTION: la fonction func que l'on passe en argument
+//            est "func(x)" et non pas "func(log10(x))"
+{
+  double signe = 1.;
+  if(lxmin>lxmax) {double tmp=lxmax; lxmax=lxmin; lxmin=tmp; signe=-1.;}
+
+  if(glorder==0) glorder = 4;
+  if(perc<=0.) perc=0.1;
+  if(dlxinc<=0.) {int n=int(-dlxinc); if(n<2) n=100; dlxinc=(lxmax-lxmin)/n;}
+  if(glorder != IntegrateFunc_GlOrder) {
+    IntegrateFunc_GlOrder = glorder;
+    Compute_GaussLeg(glorder,IntegrateFunc_x,IntegrateFunc_w,0.,1.);
+  }
+
+  // Recherche des intervalles [lx(i),lx(i+1)]
+  int_4 ninter = 0;
+  double sum = 0., lxbas=lxmin, fbas=func(pow(10.,lxbas)), fabsfbas=fabs(fbas);
+  for(double lx=lxmin+dlxinc; lx<lxmax+dlxinc/2.; lx += dlxinc) {
+    double f = func(pow(10.,lx));
+    double dlx = lx-lxbas;
+    bool doit = false;
+    if( lx>lxmax ) {doit = true; lx=lxmax;}
+    else if( dlxmax>0. && dlx>dlxmax ) doit = true;
+    else if( fabs(f-fbas)>perc*fabsfbas ) doit = true;
+    if( ! doit ) continue;
+    double s = 0.;
+    for(unsigned short i=0;i<IntegrateFunc_GlOrder;i++) {
+      double y = pow(10.,lxbas+IntegrateFunc_x[i]*dlx);
+      s += IntegrateFunc_w[i]*y*func(y);
+    }
+    sum += s*dlx;
+    lxbas = lx; fbas = f; fabsfbas=fabs(fbas); ninter++;
+  }
+  //cout<<"Ninter="<<ninter<<endl;
+
+  return M_LN10*sum*signe;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+/*
+Integration des fonctions a une dimension y=f(x) par la Methode de Gauss-Legendre.
+  --> Calcul des coefficients du developpement pour [x1,x2]
+| INPUT:
+|  x1,x2 : bornes de l'intervalle (dans nbinteg.h -> x1=-0.5 x2=0.5)
+|  glorder = degre n du developpement de Gauss-Legendre
+| OUTPUT:
+|  x[] = valeur des abscisses ou l'on calcule (dim=n)
+|  w[] = valeur des coefficients associes
+| REMARQUES:
+|  - x et w seront dimensionnes a n.
+|  - l'integration est rigoureuse si sur l'intervalle d'integration
+|    la fonction f(x) peut etre approximee par un polynome
+|    de degre 2*m (monome le + haut x**(2*n-1) )
+*/
+void Compute_GaussLeg(unsigned short glorder,vector<double>& x,vector<double>& w,double x1,double x2)
+{
+  if(glorder==0) return;
+  int n = (int)glorder;
+  x.resize(n,0.); w.resize(n,0.);
+
+   int m,j,i;
+   double z1,z,xm,xl,pp,p3,p2,p1;
+
+   m=(n+1)/2;
+   xm=0.5*(x2+x1);
+   xl=0.5*(x2-x1);
+   for (i=1;i<=m;i++)  {
+      z=cos(M_PI*(i-0.25)/(n+0.5));
+      do {
+         p1=1.0;
+         p2=0.0;
+         for (j=1;j<=n;j++) {
+            p3=p2;
+            p2=p1;
+            p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
+         }
+         pp=n*(z*p1-p2)/(z*z-1.0);
+         z1=z;
+         z=z1-p1/pp;
+      } while (fabs(z-z1) > 3.0e-11);  // epsilon
+      x[i-1]=xm-xl*z;
+      x[n-i]=xm+xl*z;
+      w[i-1]=2.0*xl/((1.0-z*z)*pp*pp);
+      w[n-i]=w[i-1];
+   }
+}
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/geneutils.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/geneutils.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/geneutils.h	(revision 3382)
@@ -0,0 +1,101 @@
+#ifndef GENEUTILS_SEEN
+#define GENEUTILS_SEEN
+
+#include "machdefs.h"
+#include <math.h>
+#include "genericfunc.h"
+#include "histos.h"
+#include "tvector.h"
+#include "cspline.h"
+
+#include <vector>
+
+namespace SOPHYA {
+
+//----------------------------------------------------
+class InterpFunc {
+public:
+  InterpFunc(double xmin,double xmax,vector<double>& y);
+  virtual ~InterpFunc(void) { }
+
+  double XMin(void) {return _xmin;}
+  double XMax(void) {return _xmax;}
+  inline double X(long i) {return _xmin + i*_dx;}
+
+  //! Retourne l'element le plus proche de f donnant y=f(x)
+  inline double operator()(double x)
+         {
+         x -= _xmin;
+         long i = long(x/_dx+0.5);  // On prend le "i" le plus proche
+         if(i<0) i=0; else if(i>=_nm1) i=_nm1-1;
+         return _y[i];
+         }
+
+  // idem operator(double) et retourne
+  // ok==0 si valeur trouvee, 1 si x<xmin, 2 si x>xmax
+  inline double operator()(double x,unsigned short& ok)
+    {ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2; return (*this)(x);}
+
+  //! Retourne l'interpolation lineaire de f donnant y=f(x)
+  // ok==0 si valeur trouvee, 1 si x<xmin, 2 si x>xmax
+  double Linear(double x,unsigned short& ok);
+
+  //! Retourne l'interpolation parabolique de f donnant y=f(x)
+  // ok==0 si valeur trouvee, 1 si x<xmin, 2 si x>xmax
+  double Parab(double x,unsigned short& ok);
+
+protected:
+  double _xmin,_xmax,_dx;
+  long _nm1;  // n-1
+  vector<double>& _y;
+};
+
+//----------------------------------------------------
+class InverseFunc {
+public:
+  InverseFunc(vector<double>& x,vector<double>& y);
+  virtual ~InverseFunc(void);
+  int ComputeLinear(long n,vector<double>& xfcty);
+  int ComputeParab(long n,vector<double>& xfcty);
+  double YMin(void) {return _ymin;}
+  double YMax(void) {return _ymax;}
+protected:
+  inline void find_in_y(double x,long& klo,long& khi)
+    {
+      long k;
+      klo=0, khi=_y.size()-1;
+      while (khi-klo > 1) {
+	k = (khi+klo) >> 1;
+	if (_y[k] > x) khi=k; else klo=k;
+      }
+    }
+
+  double _ymin,_ymax;
+  vector<double>& _x;
+  vector<double>& _y;
+};
+
+//----------------------------------------------------
+double InterpTab(double x0,vector<double>& X,vector<double>& Y,unsigned short typint=0);
+
+//----------------------------------------------------
+int FuncToHisto(GenericFunc& func,Histo& h,bool logaxex=false);
+int FuncToVec(GenericFunc& func,TVector<r_8>& h,double xmin,double xmax,bool logaxex=false);
+
+//----------------------------------------------------
+double AngSol(double dtheta,double dphi,double theta0=M_PI/2.);
+double AngSol(double dtheta);
+double FrAngSol(double angsol);
+
+//----------------------------------------------------
+double IntegrateFunc(GenericFunc& func,double xmin,double xmax
+         ,double perc=0.1,double dxinc=-1.,double dxmax=-1.,unsigned short glorder=4);
+
+double IntegrateFuncLog(GenericFunc& func,double lxmin,double lxmax
+         ,double perc=0.1,double dlxinc=-1.,double dlxmax=-1.,unsigned short glorder=4);
+
+void Compute_GaussLeg(unsigned short glorder,vector<double>& x,vector<double>& w,double x1=0.,double x2=1.);
+
+}  // Fin namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/hu_power.c
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/hu_power.c	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/hu_power.c	(revision 3382)
@@ -0,0 +1,274 @@
+/* Fitting Formulae for CDM + Baryon + Massive Neutrino (MDM) cosmologies. */
+/* Daniel J. Eisenstein & Wayne Hu, Institute for Advanced Study */
+
+/* There are two primary routines here, one to set the cosmology, the
+other to construct the transfer function for a single wavenumber k. 
+You should call the former once (per cosmology) and the latter as 
+many times as you want. */
+
+/* TFmdm_set_cosm() -- User passes all the cosmological parameters as
+	arguments; the routine sets up all of the scalar quantites needed 
+	computation of the fitting formula.  The input parameters are: 
+	1) omega_matter -- Density of CDM, baryons, and massive neutrinos,
+				in units of the critical density. 
+	2) omega_baryon -- Density of baryons, in units of critical. 
+	3) omega_hdm    -- Density of massive neutrinos, in units of critical 
+	4) degen_hdm    -- (Int) Number of degenerate massive neutrino species 
+	5) omega_lambda -- Cosmological constant 
+	6) hubble       -- Hubble constant, in units of 100 km/s/Mpc 
+	7) redshift     -- The redshift at which to evaluate */
+
+/* TFmdm_onek_mpc() -- User passes a single wavenumber, in units of Mpc^-1.
+	Routine returns the transfer function from the Eisenstein & Hu
+	fitting formula, based on the cosmology currently held in the 
+	internal variables.  The routine returns T_cb (the CDM+Baryon
+	density-weighted transfer function), although T_cbn (the CDM+
+	Baryon+Neutrino density-weighted transfer function) is stored
+	in the global variable tf_cbnu. */
+
+/* We also supply TFmdm_onek_hmpc(), which is identical to the previous
+	routine, but takes the wavenumber in units of h Mpc^-1. */
+
+/* We hold the internal scalar quantities in global variables, so that
+the user may access them in an external program, via "extern" declarations. */
+
+/* Please note that all internal length scales are in Mpc, not h^-1 Mpc! */
+
+/* -------------------------- Prototypes ----------------------------- */
+
+int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
+	int degen_hdm, double omega_lambda, double hubble, double redshift);
+double TFmdm_onek_mpc(double kk);
+double TFmdm_onek_hmpc(double kk);
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Convenience from Numerical Recipes in C, 2nd edition
+------------ COMPLETEMENT DEBILE (cmv) ????????? ------------
+static double sqrarg;
+#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
+*/
+#define SQR(a) (a*a)
+
+/* ------------------------- Global Variables ------------------------ */
+
+/* The following are set in TFmdm_set_cosm() */
+double   alpha_gamma,	/* sqrt(alpha_nu) */
+	alpha_nu,	/* The small-scale suppression */
+	beta_c,		/* The correction to the log in the small-scale */
+	num_degen_hdm,	/* Number of degenerate massive neutrino species */
+	f_baryon,	/* Baryon fraction */
+	f_bnu,		/* Baryon + Massive Neutrino fraction */
+	f_cb,		/* Baryon + CDM fraction */
+	f_cdm,		/* CDM fraction */
+	f_hdm,		/* Massive Neutrino fraction */
+	growth_k0,	/* D_1(z) -- the growth function as k->0 */
+	growth_to_z0,	/* D_1(z)/D_1(0) -- the growth relative to z=0 */
+	hhubble,	/* Need to pass Hubble constant to TFmdm_onek_hmpc() */
+	k_equality,	/* The comoving wave number of the horizon at equality*/
+	obhh,		/* Omega_baryon * hubble^2 */
+	omega_curv,	/* = 1 - omega_matter - omega_lambda */
+	omega_lambda_z, /* Omega_lambda at the given redshift */
+	omega_matter_z,	/* Omega_matter at the given redshift */
+	omhh,		/* Omega_matter * hubble^2 */
+	onhh,		/* Omega_hdm * hubble^2 */
+	p_c,		/* The correction to the exponent before drag epoch */
+	p_cb,		/* The correction to the exponent after drag epoch */
+	sound_horizon_fit,  /* The sound horizon at the drag epoch */
+	theta_cmb,	/* The temperature of the CMB, in units of 2.7 K */
+	y_drag,		/* Ratio of z_equality to z_drag */
+	z_drag,		/* Redshift of the drag epoch */
+	z_equality;	/* Redshift of matter-radiation equality */
+
+/* The following are set in TFmdm_onek_mpc() */
+double	gamma_eff,	/* Effective \Gamma */
+	growth_cb,	/* Growth factor for CDM+Baryon perturbations */
+	growth_cbnu,	/* Growth factor for CDM+Baryon+Neutrino pert. */
+	max_fs_correction,  /* Correction near maximal free streaming */
+	qq,		/* Wavenumber rescaled by \Gamma */
+	qq_eff,		/* Wavenumber rescaled by effective Gamma */
+	qq_nu,		/* Wavenumber compared to maximal free streaming */
+	tf_master,	/* Master TF */
+	tf_sup,		/* Suppressed TF */
+	y_freestream; 	/* The epoch of free-streaming for a given scale */
+
+/* Finally, TFmdm_onek_mpc() and TFmdm_onek_hmpc() give their answers as */
+double   tf_cb,		/* The transfer function for density-weighted
+			CDM + Baryon perturbations. */
+	tf_cbnu;	/* The transfer function for density-weighted
+			CDM + Baryon + Massive Neutrino perturbations. */
+
+/* By default, these functions return tf_cb */
+
+/* ------------------------- TFmdm_set_cosm() ------------------------ */
+int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
+	int degen_hdm, double omega_lambda, double hubble, double redshift)
+/* This routine takes cosmological parameters and a redshift and sets up
+all the internal scalar quantities needed to compute the transfer function. */
+/* INPUT: omega_matter -- Density of CDM, baryons, and massive neutrinos,
+				in units of the critical density. */
+/* 	  omega_baryon -- Density of baryons, in units of critical. */
+/* 	  omega_hdm    -- Density of massive neutrinos, in units of critical */
+/* 	  degen_hdm    -- (Int) Number of degenerate massive neutrino species */
+/*        omega_lambda -- Cosmological constant */
+/* 	  hubble       -- Hubble constant, in units of 100 km/s/Mpc */
+/*        redshift     -- The redshift at which to evaluate */
+/* OUTPUT: Returns 0 if all is well, 1 if a warning was issued.  Otherwise,
+	sets many global variables for use in TFmdm_onek_mpc() */
+{
+    double z_drag_b1, z_drag_b2, omega_denom;
+    int qwarn;
+    qwarn = 0;
+
+    theta_cmb = 2.728/2.7;	/* Assuming T_cmb = 2.728 K */
+
+    /* Look for strange input */
+    if (omega_baryon<0.0) {
+	fprintf(stderr,
+	  "TFmdm_set_cosm(): Negative omega_baryon set to trace amount.\n");
+	qwarn = 1;
+    }
+    if (omega_hdm<0.0) {
+	fprintf(stderr,
+	  "TFmdm_set_cosm(): Negative omega_hdm set to trace amount.\n");
+	qwarn = 1;
+    }
+    if (hubble<=0.0) {
+	fprintf(stderr,"TFmdm_set_cosm(): Negative Hubble constant illegal.\n");
+	exit(1);  /* Can't recover */
+    } else if (hubble>2.0) {
+	fprintf(stderr,"TFmdm_set_cosm(): Hubble constant should be in units of 100 km/s/Mpc.\n");
+	qwarn = 1;
+    }
+    if (redshift<=-1.0) {
+	fprintf(stderr,"TFmdm_set_cosm(): Redshift < -1 is illegal.\n");
+	exit(1);
+    } else if (redshift>99.0) {
+	fprintf(stderr,
+	  "TFmdm_set_cosm(): Large redshift entered.  TF may be inaccurate.\n");
+	qwarn = 1;
+    }
+    if (degen_hdm<1) degen_hdm=1;
+    num_degen_hdm = (double) degen_hdm;	
+	/* Have to save this for TFmdm_onek_mpc() */
+    /* This routine would crash if baryons or neutrinos were zero, 
+	so don't allow that */
+    if (omega_baryon<=0) omega_baryon=1e-5;
+    if (omega_hdm<=0) omega_hdm=1e-5;
+
+    omega_curv = 1.0-omega_matter-omega_lambda;
+    omhh = omega_matter*SQR(hubble);
+    obhh = omega_baryon*SQR(hubble);
+    onhh = omega_hdm*SQR(hubble);
+    f_baryon = omega_baryon/omega_matter;
+    f_hdm = omega_hdm/omega_matter;
+    f_cdm = 1.0-f_baryon-f_hdm;
+    f_cb = f_cdm+f_baryon;
+    f_bnu = f_baryon+f_hdm;
+
+    /* Compute the equality scale. */
+    z_equality = 25000.0*omhh/SQR(SQR(theta_cmb));	/* Actually 1+z_eq */
+    k_equality = 0.0746*omhh/SQR(theta_cmb);
+
+    /* Compute the drag epoch and sound horizon */
+    z_drag_b1 = 0.313*pow(omhh,-0.419)*(1+0.607*pow(omhh,0.674));
+    z_drag_b2 = 0.238*pow(omhh,0.223);
+    z_drag = 1291*pow(omhh,0.251)/(1.0+0.659*pow(omhh,0.828))*
+		(1.0+z_drag_b1*pow(obhh,z_drag_b2));
+    y_drag = z_equality/(1.0+z_drag);
+
+    sound_horizon_fit = 44.5*log(9.83/omhh)/sqrt(1.0+10.0*pow(obhh,0.75));
+
+    /* Set up for the free-streaming & infall growth function */
+    p_c = 0.25*(5.0-sqrt(1+24.0*f_cdm));
+    p_cb = 0.25*(5.0-sqrt(1+24.0*f_cb));
+
+    omega_denom = omega_lambda+SQR(1.0+redshift)*(omega_curv+
+			omega_matter*(1.0+redshift));
+    omega_lambda_z = omega_lambda/omega_denom;
+    omega_matter_z = omega_matter*SQR(1.0+redshift)*(1.0+redshift)/omega_denom;
+    growth_k0 = z_equality/(1.0+redshift)*2.5*omega_matter_z/
+	    (pow(omega_matter_z,4.0/7.0)-omega_lambda_z+
+	    (1.0+omega_matter_z/2.0)*(1.0+omega_lambda_z/70.0));
+    growth_to_z0 = z_equality*2.5*omega_matter/(pow(omega_matter,4.0/7.0)
+	    -omega_lambda + (1.0+omega_matter/2.0)*(1.0+omega_lambda/70.0));
+    growth_to_z0 = growth_k0/growth_to_z0;	
+    
+    /* Compute small-scale suppression */
+    alpha_nu = f_cdm/f_cb*(5.0-2.*(p_c+p_cb))/(5.-4.*p_cb)*
+	pow(1+y_drag,p_cb-p_c)*
+	(1+f_bnu*(-0.553+0.126*f_bnu*f_bnu))/
+	(1-0.193*sqrt(f_hdm*num_degen_hdm)+0.169*f_hdm*pow(num_degen_hdm,0.2))*
+	(1+(p_c-p_cb)/2*(1+1/(3.-4.*p_c)/(7.-4.*p_cb))/(1+y_drag));
+    alpha_gamma = sqrt(alpha_nu);
+    beta_c = 1/(1-0.949*f_bnu);
+    /* Done setting scalar variables */
+    hhubble = hubble;	/* Need to pass Hubble constant to TFmdm_onek_hmpc() */
+    return qwarn;
+}
+
+/* ---------------------------- TFmdm_onek_mpc() ---------------------- */
+
+double TFmdm_onek_mpc(double kk)
+/* Given a wavenumber in Mpc^-1, return the transfer function for the
+cosmology held in the global variables. */
+/* Input: kk -- Wavenumber in Mpc^-1 */
+/* Output: The following are set as global variables:
+	growth_cb -- the transfer function for density-weighted
+			CDM + Baryon perturbations. 
+ 	growth_cbnu -- the transfer function for density-weighted
+			CDM + Baryon + Massive Neutrino perturbations. */
+/* The function returns growth_cb */
+{
+    double tf_sup_L, tf_sup_C;
+    double temp1, temp2;
+
+    qq = kk/omhh*SQR(theta_cmb);
+
+    /* Compute the scale-dependent growth functions */
+    y_freestream = 17.2*f_hdm*(1+0.488*pow(f_hdm,-7.0/6.0))*
+		SQR(num_degen_hdm*qq/f_hdm);
+    temp1 = pow(growth_k0, 1.0-p_cb);
+    temp2 = pow(growth_k0/(1+y_freestream),0.7);
+    growth_cb = pow(1.0+temp2, p_cb/0.7)*temp1;
+    growth_cbnu = pow(pow(f_cb,0.7/p_cb)+temp2, p_cb/0.7)*temp1;
+
+    /* Compute the master function */
+    gamma_eff =omhh*(alpha_gamma+(1-alpha_gamma)/
+		(1+SQR(SQR(kk*sound_horizon_fit*0.43))));
+    qq_eff = qq*omhh/gamma_eff;
+
+    tf_sup_L = log(2.71828+1.84*beta_c*alpha_gamma*qq_eff);
+    tf_sup_C = 14.4+325/(1+60.5*pow(qq_eff,1.11));
+    tf_sup = tf_sup_L/(tf_sup_L+tf_sup_C*SQR(qq_eff));
+
+    qq_nu = 3.92*qq*sqrt(num_degen_hdm/f_hdm);
+    max_fs_correction = 1+1.2*pow(f_hdm,0.64)*pow(num_degen_hdm,0.3+0.6*f_hdm)/
+		(pow(qq_nu,-1.6)+pow(qq_nu,0.8));
+    tf_master = tf_sup*max_fs_correction;
+
+    /* Now compute the CDM+HDM+baryon transfer functions */
+    tf_cb = tf_master*growth_cb/growth_k0;
+    tf_cbnu = tf_master*growth_cbnu/growth_k0;
+    return tf_cb;
+}
+
+/* ---------------------------- TFmdm_onek_hmpc() ---------------------- */
+
+double TFmdm_onek_hmpc(double kk)
+/* Given a wavenumber in h Mpc^-1, return the transfer function for the
+cosmology held in the global variables. */
+/* Input: kk -- Wavenumber in h Mpc^-1 */
+/* Output: The following are set as global variables:
+	growth_cb -- the transfer function for density-weighted
+			CDM + Baryon perturbations. 
+ 	growth_cbnu -- the transfer function for density-weighted
+			CDM + Baryon + Massive Neutrino perturbations. */
+/* The function returns growth_cb */
+{
+    return TFmdm_onek_mpc(kk*hhubble);
+}
+
+
Index: /tags/V1_0/Cosmo/SimLSS/hu_power.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/hu_power.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/hu_power.h	(revision 3382)
@@ -0,0 +1,17 @@
+#ifndef HU_POWER_SEEN
+#define HU_POWER_SEEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
+	int degen_hdm, double omega_lambda, double hubble, double redshift);
+double TFmdm_onek_mpc(double kk);
+double TFmdm_onek_hmpc(double kk);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HU_POWER_SEEN
Index: /tags/V1_0/Cosmo/SimLSS/hu_sigma8.c
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/hu_sigma8.c	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/hu_sigma8.c	(revision 3382)
@@ -0,0 +1,526 @@
+/* Code to calculate sigma8 for COBE-normalized CDM and MDM models, 
+using the approximation of Eisenstein & Hu (1997). */
+
+/* This code will calculate sigma_8 and other quantities for CDM and
+MDM models.  Because the fitting form for the transfer function does not
+include the baryon oscillations, the answer will not be accurate for
+large baryon fractions.  The COBE normalization is from the papers
+on Bunn & White (1997) and Hu & White (1997). */
+
+/* Accuracy is generally better than 5%.  Recall that the COBE normalization
+is only 7% accurate (1-sigma).  This program gives low answers compared to
+CMBfast for lower values of Omega_0*h^2, and vice versa for higher values. 
+Values of Omega_0 near 0.2 can produce answers that are 5% low. */
+
+/* The integrator used here is a bit crude, but suffices for rapid
+10^-3 accuracy.  You could get better performance by substituting an
+integrator from a numerical package.  See the end of the file for details. */
+
+/* This program uses the routines TFmdm_set_cosm() and TFmdm_onek_hmpc(),
+available from http://www.sns.ias.edu/~whu/power/power.html in the file
+power.c.  To compile this program, you'll need that file as well, e.g.
+	cc -O sigma8.c power.c -o sigma8 -lm 		*/
+
+/* Lists of versions and bugs:
+v1.0 -- 10/23/97 -- Original release version.
+v1.1 -- 11/13/97 -- We correct a missing factor of omega_m in the
+		    conversion between mass and length scales [lines
+		    32 and 34 of main()].  This only affects the results 
+		    if you explicitly used the -mass option.
+v1.2 -- 04/08/98 -- We correct a typo in the second-order tilt scaling
+		    of the COBE normalization for flat models with tensors.
+v1.3 -- 09/15/98 -- We correct a typo in the tilt scaling of the COBE
+		    normalization for open models with tensors.
+v1.4 -- 12/02/98 -- We correct the COBE normalization for tilted open models,
+		    undoing the change of v1.3 and fixing what was
+		    wrong there to begin with.
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
+	int degen_hdm, double omega_lambda, double hubble, double redshift);
+double TFmdm_onek_hmpc(double kk);
+
+double sig2tophat(double x);
+double sig2gauss(double x);
+double sig2sharpk(double x);
+double sig2tophatnu(double x);
+double sig2gaussnu(double x);
+double sig2sharpknu(double x);
+
+#define WEIRD  -2538	/* A strange number, unlikely to be entered */
+#define RHOCRIT 2.78e11	/* The critical density, for h=1, in Msun/Mpc^3 */
+
+/* Convenience from Numerical Recipes in C, 2nd edition
+------------ COMPLETEMENT DEBILE (cmv) ????????? ------------
+static double sqrarg;
+#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
+*/
+#define SQR(a) (a*a)
+
+/* Global variable */
+double   omega_m, omega_b, omega_n, 
+	numdegen, lambda, redshift, 
+	hubble, scale, mass, tilt;
+double   deltaH;		/* COBE-normalization */
+double   sig2_scale;	/* For passing a length scale to the integrator */
+int 	qtensors, quiet, qredshift;
+
+/* ========================== User interaction routines ============== */
+void usage()
+/* Print out information about the allowed options and then quit. */
+{
+    fprintf(stderr,"Command line options:\n");
+    fprintf(stderr,"-om or -omega <omega_matter, including CDM, baryons, massive neutrinos>\n");
+    fprintf(stderr,"-ob <omega_baryon> -fb <baryon_fraction>\n");
+    fprintf(stderr,"-on <omega_neutrino> -fn <neutrino_fraction>\n");
+    fprintf(stderr,"-numdegen or -Nnu <number of degenerate neutrino species>, default 1\n");
+    fprintf(stderr,"-lambda <omega_lambda> -flat (choose lambda appropriately)\n");
+    fprintf(stderr,"-h or -hubble <H_0, units of 100 km/s/Mpc>\n");
+    fprintf(stderr,"-H or -Hubble <H_0, units of 1 km/s/Mpc>\n");
+    fprintf(stderr,"-tilt or -n <scalar spectral tilt>, no tensors.\n");
+    fprintf(stderr,"-Tilt or -N <scalar spectral tilt>, power-law tensors.\n");
+    fprintf(stderr,"-z <redshift>, if none given then appropriate value assumed.\n");
+    fprintf(stderr,"The following request the rms fluctuations inside a tophat window function:\n");
+    fprintf(stderr,"-scale <comoving length scale, h^-1 Mpc>\n");
+    fprintf(stderr,"-mass <mass scale, h^-1 Msun>\n");
+    fprintf(stderr,"If neither -scale or -mass is given, sigma_8 and other quantities are computed.\n");
+    fprintf(stderr,"-quiet (print only answer to stdout)\n");
+    exit(1);
+    return;
+}
+
+void crash(char *s)
+{
+    fprintf(stderr,"%s\n", s); exit(1); return;
+}
+
+void warn(char *s)
+{
+    fprintf(stderr,"%s\n", s); return;
+}
+
+
+void parse_command_line(int argc, char *argv[])
+/* Parse the command line, and look for illegal entries */
+{
+    int i;
+    if (argc==1) usage();
+    i = 1;
+    omega_m = 1.0;
+    omega_b = 0.05;
+    omega_n = 0.0;
+    numdegen = 1.0;
+    lambda = 0.0;
+    redshift = 0.0;
+    hubble = 0.5;
+    scale = -1.0;
+    mass = -1.0;
+    qtensors = 0;
+    quiet = 0;
+    tilt = 1.0;
+    qredshift = 0;
+
+    while (i<argc) {
+	if (!strcmp(argv[i],"-om")||!strcmp(argv[i],"-omega")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&omega_m); ++i;
+	} else if (!strcmp(argv[i],"-ob")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&omega_b); ++i;
+	} else if (!strcmp(argv[i],"-fb")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&omega_b); ++i;
+	    omega_b *= -1.0;	/* Signal that a fraction was desired */
+	} else if (!strcmp(argv[i],"-on")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&omega_n); ++i;
+	} else if (!strcmp(argv[i],"-fn")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&omega_n); ++i;
+	    omega_n *= -1.0;	/* Signal that a fraction was desired */
+	} else if (!strcmp(argv[i],"-h")||!strcmp(argv[i],"-hubble")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&hubble); ++i;
+	} else if (!strcmp(argv[i],"-H")||!strcmp(argv[i],"-Hubble")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&hubble); ++i;
+	    hubble /= 100.0;	/* Units were 1 km/s/Mpc */
+	} else if (!strcmp(argv[i],"-lambda")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&lambda); ++i;
+	} else if (!strcmp(argv[i],"-flat")) {
+	    ++i;
+	    lambda = WEIRD;
+	} else if (!strcmp(argv[i],"-numdegen")||!strcmp(argv[i],"-Nnu")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&numdegen); ++i;
+	} else if (!strcmp(argv[i],"-n")||!strcmp(argv[i],"-tilt")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&tilt); ++i;
+	    qtensors = 0;
+	} else if (!strcmp(argv[i],"-N")||!strcmp(argv[i],"-Tilt")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&tilt); ++i;
+	    qtensors = 1;
+	} else if (!strcmp(argv[i],"-z")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&redshift); ++i;
+	    qredshift = 1;
+	} else if (!strcmp(argv[i],"-scale")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&scale); ++i;
+	} else if (!strcmp(argv[i],"-mass")) {
+	    ++i;
+	    if (i>=argc) usage();
+	    sscanf(argv[i],"%lf",&mass); ++i;
+	} else if (!strcmp(argv[i],"-quiet")) {
+	    ++i;
+	    quiet = 1;
+	} else usage();
+    }
+
+    /* Look for illegal entries */
+    if (omega_m<=0.0) crash("Omega must be positive.");
+    if (hubble<=0.0) crash("Hubble constant must be positive.");
+	else if (hubble>10.0) warn("Did you get the Hubble units right?");
+    if (numdegen<0) {
+	warn("Negative number of degenerate species reset to 1.");
+	numdegen = 1.0;
+    }
+    if (redshift<=-1.0) crash("Redshift must exceed -1.");
+    if (scale>0.0 && mass>0.0) {
+	warn("Input length OR mass scale.  Defaulting to length.");
+	mass = -1.0;
+    }
+
+    /* Now look for fractions, if they were input. */
+    if (omega_b<0.0) omega_b = omega_m*(-omega_b);	
+    if (omega_n<0.0) omega_n = omega_m*(-omega_n);	
+    if (lambda== WEIRD) lambda = 1-omega_m;	/* Set to be flat */
+
+    if (omega_b+omega_n>omega_m) crash("Baryons + Neutrinos exceeds Omega_0.");
+	else if (omega_b+omega_n>0.6*omega_m) 
+	    warn("CDM fraction is below range of TF fitting formula.");
+    if (tilt>1.3 || tilt < 0.7) 
+	warn("Tilt out of range of Bunn and White fitting formula.");
+    if (tilt!=1 && (omega_m<0.2 || omega_m>1.0)) 
+	warn("Omega out of range of Bunn and White fitting formula.");
+    if (tilt==1 && (omega_m<0.2 || omega_m>1.6 || lambda<0.0 || lambda>0.8))
+	warn("Omega or Lambda out of range of Bunn and White fitting formula.");
+    if (qtensors!=0&&(tilt>1.0||
+	(fabs(lambda)>1e-5&&fabs(1.0-omega_m-lambda)>1e-5))) 
+	crash("Tensor formulae only hold for tilts < 1 and simple cosmologies.");
+    if (omega_b/omega_m>0.4) warn("Baryon oscillations will be large.  TF fitting form will be inaccurate.");
+    if (omega_n/omega_m>0.4) warn("Neutrino fraction outside of range of TF fitting form.");
+    if (omega_m*hubble*hubble>0.4) warn("Omega_0 h^2 outside of range of TF fitting form.");
+    if (omega_m*hubble*hubble<0.06) warn("Omega_0 h^2 outside of range of TF fitting form.");
+    if (redshift>29) warn("Redshift is higher than range of TF fitting form.");
+
+    return;
+}
+
+/* ==================================== MAIN() ========================= */
+
+void main(int argc, char *argv[])
+{
+    double erfcc(double x);
+    double sigma, sigma8;
+    extern double growth_to_z0, z_equality, alpha_nu, beta_c;
+    double cobenorm();
+    double integrate(double (*func)(double));
+    parse_command_line(argc, argv);
+
+    /* Set all the background quantities */
+    TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda, 
+			hubble, redshift);
+    deltaH = cobenorm();
+
+    if (!quiet) {	/* Echo cosmological information to the screen */
+	printf("Omega_0  = %5.3f, Omega_baryon = %5.3f, Omega_neutrino = %5.3f\n",
+		omega_m, omega_b, omega_n);
+	printf("Hubble   = %5.3f, Lambda       = %5.3f, N_neutrinos    = %d\n",
+		hubble, lambda, (int) numdegen);
+	printf("Redshift = %5.3f, Growth = %6.4f relative to z=0\n",
+		redshift, growth_to_z0);
+	printf("Tilt     = %5.3f, COBE normalization: deltaH = %8.3e",
+		tilt, deltaH);
+	if (tilt!=1.0) 
+	    if (qtensors) printf(" with tensors.\n");
+	    else printf(" without tensors.\n");
+	else printf("\n");
+    }
+    /* If we've been asked to compute for a particular scale, do that */
+    if (scale>0 || mass>0) {
+	if (mass<0)
+	    mass = 4.0*M_PI/3.0*omega_m*RHOCRIT*scale*scale*scale;
+	else if (scale<0) 
+	    scale = pow(3.0/4.0/M_PI/RHOCRIT/omega_m*mass, 1.0/3.0);
+	/* Integrate tophat for the given scale */
+	sig2_scale = scale;
+	sigma = sqrt(integrate(sig2tophatnu));
+
+	/* Print out the result */
+	if (!quiet) printf("For length scale %6.4f h^-1 Mpc, mass scale %8.3e h^-1 Msun.\nrms tophat fluctuations are ",
+		sig2_scale, mass);
+	printf("%6.4f\n", sigma);
+    } else {	
+	/* No scale was requested, so we do the standard tasks */
+	/* Calculate sigma_8 */
+	sig2_scale = 8.0;	
+	sigma8 = sqrt(integrate(sig2tophatnu));
+	if (quiet) {
+	    printf("%6.4f\n", sigma8);
+	    return;	/* This is all we're doing */
+	}
+	printf("Sigma_8  = %6.4f\n", sigma8);
+
+	/* Calculate sigma_50 */
+	sig2_scale = 50.0;
+	sigma = sqrt(integrate(sig2tophatnu));
+	printf("Sigma_50 = %6.4f   Sigma_50/sigma_8 = %6.4f\n",
+		sigma, sigma/sigma8);
+
+	/* We default to z=4 for DLA */
+	if (!qredshift) {
+	    redshift = 4.0;		
+	    TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda, 
+			hubble, redshift);
+	}
+	sig2_scale = 50.0/100.0/sqrt(1+redshift)/sqrt(2*3.14159)*
+		pow(8.0*3.14159/3.0/sqrt(89.0),1./3.);
+	sigma = sqrt(integrate(sig2gaussnu));
+	printf("Omega_gas = %8.3e at redshift %5.3f due to \n   sigma(50 km/s) = sigma(%5.3f h^-1 Mpc) = %6.4f (DLA, Klypin et al. 1994)\n", 
+	    omega_b*erfcc(1.33/1.414/sigma), redshift, sig2_scale, sigma);
+
+	/* We default to z=3 for Lyman alpha forest */
+	if (!qredshift) {
+	    redshift = 3.0;		
+	    TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda, 
+			hubble, redshift);
+	}
+	sig2_scale = 1.0/(34.0*sqrt(omega_m/2.0));	/* Gnedin's k_34 */
+	sigma = sqrt(integrate(sig2gauss));
+	printf("Sigma_Lya = %6.4f at redshift %5.3f (Ly-alpha forest, Gnedin 1997)\n", 
+		sigma, redshift);
+
+	printf("Small-scale: alpha_nu = %6.4f, beta_c = %6.4f\n", 
+		alpha_nu, beta_c);
+    }
+    return;
+}
+
+/* ========================== Integration Kernals ======================= */
+
+double W2tophat(double x)
+/* The square of the tophat window */
+{
+    double j1onx;
+    if (x<0.03) 
+	j1onx = (1.0/3.0-x*x*1.0/30.0);
+    else j1onx = (cos(x)-sin(x)/x)/x/x;
+    return 9.0*j1onx*j1onx;
+}
+
+double sig2tophat(double x)
+/* This is the integrand for the mass fluctuation integral
+sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
+broken and recombined so that one integrates on (0,1] in a new variable x. */
+/* Here, the window is a real-space tophat of radius sig2_scale, the
+latter being passed from outside in units of h^-1 Mpc */
+{
+    double powerspcb(double k);
+    return (powerspcb(x/sig2_scale)*W2tophat(x)+
+ 	    powerspcb(1.0/x/sig2_scale)*W2tophat(1.0/x))/x;
+}
+
+double sig2tophatnu(double x)
+/* Same as sig2tophat(), but with P_cbnu */
+{
+    double powerspcbnu(double k);
+    return (powerspcbnu(x/sig2_scale)*W2tophat(x)+
+ 	    powerspcbnu(1.0/x/sig2_scale)*W2tophat(1.0/x))/x;
+}
+
+double sig2gauss(double x)
+/* This is the integrand for the mass fluctuation integral
+sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
+broken and recombined so that one integrates on (0,1] in a new variable x. */
+/* Here, the window is a gaussian of radius sig2_scale, the
+latter being passed from outside in units of h^-1 Mpc */
+{
+    double powerspcb(double k);
+    return (powerspcb(x/sig2_scale)*exp(-x*x)+
+ 	    powerspcb(1.0/x/sig2_scale)*exp(-1.0/x/x))/x;
+}
+
+double sig2gaussnu(double x)
+/* Same as sig2gauss(), but with P_cbnu */
+{
+    double powerspcbnu(double k);
+    return (powerspcbnu(x/sig2_scale)*exp(-x*x)+
+ 	    powerspcbnu(1.0/x/sig2_scale)*exp(-1.0/x/x))/x;
+}
+
+double sig2sharpk(double x)
+/* This is the integrand for the mass fluctuation integral
+sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
+broken and recombined so that one integrates on (0,1] in a new variable x. */
+/* Here, the window is a k-space tophat of radius 1/sig2_scale, the
+latter being passed from outside in units of h^-1 Mpc */
+{
+    double powerspcb(double k);
+    return (powerspcb(x/sig2_scale))/x;
+}
+
+double sig2sharpknu(double x)
+/* Same as sig2sharpk(), but with P_cbnu */
+{
+    double powerspcbnu(double k);
+    return (powerspcbnu(x/sig2_scale))/x;
+}
+
+/* ============================ Power Spectrum and COBE ================ */
+double powerspcbnu(double k)
+/* Returns Delta^2(k), COBE-normalized, based on the approximations of 
+Eisenstein & Hu (1997).  k is in h^-1 Mpc. */
+/* TFmdm_set_cosm() and cobenorm() must have been called before this */
+/* Returns the density-weighted CDM+Baryon+Neutrino power spectrum */
+{
+    extern double tf_cbnu, growth_to_z0;
+    TFmdm_onek_hmpc(k);  /* This sets the value in tf_cbnu */
+    return pow(2997.0*k, tilt+3.0)*SQR(deltaH*tf_cbnu*growth_to_z0);
+}
+
+double powerspcb(double k)
+/* Returns Delta^2(k), COBE-normalized, based on the approximations of 
+Eisenstein & Hu (1997).  k is in h^-1 Mpc. */
+/* TFmdm_set_cosm() and cobenorm() must have been called before this */
+/* Returns the density-weighted CDM+Baryon power spectrum */
+{
+    extern double growth_to_z0;
+    return pow(2997.0*k, tilt+3.0)*SQR(deltaH*TFmdm_onek_hmpc(k)*growth_to_z0); 
+}
+
+double cobenorm()
+/* Return the Bunn & White (1997) fit for delta_H */
+/* Given lambda, omega_m, qtensors, and tilt */
+/* Open model with tensors is from Hu & White */
+{
+    double n;
+    n = tilt-1;
+    if (fabs(omega_m+lambda-1.0)<1e-5) {	/* Flat universe */
+	if (qtensors) 
+	    return 1.94e-5*pow(omega_m, -0.785-0.05*log(omega_m))*
+		exp(n+1.97*n*n);
+	else return 1.94e-5*pow(omega_m, -0.785-0.05*log(omega_m))*
+		exp(-0.95*n-0.169*n*n);
+	/* Error -- was 0.0169 in earlier version of code */
+    } else if (fabs(lambda)<1e-5) {	/* No lambda */
+	if (qtensors)
+	    return 1.95e-5*pow(omega_m,-0.35-0.19*log(omega_m)-0.15*n)*
+		exp(+1.02*n+1.7*n*n);
+	 /* Error -- was exp(-1.02n-1.7*n*n) in earlier version (v1-1.3)*/
+	else return 1.95e-5*pow(omega_m, -0.35-0.19*log(omega_m)-0.17*n)*
+		exp(-n-0.14*n*n);
+	 /* Error -- was exp(-n-0.14*n*n) in earlier version (v1-1.2)*/
+	 /* Error -- was exp(n+0.14*n*n) in earlier version (v1.3) */
+    } else return 1e-5*(2.422-1.166*exp(omega_m)+0.800*exp(lambda)
+	+3.780*omega_m-2.267*omega_m*exp(lambda)+0.487*SQR(omega_m)+
+	0.561*lambda+3.329*lambda*exp(omega_m)-8.568*omega_m*lambda+
+	1.080*SQR(lambda));
+}
+
+/* The following routine is from Numerical Recipes in C, 2nd edition,
+by Press, Teulkolsky, Vetterling, and Flannery, (Cambridge Univ. Press) */
+double erfcc(double x)
+{
+	double t,z,ans;
+	z=fabs(x);
+	t=1.0/(1.0+0.5*z);
+	ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
+		t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
+		t*(-0.82215223+t*0.17087277)))))))));
+	return x >= 0.0 ? ans : 2.0-ans;
+}
+
+/* ======================= Integration Engine ======================= */
+
+double midpoint_int(double (*func)(double))
+/* Integrate the function func() on the range (0,1] */
+/* Use midpoint rule, expanding by factor of 3 each time */
+/* Linearly extrapolate to zero stepsize.  Not fancy */
+{
+    int iter, bins, j;
+    double width, xeval, sum[11];
+
+    sum[0] = (*func)(0.5);	/* First step is easy */
+    bins = 1; width = 1.0;
+    for (iter=1; iter<11; iter++) {	/* Now start increasing the bins */
+	bins *= 3;
+	width /= 3.0;
+	sum[iter]=0.0;
+	for (xeval=width/2.0,j=1;j<=bins;xeval+=width,j++) {
+	    if (j%3==2) continue;	/* We've already done this one */
+	    sum[iter]+=(*func)(xeval);
+	}
+	/* Add the new evaluations to the old ones. */
+	sum[iter]=sum[iter]*width+sum[iter-1]/3.0;
+	/* printf("%d iteration, sum = %f\n", iter, sum[iter]); */
+	/* Now decide if we're done */
+	if (iter<4) continue;	/* We certainly want to do some work */
+	/* If error scales as width^2, then linear extrapolation in
+	quantity width^2 is sum[iter]+(sum[iter]-sum[iter-1])/8.0 */
+	if (fabs( (sum[iter]+(sum[iter]-sum[iter-1])/8.0)/
+		  (sum[iter-1]+(sum[iter-1]-sum[iter-2])/8.0)-1.0)<1e-4) 
+	    return sum[iter]+(sum[iter]-sum[iter-1])/8.0;
+	/* if (fabs(sum[iter-1]/sum[iter]-1)<1e-4) return sum[iter];  */
+    }
+    crash("Too many steps in the integration.");
+}
+
+double integrate(double (*func)(double))
+/* Integrate the function func() on the range (0,1] */
+{
+    double midpoint_int(double (*func)(double));
+    return midpoint_int(func);
+}
+
+/* The above is a simple integrator.  You could get faster execution times
+by using a more accurate integrator.  The following is an example from 
+Numerical Recipes, but all that is needed is for the call to integrate()
+to return the value of func() integrated on the range (0,1]. */
+
+#ifdef YES_NR
+#include "qromo.c"
+#include "midpnt.c"
+#include "polint.c"
+#include "nrutil.c"
+
+float integrate(float (*func)(float))
+/* Integrate the function func() on the range (0,1] */
+{
+    float qromo(float (*func)(float), float a, float b,
+	float (*choose)(float(*)(float),float,float,int));
+    float midpnt(float (*func)(float), float a, float b, int n);
+    return qromo(func,0,1,midpnt);
+}
+#endif
+
Index: /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.c
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.c	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.c	(revision 3382)
@@ -0,0 +1,358 @@
+/* The following routines implement all of the fitting formulae in 
+Eisenstein \& Hu (1997) */
+
+/* There are two sets of routines here.  The first set,
+
+	TFfit_hmpc(), TFset_parameters(), and TFfit_onek(),
+
+calculate the transfer function for an arbitrary CDM+baryon universe using
+the fitting formula in Section 3 of the paper.  The second set,
+
+	TFsound_horizon_fit(), TFk_peak(), TFnowiggles(), and TFzerobaryon(),
+
+calculate other quantities given in Section 4 of the paper. */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void TFset_parameters(double omega0hh, double f_baryon, double Tcmb);
+double TFfit_onek(double k, double *tf_baryon, double *tf_cdm); 
+
+void TFfit_hmpc(double omega0, double f_baryon, double hubble, double Tcmb,
+	int numk, double *k, double *tf_full, double *tf_baryon, double *tf_cdm);
+
+double TFsound_horizon_fit(double omega0, double f_baryon, double hubble);
+double TFk_peak(double omega0, double f_baryon, double hubble);
+double TFnowiggles(double omega0, double f_baryon, double hubble, 
+		double Tcmb, double k_hmpc);
+double TFzerobaryon(double omega0, double hubble, double Tcmb, double k_hmpc);
+
+/* ------------------------ DRIVER ROUTINE --------------------------- */
+/* The following is an example of a driver routine you might use. */
+/* Basically, the driver routine needs to call TFset_parameters() to
+set all the scalar parameters, and then call TFfit_onek() for each 
+wavenumber k you desire. */
+
+/* While the routines use Mpc^-1 units internally, this driver has been
+written to take an array of wavenumbers in units of h Mpc^-1.  On the
+other hand, if you want to use Mpc^-1 externally, you can do this by
+altering the variables you pass to the driver:  
+	omega0 -> omega0*hubble*hubble, hubble -> 1.0 		*/
+
+/* INPUT: omega0 -- the matter density (baryons+CDM) in units of critical 
+	  f_baryon -- the ratio of baryon density to matter density 
+	  hubble -- the Hubble constant, in units of 100 km/s/Mpc
+	  Tcmb -- the CMB temperature in Kelvin. T<=0 uses the COBE value 2.728.
+	  numk -- the length of the following zero-offset array
+	  k[] -- the array of wavevectors k[0..numk-1]  */
+
+/* INPUT/OUTPUT: There are three output arrays of transfer functions. 
+All are zero-offset and, if used, must have storage [0..numk-1] declared
+in the calling program.  However, if you substitute the NULL pointer for
+one or more of the arrays, then that particular transfer function won't
+be outputted. The transfer functions are:
+
+	tf_full[] -- The full fitting formula, eq. (16), for the matter
+			transfer function. 
+	tf_baryon[] -- The baryonic piece of the full fitting formula, eq. 21.
+	tf_cdm[] -- The CDM piece of the full fitting formula, eq. 17. */
+
+/* Again, you can set these pointers to NULL in the function call if
+you don't want a particular output. */
+
+/* Various intermediate scalar quantities are stored in global variables, 
+so that you might more easily access them.  However, this also means that
+you would be better off not simply #include'ing this file in your programs,
+but rather compiling it separately, calling only the driver, and using
+extern declarations to access the intermediate quantities. */
+
+/* ----------------------------- DRIVER ------------------------------- */
+
+void TFfit_hmpc(double omega0, double f_baryon, double hubble, double Tcmb,
+	int numk, double *k, double *tf_full, double *tf_baryon, double *tf_cdm)
+/* Remember: k[0..numk-1] is in units of h Mpc^-1. */
+{
+    int j;
+    double tf_thisk, baryon_piece, cdm_piece;
+
+    TFset_parameters(omega0*hubble*hubble, f_baryon, Tcmb);
+
+    for (j=0;j<numk;j++) {
+    	tf_thisk = TFfit_onek(k[j]*hubble, &baryon_piece, &cdm_piece); 
+	if (tf_full!=NULL) tf_full[j] = tf_thisk;
+	if (tf_baryon!=NULL) tf_baryon[j] = baryon_piece;
+	if (tf_cdm!=NULL) tf_cdm[j] = cdm_piece;
+    }
+    return;
+}
+
+/* ------------------------ FITTING FORMULAE ROUTINES ----------------- */
+
+/* There are two routines here.  TFset_parameters() sets all the scalar
+parameters, while TFfit_onek() calculates the transfer function for a 
+given wavenumber k.  TFfit_onek() may be called many times after a single
+call to TFset_parameters() */
+
+/* Global variables -- We've left many of the intermediate results as 
+global variables in case you wish to access them, e.g. by declaring
+them as extern variables in your main program. */
+/* Note that all internal scales are in Mpc, without any Hubble constants! */
+
+double	omhh,		/* Omega_matter*h^2 */
+	obhh,		/* Omega_baryon*h^2 */
+	theta_cmb,	/* Tcmb in units of 2.7 K */
+	z_equality,	/* Redshift of matter-radiation equality, really 1+z */
+	k_equality,	/* Scale of equality, in Mpc^-1 */
+	z_drag,		/* Redshift of drag epoch */
+	R_drag,		/* Photon-baryon ratio at drag epoch */
+	R_equality,	/* Photon-baryon ratio at equality epoch */
+	sound_horizon,	/* Sound horizon at drag epoch, in Mpc */
+	k_silk,		/* Silk damping scale, in Mpc^-1 */
+	alpha_c,	/* CDM suppression */
+	beta_c,		/* CDM log shift */
+	alpha_b,	/* Baryon suppression */
+	beta_b,		/* Baryon envelope shift */
+	beta_node,	/* Sound horizon shift */
+	k_peak,		/* Fit to wavenumber of first peak, in Mpc^-1 */
+	sound_horizon_fit,	/* Fit to sound horizon, in Mpc */
+	alpha_gamma;	/* Gamma suppression in approximate TF */
+
+/* Convenience from Numerical Recipes in C, 2nd edition
+------------ COMPLETEMENT DEBILE (cmv) ????????? ------------
+static double sqrarg;
+#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
+static double cubearg;
+#define CUBE(a) ((cubearg=(a)) == 0.0 ? 0.0 : cubearg*cubearg*cubearg)
+static double pow4arg;
+#define POW4(a) ((pow4arg=(a)) == 0.0 ? 0.0 : pow4arg*pow4arg*pow4arg*pow4arg)
+	Yes, I know the last one isn't optimal; it doesn't appear much */
+#define SQR(a) (a*a)
+#define CUBE(a) (a*a*a)
+#define POW4(a) (a*a*a*a)
+
+void TFset_parameters(double omega0hh, double f_baryon, double Tcmb)
+/* Set all the scalars quantities for Eisenstein & Hu 1997 fitting formula */
+/* Input: omega0hh -- The density of CDM and baryons, in units of critical dens,
+		multiplied by the square of the Hubble constant, in units
+		of 100 km/s/Mpc */
+/* 	  f_baryon -- The fraction of baryons to CDM */
+/*        Tcmb -- The temperature of the CMB in Kelvin.  Tcmb<=0 forces use
+			of the COBE value of  2.728 K. */
+/* Output: Nothing, but set many global variables used in TFfit_onek(). 
+You can access them yourself, if you want. */
+/* Note: Units are always Mpc, never h^-1 Mpc. */
+{
+    double z_drag_b1, z_drag_b2;
+    double alpha_c_a1, alpha_c_a2, beta_c_b1, beta_c_b2, alpha_b_G, y;
+
+    if (f_baryon<=0.0 || omega0hh<=0.0) {
+	fprintf(stderr, "TFset_parameters(): Illegal input.\n");
+	exit(1);
+    }
+    omhh = omega0hh;
+    obhh = omhh*f_baryon;
+    if (Tcmb<=0.0) Tcmb=2.728;	/* COBE FIRAS */
+    theta_cmb = Tcmb/2.7;
+
+    z_equality = 2.50e4*omhh/POW4(theta_cmb);  /* Really 1+z */
+    k_equality = 0.0746*omhh/SQR(theta_cmb);
+
+    z_drag_b1 = 0.313*pow(omhh,-0.419)*(1+0.607*pow(omhh,0.674));
+    z_drag_b2 = 0.238*pow(omhh,0.223);
+    z_drag = 1291*pow(omhh,0.251)/(1+0.659*pow(omhh,0.828))*
+		(1+z_drag_b1*pow(obhh,z_drag_b2));
+    
+    R_drag = 31.5*obhh/POW4(theta_cmb)*(1000/(1+z_drag));
+    R_equality = 31.5*obhh/POW4(theta_cmb)*(1000/z_equality);
+
+    sound_horizon = 2./3./k_equality*sqrt(6./R_equality)*
+	    log((sqrt(1+R_drag)+sqrt(R_drag+R_equality))/(1+sqrt(R_equality)));
+
+    k_silk = 1.6*pow(obhh,0.52)*pow(omhh,0.73)*(1+pow(10.4*omhh,-0.95));
+
+    alpha_c_a1 = pow(46.9*omhh,0.670)*(1+pow(32.1*omhh,-0.532));
+    alpha_c_a2 = pow(12.0*omhh,0.424)*(1+pow(45.0*omhh,-0.582));
+    alpha_c = pow(alpha_c_a1,-f_baryon)*
+		pow(alpha_c_a2,-CUBE(f_baryon));
+    
+    beta_c_b1 = 0.944/(1+pow(458*omhh,-0.708));
+    beta_c_b2 = pow(0.395*omhh, -0.0266);
+    beta_c = 1.0/(1+beta_c_b1*(pow(1-f_baryon, beta_c_b2)-1));
+
+    y = z_equality/(1+z_drag);
+    alpha_b_G = y*(-6.*sqrt(1+y)+(2.+3.*y)*log((sqrt(1+y)+1)/(sqrt(1+y)-1)));
+    alpha_b = 2.07*k_equality*sound_horizon*pow(1+R_drag,-0.75)*alpha_b_G;
+
+    beta_node = 8.41*pow(omhh, 0.435);
+    beta_b = 0.5+f_baryon+(3.-2.*f_baryon)*sqrt(pow(17.2*omhh,2.0)+1);
+
+    k_peak = 2.5*3.14159*(1+0.217*omhh)/sound_horizon;
+    sound_horizon_fit = 44.5*log(9.83/omhh)/sqrt(1+10.0*pow(obhh,0.75));
+
+    alpha_gamma = 1-0.328*log(431.0*omhh)*f_baryon + 0.38*log(22.3*omhh)*
+		SQR(f_baryon);
+    
+    return;
+}
+
+double TFfit_onek(double k, double *tf_baryon, double *tf_cdm)
+/* Input: k -- Wavenumber at which to calculate transfer function, in Mpc^-1.
+	  *tf_baryon, *tf_cdm -- Input value not used; replaced on output if
+				the input was not NULL. */
+/* Output: Returns the value of the full transfer function fitting formula.
+		This is the form given in Section 3 of Eisenstein & Hu (1997).
+  	  *tf_baryon -- The baryonic contribution to the full fit.
+	  *tf_cdm -- The CDM contribution to the full fit. */
+/* Notes: Units are Mpc, not h^-1 Mpc. */
+{
+    double T_c_ln_beta, T_c_ln_nobeta, T_c_C_alpha, T_c_C_noalpha;
+    double q, xx, xx_tilde, q_eff;
+    double T_c_f, T_c, s_tilde, T_b_T0, T_b, f_baryon, T_full;
+    double T_0_L0, T_0_C0, T_0, gamma_eff; 
+    double T_nowiggles_L0, T_nowiggles_C0, T_nowiggles;
+
+    k = fabs(k);	/* Just define negative k as positive */
+    if (k==0.0) {
+	if (tf_baryon!=NULL) *tf_baryon = 1.0;
+	if (tf_cdm!=NULL) *tf_cdm = 1.0;
+	return 1.0;
+    }
+
+    q = k/13.41/k_equality;
+    xx = k*sound_horizon;
+
+    T_c_ln_beta = log(2.718282+1.8*beta_c*q);
+    T_c_ln_nobeta = log(2.718282+1.8*q);
+    T_c_C_alpha = 14.2/alpha_c + 386.0/(1+69.9*pow(q,1.08));
+    T_c_C_noalpha = 14.2 + 386.0/(1+69.9*pow(q,1.08));
+
+    T_c_f = 1.0/(1.0+POW4(xx/5.4));
+    T_c = T_c_f*T_c_ln_beta/(T_c_ln_beta+T_c_C_noalpha*SQR(q)) +
+	    (1-T_c_f)*T_c_ln_beta/(T_c_ln_beta+T_c_C_alpha*SQR(q));
+    
+    s_tilde = sound_horizon*pow(1+CUBE(beta_node/xx),-1./3.);
+    xx_tilde = k*s_tilde;
+
+    T_b_T0 = T_c_ln_nobeta/(T_c_ln_nobeta+T_c_C_noalpha*SQR(q));
+    T_b = sin(xx_tilde)/(xx_tilde)*(T_b_T0/(1+SQR(xx/5.2))+
+		alpha_b/(1+CUBE(beta_b/xx))*exp(-pow(k/k_silk,1.4)));
+
+    f_baryon = obhh/omhh;
+    T_full = f_baryon*T_b + (1-f_baryon)*T_c;
+
+    /* Now to store these transfer functions */
+    if (tf_baryon!=NULL) *tf_baryon = T_b;
+    if (tf_cdm!=NULL) *tf_cdm = T_c;
+    return T_full;
+}
+
+/* ======================= Approximate forms =========================== */
+
+double TFsound_horizon_fit(double omega0, double f_baryon, double hubble)
+/* Input: omega0 -- CDM density, in units of critical density
+	  f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
+	  hubble -- Hubble constant, in units of 100 km/s/Mpc */
+/* Output: The approximate value of the sound horizon, in h^-1 Mpc. */
+/* Note: If you prefer to have the answer in  units of Mpc, use hubble -> 1
+and omega0 -> omega0*hubble^2. */ 
+{
+    double omhh, sound_horizon_fit_mpc;
+    omhh = omega0*hubble*hubble;
+    sound_horizon_fit_mpc = 
+	44.5*log(9.83/omhh)/sqrt(1+10.0*pow(omhh*f_baryon,0.75));
+    return sound_horizon_fit_mpc*hubble;
+}
+
+double TFk_peak(double omega0, double f_baryon, double hubble)
+/* Input: omega0 -- CDM density, in units of critical density
+	  f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
+	  hubble -- Hubble constant, in units of 100 km/s/Mpc */
+/* Output: The approximate location of the first baryonic peak, in h Mpc^-1 */
+/* Note: If you prefer to have the answer in  units of Mpc^-1, use hubble -> 1
+and omega0 -> omega0*hubble^2. */ 
+{
+    double omhh, k_peak_mpc;
+    omhh = omega0*hubble*hubble;
+    k_peak_mpc = 2.5*3.14159*(1+0.217*omhh)/TFsound_horizon_fit(omhh,f_baryon,1.0);
+    return k_peak_mpc/hubble;
+}
+
+double TFnowiggles(double omega0, double f_baryon, double hubble, 
+		double Tcmb, double k_hmpc)
+/* Input: omega0 -- CDM density, in units of critical density
+	  f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
+	  hubble -- Hubble constant, in units of 100 km/s/Mpc
+	  Tcmb -- Temperature of the CMB in Kelvin; Tcmb<=0 forces use of
+			COBE FIRAS value of 2.728 K
+	  k_hmpc -- Wavenumber in units of (h Mpc^-1). */
+/* Output: The value of an approximate transfer function that captures the
+non-oscillatory part of a partial baryon transfer function.  In other words,
+the baryon oscillations are left out, but the suppression of power below
+the sound horizon is included. See equations (30) and (31).  */
+/* Note: If you prefer to use wavenumbers in units of Mpc^-1, use hubble -> 1
+and omega0 -> omega0*hubble^2. */ 
+{
+    double k, omhh, theta_cmb, k_equality, q, xx, alpha_gamma, gamma_eff;
+    double q_eff, T_nowiggles_L0, T_nowiggles_C0;
+
+    k = k_hmpc*hubble;	/* Convert to Mpc^-1 */
+    omhh = omega0*hubble*hubble;
+    if (Tcmb<=0.0) Tcmb=2.728;	/* COBE FIRAS */
+    theta_cmb = Tcmb/2.7;
+
+    k_equality = 0.0746*omhh/SQR(theta_cmb);
+    q = k/13.41/k_equality;
+    xx = k*TFsound_horizon_fit(omhh, f_baryon, 1.0);
+
+    alpha_gamma = 1-0.328*log(431.0*omhh)*f_baryon + 0.38*log(22.3*omhh)*
+		SQR(f_baryon);
+    gamma_eff = omhh*(alpha_gamma+(1-alpha_gamma)/(1+POW4(0.43*xx)));
+    q_eff = q*omhh/gamma_eff;
+
+    T_nowiggles_L0 = log(2.0*2.718282+1.8*q_eff);
+    T_nowiggles_C0 = 14.2 + 731.0/(1+62.5*q_eff);
+    return T_nowiggles_L0/(T_nowiggles_L0+T_nowiggles_C0*SQR(q_eff));
+}
+
+/* ======================= Zero Baryon Formula =========================== */
+
+double TFzerobaryon(double omega0, double hubble, double Tcmb, double k_hmpc)
+/* Input: omega0 -- CDM density, in units of critical density
+	  hubble -- Hubble constant, in units of 100 km/s/Mpc
+	  Tcmb -- Temperature of the CMB in Kelvin; Tcmb<=0 forces use of
+			COBE FIRAS value of 2.728 K
+	  k_hmpc -- Wavenumber in units of (h Mpc^-1). */
+/* Output: The value of the transfer function for a zero-baryon universe. */
+/* Note: If you prefer to use wavenumbers in units of Mpc^-1, use hubble -> 1
+and omega0 -> omega0*hubble^2. */ 
+{
+    double k, omhh, theta_cmb, k_equality, q, T_0_L0, T_0_C0;
+
+    k = k_hmpc*hubble;	/* Convert to Mpc^-1 */
+    omhh = omega0*hubble*hubble;
+    if (Tcmb<=0.0) Tcmb=2.728;	/* COBE FIRAS */
+    theta_cmb = Tcmb/2.7;
+
+    k_equality = 0.0746*omhh/SQR(theta_cmb);
+    q = k/13.41/k_equality;
+
+    T_0_L0 = log(2.0*2.718282+1.8*q);
+    T_0_C0 = 14.2 + 731.0/(1+62.5*q);
+    return T_0_L0/(T_0_L0+T_0_C0*q*q);
+}
+
+
+/* Added by cmv 24/08/2007 */
+void TFprint_parameters(void)
+{
+  printf("omhh=%g obhh=%g theta_cmb=%g\n",omhh,obhh,theta_cmb);
+  printf("z_equality=%g k_equality=%g R_equality=%g\n",z_equality,k_equality,R_equality);
+  printf("z_drag=%g R_drag=%g sound_horizon=%g\n",z_drag,R_drag,sound_horizon);
+  printf("k_silk=%g\n",k_silk);
+  printf("alpha_c=%g beta_c=%g\n",alpha_c,beta_c);
+  printf("alpha_b=%g beta_b=%g\n",alpha_b,beta_b);
+  printf("beta_node=%g\n",beta_node);
+  printf("k_peak=%g sound_horizon_fit=%g\n",k_peak,sound_horizon_fit);
+  printf("alpha_gamma=%g\n",alpha_gamma);
+}
Index: /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/hu_tf_fit.h	(revision 3382)
@@ -0,0 +1,29 @@
+#ifndef HU_TF_FIT_SEEN
+#define HU_TF_FIT_SEEN
+
+//http://background.uchicago.edu/~whu/transfer/transferpage.html
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void TFset_parameters(double omega0hh, double f_baryon, double Tcmb);
+double TFfit_onek(double k, double *tf_baryon, double *tf_cdm); 
+
+void TFfit_hmpc(double omega0, double f_baryon, double hubble, double Tcmb,
+	int numk, double *k, double *tf_full, double *tf_baryon, double *tf_cdm);
+
+double TFsound_horizon_fit(double omega0, double f_baryon, double hubble);
+double TFk_peak(double omega0, double f_baryon, double hubble);
+double TFnowiggles(double omega0, double f_baryon, double hubble, 
+		double Tcmb, double k_hmpc);
+double TFzerobaryon(double omega0, double hubble, double Tcmb, double k_hmpc);
+
+/* Added by cmv 24/08/2007 */
+void TFprint_parameters(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HU_TF_FIT_SEEN
Index: /tags/V1_0/Cosmo/SimLSS/pkspectrum.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/pkspectrum.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/pkspectrum.cc	(revision 3382)
@@ -0,0 +1,692 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "pexceptions.h"
+
+#include "constcosmo.h"
+#include "geneutils.h"
+#include "pkspectrum.h"
+
+namespace SOPHYA {
+
+///////////////////////////////////////////////////////////
+//******************** InitialSpectrum ******************//
+///////////////////////////////////////////////////////////
+
+InitialSpectrum::InitialSpectrum(double n,double a)
+  : n_(n), A_(a)
+{
+}
+
+InitialSpectrum::InitialSpectrum(InitialSpectrum& pkinf)
+  : n_(pkinf.n_), A_(pkinf.A_)
+{
+}
+
+InitialSpectrum::~InitialSpectrum(void)
+{
+}
+
+
+///////////////////////////////////////////////////////////
+//****************** TransfertEisenstein ****************//
+///////////////////////////////////////////////////////////
+
+// From Eisenstein & Hu ApJ 496:605-614 1998 April 1 (ou astro-ph/9709112)
+TransfertEisenstein::TransfertEisenstein(double h100,double OmegaCDM0,double OmegaBaryon0,double tcmb,bool nobaryon,int lp)
+  : lp_(lp)
+  , Oc_(OmegaCDM0) , Ob_(OmegaBaryon0) , h100_(h100) , tcmb_(tcmb)
+  , nobaryon_(nobaryon) , nooscenv_(0), retpart_(ALL)
+{
+ zero_();
+ Init_();
+}
+
+TransfertEisenstein::TransfertEisenstein(TransfertEisenstein& tf)
+  : lp_(tf.lp_)
+  ,Oc_(tf.Oc_) , Ob_(tf.Ob_) , h100_(tf.h100_) , tcmb_(tf.tcmb_)
+  , nobaryon_(tf.nobaryon_) , nooscenv_(tf.nooscenv_), retpart_(tf.retpart_)
+{
+ zero_();
+ Init_();
+}
+
+TransfertEisenstein::~TransfertEisenstein(void)
+{
+}
+
+void TransfertEisenstein::zero_(void)
+{
+ th2p7_=zeq_=keq_=zd_=Req_=Rd_=s_=ksilk_=alphac_=betac_=bnode_
+       =alphab_=betab_=alphag_=sfit_=kpeak_=1.e99;
+}
+
+void TransfertEisenstein::Init_(void)
+{
+
+  O0_ = Oc_ + Ob_;
+  if(nobaryon_) {O0_ = Oc_; Ob_ = 0.;}
+  double H0 = 100. * h100_, h2 = h100_*h100_;
+  if(lp_) cout<<"h100="<<h100_<<" H0="<<H0<<") Omatter="<<O0_<<" Ocdm="<<Oc_<<" Ob="<<Ob_<<endl;
+
+
+  if(tcmb_<0.) tcmb_ = T_CMB_Par;
+  th2p7_ = tcmb_/2.7;
+  double th2p7P4 = th2p7_*th2p7_*th2p7_*th2p7_;
+  if(lp_) cout<<"tcmb = "<<tcmb_<<" K = "<<th2p7_<<" *2.7K "<<endl;
+
+  // Formule 2 p 606
+  zeq_ = 2.50e4 * O0_ * h2 / th2p7P4;
+  if(lp_) cout<<"zeq = "<<zeq_<<" (redshift of matter-radiation equality)"<<endl;
+
+  // Formule 3 p 607
+  // (attention ici C=1 : H0 -> H0/C si on utilise la premiere formule)
+  //  keq_ = sqrt(2.*O0_*H0*H0*zeq_) / SpeedOfLight_Cst;
+  keq_ = 7.46e-2 * O0_ * h2 / (th2p7_*th2p7_);
+  if(lp_) cout<<"keq = "<<keq_<<" Mpc^-1 (scale of equality)"<<endl;
+
+  // On s'arrete ici si pas de baryons
+  if(nobaryon_) return;
+
+  // Formule 4 p 607
+  double b1_eq4 = 0.313*pow(O0_*h2,-0.419)*(1. + 0.607*pow(O0_*h2,0.674));
+  double b2_eq4 = 0.238*pow(O0_*h2,0.223);
+  zd_ = 1291. * pow(O0_*h2,0.251) / (1.+0.659* pow(O0_*h2,0.828))
+              * (1. + b1_eq4*pow(Ob_*h2,b2_eq4));
+  if(lp_) cout<<"zd = "<<zd_<<" (Redshift of drag epoch)"<<endl;
+
+  // Formule 5 page 607    (R = 3*rho_baryon/4*rho_gamma)
+  Req_ = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zeq_);
+  //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: zd -> (1+zd)
+  Rd_  = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zd_);
+  //in tf_fit.c: Rd_  = 31.5*Ob_*h2 / th2p7P4 * (1.e3/(1.+zd_));
+  if(lp_) {
+    cout<<"Req = "<<Req_<<" Rd = "<<Rd_
+        <<" (Photon-baryon ratio at equality/drag epoch)"<<endl;
+    cout<<"Sound speed at equality "<<1./sqrt(3.*(1.+Req_))
+        <<", at drag "<<1./sqrt(3.*(1.+Rd_))<<" in unit of C"<<endl;
+  }
+
+  // Formule 6 p 607
+  s_ = 2./(3.*keq_) * sqrt(6./Req_)
+      * log( (sqrt(1.+Rd_) + sqrt(Rd_+Req_)) / (1.+sqrt(Req_)) );
+  if(lp_) cout<<"s = "<<s_<<" Mpc (sound horizon at drag epoch)"<<endl;
+
+  // Formule 7 page 607
+  ksilk_ = 1.6*pow(Ob_*h2,0.52)*pow(O0_*h2,0.73) * (1. + pow(10.4*O0_*h2,-0.95));
+  if(lp_) cout<<"ksilk = "<<ksilk_<<" Mpc^-1 (silk damping scale)"<<endl;
+
+  // Formules 10 page 608
+  double a1 = pow(46.9*O0_*h2,0.670) * (1. + pow(32.1*O0_*h2,-0.532));
+  double a2 = pow(12.0*O0_*h2,0.424) * (1. + pow(45.0*O0_*h2,-0.582));
+  alphac_ = pow(a1,-Ob_/O0_) * pow(a2,-pow(Ob_/O0_,3.));
+  double b1 = 0.944 / (1. + pow(458.*O0_*h2,-0.708));
+  double b2 = pow(0.395*O0_*h2,-0.0266);
+  betac_ = 1 / ( 1. + b1*(pow(Oc_/O0_,b2) - 1.) );
+  if(lp_) cout<<"alphac = "<<alphac_<<" betac = "<<betac_
+               <<" (CDM suppression/log shift)"<<endl;
+
+  // Formule 23 page 610
+  bnode_ = 8.41 * pow(O0_*h2,0.435);
+  if(lp_) cout<<"bnode = "<<bnode_<<" (sound horizon shift)"<<endl;
+
+  // Formule 14 page 608
+  //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: (1+zeq) -> zeq
+  double y = (1.+zeq_)/(1.+zd_);
+  //in tf_fit.c: double y = zeq_/(1.+zd_);
+  double s1py = sqrt(1.+y);
+  double Gy = y*( -6.*s1py + (2.+3.*y)*log((s1py+1.)/(s1py-1.)) );
+  alphab_ = 2.07*keq_*s_*pow(1.+Rd_,-3./4.)*Gy;
+
+  // Formule 24 page 610
+  betab_ = 0.5 + Ob_/O0_
+         + (3.-2.*Ob_/O0_) * sqrt(pow(17.2*O0_*h2,2.) + 1.);
+  if(lp_) cout<<"alphab = "<<alphab_<<" betab = "<<betab_
+               <<" (Baryon suppression/envelope shift)"<<endl;
+
+  // Formule 31 page 612
+  alphag_ = 1.
+          - 0.328*log(431.*O0_*h2)*Ob_/O0_
+          + 0.38*log(22.3*O0_*h2)*pow(Ob_/O0_,2.);
+  if(lp_) cout<<"alphag = "<<alphag_<<" (gamma suppression in approximate TF)"<<endl;
+
+ // The approximate value of the sound horizon, formule 26 page 611
+ sfit_ = 44.5*log(9.83/(O0_*h2)) / sqrt(1.+10.*pow(Ob_*h2,3./4.));  // Mpc
+ if(lp_) cout<<"sfit="<<sfit_<<" Mpc (fit to sound horizon)"<<endl;
+
+ // La positoin du premier pic acoustique, formule 25 page 611
+ kpeak_ = 5*M_PI/(2.*sfit_) * (1.+0.217*O0_*h2);  // 1/Mpc
+ if(lp_) cout<<"kpeak="<<kpeak_<<" Mpc^-1 (fit to wavenumber of first peak)"<<endl;
+
+  return;
+}
+
+bool TransfertEisenstein::SetParTo(double h100,double OmegaCDM0,double OmegaBaryon0)
+// Changement des valeurs des parametres (suivi de re-init eventuel)
+// Si h100,Omega...<=0. alors pas de changement, on garde l'ancienne valeur
+{
+ bool haschanged = false;
+
+ if(h100>0.) {h100_ = h100; haschanged = true;}
+ if(OmegaCDM0>0.) {Oc_ = OmegaCDM0; haschanged = true;}
+ if(OmegaBaryon0>0.) {Ob_ = OmegaBaryon0; haschanged = true;}
+
+ // et on recalcule les initialisations
+ if(haschanged) Init_();
+
+ return haschanged;
+}
+
+void TransfertEisenstein::SetNoOscEnv(unsigned short nooscenv)
+// To obtain an approximate form of the non-oscillatory part of the transfert function
+// nooscenv = 0 : use the baryon oscillatory part of transfert function (full tf)
+// nooscenv = 1 : use approx. paragraph 3.3 p610 (middle of right column)
+//                Replace  j0(k*stilde)  ->  [1+(k*stilde)^4]^(-1/4)
+// nooscenv = 2 : use formulae 29+30+31 page 612
+//                The value of an approximate transfer function that captures
+//                the non-oscillatory part of a partial baryon transfer function.
+//                In other words, the baryon oscillations are left out,
+//                but the suppression of power below the sound horizon is included.
+{
+ if(nooscenv!=1 && nooscenv!=2) nooscenv = 0;
+ nooscenv_ = nooscenv;
+}
+
+void TransfertEisenstein::SetReturnPart(ReturnPart retpart)
+// To return only baryon or CDM part part of transfert function
+// retpart = ALL: return full transfert function
+//         = CDM : return only CDM part of transfert function
+//         = BARYON : return only Baryon part of transfert function
+// WARNING: only relevant for nobaryon_=false AND nooscenv!=2
+{
+ retpart_ = retpart;
+}
+
+void TransfertEisenstein::SetPrintLevel(int lp)
+{
+ lp_ = lp;
+}
+
+
+double TransfertEisenstein::T0tild(double k,double alphac,double betac)
+{
+  // Formule 10 p 608
+  //double q = k*th2p7_*th2p7_/(O0_*h100_*h100_);
+  double q = k/(13.41*keq_);
+  // Formule 20 p 610
+  double C = (14.2/alphac) + 386./(1.+69.9*pow(q,1.08));
+  // Formule 19 p 610
+  double x = log(M_E+1.8*betac*q);
+  return x / (x + C*q*q);
+}
+
+double TransfertEisenstein::operator() (double k)
+{
+
+  // --- Pour zero baryon
+  //  OU Pour function lissee sans oscillation baryon
+  if(nobaryon_  || nooscenv_ == 2) {
+    double gamma = O0_*h100_;
+    // Calcul de Gamma_eff, formule 30 page 612 (pour fct lissee)
+    if( nobaryon_==false && nooscenv_ == 2 )
+      gamma = O0_*h100_*(alphag_ + (1.-alphag_)/(1.+pow(0.43*k*sfit_,4.))); // Gamma_eff
+    // Formule 28 page 612 : qui est est equivalent a:
+    //    q = k / h100_ * th2p7_*th2p7_ / gamma;
+    // qui est est equivalent a:
+    //    q = k / (13.41 * keq)                   pour Ob=0
+    //    q = k / (13.41 * keq) * (O0*h/Gamma)    pour le spectre lisse
+    // Les resultats sont legerement differents a cause des valeurs approx.
+    // des constantes numeriques: on prend comme W.Hu (tf_fit.c)
+    //double q = k / h100_ * th2p7_*th2p7_ / gamma;  // Mpc^-1
+    double q = k/(13.41*keq_) * (O0_*h100_/gamma);  // Mpc^-1
+    // Formules 29 page 612
+    double l0 = log(2.*M_E + 1.8*q);
+    double c0 = 14.2 + 731./(1.+62.5*q);
+    return l0 / (l0 + c0*q*q);
+  }
+
+  // --- Pour CDM + Baryons
+  // --- CDM
+  double f = 1. / (1. + pow(k*s_/5.4,4.));
+  double Tc = f*T0tild(k,1.,betac_) + (1.-f)*T0tild(k,alphac_,betac_);
+  if(retpart_ == CDM) return Tc; 
+
+  // --- Baryons
+  // Formule 22 page 610
+  double stilde, ksbnode = k*s_/bnode_;
+  if(ksbnode<0.001) stilde =s_ * ksbnode;
+     else   stilde = s_ / pow(1. + pow(1./ksbnode,3.), 1./3.);
+  // Formule 21 page 610
+  double j0kst = 0.;
+  if(nooscenv_ == 1) {
+    j0kst = pow(1.+pow(k*stilde,4.) , -1./4.); //lissee sans oscillation baryon
+  } else {
+    double x = k*stilde;
+    if(x<0.01) j0kst = 1. - x*x/6.*(1.-x*x/20.);
+      else j0kst = sin(x)/x;
+    //cout<<"DEBUG: k="<<k<<" stilde="<<stilde<<" x="<<x<<" j0kst="<<j0kst<<endl;
+  }
+  double Tb = T0tild(k,1.,1.) / (1. + pow(k*s_/5.2,2.));
+  Tb += alphab_/(1.+pow(betab_/(k*s_),3.)) * exp(-pow(k/ksilk_,1.4));
+  Tb *= j0kst;
+  if(retpart_ == BARYON) return Tb;
+
+  // --- Total
+  double T = (Ob_/O0_)*Tb + (Oc_/O0_)*Tc;
+
+  return T;
+}
+
+double TransfertEisenstein::KPeak(void)
+// Position du premier pic acoustic
+{
+ if(nobaryon_) return -1.;
+ return kpeak_;
+}
+
+
+///////////////////////////////////////////////////////////
+//******************* TransfertTabulate *****************//
+///////////////////////////////////////////////////////////
+
+TransfertTabulate::TransfertTabulate(double h100,double OmegaCDM0,double OmegaBaryon0)
+: Oc_(OmegaCDM0) , Ob_(OmegaBaryon0) , h100_(h100) , kmin_(1.) , kmax_(-1.)
+, interptyp_(0)
+{
+}
+
+TransfertTabulate::TransfertTabulate(TransfertTabulate& tf)
+: Oc_(tf.Oc_) , Ob_(tf.Ob_) , h100_(tf.h100_) , kmin_(tf.kmin_) , kmax_(tf.kmax_)
+, interptyp_(tf.interptyp_) , k_(tf.k_) , tf_(tf.tf_)
+{
+}
+
+TransfertTabulate::~TransfertTabulate(void)
+{
+}
+
+void TransfertTabulate::SetInterpTyp(int typ)
+// see comment in InterpTab
+{
+ if(typ<0) typ=0; else if(typ>2) typ=2;
+ interptyp_ = typ;
+}
+
+double TransfertTabulate::operator() (double k)
+{
+ return InterpTab(k,k_,tf_,interptyp_);
+}
+
+int TransfertTabulate::ReadCMBFast(string filename)
+{
+ FILE *file = fopen(filename.c_str(),"r");
+ if(file==NULL) return -1;
+
+ const int lenline = 512;
+ char *line = new char[lenline];
+
+ int nread = 0;
+ double tmax = -1.;
+ while ( fgets(line,lenline,file) != NULL ) {
+   double k,tc,tb,tf;
+   sscanf(line,"%lf %lf %lf",&k,&tc,&tb);
+   k *= h100_;     // convert h^-1 Mpc  ->  Mpc
+   tf = (Oc_*tc+Ob_*tb)/(Oc_+Ob_);
+   if(tf>tmax) tmax = tf;
+   k_.push_back(k);
+   tf_.push_back(tf);
+   nread++;
+ }
+
+ cout<<"TransfertTabulate::ReadCMBFast: nread="<<nread<<" tf_max="<<tmax<<endl;
+ delete [] line;
+ if(nread==0) return nread;
+
+ for(unsigned int i=0;i<tf_.size();i++) tf_[i] /= tmax;
+
+ return nread;
+}
+
+///////////////////////////////////////////////////////////
+//********************* GrowthFactor ********************//
+///////////////////////////////////////////////////////////
+
+// From Eisenstein & Hu ApJ 496:605-614 1998 April 1
+// Pour avoir D(z) = 1/(1+z) faire: OmegaMatter0=1 OmegaLambda0=0
+GrowthFactor::GrowthFactor(double OmegaMatter0,double OmegaLambda0)
+  : O0_(OmegaMatter0) , Ol_(OmegaLambda0)
+{
+  if(OmegaMatter0==0.) {
+    cout<<"GrowthFactor::GrowthFactor: Error bad OmegaMatter0  value : "<<OmegaMatter0<<endl;
+    throw ParmError("GrowthFactor::GrowthFactor: Error badOmegaMatter0  value");
+  }
+}
+
+GrowthFactor::GrowthFactor(GrowthFactor& d1)
+  : O0_(d1.O0_) , Ol_(d1.Ol_)
+{
+}
+
+GrowthFactor::~GrowthFactor(void)
+{
+}
+
+double GrowthFactor::operator() (double z)
+// see Formulae A4 + A5 + A6 page 614
+{
+ z += 1.;
+ double z2 = z*z, z3 = z2*z;
+
+ // Calcul de la normalisation (pour z=0 -> growth=1.)
+ double D1z0 = pow(O0_,4./7.) - Ol_ + (1.+O0_/2.)*(1.+Ol_/70.);
+ D1z0 = 2.5*O0_ / D1z0;
+
+ // Calcul du growthfactor pour z
+ double Ok = 1. - O0_ - Ol_;
+ double den = Ol_ + Ok*z2 + O0_*z3;
+ double o0z = O0_ *z3 / den;
+ double olz = Ol_ / den;
+
+ double D1z = pow(o0z,4./7.) - olz + (1.+o0z/2.)*(1.+olz/70.);
+ D1z = 2.5*o0z / z / D1z;
+
+ return D1z / D1z0;
+}
+
+void GrowthFactor::SetParTo(double OmegaMatter0,double OmegaLambda0)
+{
+ if(OmegaMatter0>0.) O0_ = OmegaMatter0;
+ Ol_ = OmegaLambda0;
+}
+
+bool GrowthFactor::SetParTo(double OmegaMatter0)
+// idem precedent sans changer OmegaLambda0
+{
+ if(OmegaMatter0<=0.) return false;
+ O0_ = OmegaMatter0;
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////
+//************** PkSpectrum0 et PkSpectrumZ *************//
+///////////////////////////////////////////////////////////
+
+PkSpectrum0::PkSpectrum0(InitialSpectrum& pkinf,TransfertEisenstein& tf)
+  : pkinf_(pkinf) , tf_(tf)
+{
+}
+
+PkSpectrum0::PkSpectrum0(PkSpectrum0& pk0)
+  : pkinf_(pk0.pkinf_) , tf_(pk0.tf_)
+{
+}
+
+PkSpectrum0::~PkSpectrum0(void)
+{
+}
+
+double PkSpectrum0::operator() (double k)
+{
+  double tf = tf_(k);
+  double pkinf = pkinf_(k);
+  return pkinf *tf*tf;
+}
+
+//------------------------------------
+PkSpectrumZ::PkSpectrumZ(PkSpectrum0& pk0,GrowthFactor& d1,double zref)
+  : pk0_(pk0) , d1_(d1) , zref_(zref) , scale_(1.) , typspec_(PK)
+{
+}
+
+PkSpectrumZ::PkSpectrumZ(PkSpectrumZ& pkz)
+  : pk0_(pkz.pk0_) , d1_(pkz.d1_) , zref_(pkz.zref_) , scale_(pkz.scale_) , typspec_(PK)
+{
+}
+
+PkSpectrumZ::~PkSpectrumZ(void) 
+{
+}
+
+void PkSpectrumZ::SetTypSpec(ReturnSpectrum typspec)
+// typsec = PK : compute Pk(k)
+//        = DELTA : compute Delta^2(k) = k^3*Pk(k)/2Pi^2
+{
+  typspec_ = typspec;
+}
+
+double PkSpectrumZ::operator() (double k)
+{
+  return (*this)(k,zref_);
+}
+
+double PkSpectrumZ::operator() (double k,double z)
+{
+  double d1 = d1_(z);
+
+  double v = pk0_(k) * d1*d1;
+  if(typspec_==DELTA) v *= k*k*k/(2.*M_PI*M_PI);
+
+  return scale_ * v;
+}
+
+
+
+///////////////////////////////////////////////////////////
+//******************* VarianceSpectrum ******************//
+///////////////////////////////////////////////////////////
+
+VarianceSpectrum::VarianceSpectrum(GenericFunc& pk,double R,TypeFilter typfilter)
+  : pk_(pk)
+{
+  SetRadius(R);
+  SetFilter(typfilter);
+}
+
+VarianceSpectrum::VarianceSpectrum(VarianceSpectrum& vpk)
+  : pk_(vpk.pk_) , R_(vpk.R_)
+{
+  SetFilter(vpk.typfilter_);
+}
+
+VarianceSpectrum::~VarianceSpectrum(void)
+{
+}
+
+void VarianceSpectrum::SetRadius(double R)
+// R = taille du filter top-hat ou gaussien
+{
+ if(R<=0.) {
+    cout<<"VarianceSpectrum::SetRadius: Error R<=0"<<endl;
+    throw ParmError("VarianceSpectrum::SetRadius: Error R<=0");
+  }
+  R_ = R;
+}
+
+//------------------------------------
+void VarianceSpectrum::SetFilter(TypeFilter typfilter)
+// typfilter = TOPHAT : spherical 3D top-hat
+//           = GAUSSIAN : spherical 3D gaussian
+//           = NOFILTER : no filter juste integrate spectrum)
+// Remarque:
+//   la meilleure approximation du filtre top-hat (R) est un filtre gaussien avec (Rg=R/sqrt(5))
+{
+  typfilter_ = typfilter;
+}
+
+void VarianceSpectrum::SetInteg(double dperc,double dlogkinc,double dlogkmax,unsigned short glorder)
+// ATTENTION: on n'integre pas f(k)*dk mais k*f(k)*d(log10(k))
+// see argument details in function IntegrateFuncLog (geneutils.cc)
+{
+  dperc_ = dperc;  if(dperc_<=0.) dperc_ = 0.1;
+  dlogkinc_ = dlogkinc;
+  dlogkmax_ = dlogkmax;
+  glorder_ = glorder;
+}
+
+
+//------------------------------------
+double VarianceSpectrum::Filter2(double x)
+// ATTENTION: c'est le filtre au carre qui est renvoye
+{
+  // Just integrate the spectrum without filtering
+  if(typfilter_ == NOFILTER) return 1.;
+
+  double x2 = x*x;
+  // Filtre gaussien G(x) = exp(-x^2/2)
+  //        remarque G(x)^2 = exp(-x^2)
+  // on prend le DL de G(x)^2 pour x->0 a l'ordre O(x^6)
+  //             DL(x) = 1-x^2*(1-x^2/2)
+  //             pour x<0.01  |DL(x)-G(X)^2|<2.0e-13
+  if(typfilter_ == GAUSSIAN)
+    if(x<0.01) return 1.-x2*(1.-x2/2.); else return exp(-x2);
+
+  // Filtre top-hat T(x) = 3*(sin(x)-x*cos(x))/x^3
+  // --- Gestion de la pseudo-divergence pour x->0
+  // on prend le DL de T(x)^2 pour x->0 a l'ordre O(x^7)
+  //             DL(x) = 1-x^2/5*(1-3*x^2/35*(1-4*x^2/81))
+  //             pour x<0.1  |DL(x)-T(X)^2|<2.5e-13
+  double f2=0.;
+  if(x<0.1) {
+    f2 = 1.-x2/5.*(1.-3.*x2/35.*(1.-4.*x2/81.));
+  } else {
+    f2 = 3.*(sin(x)-x*cos(x))/(x2*x);
+    f2 *= f2;
+  }
+  return f2;
+  
+}
+
+double VarianceSpectrum::Variance(double kmin,double kmax)
+// Compute variance of spectrum pk_ by integration
+// Input:
+//     kmin,kmax = bornes en k de l'integrale pour calculer la variance
+// Return:
+//     valeur de la variance (sigma^2)
+// Remarque:
+//   la variance renvoyee est la variance de la masse
+{
+  if(kmin<=0 || kmax<=0. || kmin>=kmax) {
+    cout<<"VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax"<<endl;
+    throw ParmError("VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax");
+  }
+
+  double lkmin = log10(kmin), lkmax = log10(kmax);
+
+  double var = IntegrateFuncLog(*this,lkmin,lkmax,dperc_,dlogkinc_,dlogkmax_,glorder_);
+
+  return var;
+}
+
+//------------------------------------
+double VarianceSpectrum::FindMaximum(double kmin,double kmax,double eps)
+// Retourne le maximum de la fonction a integrer
+// La recherche a lieu entre [kmin,kmax] par pas logarithmiques
+// Input:
+//     kmin,kmax : intervalle de recherche
+//     eps : precision requise sur les valeurs
+// Return:
+//     position (en k) du maximum
+{
+  if(kmin<=0 || kmax<=0. || kmin>=kmax) {
+    cout<<"VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0"<<endl;
+    throw ParmError("VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
+  }
+
+  int n = 10; // toujours >2
+  double lkmin = log10(kmin), lkmax = log10(kmax), dlk = (lkmax-lkmin)/n;
+
+  double lkfind=lkmin, pkfind=-1.;
+  while(1) {
+    for(int i=0; i<=n; i++) {
+      double lk = lkmin  + i*dlk;
+      double v = (*this)(pow(10.,lk));
+      if(v<pkfind) continue;
+      pkfind = v; lkfind = lk;
+    }
+    //cout<<"VarianceSpectrum::FindMaximum: lkfind="<<lkfind<<" pkfind="<<pkfind
+    //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
+    // --- Convergence si l'encadrement de "kfind" est tel que "dk/kfind<eps"
+    // On a dk = 10^(lkfind+dlk) - 10^(lkfind-dlk) = kfind * (10^(dlk) - 10^(-dlk))
+    if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
+    if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
+    if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
+    dlk = (lkmax-lkmin)/n;
+  }
+
+  return pow(10.,lkfind);
+}
+
+int VarianceSpectrum::FindLimits(double high,double &kmin,double &kmax,double eps)
+// Retourne "[kmin,kmax]" tel que la fonction a integrer soit "f(k) <= high"
+//   La recherche a lieu entre [kmin,kmax] par pas logarithmiques
+// Input:
+//     kmin,kmax : intervalle de recherche
+//     eps : precision requise sur les valeurs kmin et kmax
+// Output:
+//     kmin,kmax telles que "f(k) <= high"
+// Return:
+//     rc  = 0 si OK
+//     rc |= 1 "f(kmin) >= high"   (bit0 =1)
+//     rc |= 2 "f(kmax) >= high"   (bit1 =1)
+//     rc |= 4 "f(k) < high pour tout k"   (bit2 =1)
+{
+  if(kmin<=0 || kmax<=0. || kmin>=kmax  || eps<=0.) {
+    cout<<"VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax or eps<=0"<<endl;
+    throw ParmError("VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
+  }
+
+  int n = 10; // toujours >2
+
+  int rc = 0;
+  double lkmin,lkmax,dlk,lkfind;
+
+  // --- Find kmin
+  lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
+  while(1) {
+    lkfind = lkmin;
+    for(int i=0;i<=n;i++) {
+      if( (*this)(pow(10,lkfind)) >= high ) break;
+      lkfind = lkmin + i*dlk;
+    }
+    //cout<<"VarianceSpectrum::FindLimits[kmin]: lkfind="<<lkfind
+    //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
+    if(fabs(lkfind-lkmax)<dlk/2.) {rc |= 4; return rc;} // protect against f(k)<high for all k
+    if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
+    if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
+    if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
+    dlk = (lkmax-lkmin)/n;
+  }
+  if(lkfind-lkmin<dlk/2.) rc |= 1;  // f(kmin) >= high
+  else kmin = pow(10.,lkmin);
+  //cout<<"rc="<<rc<<" lkmin="<<lkmin<<"  pk="<<(*this)(pow(10.,lkmin))<<endl;
+
+  // --- Find kmax
+  lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
+  while(1) {
+    lkfind=lkmax;
+    for(int i=0;i<=n;i++) {
+      if( (*this)(pow(10,lkfind)) >= high ) break;
+      lkfind -= dlk;
+      lkfind = lkmax - i*dlk;
+    }
+    //cout<<"VarianceSpectrum::FindLimits[kmax]: lkfind="<<lkfind
+    //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
+    if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
+    if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
+    if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
+    dlk = (lkmax-lkmin)/n;
+  }
+  if(lkmax-lkfind<dlk/2.) rc |= 2;  // f(kmax) >= high
+  else kmax = pow(10.,lkmax);
+  //cout<<"rc="<<rc<<" lkmax="<<lkmax<<"  pk="<<(*this)(pow(10.,lkmax))<<endl;
+
+  return rc;
+}
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/pkspectrum.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/pkspectrum.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/pkspectrum.h	(revision 3382)
@@ -0,0 +1,160 @@
+#ifndef PKSPECTRUM_SEEN
+#define PKSPECTRUM_SEEN
+
+#include "machdefs.h"
+#include "genericfunc.h"
+
+namespace SOPHYA {
+
+//-----------------------------------------------------------------------------------
+class InitialSpectrum : public GenericFunc {
+public:
+  InitialSpectrum(double n,double a=1.);
+  InitialSpectrum(InitialSpectrum& pkinf);
+  virtual ~InitialSpectrum(void);
+  virtual double operator() (double k) {return A_ * pow(k,n_);}
+  void SetNorm(double a) {A_ = a;}
+  void SetSlope(double n) {n_ = n;}
+protected:
+  double n_, A_;
+};
+
+//-----------------------------------------------------------------------------------
+class TransfertEisenstein : public GenericFunc {
+public:
+
+  typedef enum{ALL=0, CDM=1, BARYON=2} ReturnPart;
+
+  TransfertEisenstein(double h100,double OmegaCDM0,double OmegaBaryon0,double tcmb,bool nobaryon=false,int lp=0);
+  TransfertEisenstein(TransfertEisenstein& tf);
+  virtual ~TransfertEisenstein(void);
+  bool SetParTo(double h100,double OmegaCDM0,double OmegaBaryon0);
+  virtual double operator() (double k);
+  double KPeak(void);
+  void SetNoOscEnv(unsigned short nooscenv=0);
+  void SetReturnPart(ReturnPart retpart=ALL);
+  void SetPrintLevel(int lp=0);
+protected:
+  int lp_;
+  double O0_,Oc_,Ob_,h100_,tcmb_;
+  double th2p7_;
+  double zeq_,keq_,zd_,Req_,Rd_,s_,ksilk_,alphac_,betac_,bnode_,alphab_,betab_;
+  double alphag_;
+  double sfit_,kpeak_;
+
+  bool nobaryon_;
+  unsigned short nooscenv_;
+  ReturnPart retpart_;
+
+  double T0tild(double k,double alphac,double betac);
+  void Init_(void);
+  void zero_(void);
+};
+
+//-----------------------------------------------------------------------------------
+class TransfertTabulate : public GenericFunc {
+public:
+  TransfertTabulate(double h100,double OmegaCDM0,double OmegaBaryon0);
+  TransfertTabulate(TransfertTabulate& tf);
+  virtual ~TransfertTabulate(void);
+  virtual double operator() (double k);
+  int NPoints(void) {return k_.size();}
+  void SetInterpTyp(int typ=0);
+  int ReadCMBFast(string filename);
+protected:
+  double Oc_,Ob_,h100_;
+  double kmin_,kmax_;
+  int interptyp_;
+  vector<double> k_, tf_;
+};
+
+
+//-----------------------------------------------------------------------------------
+class GrowthFactor : public GenericFunc {
+public:
+  GrowthFactor(double OmegaMatter0,double OmegaLambda0);
+  GrowthFactor(GrowthFactor& d1);
+  virtual ~GrowthFactor(void);
+  virtual double operator() (double z);
+  void SetParTo(double OmegaMatter0,double OmegaLambda0);
+  bool SetParTo(double OmegaMatter0);
+protected:
+  double O0_,Ol_;
+};
+
+
+//-----------------------------------------------------------------------------------
+class PkSpectrum0 : public GenericFunc {
+public:
+  PkSpectrum0(InitialSpectrum& pkinf,TransfertEisenstein& tf);
+  PkSpectrum0(PkSpectrum0& pk0);
+  virtual ~PkSpectrum0(void);
+  virtual double operator() (double z);
+  InitialSpectrum& GetPkIni(void) {return pkinf_;}
+  TransfertEisenstein& GetTransfert(void) {return tf_;}
+protected:
+  InitialSpectrum& pkinf_;
+  TransfertEisenstein& tf_;
+};
+
+//-----------------------------------------------------------------------------------
+class PkSpectrumZ : public GenericFunc {
+public:
+  typedef enum {PK=0, DELTA=1} ReturnSpectrum;
+  PkSpectrumZ(PkSpectrum0& pk0,GrowthFactor& d1,double zref=0.);
+  PkSpectrumZ(PkSpectrumZ& pkz);
+  virtual ~PkSpectrumZ(void);
+  virtual double operator() (double k);
+  virtual double operator() (double k,double z);
+  void   SetZ(double z) {zref_ = z;}
+  double GetZ(void) {return zref_;}
+  void SetTypSpec(ReturnSpectrum typspec=PK);
+  void SetScale(double scale=1.) {scale_=scale;}
+  double GetScale(void) {return scale_;}
+  PkSpectrum0& GetPk0(void) {return pk0_;}
+  GrowthFactor& GetGrowthFactor(void) {return d1_;}
+protected:
+  PkSpectrum0& pk0_;
+  GrowthFactor& d1_;
+  double zref_, scale_;
+  ReturnSpectrum typspec_;
+};
+
+//-----------------------------------------------------------------------------------
+class VarianceSpectrum : public GenericFunc {
+public:
+
+  typedef enum {TOPHAT=0, GAUSSIAN=1, NOFILTER=2} TypeFilter;
+
+  VarianceSpectrum(GenericFunc& pk,double R,TypeFilter typfilter);
+  VarianceSpectrum(VarianceSpectrum& pkinf);
+  virtual ~VarianceSpectrum(void);
+
+  void SetRadius(double R);
+  void SetFilter(TypeFilter typfilter=TOPHAT);
+  void SetInteg(double dperc=0.1,double dlogkinc=-1.,double dlogkmax=-1.,unsigned short glorder=4);
+
+  double Variance(double kmin,double kmax);
+
+  // ATTENTION: La fonction a integrer est : f(k)dk = k^3*Pk(k)/(2Pi^2) *filter2(k*R) *dk/k
+  virtual double operator() (double k) {return k*k*pk_(k)*Filter2(k*R_)/(2.*M_PI*M_PI);}
+  double Filter2(double x);
+
+  // Aide a l'integration
+  double FindMaximum(double kmin,double kmax,double eps=1.e-3);
+  int FindLimits(double high,double &kmin,double &kmax,double eps=1.e-3);
+
+protected:
+
+  GenericFunc& pk_;
+  TypeFilter typfilter_;
+  double R_;
+
+  double dperc_,dlogkinc_,dlogkmax_;
+  unsigned short glorder_;
+
+};
+
+} // Fin du namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/planckspectra.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/planckspectra.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/planckspectra.cc	(revision 3382)
@@ -0,0 +1,323 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "pexceptions.h"
+
+#include "constcosmo.h"
+#include "planckspectra.h"
+
+namespace SOPHYA {
+
+/*
+----------------------------------------------------------------
+- UNITES:
+     Temperature en Kelvin  "K"
+     Frequence en GigaHertz  "Hz"
+     Longueur d'onde en Metre  "m"
+----------------------------------------------------------------
+- Frequence / Longeur d'onde
+ l = c/f ; f = c/l
+ dl = c/f^2 df = l^2/c df
+ df = c/l^2 dl = f^2/c dl
+ P[f] df = P[l] dl = P[f] c/l^2 dl = P[l] c/f^2 df
+----------------------------------------------------------------
+- Lois de Planck Wien et Rayleigh
+     Planck   H*Nu/(K*T) = H*C/(Lambda*K*T) quelconque
+     Wien     H*Nu/(K*T) = H*C/(Lambda*K*T) >> 1
+     Rayleigh H*Nu/(K*T) = H*C/(Lambda*K*T) << 1
+----------------------------------------------------------------
+- Les termes en facteur pour les lois de Planck Wien et Rayleigh
+        (la partie contenant l'exponentielle)
+ ainsi que pour les derivees des ces termes par rapport a la temperature
+ Planck:   1/[exp(H*f/(K*t))-1] = 1/[exp(HC/(l*K*t))-1]
+     der=  H*f/(K*t) /t * exp(HC/(l*K*t))/[exp(HC/(l*K*t))-1]^2
+ Wien:     1/exp(H*f/(K*t))
+     der=  H*f/(K*t) /t /exp(H*f/(K*t))
+ Rayleigh: 1/(H*f/(K*t))
+     der=  K/(H*f)
+ Pour x->0: compute exp(x)=1+x+x^2/2 for 1/(exp(x)-1)
+            soit 1/(exp(x)-1)  -> 1/(x+x^2/2)
+  car exp(x)-1 vaut zero plus vite que son DL a cause de la soustraction
+----------------------------------------------------------------
+ - RADIANCE (Brillance) en fonction de nu ou lambda
+ nombre de watts (ou photons par seconde)
+ radies par unite de surface par steradian et par hertz (ou metre)
+    2*f^2/c^2   * 1/(exp()-1)    ph/s/m^2/Sr/Hz
+    2*h*f^3/c^2 * 1/(exp()-1)    W/m^2/Sr/Hz
+    2*c/l^4     * 1/(exp()-1)    ph/s/m^2/Sr/m
+    2*h*c^2/l^5 * 1/(exp()-1)    W/m^2/Sr/m
+----------------------------------------------------------------
+ - EMITTANCE en fonction de nu ou lambda
+ nombre de watts (ou photons par seconde)
+ radies dans un hemisphere (2*PI sr)
+ par unite de surface et par hertz (ou metre)
+ ..quand on integre sur 2Pi sr il faut
+ ..multiplier par cos(theta)  -> facteur Pi uniquement
+    EMITTANCE = Pi * RADIANCE
+    2*Pi*f^2/c^2   * 1/(exp()-1)    ph/s/m^2/Hz
+    2*Pi*h*f^3/c^2 * 1/(exp()-1)    W/m^2/Hz
+    2*Pi*c/l^4     * 1/(exp()-1)    ph/s/m^2/m
+    2*Pi*h*c^2/l^5 * 1/(exp()-1)    W/m^2/m
+----------------------------------------------------------------
+ - DENSITE en fonction de nu ou lambda
+ nombre de joules (ou photons) par m^3  et par hertz (ou metre)
+   DENSITE = 4*Pi/c * RADIANCE
+   8*Pi*f^2/c^3    * 1/(exp()-1)    ph/m^3/Hz
+   8*Pi*h*f^3/c^3  * 1/(exp()-1)    J/m^3/Hz
+   8*Pi/l^4        * 1/(exp()-1)    ph/m^3/m
+   8*Pi*h*c/l^5    * 1/(exp()-1)    J/m^3/m
+----------------------------------------------------------------
+ - DENSITE d'energie totale  (loi de Stefan-Boltzman)
+   4*sigma*T^4/C   J/m^3
+   Sigma = 2*PI^5*K^4/(15.*C^2*H^3) = PI^2*K^4/(60.*Hbar^3*C2)
+----------------------------------------------------------------
+*/
+
+/*
+POUR TESTER LES LIMITES DE L'EXPONENTIELLE:
+1-/ copier/coller les lignes suivantes dans toto.icc
+double x=10.;
+for(int i=0;i<35;i++) {
+  double ex = exp(x);
+  double exm1a = x*(1.+x/2.*(1.+x/3.)),;
+  printf("x=%g exp(x)=%e exp(x)-1=%e dl=%e (d=%e)\n",x,ex,ex-1.,exm1a,ex-1.-exm1a);
+  x /= 10.;
+}
+2-/ executer sous spiapp: > c++execfrf toto.icc
+*/
+
+
+#define MAXARGEXP 100.    /* maxi = 709.7827128933840 */
+#define MINARGEXP 1.e-10  /* Replace exp(x) by DL for 1/(exp(x)-1) when x->0 */
+
+//************************************************************************
+// vitesse de la lumiere en m/s
+double CinM_ = SpeedOfLight_Cst*1e+3;
+// h/k pour une frequence en Hz
+double HsK_ = h_Planck_Cst/k_Boltzman_Cst;
+// hc/k pour une longeur d'onde en metre
+double HCsK_ = h_Planck_Cst*CinM_/k_Boltzman_Cst;
+
+//************************************************************************
+PlanckSpectra::PlanckSpectra(double T)
+  : T_(T) , spectraapprox_(PLANCK) , spectrafunc_(VALUE) , spectravar_(NU)
+  , spectraunit_(ANGSFLUX) , spectrapower_(POWER)
+{
+}
+
+PlanckSpectra::PlanckSpectra(PlanckSpectra& s)
+  : T_(s.T_) , spectraapprox_(s.spectraapprox_) , spectrafunc_(s.spectrafunc_) , spectravar_(s.spectravar_)
+  , spectraunit_(s.spectraunit_), spectrapower_(s.spectrapower_)
+{
+}
+
+PlanckSpectra::~PlanckSpectra(void)
+{
+}
+
+//************************************************************************
+void PlanckSpectra::SetSpectraApprox(SpectraApprox spectraapprox)
+// spectraapprox = PLANCK   : Planck spectra
+//               = RAYLEIGH : Rayleigh spectra
+//               = WIEN     : Wien spectra
+{
+  spectraapprox_ = spectraapprox;
+}
+
+void PlanckSpectra::SetSpectraFunc(SpectraFunc spectrafunc)
+// spectrafunc = VALUE : spectra
+//             = DERIV : derivative of spectra relative to temperature
+{
+  spectrafunc_ = spectrafunc;
+}
+
+void PlanckSpectra::SetSpectraVar(SpectraVar spectravar)
+// spectravar = NU     : variable is frequency (Hz)
+//            = LAMBDA : variable is wavelength (m)
+{
+  spectravar_ = spectravar;
+}
+
+void PlanckSpectra::SetSpectraPower(SpectraPower spectrapower)
+// spectrapower = POWER : in W/...
+//              = PHOTON : in photon/s/...
+{
+  spectrapower_ = spectrapower;
+}
+
+void PlanckSpectra::SetSpectraUnit(SpectraUnit spectraunit)
+// spectraunit = ANGSFLUX  : radiance   W/m^2/Sr/Hz  or ...
+//             = SFLUX     : emittance  W/m^2/Hz     or ... 
+//             = DENSENERG : density    J/m^3/Hz     or ...
+//             = EXPON     : just the function exp() or equivalent for Rayleigh
+{
+  spectraunit_ = spectraunit;
+}
+
+
+//************************************************************************
+double PlanckSpectra::F2L(double nu_or_lambda)
+// Convert frequency (GHz) to/from Wavelength (m)
+// Lambda(m) * Nu(GHz) = C(km/s) * 10^-6
+{
+  return CinM_ / nu_or_lambda;
+}
+
+//************************************************************************
+double PlanckSpectra::PlanckExp(double fl)
+{
+  double x = (spectravar_==LAMBDA) ? HCsK_/(fl*T_) : HsK_*fl/T_;
+
+  if(spectraapprox_ == RAYLEIGH) return 1./x;  // Rayleigh
+
+  if(x>MAXARGEXP) return 0.;
+
+  if(spectraapprox_ == WIEN) return exp(-x);  // Wien
+
+  if(x<MINARGEXP) return 1./(x*(1.+x/2.));
+  return 1./(exp(x)-1.);
+}
+
+double PlanckSpectra::DPlanckExp_DT(double fl)
+{
+  if(spectraapprox_ == RAYLEIGH)
+    return (spectravar_==LAMBDA) ? fl/HCsK_: 1. / (HsK_*fl);  // Rayleigh
+
+  double x = (spectravar_==LAMBDA) ? HCsK_/(fl*T_) : HsK_*fl/T_;
+
+  if(x>MAXARGEXP) return 0.;
+
+  if(spectraapprox_ == WIEN) return x/T_ * exp(-x);  // Wien
+
+  double v;
+  if(x<MINARGEXP) { // 1/(exp(x)-1)  -derive-> -exp(x)/(exp(x)-1)^2
+    v = x*(1.+x/2.);
+    return x/T_ * (1.+v)/(v*v);
+  }
+  v = exp(x);
+  return x/T_ * v/((v-1.)*(v-1.));  
+}
+
+//------------------------------------------------------------
+double PlanckSpectra::operator() (double x)
+{
+  // --- type de spectre et d'approximation selon choix variable
+  double fex = (spectrafunc_==DERIV) ? DPlanckExp_DT(x): PlanckExp(x);
+
+  // --- le coefficient multiplicateur devant l'expo
+  if(spectraunit_ == EXPON) return fex;  // expo seule
+
+  // radiance en ph/...               longeur d'onde         frequency
+  double coeff = (spectravar_==LAMBDA) ? 2.*CinM_/(x*x*x*x): 2.*x*x/(CinM_*CinM_);
+
+  if(spectraunit_ == SFLUX)      coeff *= M_PI;  // emittance en ph/...
+  else if(spectraunit_ == DENSENERG) coeff *= 4.*M_PI/CinM_;  // densite en ph/...
+
+  // unite en W/...                longeur d'onde         frequency
+  if(spectrapower_ == POWER)
+    coeff *= (spectravar_==LAMBDA) ? h_Planck_Cst*CinM_/x: h_Planck_Cst*x;
+
+  return coeff * fex;
+}
+
+//------------------------------------------------------------
+double PlanckSpectra::PlanckEnergie(void)
+//  densite d'energie: energie par m^3  en "J / m^3"
+// cste de Stefan-Boltzmann en W/m^2/K^4
+{
+  return 4.*StefBoltz_Cst*T_*T_*T_*T_/(SpeedOfLight_Cst*1000.);
+}
+
+//------------------------------------------------------------
+double PlanckSpectra::PlanckPhoton(void)
+//  densite de photons: nombre de photons par m^3  en "ph / m^3"
+{
+  double x = k_Boltzman_Cst*T_/(h_Planck_Cst*SpeedOfLight_Cst*1000.);
+  return 16.*M_PI*Zeta_3_Cst* x*x*x;
+}
+
+double PlanckSpectra::WienLaw(void)
+// Retourne la frequence (ou longeur d'onde) du maximum
+// du spectre de radiance (ou emittance ou densite).
+// La valeur du maximum depend de l'unite du spectre (W/... ou Ph/s/...)
+/*
+--- Les fonctions:
+En frequence: n = 3  en W/...  ,  n = 2  en Ph/...
+En longueur d'onde: n = 5  en W/...  ,  n = 4  en Ph/...
+f[x_] := x^n*Exp[-x]; Solve[f'[x]==0,x]   // Wien
+f[x_] := x^n/(Exp[x]-1); NSolve[f'[x]==0,x,17]  // Planck
+La derivee par rapport a T des fonctions en frequence:
+df/dT[x_] := x^(n+1)*Exp[-x]; Solve[f'[x]==0,x]  // Wien
+df/dT[x_] := x^(n+1)*Exp[x]/(Exp[x]-1)^2; NSolve[f'[x]==0,x,17]  // Planck
+*/
+{
+  double x=-1.;
+  if(spectravar_ == NU) { // Frequence
+    if(spectrafunc_ == VALUE) {  // Le spectre
+      if(spectrapower_ == POWER) //  W/...
+        {if(spectraapprox_==PLANCK) x=2.82143938074; else if(spectraapprox_==WIEN) x=3.;}
+      else if(spectrapower_ == PHOTON) //  Ph/s/...
+        {if(spectraapprox_==PLANCK) x=1.59362426; else if(spectraapprox_==WIEN) x=2.;}
+    } else if(spectrafunc_ == DERIV) {  // La derivee du spectre
+      if(spectrapower_ == POWER) //  W/... 
+        {if(spectraapprox_==PLANCK) x=3.830016095; else if(spectraapprox_==WIEN) x=4.;}
+      else if(spectrapower_ == PHOTON) //  Ph/s/...
+        {if(spectraapprox_==PLANCK) x=2.575678888; else if(spectraapprox_==WIEN) x=3.;}
+    }
+  } else { // Longeur d'onde
+    if(spectrafunc_ == VALUE) {  // Le spectre
+      if(spectrapower_ == POWER) //  W/...
+        {if(spectraapprox_==PLANCK) x=4.96511420; else if(spectraapprox_==WIEN) x=5.;}
+      else if(spectrapower_ == PHOTON) //  Ph/s/...
+        {if(spectraapprox_==PLANCK) x=3.9206904099; else if(spectraapprox_==WIEN) x=4.;}
+    } else if(spectrafunc_ == DERIV) {  // La derivee du spectre
+      if(spectrapower_ == POWER) //  W/...
+        {if(spectraapprox_==PLANCK) x=5.969409190; else if(spectraapprox_==WIEN) x=6.;}
+     else if(spectrapower_ == PHOTON) //  Ph/s/...
+        {if(spectraapprox_==PLANCK) x=4.928119345; else if(spectraapprox_==WIEN) x=5.;}
+    }
+  }
+
+  if(x<0.) return x;  // Rayleigh n'a pas de maximum
+  if(spectravar_ == NU) return x / HsK_ *T_; // Frequence
+  return HCsK_ / x /T_; // Longeur d'onde
+}
+
+double PlanckSpectra::FindMaximum(double eps)
+// Retourne le maximum des spectres (a la precicion eps)
+{
+  if(spectraapprox_ == RAYLEIGH) {  // Pas de maximum pour les spectres de Raleigh
+    cout<<"PlanckSpectra::FindMaximum : no maximum for Raleigh spectra"<<endl;
+    throw ParmError("PlanckSpectra::FindMaximum : no maximum for Raleigh spectra");
+  }
+  if(eps<=0.) eps = 0.001;
+
+  double xmax = WienLaw(), wmax=(*this)(xmax);
+  double xlim[2]={xmax,xmax};
+
+  // Encadrement du maximum par xlim[0] et xlim[1]
+  while( (*this)(xlim[1])>=0.01*wmax ) xlim[1] *= 2.;
+  while( (*this)(xlim[0])>=0.01*wmax ) xlim[0] /= 2.;
+  //cout<<"FindMaximum: wmax="<<wmax<<" pour x=["<<xlim[0]<<","<<xlim[1]<<"]"<<endl;
+
+  while( (xlim[1]-xlim[0])/xmax > eps ) {
+   wmax=-1.;
+   double dx = (xlim[1]-xlim[0])/10.;
+   for(double x=xlim[0]; x<=xlim[1]; x+=dx) {
+     double f=(*this)(x);
+     if(f>wmax) {wmax=f; xmax=x;}
+   }
+   //cout<<"...wmax="<<wmax<<" pour xmax="<<xmax<<" dx="<<dx<<endl;
+   xlim[0] = xmax-dx*1.1; xlim[1] = xmax+dx*1.1;
+ }
+
+
+  //cout<<"wmax="<<wmax<<" pour x="<<xmax<<"  dx="<<xlim[1]-xlim[0]<<endl;
+  return xmax;
+}
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/planckspectra.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/planckspectra.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/planckspectra.h	(revision 3382)
@@ -0,0 +1,56 @@
+#ifndef PLANCKSPECTRA_SEEN
+#define PLANCKSPECTRA_SEEN
+
+#include "machdefs.h"
+#include "genericfunc.h"
+
+namespace SOPHYA {
+
+//-----------------------------------------------------------------------------------
+class PlanckSpectra : public GenericFunc {
+public:
+
+  typedef enum {PLANCK=0, RAYLEIGH=1, WIEN=2} SpectraApprox;
+  typedef enum {POWER=0, PHOTON=1} SpectraPower;
+  typedef enum {VALUE=0, DERIV=1} SpectraFunc;
+  typedef enum {NU=0, LAMBDA=1} SpectraVar;
+  typedef enum {ANGSFLUX=0, SFLUX=1, DENSENERG=2, EXPON=3} SpectraUnit;
+
+  PlanckSpectra(double T);
+  PlanckSpectra(PlanckSpectra& s);
+  virtual ~PlanckSpectra(void);
+
+  inline void SetTemperature(double T) {T_ = T;}
+  inline double GetTemperature(void) {return T_;}
+
+  void SetSpectraApprox(SpectraApprox spectraapprox=PLANCK);
+  void SetSpectraFunc(SpectraFunc spectrafunc=VALUE);
+  void SetSpectraVar(SpectraVar spectravar=NU);
+  void SetSpectraUnit(SpectraUnit spectraunit=ANGSFLUX);
+  void SetSpectraPower(SpectraPower spectrapower=POWER);
+
+
+  virtual double operator() (double x);
+
+  double F2L(double nu_or_lambda);
+  double PlanckEnergie(void);
+  double PlanckPhoton(void);
+  double WienLaw(void);
+  double FindMaximum(double eps=0.001);
+
+protected:
+  double T_;
+  SpectraApprox spectraapprox_;
+  SpectraFunc spectrafunc_;
+  SpectraVar spectravar_;
+  SpectraUnit spectraunit_;
+  SpectraPower spectrapower_;
+
+  double PlanckExp(double fl);
+  double DPlanckExp_DT(double fl);
+
+};
+
+} // Fin du namespace SOPHYA
+
+#endif
Index: /tags/V1_0/Cosmo/SimLSS/schechter.cc
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/schechter.cc	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/schechter.cc	(revision 3382)
@@ -0,0 +1,473 @@
+#include "machdefs.h"
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "pexceptions.h"
+#include "histos.h"
+#include "perandom.h"
+#include "tvector.h"
+#include "fioarr.h"
+
+#include "constcosmo.h"
+#include "geneutils.h"
+#include "schechter.h"
+
+namespace SOPHYA {
+
+///////////////////////////////////////////////////////////
+//***************** Schechter Functions *****************//
+///////////////////////////////////////////////////////////
+
+// HI mass function:
+//    see M.Zwaan astroph-0502257 (MNRAS Letters, Volume 359, Issue 1, pp. L30-L34.)
+//    see M.Zwaan astroph-9707109 (ApJ, Volume 509, Issue 2, pp. 687-702.)
+
+Schechter::Schechter(double nstar,double mstar,double alpha)
+  : nstar_(nstar) , mstar_(mstar) , alpha_(alpha) , outvalue_(0)
+{
+}
+
+Schechter::Schechter(Schechter& f)
+  : nstar_(f.nstar_) , mstar_(f.mstar_) , alpha_(f.alpha_) , outvalue_(f.outvalue_)
+{
+}
+
+Schechter::Schechter(void)
+  : nstar_(0.) , mstar_(0.) , alpha_(0.) , outvalue_(0)
+{
+}
+
+Schechter::~Schechter(void)
+{
+}
+
+void Schechter::SetOutValue(unsigned short outvalue)
+// outvalue = 0 : give dn/dm
+//          = 1 : give m*dn/dm
+{
+  if(outvalue>1) {
+    cout<<"Schechter::SetOutValue: Error bad outvalue: "<<outvalue<<endl;
+    throw ParmError("Schechter::SetOutValue: Error bad outvalue");
+  }
+  outvalue_ = outvalue;
+}
+
+unsigned short Schechter::GetOutValue(void)
+{
+  return outvalue_;
+}
+
+void Schechter::SetParam(double nstar,double mstar,double alpha)
+{
+  nstar_ = nstar; mstar_ = mstar; alpha_ = alpha;
+}
+
+void Schechter::GetParam(double& nstar,double& mstar,double& alpha)
+{
+  nstar = nstar_; mstar = mstar_; alpha = alpha_;
+}
+
+double Schechter::operator() (double m)
+// Return : "dn/dm = f(m)" or "m*dn/dm = f(m)"
+{
+  double x = m/mstar_;
+  double dndm = nstar_/mstar_ * pow(x,alpha_) * exp(-x);
+  if(outvalue_) dndm *= m;  // on veut m*dn/dm
+  return dndm;
+}
+
+
+double Schechter::Integrate(double massmin,double massmax,int npt)
+// Integrate from massmin to massmax with at least npt points log10 spaced
+{
+ if(massmin<=0. || massmax<=0. || massmax<=massmin) return 0.;
+ if(npt<1) npt = 100;
+ double lmassmin = log10(massmin), lmassmax = log10(massmax);
+ double perc=0.01, dlxinc=(lmassmax-lmassmin)/npt, dlxmax=10.*dlxinc; unsigned short glorder=4;
+ double sum = IntegrateFuncLog(*this,lmassmin,lmassmax,perc,dlxinc,dlxmax,glorder);
+ return sum;
+}
+
+void Schechter::Print(void)
+{
+  cout<<"Schechter::Print: nstar="<<nstar_<<" Mpc^-3"
+      <<"  mstar="<<mstar_<<" MSol"
+      <<"  alpha="<<alpha_
+      <<"  (outvalue="<<outvalue_<<" -> return ";
+  if(outvalue_) cout<<"m*dn/dm)"; else cout<<"dn/dm)";
+  cout<<endl;
+}
+
+///////////////////////////////////////////////////////////
+//******* Les facilites pour tirer sur Schechter ********//
+///////////////////////////////////////////////////////////
+
+SchechterMassDist::SchechterMassDist(Schechter sch,double massmin,double massmax,int nbinmass)
+// On veut une fonction de tirage aleatoire de la masse de N galaxies sur une Schechter
+// Pour optimiser on cree (eventuellement) des histos de tirage
+// ATTENTION: on donne les limites en masses pour les histos mais leurs abscisses
+//   sont en log10(masse): histo [log10(massmin),log10(massmax)] avec nbinmass bins
+// Si nbinmass<0 alors c'est le nombre de points par decade
+  : sch_(sch) , sch_outvalue_(sch.GetOutValue())
+  , massmin_(massmin) , massmax_(massmax) , nbinmass_(nbinmass)
+  , ngalmin_(0) , ngalmax_(0) , nvalngal_(0)
+  , ntrial_dir(0) , ntrial_tab(0)
+  , hmdndm_(NULL) , tirhmdndm_(NULL)
+{
+  if(massmin_>massmax_  || massmin_<=0. || massmax_<=0.|| nbinmass_==0) {
+    cout<<"SchechterMassDist::SchechterMassDist: error in input values"<<endl;
+    throw ParmError("SchechterMassDist::SchechterMassDist: error in input values");
+  }
+
+  // Creation du tirage aleatoire sur la Schechter
+  sch_outvalue_ = sch.GetOutValue();  // on sauve la configuration de la schechter
+  sch.SetOutValue(1);  // on veut m*dN/dm
+  double lnx1 = log10(massmin_), lnx2 = log10(massmax_); // Binning en log10 de la masse
+  if(nbinmass_<0) nbinmass_ = int((-nbinmass_)*(lnx2-lnx1+1.));
+  hmdndm_ = new Histo(lnx1,lnx2,nbinmass_); hmdndm_->ReCenterBin();
+  FuncToHisto(sch,*hmdndm_,true);  // true -> bin en log10(x)
+  tirhmdndm_ = new FunRan(*hmdndm_,true);  // true -> histo est pdf
+  sch.SetOutValue(sch_outvalue_);  // on remet a la valeur initiale
+}
+
+SchechterMassDist::SchechterMassDist(void)
+  : sch_outvalue_(0)
+  , massmin_(0.) , massmax_(0.) , nbinmass_(0)
+  , ngalmin_(0) , ngalmax_(0) , nvalngal_(0)
+  , ntrial_dir(0) , ntrial_tab(0)
+  , hmdndm_(NULL) , tirhmdndm_(NULL)
+{
+}
+
+SchechterMassDist::~SchechterMassDist(void)
+{
+ Delete();
+}
+
+void SchechterMassDist::Delete(void)
+{
+ if(hmdndm_) delete hmdndm_;
+ if(tirhmdndm_) delete tirhmdndm_;
+ hmass_.resize(0);
+ tmass_.resize(0);
+ ntrial_dir = ntrial_tab = 0;
+}
+
+int SchechterMassDist::GetMassLim(double& massmin,double& massmax)
+{
+ massmin = massmin_;
+ massmax = massmax_;
+ return nbinmass_;
+}
+
+int SchechterMassDist::SetNgalLim(int ngalmax,int ngalmin,unsigned long nalea)
+// Creation des Histos de tirage pour ngalmin a ngalmax galaxies
+{
+ int lp=2;
+ ngalmin_=ngalmax_=nvalngal_=0;
+ if(ngalmin<=0) ngalmin=1;
+ if(ngalmax<ngalmin || ngalmax==1) return 0;
+ ngalmin_ = ngalmin;
+ ngalmax_ = ngalmax;
+ nvalngal_ = ngalmax-ngalmin+1;
+  
+ if(nalea<1) nalea = 100000;
+
+ if(lp>0) cout<<"SchechterMassDist::SetNgalLim: ngal=["
+              <<ngalmin_<<","<<ngalmax_<<"] n="<<nvalngal_
+              <<" filling with "<<nalea<<" trials"<<endl;
+
+ //------- Construct histo
+ double lnx1 = log10(massmin_), lnx2 = log10(massmax_);
+ if(lp>0) cout<<"> Creating "<<nvalngal_<<" histos ["<<lnx1<<","<<lnx2<<"] n="<<nbinmass_<<endl;
+ for(int i=ngalmin_;i<=ngalmax_;i++) {
+   Histo h(*hmdndm_); h.Zero();
+   hmass_.push_back(h);
+ }
+ if(lp>1) cout<<"...number of histos is "<<hmass_.size()<<endl;
+
+ //------- Remplissage random
+ sch_.SetOutValue(1);  // on veut m*dN/dm
+ int lpmod = nalea/20; if(lpmod<=0) lpmod=1;
+ double s1=0., sc1=0.; unsigned long ns1=0;
+ double sax=0., scax=0.; unsigned long nsax=0;
+ for(unsigned long ia=0;ia<nalea;ia++) {
+   if(lp>1 && ia%lpmod==0) cout<<"...tirage "<<ia<<endl;
+   double sum = 0.;
+   for(int i=1;i<=ngalmax_;i++) {
+     //double l10m = tirhmdndm_->Random();
+     double l10m = tirhmdndm_->RandomInterp();
+     double m = pow(10.,l10m);
+     sum += m;
+     s1 += m; sc1 += m*m; ns1++;
+     int ipo = i-ngalmin_;
+     if(ipo<0) continue;
+     // ATTENTION: l'histo de tirage stoque le log10(moyenne=somme_masses/ngal).
+     //            Ca permet d'avoir le meme binning quelque soit ngal
+     double v = log10(sum/(double)i);
+     hmass_[ipo].Add(v);
+     if(i==ngalmax) {sax += sum/(double)i; scax += sum/(double)i*sum/(double)i; nsax++;}
+   }
+ }
+ sch_.SetOutValue(sch_outvalue_);  // on remet a la valeur initiale
+
+ if(ns1>1) {
+   s1 /= ns1; sc1 = sc1/ns1 - s1*s1;
+   cout<<"...Mean mass for ngal=1: "<<s1<<" ("<<log10(fabs(s1))<<")"
+       <<" s="<<sqrt(fabs(sc1))<<" (ntrials "<<ns1<<")"<<endl;
+ }
+ if(nsax>1) {
+   sax /= nsax; scax = scax/nsax - sax*sax;
+   cout<<"...Mean mass for ngal="<<ngalmax_<<": "<<sax<<" ("<<log10(fabs(sax))<<")"
+       <<" s="<<sqrt(fabs(scax))<<" (ntrials "<<nsax<<")"<<endl;
+ }
+
+ //------- Generation des classes de tirage aleatoire et des histos de verif
+ if(lp>0) cout<<"> Creating "<<nvalngal_<<" FunRan"<<endl;
+ for(unsigned int i=0;i<hmass_.size();i++) {
+   FunRan t(hmass_[i],true);
+   tmass_.push_back(t);
+ }
+ if(lp>1) cout<<"...number of funran is "<<tmass_.size()<<endl;
+
+ return nvalngal_;
+}
+
+int SchechterMassDist::GetNgalLim(int& ngalmax,int& ngalmin)
+{
+ ngalmax = ngalmax_;
+ ngalmin = ngalmin_;
+ return nvalngal_;
+}
+
+Histo SchechterMassDist::GetHmDnDm(void) const
+{
+  return *hmdndm_;
+}
+
+FunRan SchechterMassDist::GetTmDnDm(void) const
+{
+  return *tirhmdndm_;
+}
+
+Histo SchechterMassDist::GetHisto(int i) const
+{
+  if(i<0 || i>=nvalngal_) {
+    cout<<"SchechterMassDist::GetHisto: error in input values"<<endl;
+    throw ParmError("SchechterMassDist::GetHisto: error in input values");
+  }
+  return hmass_[i];
+}
+
+FunRan SchechterMassDist::GetFunRan(int i) const
+{
+  if(i<0 || i>=nvalngal_) {
+    cout<<"SchechterMassDist::GetFunRan: error in input values"<<endl;
+    throw ParmError("SchechterMassDist::GetFunRan: error in input values");
+  }
+  return tmass_[i];
+}
+
+double SchechterMassDist::TirMass(int ngal)
+{
+ if(ngal<1) return 0.;
+
+ int ipo = IndexFrNGal(ngal);
+ double masse_des_ngal = 0.;
+ if(ipo<0) {  // Pas d'histos de tirage pour ce nombre de galaxies
+   for(long i=0;i<ngal;i++) {  // On tire donc ngal fois sur la Schechter
+     // double lm = tirhmdndm_->Random();
+     double lm = tirhmdndm_->RandomInterp();
+     masse_des_ngal += pow(10.,lm);  // ATTENTION abscisse en log10(masse)
+   }
+   ntrial_dir++;
+ } else {
+   // ATTENTION l'histo de tirage stoque le log10(moyenne=somme_masses/ngal)
+   //double lmngal = tmass_[ipo].Random();
+   double lmngal = tmass_[ipo].RandomInterp();
+   masse_des_ngal = pow(10.,lmngal) * ngal;
+   ntrial_tab++;
+ }
+
+ return masse_des_ngal;
+}
+
+void SchechterMassDist::Print(void)
+{
+ cout<<"SchechterMassDist::Print: mass=["<<massmin_<<","<<massmax_<<"] n="<<nbinmass_<<endl
+     <<"                 ngal=["<<ngalmin_<<","<<ngalmax_<<"] n="<<nvalngal_<<endl;
+ sch_.Print();
+}
+
+void SchechterMassDist::PrintStatus(void)
+{
+ cout<<"SchechterMassDist::PrintStatus: number of trials: direct="<<ntrial_dir
+     <<" tabulated="<<ntrial_tab<<endl;
+}
+
+void SchechterMassDist::WritePPF(string ppfname)
+{
+ char str[64];
+ cout<<"SchechterMassDist::WritePPF into "<<ppfname<<endl;
+ POutPersist pos(ppfname.c_str());
+
+ double nstar,mstar,alpha;
+ sch_.GetParam(nstar,mstar,alpha);
+ TVector<r_8> tdum(20); tdum = 0.;
+ tdum(0) = nstar;
+ tdum(1) = mstar;
+ tdum(2) = alpha;
+ tdum(3) = sch_outvalue_;
+ tdum(4) = massmin_;
+ tdum(5) = massmax_;
+ tdum(6) = nbinmass_;
+ tdum(7) = ngalmin_;
+ tdum(8) = ngalmax_;
+ tdum(9) = nvalngal_;
+ tdum(10) = hmass_.size();
+ tdum(11) = tmass_.size();
+ pos << PPFNameTag("SMDparam") << tdum;
+
+ pos << PPFNameTag("SMDhmdndm") << *hmdndm_;
+ pos << PPFNameTag("SMDtirhmdndm") << *tirhmdndm_;
+
+ if(hmass_.size()>0) {
+   for(unsigned int i=0;i<hmass_.size();i++) {
+     sprintf(str,"SMDh%d",NGalFrIndex(i));
+     pos << PPFNameTag(str) << hmass_[i];
+   }
+ }
+
+ if(tmass_.size()>0) {
+   for(unsigned int i=0;i<tmass_.size();i++) {
+     sprintf(str,"SMDt%d",NGalFrIndex(i));
+     Histo hdum(tmass_[i]);
+     pos << PPFNameTag(str) << hdum;
+   }
+ }
+
+}
+
+void SchechterMassDist::ReadPPF(string ppfname)
+{
+ Delete(); // On des-alloue si deja remplit!
+
+ char str[64];
+ cout<<"SchechterMassDist::ReadPPF from "<<ppfname<<endl;
+ PInPersist pis(ppfname.c_str());
+
+ TVector<r_8> tdum;
+ pis >> PPFNameTag("SMDparam") >> tdum;
+ sch_.SetParam(tdum(0),tdum(1),tdum(2));
+ sch_.SetOutValue((unsigned short)(tdum(3)+0.1));
+ massmin_ = tdum(4);
+ massmax_ = tdum(5);
+ nbinmass_ = int(tdum(6)+0.1);
+ ngalmin_ = int(tdum(7)+0.1);
+ ngalmax_ = int(tdum(8)+0.1);
+ nvalngal_ = int(tdum(9)+0.1);
+ unsigned int nhmass = (unsigned int)(tdum(10)+0.1);
+ unsigned int ntmass = (unsigned int)(tdum(11)+0.1);
+
+ {
+ Histo hdum;
+ pis >> PPFNameTag("SMDhmdndm") >> hdum;
+ hmdndm_ = new Histo(hdum);
+ pis >> PPFNameTag("SMDtirhmdndm") >> hdum;
+ tirhmdndm_ = new FunRan(hdum,false);
+ }
+
+ if(nhmass>0) {
+   for(unsigned int i=0;i<nhmass;i++) {
+     sprintf(str,"SMDh%d",NGalFrIndex(i));
+     Histo hdum;
+     pis >> PPFNameTag(str) >> hdum;
+     hmass_.push_back(hdum);
+   }
+ }
+
+ if(ntmass>0) {
+   for(unsigned int i=0;i<ntmass;i++) {
+     sprintf(str,"SMDt%d",NGalFrIndex(i));
+     Histo hdum;
+     pis >> PPFNameTag(str) >> hdum;
+     FunRan fdum(hdum,false);
+     tmass_.push_back(fdum);
+   }
+ }
+
+}
+
+///////////////////////////////////////////////////////////
+//***************** Fonctions de Check ******************//
+///////////////////////////////////////////////////////////
+
+bool IsCompatible(Schechter& sch1,Schechter& sch2,double eps)
+// on compare les differences a eps pres
+{
+  if(eps<=0.) eps=1.e-4;
+  double nstar1,mstar1,alpha1;
+  sch1.GetParam(nstar1,mstar1,alpha1);
+  double nstar2,mstar2,alpha2;
+  sch2.GetParam(nstar2,mstar2,alpha2);
+
+  // nstar et mstar ne sont jamais nuls
+  if(fabs(nstar1-nstar2)>fabs(nstar1+nstar2)/2.*eps) return false;
+  if(fabs(mstar1-mstar2)>fabs(mstar1+mstar2)/2.*eps) return false;
+
+  // alpha peut etre eventuellement nul
+  if(fabs(alpha1)<1.e-100 && fabs(alpha2)<1.e-100 && fabs(alpha1-alpha2)>eps) return false;
+  if(fabs(alpha1-alpha2)>fabs(alpha1+alpha2)/2.*eps) return false;
+  return true;
+}
+
+
+///////////////////////////////////////////////////////////
+//******************* Le Flux a 21cm ********************//
+///////////////////////////////////////////////////////////
+double Msol2LumiHI(double m)
+// Input:
+//    m : masse de HI en "Msol"
+// Return:
+//    la luminosite en W
+// L(m) =  2.393e+18* m(en masse solaire) en W
+{
+  return 2.393e+18 * m;
+}
+
+double Msol2FluxHI(double m,double d)
+// Input:
+//    m : masse de HI en "Msol"
+//    d : distance en "Mpc"  (si cosmo d=DLum(z))
+// Return:
+//    le flux total emis a 21 cm en W/m^2
+// Ref:
+// -- Binney & Merrifield, Galactic Astronomy p474 (ed:1998)
+// S(W/m^2) = 1e-26 * Nu_21cm(Hz) * m(en masse solaire) /(2.35e5 * C(km/s) * Dlum^2)
+//          = 2.0e-28 * m / Dlum^2
+// -- J.Peterson & K.Bandura, astroph-0606104  (eq 7)
+//    F.Abdalla & Rawlings, astroph-0411342 (eq 7 mais pb de d'unites?)
+//          (A_21cm = 2.86888e-15 s^-1)
+// S(W/m^2) = 3/4 * h(J.s) * Nu_21cm(Hz) * A_21cm(s^-1) * Msol(kg)/m_proton(kg)
+//                         / (4 Pi) / (Dlum(Mpc) * 3.0857e22(m/Mpc))^2
+//          = 2.0e-28 * m / Dlum^2
+//-------------
+{
+  return  2.0e-28 * m / (d*d);
+}
+
+double FluxHI2Msol(double f,double d)
+// Input:
+//    f : flux total emis a 21 cm en W/m^2
+//    d : distance en "Mpc"  (si cosmo d=DLum(z))
+// Return:
+//    m : masse de HI en "Msol"
+{
+  return f *d*d / 2.0e-28;
+}
+
+
+}  // Fin namespace SOPHYA
Index: /tags/V1_0/Cosmo/SimLSS/schechter.h
===================================================================
--- /tags/V1_0/Cosmo/SimLSS/schechter.h	(revision 3382)
+++ /tags/V1_0/Cosmo/SimLSS/schechter.h	(revision 3382)
@@ -0,0 +1,101 @@
+#ifndef SCHECHTER_SEEN
+#define SCHECHTER_SEEN
+
+#include "machdefs.h"
+#include "genericfunc.h"
+
+namespace SOPHYA {
+
+class Histo;
+class FunRan;
+
+//-----------------------------------------------------------------------------------
+class Schechter : public GenericFunc {
+public:
+  Schechter(double nstar,double mstar,double alpha);
+  Schechter(Schechter& f);
+  Schechter(void);
+  virtual ~Schechter(void);
+
+  void SetOutValue(unsigned short outvalue=0);
+  unsigned short GetOutValue(void);
+  void SetParam(double nstar,double mstar,double alpha);
+  void GetParam(double& nstar,double& mstar,double& alpha);
+
+  virtual double operator() (double m);
+
+  double Integrate(double massmin,double massmax,int npt=100);
+
+  virtual void Print(void);
+
+protected:
+  double nstar_,mstar_,alpha_;
+  unsigned short outvalue_;
+};
+
+//-----------------------------------------------------------------------------------
+class SchechterMassDist : public AnyDataObj {
+  friend class ObjFileIO<SchechterMassDist>;
+public:
+  SchechterMassDist(Schechter sch,double massmin,double massmax,int nbinmass);
+  SchechterMassDist(void);
+  virtual ~SchechterMassDist(void);
+
+  int GetMassLim(double& massmin,double& massmax);
+  int SetNgalLim(int ngalmax,int ngalmin=1,unsigned long nalea=10000);
+  int GetNgalLim(int& ngalmax,int& ngalmin);
+  int GetNgalLim(void) {return nvalngal_;}
+  Schechter& GetSchechter(void) {return sch_;}
+
+  inline int IndexFrNGal(int ngal) {
+    int i = ngal-ngalmin_;
+    if(nvalngal_<1 || i<0) return -1;
+    if(i>=nvalngal_) return -2; else return i;
+  }
+  inline int NGalFrIndex(int i) {
+    if(nvalngal_<1 || i<0 || i>=nvalngal_) return -1;
+    return ngalmin_+i;
+  }
+
+  Histo GetHmDnDm(void) const;
+  FunRan GetTmDnDm(void) const;
+
+  Histo GetHisto(int i) const;
+  FunRan GetFunRan(int i) const;
+
+  double TirMass(int ngal);
+
+  void Print(void);
+  void PrintStatus(void);
+
+  void WritePPF(string ppfname);
+  void ReadPPF(string ppfname);
+
+protected:
+ void Delete(void);
+
+ Schechter sch_;
+ unsigned short sch_outvalue_;
+
+ double massmin_,massmax_;   int nbinmass_;
+ int ngalmin_,ngalmax_,nvalngal_;
+ unsigned long ntrial_dir, ntrial_tab;
+
+ Histo* hmdndm_;
+ FunRan* tirhmdndm_;
+
+ vector<Histo> hmass_;
+ vector<FunRan> tmass_;
+};
+
+//-----------------------------------------------------------------------------------
+bool IsCompatible(Schechter& sch1,Schechter& sch2,double eps=1.e-4);
+
+//-----------------------------------------------------------------------------------
+double Msol2LumiHI(double m);
+double Msol2FluxHI(double m,double d);
+double FluxHI2Msol(double f,double d);
+
+} // Fin du namespace SOPHYA
+
+#endif
