Index: trunk/Cosmo/SimLSS/Makefile
===================================================================
--- trunk/Cosmo/SimLSS/Makefile	(revision 3155)
+++ trunk/Cosmo/SimLSS/Makefile	(revision 3157)
@@ -19,5 +19,5 @@
        $(EXE)cmvtstsch $(EXE)cmvtstblack $(EXE)cmvtvarspec \
        $(EXE)cmvdefsurv $(EXE)cmvobserv3d $(EXE)cmvtintfun \
-       $(EXE)cmvtpoisson $(EXE)cmvconcherr
+       $(EXE)cmvtpoisson $(EXE)cmvconcherr $(EXE)cmvtinterp
 #$(EXE)cmvtluc
  
@@ -25,5 +25,5 @@
           $(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)cmvobserv3d.o $(OBJ)cmvtintfun.o $(OBJ)cmvtinterp.o \
           $(OBJ)cmvtpoisson.o $(OBJ)cmvconcherr.o $(OBJ)cmvtluc.o
  
@@ -165,4 +165,12 @@
 
 ##############################################################################
+cmvtinterp: $(EXE)cmvtinterp
+	echo $@ " done"
+$(EXE)cmvtinterp: $(OBJ)cmvtinterp.o $(LIB)libcmvsimbao.a
+	$(CXXLINK) $(CXXREP) -o $@ $(OBJ)cmvtinterp.o $(MYLIB) 
+$(OBJ)cmvtinterp.o: cmvtinterp.cc
+	$(CXXCOMPILE) $(CXXREP) -I$(MYEXTINC) -o $@ cmvtinterp.cc
+
+##############################################################################
 cmvtluc: $(EXE)cmvtluc
 	echo $@ " done"
Index: trunk/Cosmo/SimLSS/cmvobserv3d.cc
===================================================================
--- trunk/Cosmo/SimLSS/cmvobserv3d.cc	(revision 3155)
+++ trunk/Cosmo/SimLSS/cmvobserv3d.cc	(revision 3157)
@@ -12,4 +12,5 @@
 
 #include "constcosmo.h"
+#include "cosmocalc.h"
 #include "schechter.h"
 #include "geneutils.h"
@@ -23,4 +24,5 @@
      <<" -a : init auto de l aleatoire"<<endl
      <<" -0 : use methode ComputeFourier0"<<endl
+     <<" -G : compute Pk(z=0) and apply growth factor in real space"<<endl
      <<" -x nx,dx : taille en x (npix,Mpc)"<<endl
      <<" -y ny,dy : taille en y (npix,Mpc)"<<endl
@@ -46,7 +48,9 @@
 
  // *** 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=5.; unsigned short glorder=4;
 
  // *** Spectrum and variance definition
@@ -75,4 +79,5 @@
  // *** type de generation
  bool computefourier0=false;
+ bool use_growth_factor = false;
  unsigned short nthread=4;
 
@@ -86,5 +91,5 @@
 
  char c;
- while((c = getopt(narg,arg,"ha0PWV2x:y:z:s:Z:")) != -1) {
+ while((c = getopt(narg,arg,"ha0PWV2Gx:y:z:s:Z:")) != -1) {
   switch (c) {
   case 'a' :
@@ -93,4 +98,7 @@
   case '0' :
     computefourier0 = true;
+    break;
+  case 'G' :
+    use_growth_factor = true;
     break;
   case 'x' :
@@ -142,5 +150,15 @@
 
  //-----------------------------------------------------------------
- cout<<endl<<"\n--- Create Spectrum and mass function"<<endl;
+ 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.Print();
+ double loscomref = univ.Dloscom(zref);
+ cout<<"zref = "<<zref<<" -> dloscom = "<<loscomref<<" Mpc"<<endl;
+
+ //-----------------------------------------------------------------
+  cout<<endl<<"\n--- Create Spectrum and mass function"<<endl;
 
  InitialSpectrum pkini(ns,as);
@@ -149,9 +167,9 @@
  //tf.SetNoOscEnv(2);
 
- GrowthFactor d1(om0,ol0);
+ GrowthFactor growth(om0,ol0);
 
  PkSpectrum0 pk0(pkini,tf);
 
- PkSpectrumZ pkz(pk0,d1,zref);
+ PkSpectrumZ pkz(pk0,growth,zref);
  
  Schechter sch(nstar,mstar,alpha);
@@ -223,5 +241,4 @@
  cout<<endl<<"\n--- Initialisation de GeneFluct3D"<<endl;
 
- pkz.SetZ(zref);
  TArray< complex<r_8> > pkgen;
  GeneFluct3D fluct3d(pkgen);
@@ -229,6 +246,10 @@
  fluct3d.SetNThread(nthread);
  fluct3d.SetSize(nx,ny,nz,dx,dy,dz);
+ fluct3d.SetObservator(zref,nz/2.);
+ fluct3d.SetCosmology(univ);
+ fluct3d.SetGrowthFactor(growth);
+ fluct3d.LosComRedshift(0.001);
  TArray<r_8>& rgen = fluct3d.GetRealArray();
- fluct3d.Print();
+ cout<<endl; fluct3d.Print();
 
  double dkmin = fluct3d.GetKincMin();
@@ -246,4 +267,5 @@
      <<" 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:
@@ -258,5 +280,8 @@
  PrtTim(">>>> End Initialisation de GeneFluct3D");
 
+ //-----------------------------------------------------------------
  cout<<"\n--- Computing a realization in Fourier space"<<endl;
+ if(use_growth_factor) 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);
@@ -326,9 +351,19 @@
  }
 
+ //-----------------------------------------------------------------
  cout<<"\n--- Computing a realization in real space"<<endl;
  fluct3d.ComputeReal();
  double rmin,rmax; rgen.MinMax(rmin,rmax);
  cout<<"rgen.Min = "<<rmin<<" , Max="<<rmax<<endl;
-   PrtTim(">>>> End Computing a realization in real space");
+ PrtTim(">>>> End Computing a realization in real space");
+
+ if(use_growth_factor) {
+   cout<<"\n--- Apply Growth factor"<<endl;
+   cout<<"...D(z=0)="<<growth(0.)<<"  D(z="<<zref<<")="<<growth(zref)<<endl;
+   fluct3d.ApplyGrowthFactor(-1);
+   rmin,rmax; rgen.MinMax(rmin,rmax);
+   cout<<"rgen.Min = "<<rmin<<" , Max="<<rmax<<endl;
+   PrtTim(">>>> End Applying growth factor");
+ }
 
  if(wfits) {
Index: trunk/Cosmo/SimLSS/cmvtinterp.cc
===================================================================
--- trunk/Cosmo/SimLSS/cmvtinterp.cc	(revision 3157)
+++ trunk/Cosmo/SimLSS/cmvtinterp.cc	(revision 3157)
@@ -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: trunk/Cosmo/SimLSS/genefluct3d.cc
===================================================================
--- trunk/Cosmo/SimLSS/genefluct3d.cc	(revision 3155)
+++ trunk/Cosmo/SimLSS/genefluct3d.cc	(revision 3157)
@@ -32,6 +32,12 @@
 GeneFluct3D::GeneFluct3D(TArray< complex<r_8 > >& T)
   : T_(T) , Nx_(0) , Ny_(0) , Nz_(0) , array_allocated_(false) , lp_(0)
-  , redshref_(-999.) , kredshref_(-999.)
-{
+  , redshref_(-999.) , kredshref_(0.) , cosmo_(NULL) , growth_(NULL)
+  , loscom_ref_(-999.), loscom_min_(-999.), loscom_max_(-999.)
+
+
+{
+ xobs_[0] = xobs_[1] = xobs_[2] = 0.;
+ zred_.resize(0);
+ loscom_.resize(0);
  SetNThread();
 }
@@ -64,9 +70,22 @@
 //     kredshref = indice (en double) correspondant a ce redshift
 //                 Si kredshref<0 alors kredshref=0
+// 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.) kredshref = 0.;
- redshref_ = redshref;
+ redshref_  = redshref;
  kredshref_ = kredshref;
+}
+
+void GeneFluct3D::SetCosmology(CosmoCalc& cosmo)
+{
+ cosmo_ = &cosmo;
+ if(lp_>1) cosmo_->Print();
+}
+
+void GeneFluct3D::SetGrowthFactor(GrowthFactor& growth)
+{
+ growth_ = &growth;
 }
 
@@ -164,4 +183,81 @@
 }
 
+//-------------------------------------------------------
+long GeneFluct3D::LosComRedshift(double zinc)
+// 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
+// 
+{
+ if(zinc<=0.) zinc = 0.01;
+ if(lp_>0) cout<<"--- LosComRedshift: zinc="<<zinc<<endl;
+
+ if(cosmo_ == NULL || redshref_<0.) {
+   cout<<"GeneFluct3D::LosComRedshift_Error: set Observator and Cosmology first"<<endl;
+   throw ParmError("");
+ }
+
+ // On calcule les coordonnees de l'observateur
+ // Il est sur un axe centre sur le milieu de la face Oxy
+ double loscom_ref_ = cosmo_->Dloscom(redshref_);
+ xobs_[0] = Nx_/2.*Dx_;
+ xobs_[1] = Ny_/2.*Dy_;
+ xobs_[2] = kredshref_*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];
+
+ // 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 = xobs_[0] - i*Nx_*Dx_; dx2 *= dx2;
+   for(long j=0;j<=1;j++) {
+     double dy2 = xobs_[1] - j*Ny_*Dy_; dy2 *= dy2;
+     for(long k=0;k<=1;k++) {
+       double dz2 = xobs_[2] - k*Nz_*Dz_; dz2 *= dz2;
+       dz2 = sqrt(dx2+dy2+dz2);
+       if(dz2>loscom_max_) loscom_max_ = dz2;
+     }
+   }
+ }
+ if(lp_>0) {
+   cout<<"...zref="<<redshref_<<" kzref="<<kredshref_<<" 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 "<<endl;
+ }
+
+ // Fill the corresponding vectors
+ 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 break apres avoir stoque un dlc>dlcmax
+ }
+
+ long n = zred_.size();
+ if(lp_>0) {
+   cout<<"...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;
+ }
+
+ return n;
+}
 
 //-------------------------------------------------------
@@ -323,5 +419,5 @@
 
  // --- On remplit avec une realisation
- if(lp_>0) cout<<"...before Fourier realization filling ---"<<endl;
+ 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;
@@ -529,4 +625,50 @@
 
 //-------------------------------------------------------------------
+void GeneFluct3D::ApplyGrowthFactor(long npoints)
+// Apply Growth to real space
+// Using the correspondance between redshift and los comoving distance
+// describe in vector "zred_" "loscom_"
+{
+ if(npoints<3) npoints = zred_.size();
+ if(lp_>0) cout<<"--- ApplyGrowthFactor ---  npoints="<<npoints<<endl;
+ check_array_alloc();
+
+ if(growth_ == NULL) {
+   cout<<"GeneFluct3D::ApplyGrowthFactor_Error: set GrowthFactor first"<<endl;
+   throw ParmError("GeneFluct3D::ApplyGrowthFactor_Error: set GrowthFactor first");
+ }
+
+ long n = zred_.size();
+ InverseFunc invfun(zred_,loscom_);
+ vector<double> invlos;
+ invfun.ComputeParab(npoints,invlos);
+
+ InterpFunc interpinv(invfun.YMin(),invfun.YMax(),invlos);
+ 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 = xobs_[0] - i*Dx_; dx2 *= dx2;
+   for(long j=0;j<Ny_;j++) {
+     double dy2 = xobs_[1] - j*Dy_; dy2 *= dy2;
+     for(long l=0;l<Nz_;l++) {
+       double dz2 = xobs_[2] - l*Dz_; dz2 *= dz2;
+       dz2 = sqrt(dx2+dy2+dz2);
+       double z = interpinv(dz2);
+       //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
Index: trunk/Cosmo/SimLSS/genefluct3d.h
===================================================================
--- trunk/Cosmo/SimLSS/genefluct3d.h	(revision 3155)
+++ trunk/Cosmo/SimLSS/genefluct3d.h	(revision 3157)
@@ -14,4 +14,5 @@
 #include <vector>
 
+#include "cosmocalc.h"
 #include "pkspectrum.h"
 
@@ -27,5 +28,8 @@
   void SetNThread(unsigned short nthread=0) {nthread_ = nthread;}
   void SetSize(long nx,long ny,long nz,double dx,double dy,double dz);  // Mpc
-  void SetObservator(double redshref=0.,double kredshref=-1.);
+  void SetObservator(double redshref=0.,double kredshref=0.);
+  void SetCosmology(CosmoCalc& cosmo);
+  void SetGrowthFactor(GrowthFactor& growth);
+  long LosComRedshift(double zinc=0.001);
 
   TArray< complex<r_8> >& GetComplexArray(void) {return T_;}
@@ -67,4 +71,5 @@
   int  ComputeSpectrum(HistoErr& herr);
   int  ComputeSpectrum2D(Histo2DErr& herr);
+  void ApplyGrowthFactor(long npoints=-1);
 
   int_8 VarianceFrReal(double R,double& var);
@@ -127,4 +132,9 @@
   // l'observateur
   double redshref_,kredshref_;
+  CosmoCalc *cosmo_;
+  GrowthFactor *growth_;
+  double xobs_[3];
+  double loscom_ref_, loscom_min_, loscom_max_;
+  vector<double> zred_, loscom_;
 };
 
Index: trunk/Cosmo/SimLSS/geneutils.cc
===================================================================
--- trunk/Cosmo/SimLSS/geneutils.cc	(revision 3155)
+++ trunk/Cosmo/SimLSS/geneutils.cc	(revision 3157)
@@ -19,6 +19,6 @@
 // Classe d'interpolation lineaire:
 // Le vecteur y a n elements y_i tels que y_i = f(x_i)
-// Les x_i sont regulierement espaces
-//   et x_0=xmin et x_{n-1}=xmax
+//   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)
@@ -29,6 +29,5 @@
   }
   _nm1   = _y.size()-1;
-  _xlarg = _xmax-_xmin;
-  _dx    = _xlarg/(double)_nm1;
+  _dx    = (_xmax-_xmin)/(double)_nm1;
 }
 
@@ -37,5 +36,5 @@
   ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
   x -= _xmin;
-  long i = long(x/_xlarg*_nm1);  // On prend le "i" juste en dessous
+  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);
@@ -46,9 +45,107 @@
   ok=0; if(x<_xmin) ok=1; else if(x>_xmax) ok=2;
   x -= _xmin;
-  long i = long(x/_xlarg*_nm1+0.5);  // On prend le "i" le + proche
+  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
+// - Le vecteur y a "Nin" elements y_i tels que "y_i = f(x_i)"
+// - On a x(i) < x(i+1) et y(i) < y(i+1)
+// - La classe renvoie ymin=y(0) , ymax=y(Nin -1)
+//   et le vecteur x = f^-1(y) de "Nout" elements
+//   Les y_i sont regulierement espaces et ymin et ymax
+//   La re-interpolation inverse est faite par lineaire
+InverseFunc::InverseFunc(vector<double>& x,vector<double>& y)
+  : _ymin(0.) , _ymax(0.) , _x(x) , _y(y)
+{
+  int_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(int_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(int_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 n,vector<double>& xfcty)
+{
+  if(n<3) return -1;
+
+  xfcty.resize(n);
+
+  long i1,i2;
+  double x;
+  for(int_4 i=0;i<n;i++) {
+    double y = _ymin + i*(_ymax-_ymin)/(n-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 n,vector<double>& xfcty)
+{
+  if(n<3) return -1;
+
+  xfcty.resize(n);
+
+  long i1,i2,i3;
+  double x;
+  for(int_4 i=0;i<n;i++) {
+    double y = _ymin + i*(_ymax-_ymin)/(n-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==_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;
 }
 
Index: trunk/Cosmo/SimLSS/geneutils.h
===================================================================
--- trunk/Cosmo/SimLSS/geneutils.h	(revision 3155)
+++ trunk/Cosmo/SimLSS/geneutils.h	(revision 3157)
@@ -7,4 +7,5 @@
 #include "histos.h"
 #include "tvector.h"
+#include "cspline.h"
 
 #include <vector>
@@ -12,4 +13,5 @@
 namespace SOPHYA {
 
+//----------------------------------------------------
 class InterpFunc {
 public:
@@ -19,4 +21,5 @@
   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)
@@ -24,5 +27,5 @@
          {
          x -= _xmin;
-         long i = long(x/_xlarg*_nm1+0.5);  // On prend le "i" le plus proche
+         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];
@@ -43,17 +46,45 @@
 
 protected:
-  double _xmin,_xmax,_xlarg,_dx;
+  double _xmin,_xmax,_dx;
+  long _nm1;  // n-1
   vector<double>& _y;
-  long _nm1;  // n-1
+};
+
+//----------------------------------------------------
+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;
+      }
+    }
+
+  vector<double>& _x;
+  vector<double>& _y;
+  double _ymin,_ymax,_dy;
 };
 
 }
 
+//----------------------------------------------------
 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);
 
+//----------------------------------------------------
 unsigned long PoissRandLimit(double mu,double mumax=10.);
 
