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