
/////////////////////////////////////////////
// windowheatgain.js
// Copyright 2006, 1995 Sustainable By Design
/////////////////////////////////////////////


///////////////////////////
// CHECK INPUTS FUNCTION //
///////////////////////////

function CheckInputs () {

	var error = false;

	var error_message = "The following inputs must be corrected before the heat gain can be calculated:\n\n";

	var f = document.theForm;

	var inputLatitude          = f.inputLatitude.value;
	var inputGroundReflectance = f.inputGroundReflectance.value;
	var inputSHGC              = f.inputSHGC.value;
	

	//////////////
	// LATITUDE //
	//////////////
	
	if (inputLatitude < 16) {
	
		error_message = error_message + "* latitude must be at least 16 degrees\n";

		error = true;
	}
	
	if (inputLatitude >= 56) {
	
		error_message = error_message + "* latitude must be less than 56 degrees\n";

		error = true;
	}
	

	////////////////////////
	// GROUND REFLECTANCE //
	////////////////////////
	
	if (inputGroundReflectance < 0 || inputGroundReflectance > 1) {
	
		error_message = error_message + "* ground reflectance must be between 0.0 and 1.0\n";

		error = true;
	}
	
	
	//////////
	// SHGC //
	//////////
	
	if (inputSHGC <= 0 || inputSHGC > 1) {
	
		error_message = error_message + "* SHGC must be greater than 0.0 and no greater than 1.0\n";

		error = true;
	}

	
	////////////////////
	// CLEARNESS DATA //
	////////////////////

	var inputClearness = new Array (12);

	inputClearness[0]  = f.inputClearnessJan.value - 0;
	inputClearness[1]  = f.inputClearnessFeb.value - 0;
	inputClearness[2]  = f.inputClearnessMar.value - 0;
	inputClearness[3]  = f.inputClearnessApr.value - 0;
	inputClearness[4]  = f.inputClearnessMay.value - 0;
	inputClearness[5]  = f.inputClearnessJun.value - 0;
	inputClearness[6]  = f.inputClearnessJul.value - 0;
	inputClearness[7]  = f.inputClearnessAug.value - 0;
	inputClearness[8]  = f.inputClearnessSep.value - 0;
	inputClearness[9]  = f.inputClearnessOct.value - 0;
	inputClearness[10] = f.inputClearnessNov.value - 0;
	inputClearness[11] = f.inputClearnessDec.value - 0;
	
	for (whichMonth = 0; whichMonth < 12; whichMonth ++) {

		if (inputClearness[whichMonth] <= 0 || inputClearness[whichMonth] > 100) {

			monthName = MonthNumToLongName (whichMonth);

			error_message = error_message + "* the clearness value for " + monthName + " must be greater than 0.0 and no greater than 100.0\n";
	
			error = true;
		}
	}

	// ALERT / RETURN

	if (error == true) { alert (error_message); }

	return (! error);
}


////////////////////////////////////////////////////////////////////////////////////
//  MAIN COMPUTE FUNCTION  
////////////////////////////////////////////////////////////////////////////////////

function compute () {

	var f = document.theForm;
	
	// data
	
		// SHGF data, organized by month, then latitude (16,24,32,40,48,56), then compass orientation (NESW),
		// so datum location = (72 * orientation) + (12 * latitude) + month

	var dataSHGF = new Array (696, 780, 886, 1130, 1784, 2244, 1866, 1206, 922, 802, 704, 656, 602, 710, 840, 1060, 1498, 1794, 1558, 1130, 876, 732, 610, 554, 498, 628, 784, 1014, 1398, 1648, 1456, 1078, 818, 650, 506, 446, 388, 532, 716, 972, 1358, 1598, 1410, 1036, 748, 554, 394, 330, 268, 428, 634, 926, 1356, 1622, 1410, 990, 664, 446, 276, 210, 146, 312, 536, 874, 1400, 1732, 1458, 940, 564, 328, 152, 90, 2748, 3120, 3364, 3396, 3352, 3304, 3309, 3324, 3247, 3040, 2715, 2570, 2420, 2897, 3276, 3452, 3512, 3503, 3473, 3385, 3159, 2822, 2392, 2207, 2047, 2633, 3151, 3484, 3654, 3688, 3619, 3419, 3031, 2560, 2024, 1801, 1621, 2311, 2983, 3485, 3781, 3866, 3752, 3424, 2859, 2243, 1601, 1347, 1131, 1923, 2762, 3463, 3905, 4050, 3881, 3403, 2633, 1862, 1118, 842, 589, 1447, 2474, 3415, 4044, 4265, 4024, 3358, 2339, 1395, 583, 323, 4930, 3670, 2010, 1094, 1082, 1096, 1108, 1136, 2014, 3550, 4838, 5274, 5296, 4406, 2890, 1540, 1182, 1180, 1204, 1532, 2848, 4258, 5200, 5474, 5384, 4920, 3712, 2270, 1574, 1420, 1566, 2218, 3622, 4750, 5282, 5374, 5130, 5180, 4378, 3076, 2256, 1990, 2220, 2990, 4238, 4986, 5030, 4890, 4424, 5128, 4836, 3814, 3046, 2752, 2992, 3702, 4646, 4916, 4328, 3886, 3070, 4650, 5042, 4408, 3806, 3546, 3742, 4278, 4800, 4428, 2996, 2162, 2748, 3120, 3364, 3396, 3352, 3304, 3309, 3324, 3247, 3040, 2715, 2570, 2420, 2897, 3276, 3452, 3512, 3503, 3473, 3385, 3159, 2822, 2392, 2207, 2047, 2633, 3151, 3484, 3654, 3688, 3619, 3419, 3031, 2560, 2024, 1801, 1621, 2311, 2983, 3485, 3781, 3866, 3752, 3424, 2859, 2243, 1601, 1347, 1131, 1923, 2762, 3463, 3905, 4050, 3881, 3403, 2633, 1862, 1118, 842, 589, 1447, 2474, 3415, 4044, 4265, 4024, 3358, 2339, 1395, 583, 323);

		// horizontal SHGF data, organized by latitude (16,24,32,40,48,56),
		// so datum location = (12 * latitude) + month
		
	var dataSHGFhorizontal = new Array (5078, 5864, 6460, 6662, 6670, 6614, 6576, 6514, 6248, 5742, 5036, 4720, 4188, 5170, 6062, 6612, 6866, 6910, 6788, 6484, 5842, 5070, 4158, 3772, 3228, 4360, 5508, 6402, 6922, 7074, 6862, 6302, 5326, 4284, 3212, 2778, 2234, 3458, 4818, 6036, 6828, 7100, 6790, 5964, 4658, 3408, 2230, 1782, 1278, 2492, 4008, 5520, 6588, 6988, 6574, 5480, 3874, 2466, 1284, 888, 502, 1518, 3096, 4872, 6214, 6750, 6226, 4866, 2990, 1514, 510, 254);
       
	// retrieve input values
	
	var inputCity = f.inputCity.options[f.inputCity.selectedIndex].text;
	
	var inputLatitude = f.inputLatitude.value - 0;
	
	var inputClearness = new Array (12);
	    inputClearness[0]  = f.inputClearnessJan.value - 0;
	    inputClearness[1]  = f.inputClearnessFeb.value - 0;
	    inputClearness[2]  = f.inputClearnessMar.value - 0;
	    inputClearness[3]  = f.inputClearnessApr.value - 0;
	    inputClearness[4]  = f.inputClearnessMay.value - 0;
	    inputClearness[5]  = f.inputClearnessJun.value - 0;
	    inputClearness[6]  = f.inputClearnessJul.value - 0;
	    inputClearness[7]  = f.inputClearnessAug.value - 0;
	    inputClearness[8]  = f.inputClearnessSep.value - 0;
	    inputClearness[9]  = f.inputClearnessOct.value - 0;
	    inputClearness[10] = f.inputClearnessNov.value - 0;
	    inputClearness[11] = f.inputClearnessDec.value - 0;
	    
	var inputSurface = f.inputSurface.options[f.inputSurface.selectedIndex].text;
	
	var inputGroundReflectance = f.inputGroundReflectance.value - 0;
	
	var inputWindow = f.inputWindow.options[f.inputWindow.selectedIndex].text;
	
	var inputSHGC = f.inputSHGC.value - 0;
	
	var inputOrientation = f.inputOrientation.options[f.inputOrientation.selectedIndex].text;

	var inputUnits = f.inputUnits.options[f.inputUnits.selectedIndex].text;
	var inputUnitsIndex = f.inputUnits.selectedIndex;

	var inputLabels = f.inputLabels.checked;
				
	// determine shgf data to use
	
	var lowerLatitudeBoundaryLine = Math.floor (inputLatitude / 8) - 2;  // yields a result between 0 and 4 (16 to 48 degrees)
	var upperLatitudeBoundaryLine = lowerLatitudeBoundaryLine + 1;       // yields a result between 1 and 5 (24 to 56 degrees)
	
	var lowerLatitudeBoundary = (lowerLatitudeBoundaryLine + 2) * 8;
	var upperLatitudeBoundary = (upperLatitudeBoundaryLine + 2) * 8;
	
	// reset output string
	
	var outputString = "";
	
	// compute value for each month
	
	for (whichMonth = 0; whichMonth < 12; whichMonth ++) {
		
		// get raw interpolated data

		var lowerLatitudeMonthlyData = dataSHGF[(72 * f.inputOrientation.selectedIndex) + (12 * lowerLatitudeBoundaryLine) + whichMonth];
		var upperLatitudeMonthlyData = dataSHGF[(72 * f.inputOrientation.selectedIndex) + (12 * upperLatitudeBoundaryLine) + whichMonth];
		
		var monthDatum = lowerLatitudeMonthlyData + (upperLatitudeMonthlyData - lowerLatitudeMonthlyData) * ((inputLatitude - lowerLatitudeBoundary) / (upperLatitudeBoundary - lowerLatitudeBoundary));

		// incorporate ground reflectance
		
		if (inputGroundReflectance != 0.2) {
			
			var lowerLatitudeMonthlyHorizontalData = dataSHGFhorizontal[(12 * lowerLatitudeBoundaryLine) + whichMonth];
			var upperLatitudeMonthlyHorizontalData = dataSHGFhorizontal[(12 * upperLatitudeBoundaryLine) + whichMonth];

			var monthHorizontalDatum = lowerLatitudeMonthlyHorizontalData + (upperLatitudeMonthlyHorizontalData - lowerLatitudeMonthlyHorizontalData) * ((inputLatitude - lowerLatitudeBoundary) / (upperLatitudeBoundary - lowerLatitudeBoundary));
			
			var groundReflectanceContribution = monthHorizontalDatum * (inputGroundReflectance - 0.20) * 0.5;    // see ASHRAE p. 27.27
 			
 			monthDatum = monthDatum + groundReflectanceContribution;
 		}
		
		// incorporate clearness
		
		monthDatum = monthDatum * (inputClearness[whichMonth] / 100.0);
		
		// incorporate shgc
		
		monthDatum = monthDatum * inputSHGC;
		
		// convert to monthly output data if appropriate
		
		if (inputUnitsIndex == 1 || inputUnitsIndex == 3) { monthDatum = monthDatum * MonthToDays (whichMonth); }
		
		// convert to IP if appropriate
		
		if (inputUnitsIndex == 2 || inputUnitsIndex == 3) { monthDatum = monthDatum * 3.412 / 10.76; }
			
		// output
		
			// add month label if appropriate
			
		if (inputLabels == true) { outputString = outputString + MonthNumToShortName (whichMonth) + " "; }
		
		outputString = outputString + Math.floor (monthDatum) + "\012";  // "\012" is carriage return octal
 	}
	
	// print footer info if requested
	
	if (inputLabels == true) {
	
		// add carriage return
	
		outputString = outputString + "\012";
		
		// add city if not custom
		
		if (f.inputCity.selectedIndex != 0) { outputString = outputString + "city = " + inputCity + "\012"; }
		
		// add latitude
		
		outputString = outputString + "latitude = " + inputLatitude + "\012";
		
		// add surface if not custom
		
		if (f.inputSurface.selectedIndex != 0) { outputString = outputString + "surface = " + inputSurface + "\012"; }
		
		// add ground reflectance
		
		outputString = outputString + "ground reflectance = " + inputGroundReflectance + "\012";

		// add window orientation
		
		outputString = outputString + "window orientation = " + inputOrientation + "\012";

		// add window if not custom
		
		if (f.inputWindow.selectedIndex != 0) { outputString = outputString + "window = " + inputWindow + "\012"; }

		// add SHGC
				
		outputString = outputString + "window SHGC = " + inputSHGC + "\012";
		
		// add units
		
		outputString = outputString + "units = " + inputUnits;
	}
	
	// print to output field
	
	f.output.value = outputString;
		
} // end compute function


////////////////////////////////////////////////////////////////////////////////////
//  OTHER FUNCTIONS  
////////////////////////////////////////////////////////////////////////////////////


function SelectCity () {

	var f = document.theForm;
	
	// data
	
		// city latitudes (order same as HTML input field)
		
	var dataLatitudes = new Array (0, 33.5, 34.0, 25.9, 33.8, 42.3, 46.8, 47.5, 43.1);

		// city clearness (order same as HTML input field, with 12 monthly values for each)
		// (first twelve are for custom values)

	var dataClearness = new Array (0,0,0,0,0,0,0,0,0,0,0,0, 78, 80, 84, 89, 93, 94, 85, 85, 89, 88, 83, 77, 69, 72, 73, 70, 66, 65, 82, 83, 79, 73, 74, 71, 65, 67, 73, 75, 72, 68, 72, 71, 70, 70, 67, 63, 49, 54, 58, 66, 68, 66, 62, 64, 62, 66, 58, 50, 53, 56, 57, 56, 58, 63, 65, 65, 63, 60, 50, 52, 48, 53, 54, 56, 57, 58, 65, 61, 52, 46, 35, 39, 28, 34, 42, 47, 52, 49, 63, 56, 53, 37, 28, 23, 47, 51, 52, 52, 58, 64, 67, 64, 60, 54, 39, 40);

	// determine selected city
		
	var whichCity = f.inputCity.selectedIndex;

	// set latitude
	
	f.inputLatitude.value = dataLatitudes[whichCity];
	
	// set clearness values
	
	f.inputClearnessJan.value = dataClearness[(whichCity * 12) +  0];
	f.inputClearnessFeb.value = dataClearness[(whichCity * 12) +  1];;
	f.inputClearnessMar.value = dataClearness[(whichCity * 12) +  2];;
	f.inputClearnessApr.value = dataClearness[(whichCity * 12) +  3];
	f.inputClearnessMay.value = dataClearness[(whichCity * 12) +  4];
	f.inputClearnessJun.value = dataClearness[(whichCity * 12) +  5];
	f.inputClearnessJul.value = dataClearness[(whichCity * 12) +  6];
	f.inputClearnessAug.value = dataClearness[(whichCity * 12) +  7];
	f.inputClearnessSep.value = dataClearness[(whichCity * 12) +  8];
	f.inputClearnessOct.value = dataClearness[(whichCity * 12) +  9];
	f.inputClearnessNov.value = dataClearness[(whichCity * 12) + 10];
	f.inputClearnessDec.value = dataClearness[(whichCity * 12) + 11];

	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}



function SelectSurface () {

	var f = document.theForm;
	
	// data
	
		// surface reflectance (order same as HTML input field)
		// (first value is for custom data)
		
	var dataSurfaces = new Array (0, 0.32, 0.23, 0.25, 0.20, 0.14, 0.10, 0.20);
	
	// determine selected surface
		
	var whichSurface = f.inputSurface.selectedIndex;

	// set reflectance
	
	f.inputGroundReflectance.value = dataSurfaces[whichSurface];
	
	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}



function SelectWindow () {

	var f = document.theForm;
	
	// data
	
		// window SHGC (order same as HTML input field)
		// (first value is for custom data)
		
	var dataSHGC = new Array (0, 0.79, 0.69, 0.65, 0.55, 0.58, 0.48, 0.55, 0.44, 0.31, 0.26, 0.37, 0.52);
	
	// determine selected window
		
	var whichWindow = f.inputWindow.selectedIndex;

	// set SHGC
	
	f.inputSHGC.value = dataSHGC[whichWindow];
	
	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}


function SetCityToCustom () {

	document.theForm.inputCity.selectedIndex = 0;
	
}


function MonthToDays (monthNumber) {
	
	if (monthNumber ==  0) { return	 (31) };
	if (monthNumber ==  1) { return	 (28) };
	if (monthNumber ==  2) { return	 (31) };
	if (monthNumber ==  3) { return	 (30) };
	if (monthNumber ==  4) { return	 (31) };
	if (monthNumber ==  5) { return	 (30) };
	if (monthNumber ==  6) { return	 (31) };
	if (monthNumber ==  7) { return	 (31) };
	if (monthNumber ==  8) { return	 (30) };
	if (monthNumber ==  9) { return	 (31) };
	if (monthNumber == 10) { return	 (30) };
	if (monthNumber == 11) { return	 (31) };
	
	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}



function MonthNumToShortName (monthNumber) {
	
	if (monthNumber ==  0) { return ("jan") };
	if (monthNumber ==  1) { return ("feb") };
	if (monthNumber ==  2) { return ("mar") };
	if (monthNumber ==  3) { return ("apr") };
	if (monthNumber ==  4) { return ("may") };
	if (monthNumber ==  5) { return ("jun") };
	if (monthNumber ==  6) { return ("jul") };
	if (monthNumber ==  7) { return ("aug") };
	if (monthNumber ==  8) { return ("sep") };
	if (monthNumber ==  9) { return ("oct") };
	if (monthNumber == 10) { return ("nov") };
	if (monthNumber == 11) { return ("dec") };
	
	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}



function MonthNumToLongName (monthNumber) {
	
	if (monthNumber ==  0) { return ("January") };
	if (monthNumber ==  1) { return ("February") };
	if (monthNumber ==  2) { return ("March") };
	if (monthNumber ==  3) { return ("April") };
	if (monthNumber ==  4) { return ("May") };
	if (monthNumber ==  5) { return ("June") };
	if (monthNumber ==  6) { return ("July") };
	if (monthNumber ==  7) { return ("August") };
	if (monthNumber ==  8) { return ("September") };
	if (monthNumber ==  9) { return ("October") };
	if (monthNumber == 10) { return ("November") };
	if (monthNumber == 11) { return ("December") };
	
	return ("Zeke the Solar Cat"); // you can't get here but I swear it made me do this
}
