GLAMERDOC++
Gravitational Lensing Code Library
image_processing.h
1 /*
2  * image_processing.h
3  *
4  * Created on: Feb 28, 2010
5  * Author: R.B. Metcalf
6  */
7 
8 #ifndef IMAGE_PROCESSING_H_
9 #define IMAGE_PROCESSING_H_
10 
11 #include <complex>
12 #include <vector>
13 #include <tuple>
14 
15 #include "point.h"
16 #include "image_info.h"
17 #include "pixelmap.h"
18 #include "fftw3.h"
19 //#include "Tree.h"
20 //#include "utilities_slsim.h"
21 //#include "utilities_slsim.h"
22 //#include "image_processing.h"
23 
24 class Source;
25 #include "fftw3.h"
26 
27 enum class Telescope {Euclid_VIS,Euclid_Y,Euclid_J,Euclid_H,KiDS_u,KiDS_g,KiDS_r,KiDS_i,HST_ACS_I,CFHT_u,CFHT_g,CFHT_r,CFHT_i,CFHT_z};
28 
29 enum class UnitType {counts_x_sec, flux} ;
30 
31 
32 class Obs{
33 public:
34 
35  Obs(size_t Npix_xx,size_t Npix_yy
36  ,double pix_size
37  ,int oversample
38  ,float seeing = 0 // seeing in arcsec
39  );
40 
41  virtual ~Obs(){};
42 
43  size_t getNxInput() const { return Npix_x_input;}
44  size_t getNyInput() const { return Npix_y_input;}
45 
46  size_t getNxOutput() const { return Npix_x_output;}
47  size_t getNyOutput() const { return Npix_y_output;}
48 
49  std::valarray<double> getPSF(){return map_psf;}
50  //void setPSF(std::string psf_file);
51  void setPSF(std::string psf_file,double resolution=0);
52  template <typename T>
53  void setPSF(PixelMap<T> &psf_map);
55  void setSeeing(double s
56  ){seeing=s;}
58  void rotatePSF(double theta
59  ,double scale_x=1
60  ,double scale_y=1
61  );
62 
64  void coaddPSF(double f
65  ,double theta1
66  ,double theta2
67  ,double scale_x
68  ,double scale_y
69  );
70 
71  template <typename T>
72  void ApplyPSF(PixelMap<T> &map_in,PixelMap<T> &map_out);
73 
74  float getPixelSize() const {return pix_size;}
75  void setNoiseCorrelation(std::string nc_file);
76 
77  // virtual methods
78 // template <typename T>
79 // virtual void AddNoise(PixelMap<T> &pmap
80 // ,PixelMap<T> &error_map
81 // ,Utilities::RandomNumbers_NR &ran,bool cosmics) = 0;
82 // template <typename T>
83 // virtual void Convert(PixelMap<T> &map_in
84 // ,PixelMap<T> &map_out
85 // ,PixelMap<T> &error_map
86 // ,bool psf
87 // ,bool noise
88 // ,Utilities::RandomNumbers_NR &ran,bool cosmics) = 0;
89 
90  virtual float getBackgroundNoise() const = 0;
91 
93  //virtual double mag_to_counts(double m) const = 0;
94  //virtual double counts_to_mag(double flux) const = 0;
95  //virtual double zeropoint() const = 0;
96  //virtual void setZeropoint(double zpoint) = 0;
97 
98 
99 protected:
100 
101  double pix_size; // pixel size (in rad)
102  template <typename T>
103  void CorrelateNoise(PixelMap<T> &pmap);
104  float seeing; // full-width at half maximum of the gaussian smoothing
105 
106  // the number of pixels in the real image
107  size_t Npix_x_output,Npix_y_output;
108  // the number of pixels in the oversamples image
109  size_t Npix_x_input,Npix_y_input;
110 
111  float psf_oversample; // psf oversampling factor
112  template <typename T>
113  void downsample(PixelMap<T> &map_in,PixelMap<T> &map_out) const; // downsize from Npix_input to Npix_output
114 
115 private:
116  double input_psf_pixel_size;
117  size_t side_ncorr; // pixels on a side of input noise correlation function
118 
119  void fftpsf(); // FFT the psf for later use
120  std::valarray<double> map_psf; // array of the point spread function
121  std::valarray<double> map_psfo; // initial array of the point spread function
122 
123  std::vector<std::complex<double> > fft_psf;
124  std::vector<std::complex<double> > fft_padded;
125  std::vector<double> image_padded;
126  std::vector<double> sqrt_noise_power; // stores sqrt root of power noise spectrum
127 
128  // size of borders for psf convolution
129  size_t nborder_x = 0;
130  size_t nborder_y = 0;
131 
132  // size of padded images
133  size_t n_x = 0;
134  size_t n_y = 0;
135 
136  fftw_plan image_to_fft;
137  fftw_plan fft_to_image;
138 
139  //PixelMap noise_correlation;
140  std::vector<std::complex<double> > noise_fft_image;
141  std::vector<double> noise_in_zeropad;
142  fftw_plan p_noise_r2c;
143  std::vector<double> noise_image_out;
144  fftw_plan p_noise_c2r;
145 };
146 
160 class ObsVIS : public Obs{
161 private:
162 
163  // standard from magnitude to e- per sec
164  //double zero_point = 24.4;
165  //double sigma_back_per_qsrttime = 0.00267 * sqrt(5.085000000000E+03);
166 
167  //double gain = 11160; // e-/ADU (Analog Digital Units)
168  //double exp_num = 4;
169  //double exp_time = 2260.; // seconds
170  //double l = 7103.43;
171  //double dl = 3318.28;
172  //double seeing = 0.18;
173 
174  // derived parameters;
175  double sigma_background2; // background variance x time
176 
177  // adds random cosmic rays to the noise map
178  template <typename T>
179  void cosmics(PixelMap<T> &error_map
180  ,double inv_sigma2 // for one dither
181  ,int nc // number of cosmics to be added
182  ,Utilities::RandomNumbers_NR &ran) const ;
183 
184 public:
185 
187  ObsVIS(size_t Npix_x
188  ,size_t Npix_y
189  ,int oversample
190  ,double resolution = 0.1*arcsecTOradians
191  );
192 
194  ObsVIS(size_t Npix_x
195  ,size_t Npix_y
196  ,const std::vector<double> &exposure_times
197  ,int oversample
198  );
199 
200  ObsVIS(size_t Npix_x
201  ,size_t Npix_y
202  ,const std::vector<double> &exposure_times
203  ,int oversample
204  ,double resolution
205  ,double background_sigma
206  ,double calibration_exposure_time
207  );
208  ~ObsVIS(){};
209 
211  template <typename T>
212  void AddPoisson(PixelMap<T> &pmap
214  );
215 
217  template <typename T>
218  void AddNoise(PixelMap<T> &pmap
219  ,PixelMap<T> &error_map
221  ,bool cosmic=true);
222 
223  template <typename T>
224  void Convert(PixelMap<T> &map_in
225  ,PixelMap<T> &map_out
226  ,PixelMap<T> &error_map // this is sigma
227  ,bool psf
228  ,bool noise
230  ,bool cosmic=false);
231 
232 
234  float getBackgroundNoise() const {
235  double dt = Utilities::vec_sum(t_exp);// 3 * t1 + t2;
236 
237  return sqrt( sigma_background2 / dt );
238  }
239 private:
240  std::vector<double> t_exp; // exposure times
241 };
242 
252 class Observation : public Obs
253 {
254 public:
255  Observation(Telescope tel_name,double exposure_time,int exposure_num
256  ,size_t Npix_x,size_t Npix_y, float oversample);
257  Observation(float diameter, float transmission, float exp_time, int exp_num, float back_mag, float read_out_noise
258  ,size_t Npix_x,size_t Npix_y,double pix_size,float seeing = 0.);
259  Observation(float diameter, float transmission, float exp_time, int exp_num, float back_mag, float read_out_noise ,std::string psf_file,size_t Npix_x,size_t Npix_y,double pix_size, float oversample = 1.);
260 
261  Observation(float zeropoint_mag, float exp_time, int exp_num, float back_mag, float read_out_noise, size_t Npix_x,size_t Npix_y,double pix_size,float seeing=0);
262  Observation(float zeropoint_mag, float exp_time, int exp_num, float back_mag, float read_out_noise ,std::string psf_file,size_t Npix_x,size_t Npix_y,double pix_size, float oversample = 1.);
263 
264  ~Observation(){};
265 
266  float getExpTime() const {return exp_time;}
267  int getExpNum() const {return exp_num;}
268  float getBackMag() const {return back_mag;}
270  float getRon() const {return read_out_noise;}
272  float getSeeing() const {return seeing;}
273  float getZeropoint() const {return mag_zeropoint;}
274  void setZeropoint(double zpoint){mag_zeropoint=zpoint;}
276  float getBackgroundNoise(float resolution, UnitType unit = UnitType::counts_x_sec) const;
277  float getBackgroundNoise() const {return 0;};
278 
279  template <typename T>
280  void AddNoise(PixelMap<T> &pmap,PixelMap<T> &error_map
281  ,Utilities::RandomNumbers_NR &ran,bool dummy);
282 
283  template <typename T>
284  void Convert(PixelMap<T> &map_in
285  ,PixelMap<T> &map_out
286  ,PixelMap<T> &error_map
287  ,bool psf
288  ,bool noise
290  ,bool cosmic=false
291  );
292 
294  //double flux_convertion_factor(){ return pow(10,-0.4*mag_zeropoint); }
295 
296  void setExpTime(float time){exp_time = time;}
297  void setPixelSize(float pixel_size){pix_size=pixel_size;}
298 
299  double mag_to_counts(double m) const {
300  if(m == 100) return 0;
301  return pow(10,-0.4*(m - mag_zeropoint));
302  }
303  double counts_to_mag(double flux) const{
304  if(flux <=0) return 100;
305  return -2.5 * log10(flux) + mag_zeropoint;
306  }
307  double zeropoint() const{
308  return mag_zeropoint;
309  }
310 private:
311 
312  //float diameter; // diameter of telescope (in cm)
313  //float transmission; // total transmission of the instrument
314  float mag_zeropoint; // magnitude of a source that produces one count/sec in the image
315  float exp_time; // total exposure time (in sec)
316  int exp_num; // number of exposures
317  float back_mag; // sky (or background) magnitude in mag/arcsec^2
318  float read_out_noise; // read-out noise in electrons/pixel
319  float gain;
320 
321  bool telescope; // was the observation created from a default telescope?
322  float e_per_s_to_ergs_s_cm2; // e- / s for zero magnitudes
323  float background_flux; // e- / s / arcsec
324 
325  void set_up();
326 
327  template <typename T>
328  void ToCounts(PixelMap<T> &pmap);
329  template <typename T>
330  void ToSurfaceBrightness(PixelMap<T> &pmap);
331  template <typename T>
332  void ToADU(PixelMap<T> &pmap);
333 };
334 
335 void pixelize(double *map,long Npixels,double range,double *center
336  ,ImageInfo *imageinfo,int Nimages,bool constant_sb,bool cleanmap
337  ,bool write_for_skymaker = false, std::string filename="");
338 void _SplitFluxIntoPixels(TreeHndl ptree,Branch *leaf,double *leaf_sb);
339 //void smoothmap(double *map_out,double *map_in,long Npixels,double range,double sigma);
340 
341 namespace Utilities{
342  //void LoadFitsImages(std::string dir,const std::string& filespec,std::vector<PixelMap> & images,int maxN,double resolution = -1,bool verbose = false);
343  //void LoadFitsImages(std::string dir,std::vector<std::string> filespecs,std::vector<std::string> file_non_specs ,std::vector<PixelMap> & images,std::vector<std::string> & names,int maxN,double resolution = -1,bool verbose = false);
344  void ReadFileNames(std::string dir,const std::string filespec
345  ,std::vector<std::string> & filenames
346  ,const std::string file_non_spec = " "
347  ,bool verbose = false);
348 }
349 
353 public:
354  MultiGridSmoother(double center[],std::size_t Nx,std::size_t Ny,double resolution);
355  MultiGridSmoother(double center[],std::size_t Nx,double resolution);
356  ~MultiGridSmoother(void){
357  maps.clear();
358  }
359 
361  PosType getHighestRes(){return maps[0].getResolution();}
363  PosType getLowestRes(){return maps.back().getResolution();}
364 
366  void add_particles(std::vector<PosType> x,std::vector<PosType> y);
368  void output_map(PixelMap<double> &map,int Nsmooth);
369  void smooth(int Nsmooth,PixelMap<double> &map);
370 
371 private:
372  void _smooth_(int k,size_t i,size_t j,int Nsmooth,PixelMap<double> &map);
373  std::vector<PixelMap<double> > maps;
374  std::vector<Utilities::Interpolator<PixelMap<double> >> interpolators;
375 };
376 
377 
378 template <typename T>
381  ){
382 
383  double dt = Utilities::vec_sum(t_exp);
384  if(ran() < 0.2){
385  // select a frame
386  int missing_frame = (int)(ran()*t_exp.size());
387 
388  dt -= t_exp[missing_frame];
389  }
390 
391  for(auto &p : pmap.data() ){
392  if(p>0) p = ran.poisson(p*dt)/dt;
393  }
394 }
395 
396 template <typename T>
398  ,PixelMap<T> &error_map
399  ,Utilities::RandomNumbers_NR &ran,bool cosmic
400  ){
401  if(pmap.getUnits() != PixelMapUnits::count_per_sec){
402  std::cerr << "ObsVIS::AddNoise() Map must be in counts_per_sec at this stage." << std::endl;
403  throw std::runtime_error("wrong uits");
404  }
405 
406  if(pmap.getNx() != pmap.getNy()){
407  std::cerr << "ObsVIS::AddNoise() Doesn't work on nonsquare maps" << std::endl;
408  throw std::runtime_error("nonsquare");
409  }
410 
411  double dt = Utilities::vec_sum(t_exp);
412  int missing_frame = -1;
413  //int drop=0;
414  if(ran() < 0.2){
415  // select a frame
416  missing_frame = (int)(ran()*t_exp.size());
417  dt -= t_exp[missing_frame];
418  //drop=1;
419  }
420 
421  double inv_sigma2 = (dt)/sigma_background2;
422  size_t N = pmap.size();
423  for (unsigned long i = 0; i < N ; i++){
424  error_map[i] = inv_sigma2;
425  }
426 
427  //double p = (t_exp.size()-drop)*t1/dt;
428  if(cosmic){
429 
430  double t = (int)(ran()*dt);
431  for(int j=0 ; j<100 ; ++j){
432  // chooses an exposure at random weighted by exposure time
433  int i=0;
434  double tt=t_exp[0];
435  while(t>tt){
436  ++i;
437  tt += t_exp[i];
438  }
439 
440  if(i != missing_frame) cosmics(error_map,t_exp[i]/sigma_background2,1,ran);
441  }
442 
443 // if(ran() < p ){
444 // cosmics(error_map,t1/sigma2,ran.poisson(100),ran);
445 // }else{
446 // cosmics(error_map,t2/sigma2,ran.poisson(100*(dt-t1)/dt),ran);
447 // }
448  }
449  for (unsigned long i = 0; i < N ; i++){
450  pmap[i] = ran.poisson(MAX<float>(pmap[i] * dt,0))/dt;
451  pmap[i] += ran.gauss() / sqrt(error_map[i]);
452 
453  error_map[i] = sqrt( 1.0 / error_map[i] + MAX<float>(pmap[i] / dt,0) ) ;
454  }
455 
456  return;
457 }
458 
459 template <typename T>
460 void ObsVIS::cosmics(
461  PixelMap<T> &error_map // inverse error
462  ,double inv_sigma2 // for one dither
463  ,int nc // number of cosmics to be added
465  ) const {
466  size_t N = error_map.size();
467  size_t Nx = error_map.getNx();
468  size_t Ny = error_map.getNy();
469 
470  int length = 2;
471  size_t ic=0;
472 
473  while (ic < nc) {
474 
475  size_t no = (size_t)(N*ran());
476  double theta = 2*PI*ran();
477  double c=cos(theta),s=sin(theta);
478 
479  size_t io = no % Nx;
480  size_t jo = no / Nx;
481 
482  double L = MAX<double>(length/tan(PI*ran()/2),1);
483  //error_map.DrawLine(io, io + L * c, jo, jo + L * s, -inv_sigma2, true); // ???
484  //error_map.DrawLine(io + 0.5*s, io + L * c + 0.5*s, jo - 0.5*c, jo + L * s - 0.5*c, -inv_sigma2, true);
485 
486  double t = tan(theta);
487  long x,y;
488  if(abs(t) < 1){
489  long x1 = (long)(io + L * c );
490  int sgn = sign(c);
491  x1 = MAX<long>(0,x1);
492  x1 = MIN<long>(Nx-1,x1);
493  for(x = io ; x != x1 ; x = x + sgn){
494  y = MAX<long>((long)(t*(x-io) + jo),0);
495  y= MIN<long>(y,Ny-2);
496  error_map(x,y) += -inv_sigma2;
497  error_map(x,y+1) += -inv_sigma2;
498  }
499  }else{
500  long y1 = (long)(jo + L * s );
501  int sgn = sign(s);
502  y1 = MAX<long>(0,y1);
503  y1 = MIN<long>(Ny-1,y1);
504  for(y = jo ; y != y1 ; y = y + sgn){
505  x = MAX<long>((long)((y-jo)/t + io),0);
506  x = MIN<long>(x,Nx-2);
507  error_map(x,y) += -inv_sigma2;
508  error_map(x+1,y) += -inv_sigma2;
509  }
510  }
511  ++ic;
512  }
513 }
514 
515 template <typename T>
516 void ObsVIS::Convert(
517  PixelMap<T> &map_in
518  ,PixelMap<T> &map_out
519  ,PixelMap<T> &error_map
520  ,bool psf
521  ,bool noise
523  ,bool cosmic
524  ){
525  assert(map_in.getNx() == Npix_x_input);
526  assert(map_in.getNy() == Npix_y_input);
527 
528  if (fabs(map_in.getResolution()*psf_oversample - pix_size) > pix_size*1.0e-5)
529  {
530  std::cout << "The resolution of the input map is different from the one of the simulated instrument in Observation::Convert!" << std::endl;
531  throw std::runtime_error("The resolution of the input map is different from the one of the simulated instrument!");
532  }
533 
534  map_out.Clean();
535 
536  if (psf == true){
537  PixelMap<T> map_scratch(Point_2d(0,0).x
538  , Npix_x_input
539  , Npix_y_input, pix_size);
540  //std::cout << "Test of psf flux conservation" << std::endl;
541  //std::cout << map_in.sum() << std::endl;
542  ApplyPSF<T>(map_in,map_scratch);
543  //std::cout << map_scratch.sum() << std::endl;
544  downsample<T>(map_scratch,map_out);
545  //std::cout << map_out.sum() << std::endl;
546  }else{
547  downsample<T>(map_in,map_out);
548  }
549 
550  if (noise == true) AddNoise<T>(map_out,error_map,ran,cosmic);
551 
552  return;
553 }
554 
555 
557 template <typename T>
558 void Obs::setPSF(PixelMap<T> &psf_map
559  ){
560 
561  input_psf_pixel_size = psf_map.getResolution();
562 
563  if( (input_psf_pixel_size - pix_size/psf_oversample)/input_psf_pixel_size > 1.0e-3){
564  std::cout << "Obs::setPSF() - psf is not resolved." << std::endl;
565  std::cout << (input_psf_pixel_size - pix_size/psf_oversample)/input_psf_pixel_size << std::endl;
566  throw std::runtime_error("");
567  }
568 
569  map_psf.resize(psf_map.size());
570  for(size_t i=0 ; i<psf_map.size() ; ++i){
571  map_psf[i] = psf_map[i];
572  }
573 
574  std::vector<size_t> size = {psf_map.getNx(),psf_map.getNy()};
575 
576  long max_x,max_y;
577  {
578  long i=0,imax=0;
579  double amax = map_psf[0];
580  for(auto &a : map_psf){
581  if(a > amax){imax=i;amax=a;}
582  ++i;
583  }
584  max_y = imax % size[0];
585  max_x = imax / size[0];
586  }
587  long Lx;
588  long Ly = Lx = 2*MIN<double>( MIN<double>(max_y,size[1]-max_y)
589  ,MIN<double>(max_x,size[0]-max_x));
590 
591  std::valarray<double> tmp(Lx*Ly);
592  long ii=0;
593  for(long i=max_x - Lx/2 ; i<max_x + Lx/2 ;++i){
594  assert(i<size[0]);
595  long jj=0;
596  for(long j=max_y - Ly/2 ; j<max_y + Ly/2 ;++j){
597  assert(j<size[1]);
598  tmp[ii + Lx*jj] = map_psf[j + size[1] * i];
599  ++jj;
600  }
601  ++ii;
602  }
603 
604  std::swap(tmp,map_psf);
605  map_psfo=map_psf;
606 
607  fftpsf();
608 }
609 
610 template <typename T>
611 void Obs::downsample(PixelMap<T> &map_in,PixelMap<T> &map_out) const{
612 
613  assert(map_in.getNx() == Npix_x_input);
614  assert(map_in.getNy() == Npix_y_input);
615  assert(map_out.getNx() == Npix_x_output);
616  assert(map_out.getNy() == Npix_y_output);
617 
618  if(psf_oversample == 1){
619  size_t n=map_in.size();
620  for(size_t i=0; i<n ; ++i ) map_out[i] = map_in[i]; // keep bounding box information
621  return;
622  }
623 
624  map_out.Clean();
625 // Point_2d x;
626 // long n = map_in.size();
627 // for(long i=0 ; i<n ; ++i){
628 // map_in.find_position(x.x, i);
629 // long k = map_out.find_index(x.x);
630 // if(k > -1) map_out[k] += map_in[i];
631 // }
632 
633  for(size_t i=0 ; i<Npix_x_input ; ++i){
634  size_t ii = MIN<long>(i / psf_oversample + 0.5, Npix_x_output - 1 ) ;
635  for(size_t j=0 ; j<Npix_y_input ; ++j){
636  size_t jj = MIN<long>(j / psf_oversample + 0.5, Npix_y_output - 1 ) ;
637 
638  map_out(ii,jj) += map_in(i,j);
639  }
640  }
641 
642  return;
643 }
644 
648 template <typename T>
649 void Obs::ApplyPSF(PixelMap<T> &map_in,PixelMap<T> &map_out)
650 {
651  if(map_in.getNx() != map_in.getNy()){
652  std::cout << "Obs::ApplyPSF() Doesn't work on nonsquare maps" << std::endl;
653  throw std::runtime_error("nonsquare");
654  }
655  if(map_in.getNx() != Npix_y_input){
656  std::cout << "Obs::ApplyPSF() Input map it the wrong size." << std::endl;
657  throw std::runtime_error("nonsquare");
658  }
659  if(map_in.getNx() != map_out.getNx()){
660  std::cout << "Obs::ApplyPSF() Input map output are not the same size." << std::endl;
661  throw std::runtime_error("nonsquare");
662  }
663 
664 
665  if (map_psf.size() == 0){
666 
667  map_out = map_in;
668 
669  if (seeing > 0.){
670  //PixelMap outmap(pmap);
671  map_out.smooth(seeing/2.355);
672  return;
673  }else{
674  return;
675  }
676 
677  }else{
678  map_out.ChangeUnits(map_in.getUnits());
679 
680  // paste image into image with padding
681  for(double &a :image_padded) a=0;
682  for(int i=0 ; i<Npix_x_input ; ++i){
683  for(int j=0 ; j<Npix_y_input ; ++j){
684  image_padded[ (i+nborder_x)*n_x + j + nborder_y] = map_in(i,j);
685  }
686  }
687 
688  fftw_execute(image_to_fft);
689 
690  // multiply by DFT of PSF
691  assert(fft_psf.size() == fft_padded.size());
692  size_t i=0;
693  for(std::complex<double> &a : fft_padded) a *= fft_psf[i++];
694 
695  // inverse DFT
696  fftw_execute(fft_to_image);
697 
698  // copy region within padding
699  size_t N = n_x*n_y;
700  for(int i=0 ; i< Npix_x_input ; ++i){
701  for(int j=0 ; j< Npix_y_input ; ++j){
702  map_out(i,j) = image_padded[ (i+nborder_x)*n_x + j + nborder_y]/N;
703  }
704  }
705 
706  return;
707 
708  }
709 }
710 
714 template <typename T>
715 void Obs::CorrelateNoise(PixelMap<T> &pmap)
716 {
717 
718  if(sqrt_noise_power.size()==0) return;
719 
720  if(pmap.getNx() != pmap.getNy()){
721  std::cout << "Observation::CorrelateNoise() Doesn't work on nonsquare maps" << std::endl;
722  throw std::runtime_error("nonsquare");
723  }
724  if(pmap.getNx() != Npix_x_output){
725  std::cout << "Observation::CorrelateNoise() Map must have the same dimensions as the observation." << std::endl;
726  throw std::runtime_error("nonsquare");
727  }
728 
729  // creates plane for fft of map, sets properly input and output data, then performs fft
730  assert(Npix_x_output == Npix_y_output);
731  size_t Npix = Npix_x_output;
732  size_t ncorr_big_zeropad_Npixels = Npix + side_ncorr;
733  long Npix_zeropad = Npix + side_ncorr;
734 
735  size_t fftsize = sqrt_noise_power.size();
736 
737  // rows and columns between first_p and last_p are copied in the zero-padded version
738  long first_p = side_ncorr/2;
739  long last_p = first_p + (Npix-1);
740 
741  // add zero-padding
742  for (int i = 0; i < Npix_zeropad*Npix_zeropad; i++)
743  {
744  long ix = i/Npix_zeropad;
745  long iy = i%Npix_zeropad;
746  if (ix >= first_p && ix <= last_p && iy >= first_p && iy <= last_p)
747  noise_in_zeropad[i] = pmap[(ix-side_ncorr/2)*Npix+(iy-side_ncorr/2)];
748  else
749  noise_in_zeropad[i] = 0.;
750  }
751 
752  fftw_execute(p_noise_r2c);
753 
754  // performs convolution in Fourier space , and transforms back to real space
755  for (unsigned long i = 0; i < fftsize ; i++)
756  {
757  size_t ix = i/(Npix_zeropad/2+1);
758  size_t iy = i%(Npix_zeropad/2+1);
759  if (ix>Npix_zeropad/2)
760  noise_fft_image[i] *= sqrt_noise_power[(ncorr_big_zeropad_Npixels-(Npix_zeropad-ix))*(ncorr_big_zeropad_Npixels/2+1)+iy];
761  else
762  noise_fft_image[i] *= sqrt_noise_power[ix*(ncorr_big_zeropad_Npixels/2+1)+iy];
763  }
764 
765  // creats plane for perform backward fft after convolution, sets output data
766  //double* image_out = new double[Npix_zeropad*Npix_zeropad];
767 
768  fftw_execute(p_noise_c2r);
769 
770  // translates array of data in (normalised) counts map
771  for (unsigned long i = 0; i < Npix_zeropad*Npix_zeropad; i++)
772  {
773  size_t ix = i/Npix_zeropad;
774  size_t iy = i%Npix_zeropad;
775  if (ix >= first_p && ix <= last_p && iy >= first_p && iy <= last_p)
776  {
777  int ii = (ix-side_ncorr/2)*Npix + (iy-side_ncorr/2);
778  pmap[ii] = noise_image_out[i]/(Npix_zeropad*Npix_zeropad);
779  }
780  }
781  return;
782 }
783 
784 
792 template <typename T>
794  ,PixelMap<T> &map_out
795  ,PixelMap<T> &error_map
796  ,bool psf
797  ,bool noise
799 ,bool cosmic)
800 {
801 
802  assert(map_in.getNx() == Npix_x_input);
803  assert(map_in.getNy() == Npix_y_input);
804 
805  if(cosmic) throw std::runtime_error("cosmics not implemented");
806  if (fabs(map_in.getResolution()*psf_oversample - pix_size) > pix_size*1.0e-5)
807  {
808  std::cout << "The resolution of the input map is different from the one of the simulated instrument in Observation::Convert!" << std::endl;
809  throw std::runtime_error("The resolution of the input map is different from the one of the simulated instrument!");
810  }
811 
812  map_out.Clean();
813  if (psf == true){
814  PixelMap<T> map_scratch(Point_2d(0,0).x
815  , Npix_x_input
816  , Npix_y_input, pix_size);
817 
818  //std::cout << "Test of psf flux conservation" << std::endl;
819  //std::cout << map_in.sum() << std::endl;
820  ApplyPSF<T>(map_in,map_scratch);
821  //std::cout << map_scratch.sum() << std::endl;
822  downsample<T>(map_scratch,map_out);
823  //std::cout << map_out.sum() << std::endl;
824 
825  }else{
826  downsample<T>(map_in,map_out);
827  }
828  ToCounts(map_out);
829 
830  if (noise == true) AddNoise<T>(map_out,error_map,ran,true);
831  //ToSurfaceBrightness(map_out);
832 
833  return;
834 }
835 
836 
838 template <typename T>
840  PixelMap<T> &pmap
841  ,PixelMap<T> &error_map
842  ,Utilities::RandomNumbers_NR &ran,bool dummy)
843 {
844  if(pmap.getNx() != pmap.getNy()){
845  std::cerr << "Observation::AddNoise() Doesn't work on nonsquare maps" << std::endl;
846  throw std::runtime_error("nonsquare");
847  }
848  if(pmap.getUnits() != PixelMapUnits::count_per_sec){
849  std::cerr << "Units need to be in counts per second in Observation::AddNoise." << std::endl;
850  throw std::runtime_error("wrong units.");
851  }
852 
853  double res_in_arcsec = pmap.getResolution() / arcsecTOradians;
854  double back_mean = background_flux * res_in_arcsec*res_in_arcsec * exp_time ;
855 
856  double var_readout = exp_num*read_out_noise*read_out_noise;
857  double norm_map;
858 
859  PixelMap<T> noise_map(pmap);
860  //double sum=0,sum2=0;
861  size_t N = pmap.size();
862  for (unsigned long i = 0; i < N ; i++)
863  {
864  norm_map = pmap[i]*exp_time; // in counts
865  if (norm_map+back_mean > 500.)
866  {
867  double sdv = sqrt(var_readout + norm_map + back_mean);
868  noise_map[i] = ran.gauss()*sdv/exp_time; // back to counts per sec
869  error_map[i] = sdv*sdv/exp_time/exp_time;
870  }
871  else
872  {
873  // photons from mean
874  int k = ran.poisson(norm_map + back_mean);
875  double noise = ran.gauss()*sqrt(var_readout);
876 
877  noise_map[i] = (k + noise - back_mean - norm_map)/exp_time;
878  error_map[i] = (back_mean + norm_map + var_readout)/exp_time;
879  }
880  }
881 
882  CorrelateNoise(noise_map);
883  pmap += noise_map;
884 
885  return;
886 }
887 
889 template <typename T>
890 void Observation::ToCounts(PixelMap<T> &pmap)
891 {
892 
893  //zero_point_flux = pow(10,-0.4*mag_zeropoint); // erg/s/Hz/cm**2
894  //background_flux = pow(10,-0.4*(back_mag-mag_zeropoint ));
895 
896  double Q;
897  PixelMapUnits units = pmap.getUnits();
898  if(units == PixelMapUnits::count_per_sec) return;
899 
900  if(units == PixelMapUnits::surfb){
901  Q = e_per_s_to_ergs_s_cm2;
902  }else if(pmap.getUnits() == PixelMapUnits::ADU){
903  Q = 1.0/gain;
904  }else{
905  std::cerr << "Map needs to be in photon flux units." << std::endl;
906  throw std::runtime_error("wrong units");
907  }
908 
909  pmap.Renormalize(Q);
910  pmap.ChangeUnits(PixelMapUnits::count_per_sec);
911  return;
912 }
913 
915 template <typename T>
916 void Observation::ToSurfaceBrightness(PixelMap<T> &pmap)
917 {
918 
919  double Q;
920  if(pmap.getUnits() == PixelMapUnits::count_per_sec){
921  Q = 1.0/e_per_s_to_ergs_s_cm2 ;
922  }else if(pmap.getUnits() == PixelMapUnits::ADU){
923  Q = 1.0/gain/e_per_s_to_ergs_s_cm2;
924  }else{
925  std::cerr << "Map needs to be in photon flux units." << std::endl;
926  throw std::runtime_error("wrong units");
927  }
928 
929  pmap.Renormalize(Q);
930  pmap.ChangeUnits(PixelMapUnits::surfb);
931  return;
932 }
933 
935 template <typename T>
936 void Observation::ToADU(PixelMap<T> &pmap)
937 {
938 
939  ToCounts(pmap);
940  pmap *= gain;
941  pmap.ChangeUnits(PixelMapUnits::ADU);
942 
943  return;
944 }
945 
946 #endif
MultiGridSmoother::getHighestRes
PosType getHighestRes()
resolution of finest grid from which interpolation is done
Definition: image_processing.h:361
Observation::getBackgroundNoise
float getBackgroundNoise(float resolution, UnitType unit=UnitType::counts_x_sec) const
pixel size in radians
Definition: observation.cpp:727
MultiGridSmoother::getLowestRes
PosType getLowestRes()
resolution of coarsest grid from which interpolation is done
Definition: image_processing.h:363
Observation::Convert
void Convert(PixelMap< T > &map_in, PixelMap< T > &map_out, PixelMap< T > &error_map, bool psf, bool noise, Utilities::RandomNumbers_NR &ran, bool cosmic=false)
Converts the input map to a realistic image.
Definition: image_processing.h:793
MultiGridSmoother::output_map
void output_map(PixelMap< double > &map, int Nsmooth)
Output a map at the resolution of the map smoothed so that no superpixel as less than Nsmooth particl...
Definition: pixelize.cpp:290
Source
Base class for all sources.
Definition: source.h:44
Branch
The box representing a branch of a binary tree structure. Used specifically in TreeStruct for organiz...
Definition: point.h:677
Observation::setExpTime
void setExpTime(float time)
returns factor by which code image units need to be multiplied by to get flux units
Definition: image_processing.h:296
Point_2d
Class for representing points or vectors in 2 dimensions. Not that the dereferencing operator is over...
Definition: point.h:48
ObsVIS
It creates a realistic image from the output of a ray-tracing simulation.
Definition: image_processing.h:160
Utilities::RandomNumbers_NR
This is a class for generating random numbers. It simplifies and fool proofs initialization and allow...
Definition: utilities_slsim.h:1068
ObsVIS::getBackgroundNoise
float getBackgroundNoise() const
returns std of pixels in e-
Definition: image_processing.h:234
ObsVIS::ObsVIS
ObsVIS(size_t Npix_x, size_t Npix_y, int oversample, double resolution=0.1 *arcsecTOradians)
exposure times are set to wide survey expectations
Definition: observation.cpp:17
MultiGridSmoother
Warning: Not tested yet. Class for doing adaptive smoothing using multiply resolution grids.
Definition: image_processing.h:352
TreeStruct
Tree: Exported struct.
Definition: Tree.h:31
ObsVIS::AddPoisson
void AddPoisson(PixelMap< T > &pmap, Utilities::RandomNumbers_NR &ran)
add poisson noise to an image that is in units of electrons
Definition: image_processing.h:379
Utilities::RandomNumbers_NR::gauss
PosType gauss()
generates a Gaussian distributed number with unit variance by polar Box-Muller transform
Definition: utilities_slsim.h:1077
Utilities::ReadFileNames
void ReadFileNames(std::string dir, const std::string filespec, std::vector< std::string > &filenames, const std::string file_non_spec=" ", bool verbose=false)
Reads all the fits files in a directory into a vector of PixelMaps.
Definition: pixelize.cpp:180
MultiGridSmoother::add_particles
void add_particles(std::vector< PosType > x, std::vector< PosType > y)
Add particles to the map. These do not need to be kept in memory after they are added.
Definition: pixelize.cpp:272
MultiGridSmoother::MultiGridSmoother
MultiGridSmoother(double center[], std::size_t Nx, std::size_t Ny, double resolution)
Definition: pixelize.cpp:222
ObsVIS::AddNoise
void AddNoise(PixelMap< T > &pmap, PixelMap< T > &error_map, Utilities::RandomNumbers_NR &ran, bool cosmic=true)
Applies noise (read-out + Poisson) on an image, returns noise map.
Definition: image_processing.h:397
Observation::getRon
float getRon() const
read-out noise in electrons/pixel
Definition: image_processing.h:270
Observation::getSeeing
float getSeeing() const
seeing in arcsecs
Definition: image_processing.h:272
PixelMap
Image structure that can be manipulated and exported to/from fits files.
Definition: pixelmap.h:42
Observation::Observation
Observation(Telescope tel_name, double exposure_time, int exposure_num, size_t Npix_x, size_t Npix_y, float oversample)
Creates an observation setup that mimics a known instrument.
Definition: observation.cpp:418
PixelMap::smooth
void smooth(double sigma)
Smoothes a map with a Gaussian kernel of width sigma (in arcseconds)
Definition: pixelmap.cpp:1760
PixelMap::Renormalize
void Renormalize(T factor)
Multiplies the whole map by a scalar factor.
Definition: pixelmap.cpp:509
Observation::AddNoise
void AddNoise(PixelMap< T > &pmap, PixelMap< T > &error_map, Utilities::RandomNumbers_NR &ran, bool dummy)
Applies realistic noise (read-out + Poisson) on an image, returns noise map.
Definition: image_processing.h:839
ImageInfo
Structure for storing information about images or curves.
Definition: image_info.h:20
Utilities
Definition: utilities.h:48
Observation
It creates a realistic image from the output of a ray-tracing simulation.
Definition: image_processing.h:253