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