///////////////////////////////////////////////////////////////////////////
//
//	Copyright (C) 2008 Michael V. Newberry. All Rights Reserved.
//
//	This copyright notice must be included in any portion of this source
//	code that is used in any form and for any purpose.
//

var _pix = 10;			// microns
var _fl = 2700;			// mm
var _bin = 1;
var _darkcur = 0;
var _darkcurbinned = 0;	// for binned pixel
var _base = 0;
var _scale = 1;			// arcsec/pix
var _gain = 1;			// e-/ADU
var _rnoise = 0;			// e-
var _vfluxatmagzero = 0;
var _fluxatmagzero = 0;
var _skyflux = 0;			// ADU/s/pix
var _vstar = 0;
var _vsky = 0;
var _bw = 800;			// Angstroms
var _eff = 75;			// percent
var _qe = 80;			// percent
var _diam = 300;			// mm
var _diamsec = 75;		// mm
var _totalbgflux = 0;		// ADU/s/pix
var _exptime = 0;		// sec
var _bgsnr = 0;
var _seeing = 2;			// arcsec
var _aper = 3;			// pixels
var _aperxfwhm = 0;
var _objareasec2 = 0;
var _objareapix = 0;
var _aperarcsec = 0;
var _objflux = 0;			// object flux through aperture
var _snr = 0;
var _magerr = 0;
var _str;
var _aperfrac = 0;		// aperture fraction of 2D Gaussian
var _trans;				// filter transmission, percent

//////////////////////////////////////////////////////////////
function DefaultInputs( form )
{
	Camera_ST8e( form );
	Telescope_1( form );
	Observation_1( form );
}

//////////////////////////////////////////////////////////////
function DarkCurrent( form )
{
/*
	t = eval( form.TEMP.value ) + 273;
	t3 = t * t * t;
	_darkcur = 1300 * 122 * t3 * Math.exp( -6400 / t )
*/
	_pix = eval( form.PIX.value );
	_bin = eval( form.BIN.value );
	
	dref = eval( form.DREF.value );
	temp = eval( form.TEMP.value );
	tref = eval( form.TREF.value );
	tdbl = eval( form.TDBL.value );

	// dark current for unbinned pixel
	_darkcur = _pix * _pix * (dref / 16.022) * Math.exp( 0.69315 * (temp - tref) / tdbl );
	
	// dark current for binned pixel
	_darkcurbinned = _darkcur * _bin * _bin;
}

//////////////////////////////////////////////////////////////
function BaseNoise( form )
{
	dn = eval( form.EXPTIME.value ) * _darkcurbinned;

	_rnoise = eval( form.RN.value );
	rn = _rnoise * _rnoise;
	
	_gain = eval( form.GAIN.value );
	gn = (_gain * _gain - 1) / 12;
	
	_base = Math.sqrt( dn + rn + gn );
}

//////////////////////////////////////////////////////////////
function ImageScale( form )
{
	_fl = eval( form.FL.value );
	
	_scale = _pix * _bin / ( _fl / 206264.8062 ) / 1000;
}

//////////////////////////////////////////////////////////////
function VFluxAtMagZero( form )
{
	_bw = eval( form.BW.value );
	_eff = eval( form.EFF.value );
	_qe = eval( form.QE.value );
	_diam = eval( form.DIAM.value );
	_diamsec = eval( form.DIAMSEC.value );
		
	_vfluxatmagzero = 940 * _bw * (_eff / 100) * (_qe / 100) * Math.PI * (_diam * _diam - _diamsec * _diamsec) / (4 * 10 * 10);
}

//////////////////////////////////////////////////////////////
function FluxAtMagZero( form )
{
	_eff = eval( form.EFF.value );
	_qe = eval( form.QE.value );
	_diam = eval( form.DIAM.value );
	_diamsec = eval( form.DIAMSEC.value );
	_filter = form.FILTER.value;
	_trans = eval( form.TRANS.value );
	
	if ( _filter == 'Johnson V' )
		flux0 = 8.66e5;
	else if ( _filter == 'Johnson B' )
		flux0 = 3.9e5;
	else if ( _filter == 'Johnson U' )
		flux0 = 5.5e5;
	else if ( _filter == 'Cousins R' )
		flux0 = 1.1e+6;
	else if ( _filter == 'Cousins I' )
		flux0 = 6.75e5;
	else if ( _filter == 'Clear' )
		flux0 = 4.3e6;
	else
		flux0 = 0;

	_fluxatmagzero = flux0 * (_trans / 100) * (_eff / 100) * (_qe / 100) * Math.PI * (_diam * _diam - _diamsec * _diamsec) / (4 * 10 * 10);
}


//////////////////////////////////////////////////////////////
function SkyFlux( form )
{
	_vsky = eval( form.VSKY.value );
	_gain = eval( form.GAIN.value );
	
	_skyflux = ( _fluxatmagzero * Math.exp( -0.4 * Math.LN10 * _vsky ) * _scale * _scale ) / _gain;
}


//////////////////////////////////////////////////////////////
function TotalBgFlux( form )
{
	_totalbgflux = _skyflux + ( _darkcurbinned ) / _gain;
}


//////////////////////////////////////////////////////////////
function BgSnr( form )
{
	_exptime = eval( form.EXPTIME.value );
	
	_bgsnr = Math.sqrt( _totalbgflux * _exptime * _gain );
}


//////////////////////////////////////////////////////////////
function AperRadPix( form )
{
	_aper = eval( form.APER.value );
	_seeing = eval( form.SEEING.value );
	if ( _aper < 0.1 )
	{
		Message( form, "Aperture too small" );
		return;
	}
	if ( _seeing < 0.1 )
	{
		Message( form, "Seeing too small" );
		return;
	}
		
//	_aper is entered in units of FWHM (e.g., "3" means 3 times FWHM in arcsec)
//	_aperradpix = _aper * _seeing / ( 2 * _scale );
//	_objareasec2 = Math.PI * _aper * _aper * _seeing * _seeing / 4;
//	_objareapix = _objareasec2 / ( _scale * _scale );

	aperradpix = _aper;
	_aperxfwhm = 2 * _aper * _scale / _seeing;
	_objareasec2 = Math.PI * (aperradpix * _scale) * (aperradpix * _scale);
	_objareapix = _objareasec2 / ( _scale * _scale );
	_aperarcsec = 2 * _aper * _scale;
}


//////////////////////////////////////////////////////////////
// comptes object flux through aperture using circular Gaussian profile
function ObjFlux( form )
{
	_vstar = eval( form.VSTAR.value );
	
	_objflux = _aperfrac * _fluxatmagzero * Math.exp( -0.4 * Math.LN10 * _vstar ) / _gain;
}


//////////////////////////////////////////////////////////////
function Snr( form )
{
	_snr = Math.sqrt( (_objflux * _exptime * _gain)
		 / ( 1 + Math.max( 1, _objareapix ) * ( (_totalbgflux * _exptime * _gain)
		  + ((_gain * _gain - 1) / 12) + (_rnoise * _rnoise) ) / (_objflux * _exptime * _gain) ) );
}


//////////////////////////////////////////////////////////////
function MagErr( form )
{
	_magerr = 2.5 / Math.LN10 / _snr;
}


//////////////////////////////////////////////////////////////
function ToStr( num )
{
	_str = sprintf( '%.3f', num );
	return _str;
}

//////////////////////////////////////////////////////////////
function CalcAll( form )
{
	DarkCurrent( form );
	BaseNoise( form );
	ImageScale( form );
	FluxAtMagZero( form );
//	VFluxAtMagZero( form );
	SkyFlux( form );
	TotalBgFlux( form );
	BgSnr( form );
	AperRadPix( form );
	GaussFrac2dLookup( form );
	ObjFlux( form );
	Snr( form );
	MagErr( form );

	form.dark_current.value = ToStr( _darkcurbinned );
	form.base_noise.value = ToStr( _base );
	form.image_scale.value = ToStr( _scale );
	form.sky_flux.value = ToStr( _skyflux );
	form.total_bg_flux.value = ToStr( _totalbgflux );
	form.noise_ratio.value = ToStr( _skyflux / _totalbgflux );
	form.bg_snr.value = ToStr( _bgsnr );
	form.aper_x_fwhm.value = ToStr( _aperxfwhm );
	form.aper_arcsec.value = ToStr( _aperarcsec );
	form.obj_area_sec2.value = ToStr( _objareasec2 );
	form.obj_flux.value = ToStr( _objflux );
	form.snr.value = ToStr( _snr );
	form.magerr.value = ToStr( _magerr );
	form.ap_frac.value = ToStr( 100 * _aperfrac );	// convert to percent
}

////////////////////////////////////////////////////////////////////
function Message( form, msg )
{
	w = 400;
	h = 150;
	var pos = sprintf( 'left=%d,top=%d,width=%d,height=%d', window.event.screenX-w/2, window.event.screenY-h/2, w, h );
	var generator=window.open( '', 'MsgWin', pos );

	generator.document.write( '<html><head><title>SNR Calculator Message</title>' );
	generator.document.write( '<link rel="stylesheet" href="styles/mirametrics.css">' );
	generator.document.write( '</head><body>' );
	generator.document.write( '<br><p class="norm140">' );
	generator.document.write( msg );
	generator.document.write( '</p>' );
	//  generator.document.write( '<p><a href="javascript:self.close()">Close</a></p>' );
	generator.document.write( '</body></html>' );
	generator.document.close();
}

//////////////////////////////////////////////////////
function ClearResults( form )
{
	form.snr.value="";
	form.magerr.value="";
	form.dark_current.value="";
	form.base_noise.value="";
	form.image_scale.value="";
	form.sky_flux.value="";
	form.total_bg_flux.value="";
	form.noise_ratio.value="";
	form.bg_snr.value="";
	form.aper_x_fwhm.value="";
	form.aper_arcsec.value="";
	form.obj_area_sec2.value="";
	form.obj_flux.value="";
	form.ap_frac.value="";
}

//////////////////////////////////////////////////////
function ClearInputs( form )
{
	form.PIX.value="";
	form.QE.value="";
	form.RN.value="";
	form.GAIN.value="";
	form.BIN.value="";
	form.TEMP.value="";
	form.TDBL.value="";
	form.TREF.value="";
	form.DREF.value="";
	form.FL.value="";
	form.DIAM.value="";
	form.DIAMSEC.value="";
//	form.BW.value="";
	form.EFF.value="";
	form.VSTAR.value="";
	form.EXPTIME.value="";
	form.SEEING.value="";
	form.VSKY.value="";
	form.APER.value="";
	form.TRANS.value="";
//	form.FILTER.value="Clear";

}

//////////////////////////////////////////////////////
function Camera_ST8e( form )
{
	form.PIX.value=9;
	form.QE.value=70;
	form.RN.value=15;
	form.GAIN.value=2.3;
	form.BIN.value=1;
	form.TEMP.value=-15;
	form.TDBL.value=6.3;
	form.TREF.value=25;
	form.DREF.value=6;
}

//////////////////////////////////////////////////////
function Telescope_1( form )
{
	form.FL.value=3000;
	form.DIAM.value=300;
	form.DIAMSEC.value=75;
	form.EFF.value=90;
}

//////////////////////////////////////////////////////
function Observation_1( form )
{
	form.VSTAR.value=15;
	form.EXPTIME.value=60;
	form.SEEING.value=2.5;
	form.VSKY.value=20;
	form.APER.value=5;
	form.TRANS.value=100;
	form.FILTER.value = 'Johnson R';
}

////////////////////////////////////////////////////////////////////////////
function GaussFrac2dLookup( form )
{
	// integral of 2-D Gaussian function I(r/sigma) = integral[ 10 * r/sigma ]
	integral = new Array();
	
	integral[0] = 0.000000;
	integral[1] = 0.005159;
	integral[2] = 0.020478;
	integral[3] = 0.043585;
	integral[4] = 0.077596;
	integral[5] = 0.118150;
	integral[6] = 0.164268;
	integral[7] = 0.217997;
	integral[8] = 0.274646;
	integral[9] = 0.332261;
	integral[10] = 0.393318;	// 1 sigma
	integral[11] = 0.454462;
	integral[12] = 0.512948;
	integral[13] = 0.570322;
	integral[14] = 0.624838;
	integral[15] = 0.675165;
	integral[16] = 0.722630;
	integral[17] = 0.764472;
	integral[18] = 0.802221;
	integral[19] = 0.835890;
	integral[20] = 0.864689;	// 2 sigmas
	integral[21] = 0.889805;
	integral[22] = 0.911216;
	integral[23] = 0.929147;
	integral[24] = 0.943950;
	integral[25] = 0.956116;
	integral[26] = 0.965995;
	integral[27] = 0.973828;
	integral[28] = 0.980198;
	integral[29] = 0.985077;
	integral[30] = 0.988897;	// 3 sigmas
	integral[31] = 0.991824;
	integral[32] = 0.994022;
	integral[33] = 0.995690;
	integral[34] = 0.996918;
	integral[35] = 0.997812;
	integral[36] = 0.998470;
	integral[37] = 0.998938;
	integral[38] = 0.999268;
	integral[39] = 0.999503;
	integral[40] = 0.999665;
	integral[41] = 0.999776;
	integral[42] = 0.999853;
	integral[43] = 0.999904;
	integral[44] = 0.999938;
	integral[45] = 0.999960;
	integral[46] = 0.999975;
	integral[47] = 0.999984;
	integral[48] = 0.999990;
	integral[49] = 0.999994;
	integral[50] = 0.999996;
	integral[51] = 0.999998;
	integral[52] = 0.999999;
	integral[53] = 0.999999;
	integral[54] = 1.000000;
	integral[55] = 1.000000;
	integral[56] = 1.000000;
	integral[57] = 1.000000;
	integral[58] = 1.000000;
	integral[59] = 1.000000;

	sigmas = _aperxfwhm * 2.354820 / 2;	// convert diameter to sigma's
	index = sigmas * 10;
	index1 = Math.floor( index );
	
	if ( index1 < 0 )	// below 0 radius
	{
		_aperfrac = 0;
	}
	else if ( index > 59 )	// 6 sigmas or greater
	{
		_aperfrac = 1;
	}
	else
	{
		var frac = index - index1;
		_aperfrac = (1-frac) * integral[ index1 ] + frac * integral[ index1+1 ];
	}

	return _aperfrac;
}

/////////////////////////////////////////////////////////////////////////
function SaveCookie()
{
	var form = document.forms['signoise'];
	if ( form == null )
		return;
		
	var dt = new Date();
	expires = sprintf( '%d,%d,%d', dt.getUTCFullYear() + 10, dt.getUTCMonth(), dt.getUTCDate() );

	var str = 
	form.elements['PIX'].value + '^' +
	form.elements['QE'].value + '^' +
	form.elements['RN'].value + '^' +
	form.elements['GAIN'].value + '^' +
	form.elements['BIN'].value + '^' +
	form.elements['TEMP'].value + '^' +
	form.elements['TDBL'].value + '^' +
	form.elements['TREF'].value + '^' +
	form.elements['DREF'].value + '^' +
	form.elements['FL'].value + '^' +
	form.elements['DIAM'].value + '^' +
	form.elements['DIAMSEC'].value + '^' +
	form.elements['FILTER'].value + '^' +
	form.elements['EFF'].value + '^' +
	form.elements['VSTAR'].value + '^' +
	form.elements['EXPTIME'].value + '^' +
	form.elements['SEEING'].value + '^' +
	form.elements['VSKY'].value + '^' +
	form.elements['APER'].value + '^' +
	form.elements['TRANS'].value + '^';

	var sCookieName = window.location.pathname;
	_delete_cookie( sCookieName );
	_set_cookie( sCookieName, str, expires );
}

/////////////////////////////////////////////////////////////////////////
function LoadCookie()
{
	var form = document.forms['signoise'];
	if ( form == null )
		return;
	
	var sCookieName = window.location.pathname;	

	var sCookie = _get_cookie( sCookieName );
	if ( sCookie )
	{
		var ca = sCookie.split('^');
		if ( ca.length >= 20 )
		{
			form.elements['PIX'].value = ca[0];
			form.elements['QE'].value = ca[1];
			form.elements['RN'].value = ca[2];
			form.elements['GAIN'].value = ca[3];
			form.elements['BIN'].value = ca[4];
			form.elements['TEMP'].value = ca[5];
			form.elements['TDBL'].value = ca[6];
			form.elements['TREF'].value = ca[7];
			form.elements['DREF'].value = ca[8];
			form.elements['FL'].value = ca[9];
			form.elements['DIAM'].value = ca[10];
			form.elements['DIAMSEC'].value = ca[11];
			form.elements['FILTER'].value = ca[12];
			form.elements['EFF'].value = ca[13];
			form.elements['VSTAR'].value = ca[14];
			form.elements['EXPTIME'].value = ca[15];
			form.elements['SEEING'].value = ca[16];
			form.elements['VSKY'].value = ca[17];
			form.elements['APER'].value = ca[18];
			form.elements['TRANS'].value = ca[19];
			
			//window.status="Your default settings were loaded";
		}
	}
	else	// no cookie, first time initialization
	{
		form.elements['PIX'].value = 9;
		form.elements['QE'].value = 70;
		form.elements['RN'].value = 14;
		form.elements['GAIN'].value = 2.3;
		form.elements['BIN'].value = 1;
		form.elements['TEMP'].value = -10;
		form.elements['TDBL'].value = 6.3;
		form.elements['TREF'].value = 25;
		form.elements['DREF'].value = 6;
		form.elements['FL'].value = 2700;
		form.elements['DIAM'].value = 300;
		form.elements['DIAMSEC'].value = 89;
		form.elements['FILTER'].value = 'Clear';
		form.elements['EFF'].value = 90;
		form.elements['VSTAR'].value = 15;
		form.elements['EXPTIME'].value = 60;
		form.elements['SEEING'].value = 2.5;
		form.elements['VSKY'].value = 20;
		form.elements['APER'].value = 6;
		form.elements['TRANS'].value = 90;
	}
}
