#!/usr/bin/perl -T $ENV{"PATH"} = "/bin:/usr/bin/:/usr/local/bin"; # Otmar Stahl, Anton Malina # This code requires only perl and the CGI.pm module # do not confuse browser with xhtml and sending non-compliant code! use CGI qw(-no_xhtml); $query = new CGI; $path_info = $query->path_info; $script_name = $query->script_name; $query_string = $query->query_string; if (!$path_info) { &print_prompt($query) }; &do_work($query); &print_end(); print $query->end_html; exit; sub print_prompt { my($query) = @_; print $query->header; print $query->start_html(-title=>'FEROS exposure time calculator', -dtd=>'-//W3C//DTD HTML 4.0 Transitional//EN', -BGCOLOR=>'white'); &printhead; print $query->startform; print "
"; print "

Object

Magnitude in V: ", $query->textfield(-name=>'vmag', -size=>5, -maxlength=>5, -default=>'12'); print "
spectral type: ", $query->popup_menu(-name=>'spec', -values=>['O', 'B', 'A', 'F', 'G', 'K', 'M'], -default=>['A']); print "
reddening E(B-V): ", $query->textfield(-name=>'ebv', -size=>5, -maxlength=>5, -default=>'0.0'); print "
"; print "

Observing conditions

"; print "Moon brightness: ", $query->popup_menu(-name=>'moon', -values=>['bright', 'grey', 'dark'], -default=>'grey'); print "
seeing (arcsec): ", $query->textfield(-name=>'seeing', -size=>4, -maxlength=>4, -default=>'1.5'); print "
airmass: ", $query->textfield(-name=>'airmass', -size=>4, -maxlength=>4, -default=>'1.5'); print "
Temperature (centigrade): ", $query->textfield(-name=>'Temp', -size=>4, -maxlength=>4, -default=>'15'); print "
atmospheric pressure (hPa): ", $query->textfield(-name=>'atmpres', -size=>4, -maxlength=>4, -default=>'773'); print "
relative humidity (percent): ", $query->textfield(-name=>'humid', -size=>3, -maxlength=>3, -default=>'25'); print "
"; print "

CCD

"; print "readout noise (electrons): ", $query->textfield(-name=>'RON', -size=>3, -maxlength=>3, # FDR -default=>'3'); -default=>'3.5'); print "
dark current (electrons/hour/pixel): ", $query->textfield(-name=>'DRK', -size=>3, -maxlength=>3, # FDR -default=>'4'); # CommI/II -default=>'13'); -default=>'1.5'); print "
full well capacity (electrons): ", $query->textfield(-name=>'FWC', -size=>7, -maxlength=>7, # FDR -default=>'150000'); -default=>'130000'); print "
"; print "

Exposure

Exposure time (sec): ", $query->textfield(-name=>'obstime', -size=>5, -maxlength=>5, -default=>'3600'); print "
Number of fibers: ", $query->radio_group(-name=>'nfiber', -values=>[' 1', ' 2'], -default=>' 2'); print "

Telescope

"; print "mirror diameter (cm): ", $query->textfield(-name=>'mirrorD', -size=>4, -maxlength=>4, -default=>'220'); print "
telescope efficiency: ", $query->textfield(-name=>'teleff', -size=>4, -maxlength=>4, -default=>'0.6'); print "
"; print "

"; print $query->submit('Action','Display result'); print "   "; print $query->defaults('Reset all fields'); print "
"; print $query->endform; } sub printhead{ print <

FEROS Exposure Time Calculator

The default values have been updated in Feb. 2004 to the configuration at the 2.2m telescope. A copy of the code can be obtained here.

The calculator computes the S/N per pixel (1 resolution element = 2.2 pixels) for a given exposure time.

Calculations are based on measured performances during the FEROS Commissioning.

ENDHEAD } sub print_end { print < Feros documentation

ENDTAIL } sub do_work { my($query) = @_; if ($query->param()) { # # various calibration data # @filters = ('U','B','V','R','I'); %imag = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); #intrinsic %rmag = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); #reddened %emag = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); #reddened %flux = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); #at earth %PeakPixel = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); # sky at new moon %MP_NewMoon = ('U', 22.0, 'B', 22.7, 'V', 21.8, 'R', 20.9, 'I', 19.9); # sky at half moon %MP_HalfMoon = ('U', 19.9, 'B', 21.6, 'V', 21.4, 'R', 20.6, 'I', 19.7); # sky at full moon %MP_FullMoon = ('U', 17.0, 'B', 19.5, 'V', 20.0, 'R', 19.9, 'I', 19.2); #spectro eff # FDR %insteff = ('U', 0.02, 'B', 0.23, 'V', 0.26, 'R', 0.25, 'I', 0.17); %insteff = ('U', 0.01, 'B', 0.26, 'V', 0.27, 'R', 0.26, 'I', 0.17); #S/N ratio %snr = ('U',0.0,'B',0.0,'V',0.0,'R',0.0,'I',0.0); #interstellar extinction (mag/E(B-V) %intext = ('U',4.7,'B',4.1,'V',3.1,'R',2.6,'I',1.9); #atmospheric extinction (mag/airmass) %atmext = ('U',0.46,'B',0.20,'V',0.11,'R',0.07,'I',0.02); #flux for star of magniude 0.0 (in photons) # 4.2e-9 6.6e-9 3.6-e-9 2.2e-9 1.2e-9 erg/cm**2/A/sec %fluxcal = ('U',760,'B',1460,'V',1000,'R',710,'I',480); #photons/cm^2/sec/A @spectypes = ('O','B','A','F','G','K','M'); %wavelen = ('U',3600,'B',4400,'V',5500,'R',6400,'I',7900); # %binsize = ('U',0.036,'B',0.044,'V',0.055,'R',0.064,'I',0.079); #A/pixel # R=110000/pix %binsize = ('U',0.033,'B',0.040,'V',0.050,'R',0.059,'I',0.071); #A/pixel #intrinsic colors %ub = ('O',-1.20,'B',-0.50,'A',0.10,'F',0.00,'G',0.20,'K',1.10,'M',1.3); %bv = ('O',-0.30,'B',-0.15,'A',0.20,'F',0.50,'G',0.70,'K',1.20,'M',1.7); %vi = ('O',-0.15,'B',-0.10,'A',0.15,'F',0.50,'G',0.76,'K',1.20,'M',3.0); %ri = ('O',-0.10,'B',-0.06,'A',0.08,'F',0.25,'G',0.36,'K',0.70,'M',1.8); $FiberRadius = 1.00; # half fiber angle (arcsec) $FiberOmega = $FiberRadius * $FiberRadius * 3.14152; #fiber spatial angle (arcsec^2) $npixel = 13; #number of pixels in cross order direction # $ShutterSpeed = 0.05; #time to open or close the shutter (sec) $ShutterSpeed = 1.0; #time to open or close the shutter (sec) $CosmicHits = 1.0; #cosmic radiation hits (1/cm^2/sec) $CCDArea = 18.87; #area of CCD chip (cm^2) $CCDPixel = 8388608; #number of pixels on CCD # $lambda1 = 3700.0; #lower wavelength limit of spectrograph $lambda1 = 3600.0; #lower wavelength limit of spectrograph # $lambda2 = 8600.0; #upper wavelength limit of spectrograph $lambda2 = 9200.0; #upper wavelength limit of spectrograph #-------------------------------------------------------------------------- # initialize values $IsOverexposed = 0; # # now get parameters # $vmag = $query->param("vmag"); $spec = $query->param("spec"); $ebv = $query->param("ebv"); $moon = $query->param("moon"); $airmass = $query->param("airmass"); $seeing = $query->param("seeing"); $mirrorD = $query->param("mirrorD"); $teleff = $query->param("teleff"); $RON = $query->param("RON"); $DRK = $query->param("DRK") / 3600.0; #dark current (electrons per second) $obstime = $query->param("obstime"); $FWC = $query->param("FWC"); $t = $query->param("Temp"); $ps = $query->param("atmpres"); $rh = $query->param("humid"); $nfiber = $query->param("nfiber"); # # now use the information collected ...! # $telarea = 3.14152 * $mirrorD * $mirrorD / 4.0; #telecope area (cm**2) # correct intrisic colors $imag{'V'} = $vmag; $imag{'B'} = $vmag + $bv{$spec}; $imag{'U'} = $imag{'B'} + $ub{$spec}; $imag{'I'} = $imag{'V'} - $vi{$spec}; $imag{'R'} = $imag{'I'} + $ri{$spec}; #compute magnitudes in all filters #V magnitude is observed, not intrinsic, so correct for it $off = $intext{'V'} * $ebv; $seeingeff = 1.0 - exp ((-$FiberRadius * $FiberRadius) / (2.0 * ($seeing / 2.345) * ($seeing / 2.345))); foreach $filter (@filters) { if ($moon eq "dark") { $skymag{$filter} = $MP_NewMoon{$filter}; } elsif ($moon eq "grey") { $skymag{$filter} = $MP_HalfMoon{$filter}; } else { $skymag{$filter} = $MP_FullMoon{$filter}; } $sky{$filter} = exp (-0.92104 * $skymag{$filter}) * $fluxcal{$filter}; #mag -> photons/cm^2/sec/A $sky{$filter} = $sky{$filter} * $FiberOmega; $sky{$filter} = $sky{$filter} * $obstime * $telarea * $teleff; $sky{$filter} = $sky{$filter} * $binsize{$filter}; $sky{$filter} = $sky{$filter} * $insteff{$filter}; $rmag{$filter} = $imag{$filter} + $intext{$filter} * $ebv - $off; $emag{$filter} = $rmag{$filter} + $atmext{$filter} * $airmass; $flux{$filter} = exp (-0.92104 * $emag{$filter}) * $fluxcal{$filter}; $flux{$filter} = $flux{$filter} * $obstime * $telarea * $teleff; $flux{$filter} = $flux{$filter} * $binsize{$filter}; $flux{$filter} = $flux{$filter} * $insteff{$filter}; $flux{$filter} = $flux{$filter} * $seeingeff; $PeakPixel{$filter} = ($flux{$filter} + $sky{$filter}) * 0.23 + $RON + $DRK * $obstime; #fraction of flux in most saturated pixel $noisesqr{$filter} = $flux{$filter} + (2.0 - $nfiber) * $sky{$filter} + $nfiber * $npixel * ($RON**2 + $DRK * $obstime); $snr{$filter} = $flux{$filter} / sqrt($noisesqr{$filter}); } $HitPixelFraction = $CosmicHits * $CCDArea * $obstime / $CCDPixel * 100.0; $HitBinFraction = $HitPixelFraction * $npixel; if ($HitPixelFraction > 100.0) { $HitPixelFraction = 100.0 }; if ($HitBinFraction > 100.0) { $HitBinFraction = 100.0 }; $r1 = &atmospheric_refraction ($airmass, $lambda1); $r2 = &atmospheric_refraction ($airmass, $lambda2); $deltar = $r1 - $r2; print_result(); } } sub print_result { print "
"; foreach $filter (@filters) { printf "", $filter; } print ""; foreach $filter (@filters) { printf "", sqrt($npixel) * $RON; } print ""; foreach $filter (@filters) { printf "", $snr{$filter}; } print ""; foreach $filter (@filters) { if ($PeakPixel{$filter} > $FWC) { $IsOverexposed = 1; } } if ($IsOverexposed == 1) { print ""; } if ($obstime < 20.0 * $ShutterSpeed) { print ""; } print "
"; print "Expected S/N per pixel in UBVRI
 %s
Flux from star (electrons/bin)
Flux from sky (electrons/bin)
Dark current   (electrons/bin)
Readout noise (electrons/bin)
%9.0f", $flux{$filter}; printf "
%9.0f", $sky{$filter}; printf "
%9.0f", $npixel * $DRK * $obstime; printf "
%9.0f
Expected S/N (per pixel)%6.1f
Additional information
"; print "Warning: The CCD is overexposed. The amount of charge collected in some pixels exceeds the full well capacity of the CCD. The charge from this pixels will bloom into neighbouring pixels in the same row and render the exposure almost unusable. Select a shorter exposure time."; print "
"; print "Warning: The observing time is in the same order of magnitude as the shutter opening time. This means, the center of your CCD will be exposed for a significantly longer time than the edges of your CCD. This may result in poor flatfileding. If possible, then use a longer exposure time."; print "
"; printf "The slit losses due to the seeing are %4.1f percent.", 100.*(1.-$seeingeff); print "
"; if ($HitPixelFraction > 10.0) { printf "Warning: %4.1f percent of your CCD pixels (%4.1f percent of your wavelength bins) are hit by cosmic rays. This means, your optimum extraction algorithm may have trouble masking the pixels, that were hit by cosmic rays. If possible, then use a shorter exposure time.", $HitPixelFraction, $HitBinFraction; } else { printf "%4.1f percent of your CCD pixels (%4.1f percent of your wavelength bins) are hit by cosmic rays.", $HitPixelFraction, $HitBinFraction; } print "
"; if ($deltar >= 2.0 * $FiberRadius) { printf "Warning: More than 50 percent of the flux in the extreme wavelengths is lost due to differential atmospheric refraction.
"; } printf "atmospheric refraction: %4.1f arcsec at lambda = %4.0f Angstrom, %4.1f arcsec at lambda = %4.0f Angstrom
", $r1, $lambda1, $r2, $lambda2; printf "length of spectrum = %4.1f arcsec, fiber diameter = %4.1f arcsec
", $deltar, 2.0 * $FiberRadius; print "

"; } #======================================================================= sub atmospheric_refraction { local($R); $z0 = atan2(sqrt(($_[0])**2-1),1); $sig = 1e4/$_[1]; $T = 273.15+$t; $x = log (($rh + 0.01)/ 100.0); $td = 238.3 * (($t + 238.3) * $x + 17.2694 * $t) / (($t + 238.3) * (17.2694 - $x) - 17.2694 * $t); $pw = 4.50874 + 0.341724 * $td + 0.0106778 * $td**2 + 0.184889E-3 * $td**3 + 0.238294E-5 * $td**4 + 0.203447E-7 * $td**5; $Pw = 1.333224 * $pw; $Ps = $ps-$Pw; $beta = 0.001254*(273.15+$t)/273.15; $kappa = 1.0; # spherical Earth $Ds = (1.+$Ps*(57.90e-8 - 9.3250e-4/$T + 0.25844/$T**2))*$Ps/$T; $Dw = (1.+$Pw*(1.+3.7e-4*$Pw)*(-2.37321e-3+2.23366/$T-710.792/$T**2+7.75141e4/$T**3))*$Pw/$T; $n0 = 1.+1.e-8*((2371.34+683939.7/(130.-$sig**2)+4547.3/(38.9-$sig**2))*$Ds+(6487.31+58.058*$sig**2-0.71150*$sig**4+0.08851*$sig**6)*$Dw); $gamma = $n0-1.; $R = $kappa*$gamma*(1.-$beta)*&tan($z0)-$kappa*$gamma*($beta-$gamma/2.)*(&tan($z0))**3; 180./3.14159*3600*$R; } sub tan { sin($_[0])/cos($_[0]); }