// Copyright 1998-2007  All Rights Reserved Richard Shelquist,  January 1998 - Sep 2007
// This calculator is the copyrighted intellectual property of Shelquist Engineering.
// This calculator may be freely used for an individual's personal use via my web site,
// or by means of one copy on an individual's own computer for that person's personal use, 
// but may not be copied or republished in any form on any web site, bulletin board or 
// any other means.

// Oct 2006 - now using the same algorithms as my density altitude calculators

// Global Variables for conversions

var mb_to_in = (1/33.86389);
var ft_to_m = 0.3048;

var in_per_mb = (1/33.86389);
var m_per_ft = 0.3048;


function resetForm()
{
	var inForm=document.inputs;
	var outForm=document.outputs;

	inForm.temperature.value = "";
	inForm.altitude.value = "";
	inForm.pressure.value = "";
	inForm.rh.value = "";

	outForm.horsepower.value = "";
	outForm.density.value = "";
	outForm.rad.value = "";	
	outForm.densalt.value = "";
	outForm.actpress.value = "";
	outForm.actualvp.value = "";
	outForm.virtemp.value = "";
	outForm.dynocf.value = "";
		
	inForm.temperature.focus();

}

function resetOut()
{
	var inForm=document.inputs;
	var outForm=document.outputs;

	outForm.horsepower.value = "";
	outForm.density.value = "";
	outForm.rad.value = "";	
	outForm.densalt.value = "";
	outForm.actpress.value = "";
	outForm.actualvp.value = "";
	outForm.virtemp.value = "";
	outForm.dynocf.value = "";
		
	inForm.temperature.focus();

}


function roundNum(Num, Places)
//  Rounding function by Jason Moon
{
   if (Places > 0) {
      if ((Num.toString().length - Num.toString().lastIndexOf('.')) > (Places + 1)) {
         var Rounder = Math.pow(10, Places);
         return Math.round(Num * Rounder) / Rounder;
      }
      else {return Num;}
   }
   else {return Math.round(Num);}
}




function calcVaporPressure_wobus(t)
// Calculate the saturation vapor pressure given the temperature(celsius)
// Polynomial from Herman Wobus 
{
	var eso=6.1078;

	var c0=0.99999683;
	var c1=-0.90826951E-02;
	var c2=0.78736169E-04;
	var c3=-0.61117958E-06;
	var c4=0.43884187E-08;
	var c5=-0.29883885E-10;
	var c6=0.21874425E-12;
	var c7=-0.17892321E-14;
	var c8=0.11112018E-16;
	var c9=-0.30994571E-19;
	
	var pol=c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*(c6+t*(c7+t*(c8+t*(c9)))))))));
	
	var es=eso/Math.pow(pol,8);

	return (es);
}





function calcDensity(abspressmb, e, tc)
//  Calculate the air density in kg/m3
{
	var Rv=461.4964;
	var Rd=287.0531;
	
	var tk=tc+273.15;
	var pv=e*100;
	var pd= (abspressmb-e)*100;
	var d= (pv/(Rv*tk)) + (pd/(Rd*tk));
	return(d);
}


function calcAltitude(d)
// Calculate the ISA altitude (meters) for a given density (kg/m3)
{
	var g=9.80665;
	var Po=101325;
	var To=288.15;
	var L=6.5;
	var R=8.314320;
	var M=28.9644;
	
	var D=d*1000;
	
	var p2=( (L*R)/(g*M-L*R) )*Math.log( (R*To*D)/(M*Po) );
	
	var H=-(To/L)*( Math.exp(p2)-1 );
	
	var h=H*1000;

	return(h);
}





function calcZ(h)
// Calculate the Z geometric altitude (meters), given the H geopotential altitide (meters)
{
	var r=6369E3;
	
	return ((r*h)/(r-h));

}



function calcH(z)
// Calculate the H geopotential altitude (meters), given the Z geometric altitide (meters)
{
	var r=6369E3;
	
	return ((r*z)/(r+z));

}




function calcAs2Press(As, h)
// Calculate the actual pressure (mb)from the altimeter setting (mb) and geopotential altitude (m)
{
	var k1=0.190263;
	var k2=8.417286E-5;

	var p=Math.pow( (Math.pow(As,k1)-(k2*h)),(1/k1) );

	return (p);
}



function calcDynoCorrection(temp, abspress, vapress)
// Calculate dyno correction given temp(celsius), absolute pressure(inchesHg)  and vapor pressure(inchesHg)
{
	var p1=29.235/(abspress-vapress);
	var p2=Math.pow( ((temp+273)/298), 0.5);
	var p3=(1.18*(p1*p2) - 0.18);
	return(p3);
}





//// Calculate virtual temperature given temp(celsius), absolute pressure(mb)  and vapor pressure(mb)

function calcVirtualTemp(tc, abspressmb, emb){

	var p1=(tc+273.15) / (1- (0.377995*emb/abspressmb) ) ;
	return(p1);
}








function validatePrompt (ctrl, prompt)
{
	alert (prompt);
	ctrl.focus();
	ctrl.select();
	return;
}




function validateForm ( temp, pressure, dewpoint, altitude)
{
// Validate temperature
	if (isNaN(temp.value) || (temp.value.length===0) || temp.value.charAt(0)===" " )
	{
		validatePrompt (temp, "Temperature entry must be a number.");
		return false;
	}

// Validate pressure
	if (isNaN(pressure.value) || (pressure.value.length===0) || pressure.value.charAt(0)===" " )
	{
		validatePrompt (pressure, "Pressure entry must be a number.");
		return false;
	}

// Validate dewpoint
	if (isNaN(dewpoint.value) || (dewpoint.value.length===0) || dewpoint.value.charAt(0)===" " )
	{
		validatePrompt (dewpoint, "Dew point temperature must be a number.");
		return false;
	}

// Validate altitude
	
	if (isNaN(altitude.value) || (altitude.value.length===0) || altitude.value.charAt(0)===" " )
	{
		validatePrompt (altitude, "Altitude entry must be a number.");
		return false;
	}

// If all of the inputs are properly validated then return true

	return true;
}	





function calc()
{
	var inForm=document.inputs;
	var outForm=document.outputs;

// Validate all four of the required inputs

	if (!validateForm(inForm.temperature, inForm.pressure, inForm.rh, inForm.altitude)) {return;}

// Process the input values

	var temp=1.0*inForm.temperature.value;
	var pressure=1.0*inForm.pressure.value;
	var rh=1.0*inForm.rh.value;
	var altitude=1.0*inForm.altitude.value;

// Convert units to metric, and convert rh to emb

	var tc=(5/9)*(temp-32 );
    var altsetmb=pressure/mb_to_in;
  
	var esmb=calcVaporPressure_wobus(tc);  
	var emb=(esmb*rh)/100;
	
	outForm.actualvp.value= roundNum(emb*in_per_mb,4);
	
	var zm=altitude*ft_to_m;
	

	
// Calculate geopotential altitude H (m) from geometric altitude (m) Z

	var hm=calcH(zm);
	
	
// Calculate the actual pressure given the altimeter setting(mb) and geopotential elevation(meters)

	var actpressmb=calcAs2Press(altsetmb,hm);
	var actpress=actpressmb*in_per_mb;	


// Calculate the air density (kg/m3) from actual pressure (mb) vapor pressure (mb) and temp (c)

	var density=calcDensity(actpressmb, emb, tc);
	var relden=100*(density/1.225);
	
	
// Calculate the geopotential altitude (m) in ISA with that same density (kg/m3)
  
    var densaltm=calcAltitude(density);
    
// Calculate geometric altitude Z (m) from geopotential altitude (m) H

    var densaltzm=calcZ(densaltm);
    
    
// Convert Units for output
    
    
	if ( densaltzm > 11000 || densaltzm < -5000 )
	{
		alert ("Out of range for Troposhere Algorithm: Altitude =" + roundNum(densaltzm,0) + " meters\nPlease check your input values." );
		resetOut();
		return;
	}
    
	
// Print the results

	outForm.actpress.value=roundNum(actpressmb*in_per_mb,2);
	outForm.rad.value=roundNum(relden,1);    
	outForm.densalt.value=roundNum(densaltzm/m_per_ft,0);
	outForm.density.value=roundNum(density,4);
	

// Calculate the dyno correction factor

	var dynocf=calcDynoCorrection(tc,actpress,emb*in_per_mb);

	outForm.horsepower.value=roundNum(100/dynocf,1);

	outForm.dynocf.value=roundNum(dynocf,3);
	
	
// Calculate the virtual temperature

	var vtk=calcVirtualTemp(tc, actpressmb, emb);

	var vtc= (vtk-273.15);

	outForm.virtemp.value=roundNum((vtc*9/5)+32,1);


	

}
