// Created by Gary Fisk in November-December of 2023. 
// The purpose is to provide a more open way to create flexible recipes. 
// User inputs enable greater control over the calcuations than the previous flex version. 
// License: Creative Commons Attribution 4.0 International
// https://creativecommons.org/licenses/by/4.0/

// *** Basic conversion functions
function gallonsToLiters(gallons){return gallons*3.78541178;}
function litersToGallons(liters) {return liters*0.264172;}
function kilogramsToPounds(kilograms) {return kilograms*2.20462;}
function SGToPlato(SG) {return (135.997 * Math.pow(SG,3)) - (630.272 * Math.pow(SG,2)) + (1111.14 * SG) - 616.868;}
function PlatoToSG (Plato) {return 1 + (Plato / (258.6 - ((Plato/258.2) * 227.1)));}
function gramsToOunces(grams) {return grams*0.035274;} 
function barrelsToLiters(barrels) {return gallonsToLiters(barrels * 31);} 

function calculate() {
   
// Create variables
    var output = ""; 
    var SG = 0; // Variable for original gravity as specific gravity
    var Plato = 0; // Variable for original gravity as degrees plato
    var GravityUnit = 0; // Variable for tracking type of gravity units
    var IBUtemp = 0; // A temporary variable for each hops IBU values
    var IBUcheck = 0; // This variable is a check to see if IBUs are correct; inputs = outputs
	var GravityPoints = 0; // This is used as part of estimating a 15% boil off rate for hop utilization
	var EstBoilGravity = 0; // Part of estimating IBUs at different time points
	var EstBoilVolume = 0; // Part of estimating IBUs at different time points
    var TempForm = ""; // A temporary variable for holding forms
    var TempArray = []; // A temporary array for holding malt and hop values
    var TempOutput = ""; // Temporary output variable
    var Gallons = 0; // Variable for volume in gallons
    var Liters = 0; // Variable for volume in liters
    var MeasureUnit = 0; // For measurement type; 0 = metric (liters, etc.), 1 = US , 2 = US barrels
    var SpMaltTotal = 0; // Variable for adding up the special malt percentages
    var ColorUnit = 0; // Variable for the color unit values 0 = SRM, 1 = MCU, 2 = EBC
    var TotalWeight = 0; // Variable that sums all weights
    var PercentCheck = 0; // An error tracking variable for the total percentages
    var MCU = 0; // Variable for malt color units value
    var SRM = 0; // Variable for standard reference method color value
    var MaltSugar = []; // Array for malt and sugar values
    var Hops = []; // Array for hop values
	var Spice = []; // Array for late kettle additions like spices
    var DryHops = []; // Array for dry hop values
    var TotalHopGrams = 0; // Sums hops weights for the boil (not including dry hop)
    var DryHopWeight = 0; // Calculated value for dry hop weight
	var YeastType = 0; // Yeast 0 = ale, 1 = lager
    
// Basic batch input values
    var OG = parseFloat(document.GravityData.og.value); //Original gravity in either SG or plato
    var MashEfficiency = parseFloat(document.EffData.eff.value); // Mash efficiency; // Mash efficiency
	var IBU = parseFloat(document.IBUData.IBU.value); // Desired IBUs
    var Volume = parseFloat(document.VolumeData.Volume.value); // volume amount
	var TempForm = document.getElementById("MeasureUnit"); //Gets the measurement unit type from the form 
		for (var i=0; i < TempForm.length; i++) { // Loop to determine which radio button is checked
			if (TempForm[i].checked) {
				var MeasureUnit = TempForm.elements[i].value; //Radio button value is assigned to unit variable
			}
    }


// Use OG to determine the SG and Plato variables, with necessary conversions
// OG values less than 1.2 are assumed to be in specific gravity units. Conversely, values over 1.2 are interpreted as degrees plato.     
    if (OG < 1.2) {
		var Plato = SGToPlato(OG); // For OG in specific gravity units 
		var SG = OG; 
    } 
    else {
		var Plato = OG; // For OG in Plato units
		var SG = PlatoToSG(OG); 
    }
// Load malt values: name, percent, lovibond, yield
    var TempForm = document.getElementById("MaltData");
	for (i = 0; i < TempForm.length; i++) {
		if (TempForm[i].value == "") {
			continue; // Skip blank fields
		}
		var TempArray = TempForm.elements[i].value.split(","); //Create a temporary array
			for (j = 1; j < 4; j++) {
				TempArray[j] = parseFloat(TempArray[j]); // Convert numbers imported as string values to numerical; Starts at position 1
			}
		TempArray.splice(1, 0, 0); // Add a 0 to array position 1 for sugar type (0 = malt)
		MaltSugar.push(TempArray); // Add these current values to the MaltSugar array
    }
// Load sugar values: Name, percent, lovibond, yield, 
    var TempForm = document.getElementById("SugarData");
	for (i = 0; i < TempForm.length; i++) {
		if (TempForm[i].value == "") {
				continue; // Skip blank fields
		}
		var TempArray = TempForm.elements[i].value.split(","); //Create a temporary array
			for (j = 1; j < 4; j++) {
				TempArray[j] = parseFloat(TempArray[j]); // Convert numbers imported as string values to numerical; Starts at position 1
			}
		TempArray.splice(1, 0, 1); // Add a 1 to array position 1 for sugar type (1 = sugar)
		MaltSugar.push(TempArray); // Add these current values to the MaltSugar array
    }
// Load hop values: Name, percent IBU, minutes, AA%
    var TempForm = document.getElementById("HopData");
	for (i = 0; i < TempForm.length; i++) {
		if (TempForm[i].value == "") {
			continue; // Skip blank fields
		}
		var TempArray = TempForm.elements[i].value.split(","); //Create a temporary array
			for (j = 1; j < 4; j++) {
				TempArray[j] = parseFloat(TempArray[j]); // Convert numbers imported as string values to numerical; Starts at position 1
			}
		Hops.push(TempArray); // Add these current values to the Hops array
    }
// Load late kettle additions such as spices To do: Create new array. 
    var TempForm = document.getElementById("LateSpice");
	for (i = 0; i < TempForm.length; i++) {
		if (TempForm[i].value == "") {
			continue; // Skip blank fields
		}
		var TempArray = TempForm.elements[i].value.split(","); //Create a temporary array
		TempArray[1] = parseFloat(TempArray[1]); // Convert numbers imported as string values to numerical; for position 1
		Spice.push(TempArray); // Add these current values to the Hops array
		}
// Load dry hop values: Name, grams/liter
    var TempForm = document.getElementById("HopDryData");
	for (i = 0; i < TempForm.length; i++) {
		if (TempForm[i].value == "") {
			continue; // Skip blank fields
		}
		var TempArray = TempForm.elements[i].value.split(","); //Create a temporary array
		TempArray[1] = parseFloat(TempArray[1]); // Convert numbers imported as string values to numerical at position 1
		DryHops.push(TempArray); // Add these current values to the Hops array
    }
// Yeast data
	var TempForm = document.getElementById("YeastData"); //Gets the unit type from the form 
    for (var i=0; i < TempForm.length; i++) { // Loop to determine which radio button is checked
	if (TempForm[i].checked) {
	    var YeastType = TempForm.elements[i].value; //Radio button value is assigned to unit variable
	}
    }
// Get the volume values entered into the proper variables. 0 = metric, 1 = gallons, 2 = barrels; A US beer barrel is 31 gallons
    if (MeasureUnit == 0) {
		var Liters = Volume; 
		var Gallons = litersToGallons(Volume);
		} 
    if (MeasureUnit == 1) {
		var Liters = gallonsToLiters(Volume); 
		var Gallons = Volume;
		} 
    if (MeasureUnit == 2) {
		var Liters = gallonsToLiters(Volume * 31); 
		var Gallons = (Volume * 31);
		} 
// Check for unusual values
    if (SG > 1.2) {
		var output = output + "*** A specific gravity value larger than 1.200 is unusual. Check the data entry. ***<br/>";
	} 
    if (Plato < 2) {
		var output = output + "*** A plato value smaller than 2.0 is unusual. Check the data entry. ***<br/>";
	}
    if (MashEfficiency > 100) {
		var output = output + "*** A mash efficiency over 100% is not possible. Check the data entry. ***<br/>";
	}
    if (MashEfficiency < 50) {
		var output = output + "*** A mash efficiency below 40% seems unusual. Check the data entry. ***<br/>";
    }
    if (SpMaltTotal > 100) {
		var output = output + "*** Error: The total malt percentage is over 100%. Check the data entry. ***<br/>";
    }
	for (i=0; i < MaltSugar.length; i++) {
		if (MaltSugar[i][4] <= 1.0) {
			var output = output + "*** Error: Yield value of less than 1% in a malt or sugar field. ***<br/>";
		if (MaltSugar[i][1] == 0 && MaltSugar[i][4] > 85) {
			var output = output + "*** Error: Malt yield of larger than 85% seems unusual. ***<br/>"; 
		}
	}
	}
	for (i=0; i < Hops.length; i++) {
		if (Hops[i][2] < 2.5 || Hops[i][2] > 25) {
			var output = output + "*** Error: Unusual alpha acid percentage of <2.5 or >25 in the hops field. ***<br/>";
		}
	}
// The following check for blank entries in the user input. Number.isNaN is a true/false test for non-numerical values. 
    if (Number.isNaN(MashEfficiency)) {
		var output = output + "*** Error: Check the mash efficiency field. ***<br/>";
    }
    if (Number.isNaN(Volume)) {
		var output = output + "*** Error: Check the volume field. ***<br/>";
    }
    if (Number.isNaN(IBU)) {
		var output = output + "*** Error: Check the IBU field. ***<br/>";
    }
    if (Number.isNaN(OG)) {
		var output = output + "*** Error: Check the original gravity field. ***<br/>";
	}
// Checks for possible percentages that don't add to 100%. 
    var MaltCheck = 0; // Checks for malt percentages adding to 100%.  
    for (i=0; i < MaltSugar.length; i++) {
		if (MaltSugar[i][0] == "none" || MaltSugar[i][0] == "None") {
			continue; 
		}
		var MaltCheck = MaltCheck + MaltSugar[i][2]; 
    }
	if (MaltCheck != 100) {
		var output = output + "*** Error: Total fermentable percentages are " + MaltCheck + "%. Must add to 100%. ***<br/>";
	}
    var HopCheck = 0;
	for (i=0; i < Hops.length; i++) {
		var HopCheck = HopCheck + Hops[i][1];
    }
	if (HopCheck != 100) {
		var output = output + "*** Error: Top IBU percentages sum to " + HopCheck + "%. These must add to 100%. ***<br/>"; 
	}
// Checks for odd array lengths in MaltSugar, Hops, Spice, Dry hops
	for (i = 0; i < MaltSugar.length; i++) {
	if (MaltSugar[i][0] == "none" || MaltSugar[i][0] == "None") {
			continue; 
		}
		if (MaltSugar[i].length > 5) {
			var output = output + "*** Error: Check the malt or sugar entry for extra data. ***<br/>"; 
		}
		for (j = 1; j < 5; j++) {
			if (Number.isNaN(MaltSugar[i][j])) {
				var output = output + "*** Error: Check the data in the malt or sugar fields for errors. ***<br/>"; 
			}
		}
	}
	for (i = 0; i < Hops.length; i++) {
		if (Hops[i].length > 4) {
			var output = output + "*** Error: Check the hop fields for missing or extra data. ***<br/>"; 
		}
		for (j = 1; j < 4; j++) {
			if (Number.isNaN(Hops[i][j])) {
				var output = output + "*** Error: Check the data in the hop fields for errors. ***<br/>"; 
			}
		}
	}
	for (i = 0; i < Spice.length; i++) {
		if (Spice[i].length > 2) {
			var output = output + "*** Error: Check the spice fields for extra data. ***<br/>"; 
		}
		if (Spice[i][0] == "None" || Spice[i][0] == "none") {
			continue; // Skips the next test if the field is labeled "none". 
		}
		if (Number.isNaN(Spice[i][1])) {
				var output = output + "*** Error: Check the data in the spice fields for errors. ***<br/>"; 
		}
		}
	for (i = 0; i < DryHops.length; i++) {
		if (DryHops[i].length > 2) {
			var output = output + "*** Error: Check the dry hop fields for extra data. ***<br/>"; 
		}
		if (DryHops[i][0] == "None" || DryHops[i][0] == "none") {
			continue; // Skips the next test if the field is labeled "none". 
		}
		if (Number.isNaN(DryHops[i][1])) {
				var output = output + "*** Error: Check the data in the dry hop fields for errors. ***<br/>"; 
		}
		}
// Start the output with overall batch information
// Use the WeightUnit variable as a measure of the true desired output units.
	var output = output + "--- Overall ---<br/>"; // Output header
    if (MeasureUnit == 0) {
		var output = output + "Volume: " + Math.round(Liters * 10) / 10 + " Liters<br/>"; // Liters output
    } 
	else if (MeasureUnit == 1) {
		var output = output + "Volume: " + Math.round(Gallons * 10) / 10 + " Gallons<br/>"; // Gallons output
	}
	else {
		var output = output +  "Volume: " + Math.round((Gallons / 31) * 10) / 10 + " US barrels<br/>"; // US barrels output
	} 
    var output = output + "Original gravity: " + OG; // Add original gravity target
		if (OG < 1.2) {
			var output = output + " SG<br/>"; // for specific gravity
		} 
		else {
			var output = output + " &deg;P<br/>"; // for degrees Plato
		} 
	var output = output + "IBU: " + IBU + "<br/>"; // Add the overall IBUs 
	// BU/GU source: https://brucrafter.com/gravity-to-bitterness-ratio-calculator/
	var output = output + "BU/GU: " + Math.round((IBU / ((SG - 1) * 1000)) * 100) / 100 + "<br/>"; // Add bitterness units / gravity units ratio

// Determine the extract amounts. The formula is from the numerator of Holle, p. 4; 1 is for liters/kg; The OG in Plato is converted to SG units for this calculation via the PlatoToSG function. Plato is used as a decimal rather than percentage. 
    var ExtractWeight = Liters * 1 * SG * Plato/100;

// Determine the Extract contribution for each grain or sugar in the grain bill
// Malt values: name, sugar (0 = false, 1 = true), percent, lovibond, yield (coarse-grind as-is)
// 1.04621 is the extract potential of sucrose. Applies to coversion of either malt or sugar. Pierce (2006) BYO magazine
    for (i = 0; i < MaltSugar.length; i++) {
		if (MaltSugar[i][0] == "None" || MaltSugar[i][0] == "none") {
			continue; // Skip the following if the field value is none. 
		} 
		if (MaltSugar[i][4] < 1.5) {
			MaltSugar[i][4] = (((MaltSugar[i][4] * 1000) - 1000) / 46.21) * 100; // Converts SG values to percentages
		}
		if (MaltSugar[i][1] == 0) { 
			var PercentGrain = ((MaltSugar[i][4]/100) * (MashEfficiency/100)); // Figure percentage for malts, with mash efficiency
		}
        else if (MaltSugar[i][1] == 1) { 
			var PercentGrain = ((MaltSugar[i][4]/100) * 1.0); // Pecentages for sugars, with no moisture, 100% efficiency
	    }
// Formula (grain percentage * total extract weight needed) / percent of grain that can be converted to extract
	var GrainWeight = ((MaltSugar[i][2] / 100) * ExtractWeight) / PercentGrain; 
	var TotalWeight = TotalWeight + GrainWeight; // Add this present weight to the total weight

// Color calculations for malt color units 
// This calculation is done with pounds and gallons because a metric version isnt in my sources.
// MaltSugar[i][3] is the lovibond value for each grain. 
	var MCU = MCU + (kilogramsToPounds(GrainWeight) * MaltSugar[i][3]);
// Save output for each grain depending upon the desired weight units
    if (MeasureUnit == 0) { 
	var TempOutput = TempOutput + MaltSugar[i][0] + " (" + MaltSugar[i][2] + "%): " +
	    Math.round(GrainWeight*1000) / 1000 + " kg<br/>"; // Metric output
    }
	else { 
	    var TempOutput = TempOutput + MaltSugar[i][0] + " (" + MaltSugar[i][2] + "%): " +
		Math.round(kilogramsToPounds(GrainWeight) * 100) / 100 + " pounds<br/>"; // Output for US
	}
	}
// Finish color output
    var MCU = MCU / Gallons; // MCU calculations are finished by dividing by gallons
    var SRM = 1.4922 * Math.pow(MCU,.6859); // Morey equation converts Malt color units to SRM
    var output = output + "Color: " + Math.round(SRM) + " SRM<br/><br/>"; 
// Finish the grain/sugar output and start the hops output
    var output = output + "---- Malts and/or Sugars ----<br/>"; // Begin the malt section header
    var output = output + TempOutput; // Individual grain/sugar contribution    
    var output = output + "Total grain/sugar weight: "; // Weight of total grain/sugar  
    if (MeasureUnit == 0) {
		var output = output + Math.round(TotalWeight*1000)/1000 + " kg<br/><br/>"; // metric output
		} 
    else {
		var output = output + Math.round(kilogramsToPounds(TotalWeight)*100)/100 + " pounds<br/><br/>"; // US output
		} 
    var output = output + "---- Hops ----<br/>"; 
// IBU calculations
// This estimates boiling gravity and volume at different time points from target original gravity. 
// A 15% boil off rate is used assuming that homebrewers use small kettles and have high boil off rates.
// Source: https://learn.kegerator.com/how-to-calculate-water-loss-during-brewing/
// Hop array order: name, percent of IBUs, alpha acid percentage, boil time in minutes, estimated boil volume, utilization value (added from calculations), IBUs calculated from hop weights, etc. 
    for (i = 0; i < Hops.length; i++) {
		var GravityPoints = ((SG * 1000) - 1000) * Liters; // Calculate gravity points with liters
		var EstBoilVolume = Liters * (1 + ((Hops[i][3] / 4) / 100)); // Estimate volume at different boil times, 15% per 60 minutes. 60 / 4 = 15. 
		var EstBoilGravity = GravityPoints / EstBoilVolume; // Estimated boil gravity in points
		var EstBoilGravity = 1 + (EstBoilGravity / 1000); // Convert estimated gravity calculations back to SG form
		var Utilization  = (1.65 * Math.pow(0.000125, (EstBoilGravity - 1))) * ((1 - Math.exp(-.04 * Hops[i][3])) / 4.15); // Utilization; Tinseth formula
		if (Hops[i][3] < 2) {
			var Utilization = .05; // Use 5% utilization for steeping or flame out hops (not zero given by the formula).
		}
		Hops[i].push(EstBoilVolume); // Add estimated boil volume for this hop time to the hop array
		Hops[i].push(Utilization); // Adds the utilization value to the hop array
// Calculate weight needed for target IBU with a rearranged IBU formula. The AA% and utilization are expressed as decimals. 
// Simplified: Weight = (volume * IBU) / (AA% * Utilization * 1000)  Note: 1000 is for metric units - liters and grams
// The IBU*Percent (as decimal) part is for dividing up multiple hop additions. 
	var HopGrams = (Hops[i][4] * (IBU * (Hops[i][1] / 100 ))) / ((Hops[i][2] / 100) * Hops[i][5] * 1000);
// This variable is an IBU calculation check to show that inputs  = outputs. It sums IBUs for  multiple hop additions.
// Source for metric formula: https://blog.homebrewing.org/how-to-calculate-ibus/		
// Tinseth IBU = (AA% * weight * Utilization * 1000) / volume; Weight is grams and volume is liters. AA% and utilization% are in decimal form.
	var IBUtemp = ((Hops[i][2] / 100) * HopGrams * Hops[i][5] * 1000) / Hops[i][4]; // IBUs for this hop addition
	Hops[i].push(IBUtemp); // Add IBUs to the hop array
	var IBUcheck = IBUcheck + IBUtemp; // Cumulative IBUs for checking hop calculations 	
// Save output for each hop depending upon the desired weight units
        if (MeasureUnit == 0) { // Output for metric
            var output = output + Hops[i][0] + " (" + Hops[i][2] + " AA%, " + Math.round(Hops[i][6]*10)/10
			+ " IBUs, " + Hops[i][1] + "%): " + Math.round(HopGrams) + " g for " + Hops[i][3] + " minutes <br/>";
		} 
		else { // Output for US units
			var output = output + Hops[i][0] + " (" + Hops[i][2] + " AA%, " + Math.round(Hops[i][6]*10)/10
			+ " IBUs, " + Hops[i][1] + "%): " + Math.round(gramsToOunces(HopGrams)*10)/10 + " oz. for " + Hops[i][3] + " minutes <br/>";
   		} 
    }
// Dry hop additions
    for (i = 0; i < DryHops.length; i++) {
	if (DryHops[i][0] == "None" || DryHops[i][0] == "none") {
	    continue; // Skip the following if the dry hop value is none. 
	} 
	var DryHopWeight = DryHops[i][1] * Liters; // Calculate dry hops from grams per liter 
	var output = output + "Dry hop (rate: " + DryHops[i][1] + " g/l): "; // Percentage
	var output = output + DryHops[i][0] + " "; // Add the hop name to the output
	if (MeasureUnit == 0) {
	    var output = output + Math.round(DryHopWeight) + " g<br/>"; // Dry hops in grams
	}
	else {
	    var output = output + Math.round(gramsToOunces(DryHopWeight)*10)/10 + " oz.<br/>"; // Dry hops in ounces
	}
    }
// Spices or other late kettle additions
    for (i = 0; i < Spice.length; i++) {
	if (Spice[i][0] == "None" || Spice[i][0] == "none") {
	    continue; // Skip the following if the value is none. 
	} 
	var output = output + "<br/>---- Other ----<br/>"; 
	var SpiceWeight = Spice[i][1] * Liters; // Calculate weight from grams per liter 
	var output = output + "Spice (rate: " + Spice[i][1] + " g/l): "; // Percentage
	var output = output + Spice[i][0] + " "; // Add the name to the output
	if (MeasureUnit == 0) {
	    var output = output + Math.round(SpiceWeight) + " g<br/>"; // Spices in grams
	}
	else {
	    var output = output + Math.round(gramsToOunces(SpiceWeight)*10)/10 + " oz.<br/>"; // Spices in ounces
	}
    }

// Yeast pitching rate calculations
    var output = output + "<br/>--- Yeast ---<br/>"; // Add yeast output header
// Base liquid yeast pitch from White and Zainasheff, Yeast, p. 122; 
    var YeastCellsToPitch = (1 * (Liters * 1000) * Plato) / 1000; // One million cells / ml / degree plato, rounded to a billion cells
// Ale calculations, with higher pitch rates for beers over 16 plato
    if (YeastType == 0) { 
	if (Plato <= 16) {
	    var output = output + "Option 1: " + Math.round(.5 * Liters * 10) / 10 + " to " + Math.round(1.0 * Liters * 10) / 10 +
		" grams of dry ale yeast (rate: 0.5 to 1.0 g/L)<br/>";
	    var output = output + "Option 2: " + Math.round(.75 * YeastCellsToPitch) +
		" billion cells of liquid ale yeast (rate: .75 million/mL/&deg;P)";
	}
	else {
	    var output = output + "Option 1: " + Math.round(1.0 * Liters * 10) / 10 +
		" grams of dry ale yeast (rate: 1.0 g/L)<br/>";
	    var output = output + "Option 2: " + Math.round(1.0 * YeastCellsToPitch) +
		" billion cells of liquid ale yeast (rate: 1.0 million/mL/&deg;P)";
	}
    }
// Lager calculations with higher pitch rates for beers over 16 plato
    if (YeastType == 1) {
       if (Plato <= 16) {
	   var output = output + "Option 1: " + Math.round(1.0 * Liters * 10) / 10 + " to " + Math.round(2.0 * Liters * 10) / 10 +
	       " grams of dry lager yeast<br/>";
	   var output = output + "Option 2: " + Math.round(1.5 * YeastCellsToPitch) +
	       " billion cells of liquid lager yeast (rate: 1.5 million/mL/&deg;P)";
	    }
	else {
            var output = output + "Option 1: " + Math.round(2.0 * Liters * 10) / 10 + " grams of dry lager yeast<br/>"; 
            var output = output + "Option 2: " + Math.round(2.0 * YeastCellsToPitch) +
		" billion cells of liquid lager yeast (rate: 2.0 million/mL/&deg;P)";
	}
    }


// Send the output to the web page
    document.getElementById("results").innerHTML = output; 
// Outputs for debugging 
	console.log("Original gravity: ", OG);
	console.log("Mash efficiency: ", MashEfficiency);
	console.log("Volume: ", Volume);
	console.log("Liters: ",Liters);
	console.log("Gallons: ",Gallons);
	console.log("IBU: ", IBU);
	console.log("Plato: ", Plato);
	console.log("SG: ", SG);
	console.log("TempForm: ", TempForm);
	console.log("TempArray: ", TempArray);
    console.log("MaltSugar array: ",MaltSugar);
    console.log("Hops: ",Hops);
	console.log("Spice array: ",Spice);
    console.log("Dry Hops: ",DryHops);
	console.log("YeastType: ",YeastType);
	console.log("Measure unit: ",MeasureUnit);
    console.log("IBUcheck for inputs = outputs: ",IBUcheck);
	console.log("GrainWeight: ",GrainWeight);
    console.log("MaltCheck (should add to 100%): ",MaltCheck);
    console.log("HopCheck (should add to 100%): ",HopCheck);

// IBU estimated boiling gravity and boiling volume was improved and verified.
// To do: Add to hops array
}