Commit 0c2a1f0e authored by Meade's avatar Meade

Added version 3.0.0. New grain calculator, accuracy fixes, graphical updates.

parent e232137f
# Maintainer: Meade And Emily <thedarkula2049@gmail.com> # Maintainer: Meade And Emily <thedarkula2049@gmail.com>
pkgname=brewstillery pkgname=brewstillery
pkgver=2.0.1 pkgver=3.0.0
pkgrel=1 pkgrel=1
pkgdesc="BrewStillery is a brewer's, vintner's, and distiller's calculator. It has a multitude of great functions, such as calculating ABV, determining carbonation, and total sparge water needed." pkgdesc="BrewStillery is a brewer's, vintner's, and distiller's calculator. It has a multitude of great functions, such as calculating ABV, determining carbonation, and total sparge water needed."
url="https://monkeylog.in" url="https://monkeylog.in"
...@@ -9,20 +9,20 @@ license=('AGPL3') ...@@ -9,20 +9,20 @@ license=('AGPL3')
makedepends=('git' 'cargo') makedepends=('git' 'cargo')
provides=('brewstillery') provides=('brewstillery')
conflicts=('brewstillery') conflicts=('brewstillery')
source=('git://github.com/MonkeyLog/BrewStillery') source=("https://github.com/MonkeyLog/BrewStillery/archive/$pkgver.tar.gz")
md5sums=('SKIP') md5sums=('SKIP')
build() { build() {
cd BrewStillery cd $srcdir/BrewStillery-$pkgver
cargo build --release cargo build --release
} }
package() { package() {
cd $srcdir/BrewStillery/target/release cd $srcdir/BrewStillery-$pkgver/target/release
install -Dm755 BrewStillery "$pkgdir/usr/bin/BrewStillery" install -Dm755 BrewStillery "$pkgdir/usr/bin/BrewStillery"
cd $srcdir/BrewStillery/Arch cd $srcdir/BrewStillery-$pkgver/Arch
install -Dm755 BrewStillery.desktop "$pkgdir/usr/share/applications/BrewStillery.desktop" install -Dm755 BrewStillery.desktop "$pkgdir/usr/share/applications/BrewStillery.desktop"
cd $srcdir/BrewStillery/media cd $srcdir/BrewStillery-$pkgver/media
install -Dm755 BrewStilleryIcon.svg "$pkgdir/usr/share/BrewStillery/BrewStilleryIcon.svg" install -Dm755 BrewStilleryIcon.svg "$pkgdir/usr/share/BrewStillery/BrewStilleryIcon.svg"
install -Dm755 BrewStilleryLogo.svg "$pkgdir/usr/share/BrewStillery/BrewStilleryLogo.svg" install -Dm755 BrewStilleryLogo.svg "$pkgdir/usr/share/BrewStillery/BrewStilleryLogo.svg"
} }
\ No newline at end of file
[root] [root]
name = "BrewStillery" name = "BrewStillery"
version = "2.0.0" version = "3.0.0"
dependencies = [ dependencies = [
"gtk 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gtk 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
......
[package] [package]
name = "BrewStillery" name = "BrewStillery"
version = "2.0.1" version = "3.0.0"
authors = ["Emily And Meade <thedarkula2049@gmail.com>"] authors = ["Emily And Meade <thedarkula2049@gmail.com>"]
description = "BrewStillery is a brewer's, vintner's, and distiller's calculator. It has a multitude of great functions, such as calculating ABV, determining carbonation, and total sparge water needed." description = "BrewStillery is a brewer's, vintner's, and distiller's calculator. It has a multitude of great functions, such as calculating ABV, determining carbonation, and total sparge water needed."
# documentation to come # documentation to come
......
...@@ -4,22 +4,27 @@ It has a multitude of great functions, such as calculating ABV, determining carb ...@@ -4,22 +4,27 @@ It has a multitude of great functions, such as calculating ABV, determining carb
Written in Rust, using GTK3 Written in Rust, using GTK3
## New In 2.0.0 ## New In 3.0.0
Added the IBU calculator to the beer tab. Added the grain calculator to the beer tab.
Reworked the maths in the RealABV calculator, because it was completely inaccurate.
Reworked the graphical layout as well.
## Screenshots: ## Screenshots:
![General Tab Screenshot](media/screenshots/BrewStilleryGeneralTab.png) ![General Tab Screenshot](media/screenshots/BrewStilleryGeneralTab.png)
![Beer Tab Screenshot](media/screenshots/BrewStilleryBeerTab.png) ![Beer Top Tab Screenshot](media/screenshots/BrewStilleryBeerTopTab.png)
![Beer Tab IBU Screenshot](media/screenshots/BrewStilleryBeerIBU.png) ![Beer Bottom Tab Screenshot](media/screenshots/BrewStilleryBeerBottomTab.png)
![Champagne Tab Screenshot](media/screenshots/BrewStilleryChampagneTab.png) ![Champagne Tab Screenshot](media/screenshots/BrewStilleryChampagneTab.png)
![About Tab Screenshot](media/screenshots/BrewStilleryABoutTab.png)
## To Do: ## To Do:
* Grain * Water Minerals
* Export To Gourmet
## Building: ## Building:
...@@ -41,4 +46,6 @@ Added the IBU calculator to the beer tab. ...@@ -41,4 +46,6 @@ Added the IBU calculator to the beer tab.
## Sources: ## Sources:
* ["Brew By Numbers - Add Up What's In Your Beer"](https://www.homebrewersassociation.org/attachments/0000/2497/Math_in_Mash_SummerZym95.pdf) - Michael L. Hall. PH.D., Zymurgy (Summer) 1995 * ["Brew By Numbers - Add Up What's In Your Beer"](https://www.homebrewersassociation.org/attachments/0000/2497/Math_in_Mash_SummerZym95.pdf) - Michael L. Hall. PH.D., Zymurgy (Summer) 1995
* ["Kraeusening"](http://www.braukaiser.com/wiki/index.php?title=Kraeusening) - Braukaiser.com, Modified: January 2, 2010 * ["Kraeusening"](http://www.braukaiser.com/wiki/index.php?title=Kraeusening) - Braukaiser.com, Modified: January 2, 2010
* ["Glenn Tinseth's Hop Page"](http://realbeer.com/hops/) - Glenn Tinseth, 1995-1999 * ["Glenn Tinseth's Hop Page"](http://realbeer.com/hops/) - Glenn Tinseth, 1995-1999
\ No newline at end of file * ["Calculating Gravity, Bitterness, And Color: Techniques"](https://byo.com/bock/item/409-calculating-gravity-bitterness-and-color-techniques) - Glenn Tinseth, 1995-1999
* ["Formulas And C Source Code"](https://web.archive.org/web/20090807084643/http://www.primetab.com:80/formulas) - PrimeTab, Modified: March 25, 2002
\ No newline at end of file
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -24,7 +22,7 @@ pub fn champagneCarbonationPrep(ref champagneCarbonationBuilderClone: &gtk::Buil ...@@ -24,7 +22,7 @@ pub fn champagneCarbonationPrep(ref champagneCarbonationBuilderClone: &gtk::Buil
} }
} }
pub fn onChampagneActivate(champagneVolume: f32, ref champagneCarbonationBuilderClone: &gtk::Builder) { fn onChampagneActivate(champagneVolume: f32, ref champagneCarbonationBuilderClone: &gtk::Builder) {
let ref champagneCarbonationSwitch: &gtk::Switch = &champagneCarbonationBuilderClone.get_object("champagneCarbonationSwitch").unwrap(); let ref champagneCarbonationSwitch: &gtk::Switch = &champagneCarbonationBuilderClone.get_object("champagneCarbonationSwitch").unwrap();
if champagneCarbonationSwitch.get_active() == true { if champagneCarbonationSwitch.get_active() == true {
......
#![allow(non_snake_case)]
use std::f32::consts::E; use std::f32::consts::E;
pub fn brixToGravity(brix: f32) -> f32 { pub fn brixToGravity(brix: f32) -> f32 {
(brix / (258.6 - ((brix / 258.2) * 227.1))) + 1.0 (brix / (258.6 - ((brix / 258.2) * 227.1))) + 1.0
} }
pub fn gravityToBrix(gravity: f32) -> f32 {
((258.6 * gravity) - 258.6) / ((0.87955073 * gravity) + 0.12044926)
}
pub fn gravityToPlato(gravity: f32) -> f32 { pub fn gravityToPlato(gravity: f32) -> f32 {
135.997 * gravity.powi(3) - 630.272 * gravity.powi(2) + 1111.14 * gravity - 616.868 135.997 * gravity.powi(3) - 630.272 * gravity.powi(2) + 1111.14 * gravity - 616.868
} }
...@@ -13,19 +16,86 @@ pub fn gramsToOunces(grams: f32) -> f32 { ...@@ -13,19 +16,86 @@ pub fn gramsToOunces(grams: f32) -> f32 {
0.03527396_f32 * grams 0.03527396_f32 * grams
} }
pub fn kilosToPounds(kilos: f32) -> f32 {
2.204623_f32 * kilos
}
pub fn litresToGallons(litres: f32) -> f32 { pub fn litresToGallons(litres: f32) -> f32 {
0.2641729_f32 * litres 0.2641729_f32 * litres
} }
pub fn validInput(stringToCheck: &String) -> f32 { pub fn validInput(stringToCheck: &String) -> f32 {
let isANumber = stringToCheck.parse::<f32>().is_ok(); let stringInput = stringToCheck.parse::<f32>();
if isANumber == true { match stringInput {
stringToCheck.parse().unwrap() Ok(number) => number,
} else { Err(_) => 0.0,
0.0
} }
} }
pub fn realIBU(brix: f32, wortVolume: f32, boilTime: f32, alphaAcid: f32, hopAmount: f32) -> f32 { pub fn realIBU(brix: f32, wortVolume: f32, boilTime: f32, alphaAcid: f32, hopAmount: f32) -> f32 {
(1.65 * 0.000125_f32.powf(brixToGravity(brix) - 1.0)) * ((1.0 - E.powf(-0.04 * boilTime)) / 4.15) * (( (alphaAcid / 100.0) * hopAmount * 7490.0 ) / wortVolume) (1.65 * 0.000125_f32.powf(brixToGravity(brix) - 1.0)) * ((1.0 - E.powf(-0.04 * boilTime)) / 4.15) * (( (alphaAcid / 100.0) * hopAmount * 7490.0 ) / wortVolume)
}
pub fn guestimateABV(originalGravity: f32) -> f32 {
let finalGravity: f32 = 1.010;
// since finalGravity is unknown, this constant is ideal
let originalExtract = (-668.962) + (1262.45 * originalGravity ) - (776.43 * originalGravity.powi(2)) + (182.94 * originalGravity.powi(3));
let apparentExtract = (-668.962) + (1262.45 * finalGravity ) - (776.43 * finalGravity.powi(2)) + (182.94 * finalGravity.powi(3));
let attenuationCoefficient = (0.22) + (0.001 * originalExtract);
let realExtract = ((attenuationCoefficient * originalExtract) + apparentExtract) / (1.0 + attenuationCoefficient);
// unneeded information, but here if we want it
//
// let realAttenuation = ((originalExtract - realExtract) / originalExtract) * 100.0;
// let realAttenuationRounded = format!("{:.2}", realAttenuation);
// println!("Your Real Attenuation is: {}", realAttenuationRounded);
let estimatedABW = (originalExtract - realExtract) / ( 2.0665 - (0.010665 * originalExtract));
let estimatedABV = estimatedABW * (finalGravity / 0.794);
estimatedABV
}
pub fn grainToABV(volumeInGallons: f32, weightInPounds: f32, grainGravity: f32) -> f32 {
let extractPotential = grainGravity % 1.0 * 1000.0;
let extractionEfficiency = 0.57;
// sane default here of 57%
let specificGravityPoints = (weightInPounds * extractPotential * extractionEfficiency) / volumeInGallons;
if specificGravityPoints == 0.0 {
let originalGravity = 1.0;
// set to the gravity of water
originalGravity
} else {
let originalGravity = specificGravityPoints / 1000.0 + 1.0;
originalGravity
}
}
pub fn grainInfo(grainType: &String) -> f32 {
match grainType.as_ref() {
"2-Row PG" => 1.037,
"2-Row LVB" => 1.8,
"6-Row PG" => 1.035,
"6-Row LVB" => 1.8,
"Black PG" => 1.025,
"Black LVB" => 500.0,
"Caramel PG" => 1.034,
"Caramel 60 LVB" => 60.0,
"Caramel 80 LVB" => 80.0,
"Caramel 120 LVB" => 120.0,
"Chocolate PG" => 1.034,
"Chocolate LVB" => 350.0,
"Corn PG" => 1.037,
"Corn LVB" => 1.3,
"Dextrine PG" => 1.033,
"Dextrine LVB" => 1.5,
"Oat PG" => 1.034,
"Oat LVB" => 1.0,
"Rice PG" => 1.032,
"Rice LVB" => 1.0,
"Rye PG" => 1.036,
"Rye LVB" => 2.0,
"Wheat PG" => 1.036,
"Wheat LVB" => 1.6,
_ => 0.0,
}
} }
\ No newline at end of file
use gtk;
use gtk::prelude::*;
use functions::commonFunctions::*;
pub fn grainABVPrep(ref grainABVBuilderClone: &gtk::Builder) {
let grainABVWortInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVWortInput").unwrap();
let grainABVWortInputBuffer = grainABVWortInput.get_text().expect("No input");
let grainABVWortInputBufferFloat = validInput(&grainABVWortInputBuffer);
let grainABVFirstAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVFirstAmountInput").unwrap();
let grainABVFirstAmountInputBuffer = grainABVFirstAmountInput.get_text().expect("No input");
let grainABVFirstAmountInputBufferFloat = validInput(&grainABVFirstAmountInputBuffer);
let grainABVFirstTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVFirstTypeInput").unwrap();
let grainABVFirstTypeInputBuffer = grainABVFirstTypeInput.get_active_id().unwrap();
let grainABVFirstTypeInputBufferFloat = grainInfo(&grainABVFirstTypeInputBuffer);
let grainABVSecondAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVSecondAmountInput").unwrap();
let grainABVSecondAmountInputBuffer = grainABVSecondAmountInput.get_text().expect("No input");
let grainABVSecondAmountInputBufferFloat = validInput(&grainABVSecondAmountInputBuffer);
let grainABVSecondTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVSecondTypeInput").unwrap();
let grainABVSecondTypeInputBuffer = grainABVSecondTypeInput.get_active_id().unwrap();
let grainABVSecondTypeInputBufferFloat = grainInfo(&grainABVSecondTypeInputBuffer);
let grainABVThirdAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVThirdAmountInput").unwrap();
let grainABVThirdAmountInputBuffer = grainABVThirdAmountInput.get_text().expect("No input");
let grainABVThirdAmountInputBufferFloat = validInput(&grainABVThirdAmountInputBuffer);
let grainABVThirdTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVThirdTypeInput").unwrap();
let grainABVThirdTypeInputBuffer = grainABVThirdTypeInput.get_active_id().unwrap();
let grainABVThirdTypeInputBufferFloat = grainInfo(&grainABVThirdTypeInputBuffer);
let grainABVFourthAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVFourthAmountInput").unwrap();
let grainABVFourthAmountInputBuffer = grainABVFourthAmountInput.get_text().expect("No input");
let grainABVFourthAmountInputBufferFloat = validInput(&grainABVFourthAmountInputBuffer);
let grainABVFourthTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVFourthTypeInput").unwrap();
let grainABVFourthTypeInputBuffer = grainABVFourthTypeInput.get_active_id().unwrap();
let grainABVFourthTypeInputBufferFloat = grainInfo(&grainABVFourthTypeInputBuffer);
let grainABVFifthAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVFifthAmountInput").unwrap();
let grainABVFifthAmountInputBuffer = grainABVFifthAmountInput.get_text().expect("No input");
let grainABVFifthAmountInputBufferFloat = validInput(&grainABVFifthAmountInputBuffer);
let grainABVFifthTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVFifthTypeInput").unwrap();
let grainABVFifthTypeInputBuffer = grainABVFifthTypeInput.get_active_id().unwrap();
let grainABVFifthTypeInputBufferFloat = grainInfo(&grainABVFifthTypeInputBuffer);
let grainABVSixthAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVSixthAmountInput").unwrap();
let grainABVSixthAmountInputBuffer = grainABVSixthAmountInput.get_text().expect("No input");
let grainABVSixthAmountInputBufferFloat = validInput(&grainABVSixthAmountInputBuffer);
let grainABVSixthTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVSixthTypeInput").unwrap();
let grainABVSixthTypeInputBuffer = grainABVSixthTypeInput.get_active_id().unwrap();
let grainABVSixthTypeInputBufferFloat = grainInfo(&grainABVSixthTypeInputBuffer);
let grainABVSeventhAmountInput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVSeventhAmountInput").unwrap();
let grainABVSeventhAmountInputBuffer = grainABVSeventhAmountInput.get_text().expect("No input");
let grainABVSeventhAmountInputBufferFloat = validInput(&grainABVSeventhAmountInputBuffer);
let grainABVSeventhTypeInput: &gtk::ComboBoxText = &grainABVBuilderClone.get_object("grainABVSeventhTypeInput").unwrap();
let grainABVSeventhTypeInputBuffer = grainABVSeventhTypeInput.get_active_id().unwrap();
let grainABVSeventhTypeInputBufferFloat = grainInfo(&grainABVSeventhTypeInputBuffer);
let grainABVBrixOutput = String::from("grainABVBrixOutput");
if grainABVWortInputBufferFloat == 0.0 {
let output: gtk::Entry = grainABVBuilderClone.get_object(&grainABVBrixOutput).unwrap();
output.set_text("Enter at least the first two inputs");
} else if grainABVFirstAmountInputBufferFloat == 0.0 {
let output: gtk::Entry = grainABVBuilderClone.get_object(&grainABVBrixOutput).unwrap();
output.set_text("Enter at least one grain amount");
} else {
if grainABVWortInputBufferFloat <= 0.0 {
let output: gtk::Entry = grainABVBuilderClone.get_object(&grainABVBrixOutput).unwrap();
output.set_text("Enter a positive number");
} else if grainABVFirstAmountInputBufferFloat <= 0.0 {
let output: gtk::Entry = grainABVBuilderClone.get_object(&grainABVBrixOutput).unwrap();
output.set_text("Enter a positive number");
} else {
onGrainABVActivate(grainABVWortInputBufferFloat, grainABVFirstAmountInputBufferFloat, grainABVFirstTypeInputBufferFloat, grainABVSecondAmountInputBufferFloat, grainABVSecondTypeInputBufferFloat, grainABVThirdAmountInputBufferFloat, grainABVThirdTypeInputBufferFloat, grainABVFourthAmountInputBufferFloat, grainABVFourthTypeInputBufferFloat, grainABVFifthAmountInputBufferFloat, grainABVFifthTypeInputBufferFloat, grainABVSixthAmountInputBufferFloat, grainABVSixthTypeInputBufferFloat, grainABVSeventhAmountInputBufferFloat, grainABVSeventhTypeInputBufferFloat, &grainABVBuilderClone);
}
}
}
fn onGrainABVActivate(grainABVWortInputBufferFloat: f32, grainABVFirstAmountInputBufferFloat: f32, grainABVFirstTypeInputBufferFloat: f32, grainABVSecondAmountInputBufferFloat: f32, grainABVSecondTypeInputBufferFloat: f32, grainABVThirdAmountInputBufferFloat: f32, grainABVThirdTypeInputBufferFloat: f32, grainABVFourthAmountInputBufferFloat: f32, grainABVFourthTypeInputBufferFloat: f32, grainABVFifthAmountInputBufferFloat: f32, grainABVFifthTypeInputBufferFloat: f32, grainABVSixthAmountInputBufferFloat: f32, grainABVSixthTypeInputBufferFloat: f32, grainABVSeventhAmountInputBufferFloat: f32, grainABVSeventhTypeInputBufferFloat: f32, ref grainABVBuilderClone: &gtk::Builder) {
let ref grainABVSwitch: &gtk::Switch = &grainABVBuilderClone.get_object("grainABVSwitch").unwrap();
if grainABVSwitch.get_active() == true {
let imperialOrMetric = String::from("metric");
grainABVMaths(grainABVWortInputBufferFloat, grainABVFirstAmountInputBufferFloat, grainABVFirstTypeInputBufferFloat, grainABVSecondAmountInputBufferFloat, grainABVSecondTypeInputBufferFloat, grainABVThirdAmountInputBufferFloat, grainABVThirdTypeInputBufferFloat, grainABVFourthAmountInputBufferFloat, grainABVFourthTypeInputBufferFloat, grainABVFifthAmountInputBufferFloat, grainABVFifthTypeInputBufferFloat, grainABVSixthAmountInputBufferFloat, grainABVSixthTypeInputBufferFloat, grainABVSeventhAmountInputBufferFloat, grainABVSeventhTypeInputBufferFloat, imperialOrMetric, &grainABVBuilderClone);
} else if grainABVSwitch.get_active() == false {
let imperialOrMetric = String::from("imperial");
grainABVMaths(grainABVWortInputBufferFloat, grainABVFirstAmountInputBufferFloat, grainABVFirstTypeInputBufferFloat, grainABVSecondAmountInputBufferFloat, grainABVSecondTypeInputBufferFloat, grainABVThirdAmountInputBufferFloat, grainABVThirdTypeInputBufferFloat, grainABVFourthAmountInputBufferFloat, grainABVFourthTypeInputBufferFloat, grainABVFifthAmountInputBufferFloat, grainABVFifthTypeInputBufferFloat, grainABVSixthAmountInputBufferFloat, grainABVSixthTypeInputBufferFloat, grainABVSeventhAmountInputBufferFloat, grainABVSeventhTypeInputBufferFloat, imperialOrMetric, &grainABVBuilderClone);
}
}
fn grainABVMaths(grainABVWortInputBufferFloat: f32, grainABVFirstAmountInputBufferFloat: f32, grainABVFirstTypeInputBuffer: f32, grainABVSecondAmountInputBufferFloat: f32, grainABVSecondTypeInputBuffer: f32, grainABVThirdAmountInputBufferFloat: f32, grainABVThirdTypeInputBuffer: f32, grainABVFourthAmountInputBufferFloat: f32, grainABVFourthTypeInputBuffer: f32, grainABVFifthAmountInputBufferFloat: f32, grainABVFifthTypeInputBuffer: f32, grainABVSixthAmountInputBufferFloat: f32, grainABVSixthTypeInputBuffer: f32, grainABVSeventhAmountInputBufferFloat: f32, grainABVSeventhTypeInputBuffer: f32, imperialOrMetric: String, ref grainABVBuilderClone: &gtk::Builder) {
let ref grainABVBrixOutput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVBrixOutput").unwrap();
let ref grainABVABVOutput: &gtk::Entry = &grainABVBuilderClone.get_object("grainABVABVOutput").unwrap();
if imperialOrMetric == "imperial" {
let totalGrain1 = grainToABV(grainABVWortInputBufferFloat, grainABVFirstAmountInputBufferFloat, grainABVFirstTypeInputBuffer);
let totalGrain2 = grainToABV(grainABVWortInputBufferFloat, grainABVSecondAmountInputBufferFloat, grainABVSecondTypeInputBuffer);
let totalGrain3 = grainToABV(grainABVWortInputBufferFloat, grainABVThirdAmountInputBufferFloat, grainABVThirdTypeInputBuffer);
let totalGrain4 = grainToABV(grainABVWortInputBufferFloat, grainABVFourthAmountInputBufferFloat, grainABVFourthTypeInputBuffer);
let totalGrain5 = grainToABV(grainABVWortInputBufferFloat, grainABVFifthAmountInputBufferFloat, grainABVFifthTypeInputBuffer);
let totalGrain6 = grainToABV(grainABVWortInputBufferFloat, grainABVSixthAmountInputBufferFloat, grainABVSixthTypeInputBuffer);
let totalGrain7 = grainToABV(grainABVWortInputBufferFloat, grainABVSeventhAmountInputBufferFloat, grainABVSeventhTypeInputBuffer);
let estimatedBrix = format!("{:.2}°Bx", gravityToBrix(1.0 + &totalGrain1 % 1.0 + &totalGrain2 % 1.0 + &totalGrain3 % 1.0 + &totalGrain4 % 1.0 + &totalGrain5 % 1.0 + &totalGrain6 % 1.0 + &totalGrain7 % 1.0));
let abv = format!("{:.2}%", guestimateABV(1.0 + &totalGrain1 % 1.0 + &totalGrain2 % 1.0 + &totalGrain3 % 1.0 + &totalGrain4 % 1.0 + &totalGrain5 % 1.0 + &totalGrain6 % 1.0 + &totalGrain7 % 1.0));
grainABVBrixOutput.set_text(&estimatedBrix);
grainABVABVOutput.set_text(&abv);
} else if imperialOrMetric == "metric" {
let totalGrain1 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVFirstAmountInputBufferFloat), grainABVFirstTypeInputBuffer);
let totalGrain2 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVSecondAmountInputBufferFloat), grainABVSecondTypeInputBuffer);
let totalGrain3 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVThirdAmountInputBufferFloat), grainABVThirdTypeInputBuffer);
let totalGrain4 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVFourthAmountInputBufferFloat), grainABVFourthTypeInputBuffer);
let totalGrain5 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVFifthAmountInputBufferFloat), grainABVFifthTypeInputBuffer);
let totalGrain6 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVSixthAmountInputBufferFloat), grainABVSixthTypeInputBuffer);
let totalGrain7 = grainToABV(litresToGallons(grainABVWortInputBufferFloat), kilosToPounds(grainABVSeventhAmountInputBufferFloat), grainABVSeventhTypeInputBuffer);
let estimatedBrix = format!("{:.2}°Bx", gravityToBrix(1.0 + &totalGrain1 % 1.0 + &totalGrain2 % 1.0 + &totalGrain3 % 1.0 + &totalGrain4 % 1.0 + &totalGrain5 % 1.0 + &totalGrain6 % 1.0 + &totalGrain7 % 1.0));
let abv = format!("{:.2}%", guestimateABV(1.0 + &totalGrain1 % 1.0 + &totalGrain2 % 1.0 + &totalGrain3 % 1.0 + &totalGrain4 % 1.0 + &totalGrain5 % 1.0 + &totalGrain6 % 1.0 + &totalGrain7 % 1.0));
grainABVBrixOutput.set_text(&estimatedBrix);
grainABVABVOutput.set_text(&abv);
}
}
\ No newline at end of file
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -8,16 +6,16 @@ pub fn guestimatePrep(ref guestimatorBuilderClone: &gtk::Builder) { ...@@ -8,16 +6,16 @@ pub fn guestimatePrep(ref guestimatorBuilderClone: &gtk::Builder) {
let guestimatorInput: &gtk::Entry = &guestimatorBuilderClone.get_object("guestimatorInput").unwrap(); let guestimatorInput: &gtk::Entry = &guestimatorBuilderClone.get_object("guestimatorInput").unwrap();
let guestimatorInput = guestimatorInput.get_text().expect("No input"); let guestimatorInput = guestimatorInput.get_text().expect("No input");
let startingBrix = validInput(&guestimatorInput); let startingBrix = validInput(&guestimatorInput);
let guestimatorOutput = String::from("guestimatorOutput"); let guestimatorOutput = String::from("guestimatorOutput");
if startingBrix == 0.0 { if startingBrix == 0.0 {
let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap(); let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap();
output.set_text("Enter a number"); output.set_text("Enter a number");
} else { } else {
if startingBrix < 3.83 { if startingBrix < 2.57 {
let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap(); let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap();
output.set_text("Enter a number greater than 3.83"); output.set_text("Enter a number greater than 2.57");
} else if startingBrix > 49.48 { } else if startingBrix > 49.48 {
let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap(); let output: gtk::Entry = guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap();
output.set_text("Enter a number less than 49.48"); output.set_text("Enter a number less than 49.48");
...@@ -27,24 +25,8 @@ pub fn guestimatePrep(ref guestimatorBuilderClone: &gtk::Builder) { ...@@ -27,24 +25,8 @@ pub fn guestimatePrep(ref guestimatorBuilderClone: &gtk::Builder) {
} }
} }
pub fn guestiMaths(startingBrix: f32, guestimatorOutput: String, ref guestimatorBuilderClone: &gtk::Builder) { fn guestiMaths(startingBrix: f32, guestimatorOutput: String, ref guestimatorBuilderClone: &gtk::Builder) {
let originalGravity = brixToGravity(startingBrix); let abv = format!("{:.2}%", guestimateABV(brixToGravity(startingBrix)));
let finalGravity: f32 = 1.015;
// since finalGravity is unknown, this constant is ideal
let originalExtract = (-668.962) + (1262.45 * originalGravity ) - (776.43 * originalGravity.powi(2)) + (182.94 * originalGravity.powi(3));
let apparentExtract = (-668.962) + (1262.45 * finalGravity ) - (776.43 * finalGravity.powi(2)) + (182.94 * finalGravity.powi(3));
let attenuationCoefficient = (0.22) + (0.001 * originalExtract);
let realExtract = ((attenuationCoefficient * originalExtract) + apparentExtract) / (1.0 + attenuationCoefficient);
// unneeded information, but here if we want it
//
// let realAttenuation = ((originalExtract - realExtract) / originalExtract) * 100.0;
// let realAttenuationRounded = format!("{:.2}", realAttenuation);
// println!("Your Real Attenuation is: {}", realAttenuationRounded);
let estimatedABW = (originalExtract - realExtract) / ( 2.0665 - (0.010665 * originalExtract));
let estimatedABV = estimatedABW * (finalGravity / 0.794);
let abv = format!("{:.2}%", estimatedABV);
let ref output: &gtk::Entry = &guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap(); let ref output: &gtk::Entry = &guestimatorBuilderClone.get_object(&guestimatorOutput).unwrap();
output.set_text(&abv.to_string()); output.set_text(&abv.to_string());
} }
\ No newline at end of file
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -75,19 +73,19 @@ pub fn guestimateIBUPrep(ref IBUBuilderClone: &gtk::Builder) { ...@@ -75,19 +73,19 @@ pub fn guestimateIBUPrep(ref IBUBuilderClone: &gtk::Builder) {
let totalIBUOutput = String::from("totalIBUOutput"); let totalIBUOutput = String::from("totalIBUOutput");
if validInput(&totalIBUPreBoilBrixInputBuffer) == 0.0 { if totalIBUPreBoilBrixInputBufferFloat == 0.0 {
let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap(); let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap();
output.set_text("Enter at least the first five inputs"); output.set_text("Enter at least the first five inputs");
} else if validInput(&totalIBUWortVolumeInputBuffer) == 0.0 { } else if totalIBUWortVolumeInputBufferFloat == 0.0 {
let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap(); let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap();
output.set_text("Enter at least the first five inputs"); output.set_text("Enter at least the first five inputs");
} else if validInput(&totalIBUBoilTimeInputBuffer) == 0.0 { } else if totalIBUBoilTimeInputBufferFloat == 0.0 {
let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap(); let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap();
output.set_text("Enter at least the first five inputs"); output.set_text("Enter at least the first five inputs");
} else if validInput(&totalIBUFirstHopAlphaInputBuffer) == 0.0 { } else if totalIBUFirstHopAlphaInputBufferFloat == 0.0 {
let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap(); let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap();
output.set_text("Enter at least the first five inputs"); output.set_text("Enter at least the first five inputs");
} else if validInput(&totalIBUFirstHopAmountInputBuffer) == 0.0 { } else if totalIBUFirstHopAmountInputBufferFloat == 0.0 {
let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap(); let output: gtk::Entry = IBUBuilderClone.get_object(&totalIBUOutput).unwrap();
output.set_text("Enter at least the first five inputs"); output.set_text("Enter at least the first five inputs");
} else { } else {
...@@ -112,7 +110,7 @@ pub fn guestimateIBUPrep(ref IBUBuilderClone: &gtk::Builder) { ...@@ -112,7 +110,7 @@ pub fn guestimateIBUPrep(ref IBUBuilderClone: &gtk::Builder) {
} }
} }
pub fn onIBUActivate(totalIBUPreBoilBrixInputBufferFloat: f32, totalIBUWortVolumeInputBufferFloat: f32, totalIBUBoilTimeInputBufferFloat: f32, totalIBUFirstHopAlphaInputBufferFloat: f32, totalIBUFirstHopAmountInputBufferFloat: f32, totalIBUSecondHopAlphaInputBufferFloat: f32, totalIBUSecondHopAmountInputBufferFloat: f32, totalIBUThirdHopAlphaInputBufferFloat: f32, totalIBUThirdHopAmountInputBufferFloat: f32, totalIBUFourthHopAlphaInputBufferFloat: f32, totalIBUFourthHopAmountInputBufferFloat: f32, totalIBUFifthHopAlphaInputBufferFloat: f32, totalIBUFifthHopAmountInputBufferFloat: f32, totalIBUSixthHopAlphaInputBufferFloat: f32, totalIBUSixthHopAmountInputBufferFloat: f32, totalIBUSeventhHopAlphaInputBufferFloat: f32, totalIBUSeventhHopAmountInputBufferFloat: f32, ref IBUBuilderClone: &gtk::Builder) { fn onIBUActivate(totalIBUPreBoilBrixInputBufferFloat: f32, totalIBUWortVolumeInputBufferFloat: f32, totalIBUBoilTimeInputBufferFloat: f32, totalIBUFirstHopAlphaInputBufferFloat: f32, totalIBUFirstHopAmountInputBufferFloat: f32, totalIBUSecondHopAlphaInputBufferFloat: f32, totalIBUSecondHopAmountInputBufferFloat: f32, totalIBUThirdHopAlphaInputBufferFloat: f32, totalIBUThirdHopAmountInputBufferFloat: f32, totalIBUFourthHopAlphaInputBufferFloat: f32, totalIBUFourthHopAmountInputBufferFloat: f32, totalIBUFifthHopAlphaInputBufferFloat: f32, totalIBUFifthHopAmountInputBufferFloat: f32, totalIBUSixthHopAlphaInputBufferFloat: f32, totalIBUSixthHopAmountInputBufferFloat: f32, totalIBUSeventhHopAlphaInputBufferFloat: f32, totalIBUSeventhHopAmountInputBufferFloat: f32, ref IBUBuilderClone: &gtk::Builder) {
let ref totalIBUSwitch: &gtk::Switch = &IBUBuilderClone.get_object("totalIBUSwitch").unwrap(); let ref totalIBUSwitch: &gtk::Switch = &IBUBuilderClone.get_object("totalIBUSwitch").unwrap();
if totalIBUSwitch.get_active() == true { if totalIBUSwitch.get_active() == true {
......
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -44,7 +42,7 @@ pub fn gyleCarbonationPrep(ref gyleBuilderClone: &gtk::Builder) { ...@@ -44,7 +42,7 @@ pub fn gyleCarbonationPrep(ref gyleBuilderClone: &gtk::Builder) {
} }
} }
pub fn onGyleActivate(startingBrix: f32, desiredCO2Level: f32, finalVolume: f32, ref gyleBuilderClone: &gtk::Builder) { fn onGyleActivate(startingBrix: f32, desiredCO2Level: f32, finalVolume: f32, ref gyleBuilderClone: &gtk::Builder) {
let ref gyleCarbonationSwitch: &gtk::Switch = &gyleBuilderClone.get_object("gyleCarbonationSwitch").unwrap(); let ref gyleCarbonationSwitch: &gtk::Switch = &gyleBuilderClone.get_object("gyleCarbonationSwitch").unwrap();
if gyleCarbonationSwitch.get_active() == true { if gyleCarbonationSwitch.get_active() == true {
......
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -44,7 +42,7 @@ pub fn increaseABVPrep(ref increaseABVBuilderClone: &gtk::Builder) { ...@@ -44,7 +42,7 @@ pub fn increaseABVPrep(ref increaseABVBuilderClone: &gtk::Builder) {
} }
} }
pub fn onIncreaseActivate(startingBrix: f32, desiredABV: f32, desiredWortVolume: f32, ref increaseABVBuilderClone: &gtk::Builder) { fn onIncreaseActivate(startingBrix: f32, desiredABV: f32, desiredWortVolume: f32, ref increaseABVBuilderClone: &gtk::Builder) {
let ref increaseABVSwitch: &gtk::Switch = &increaseABVBuilderClone.get_object("increaseABVSwitch").unwrap(); let ref increaseABVSwitch: &gtk::Switch = &increaseABVBuilderClone.get_object("increaseABVSwitch").unwrap();
if increaseABVSwitch.get_active() == true { if increaseABVSwitch.get_active() == true {
......
...@@ -5,4 +5,5 @@ pub mod waterSparge; ...@@ -5,4 +5,5 @@ pub mod waterSparge;
pub mod gyleCarbonation; pub mod gyleCarbonation;
pub mod guestimateIBU; pub mod guestimateIBU;
pub mod champagneCarbonation; pub mod champagneCarbonation;
pub mod commonFunctions; pub mod commonFunctions;
\ No newline at end of file pub mod grainToABV;
\ No newline at end of file
#![allow(non_snake_case)]
use gtk; use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use functions::commonFunctions::*; use functions::commonFunctions::*;
...@@ -13,23 +11,23 @@ pub fn realABVPrep(ref realABVBuilderClone: &gtk::Builder) { ...@@ -13,23 +11,23 @@ pub fn realABVPrep(ref realABVBuilderClone: &gtk::Builder) {
let realABVFinalBrixInputBuffer = realABVFinalBrixInput.get_text().expect("No input"); let realABVFinalBrixInputBuffer = realABVFinalBrixInput.get_text().expect("No input");
let finalBrix = validInput(&realABVFinalBrixInputBuffer); let finalBrix = validInput(&realABVFinalBrixInputBuffer);
let realABVRealAttenuationOutput = String::from("realABVRealAttenuationOutput"); let realABVFinalABVOutput = String::from("realABVFinalABVOutput");
if startingBrix == 0.0 { if startingBrix == 0.0 {
let output: gtk::Entry = realABVBuilderClone.get_object(&realABVRealAttenuationOutput).unwrap(); let output: gtk::Entry = realABVBuilderClone.get_object(&realABVFinalABVOutput).unwrap();
output.set_text("Enter a number"); output.set_text("Enter a number");
} else if finalBrix == 0.0 { } else if finalBrix == 0.0 {
let output: gtk::Entry = realABVBuilderClone.get_object(&realABVRealAttenuationOutput).unwrap(); let output: gtk::Entry = realABVBuilderClone.get_object(&realABVFinalABVOutput).unwrap();
output.set_text("Enter a number"); output.set_text("Enter a number");
} else { } else {
if startingBrix <= 0.0 { if startingBrix <= 0.0 {
let output: gtk::Entry = realABVBuilderClone.get_object(&realABVRealAttenuationOutput).unwrap(); let output: gtk::Entry = realABVBuilderClone.get_object(&realABVFinalABVOutput).unwrap();
output.set_text("Enter a positive number"); output.set_text("Enter a positive number");
} else if finalBrix <= 0.0 { } else if finalBrix <= 0.0 {
let output: gtk::Entry = realABVBuilderClone.get_object(&realABVRealAttenuationOutput).unwrap(); let output: gtk::Entry = realABVBuilderClone.get_object(&realABVFinalABVOutput).unwrap();
output.set_text("Enter a positive number"); output.set_text("Enter a positive number");
} else if startingBrix < finalBrix { } else if startingBrix < finalBrix {
let output: gtk::Entry = realABVBuilderClone.get_object(&realABVRealAttenuationOutput).unwrap(); let output: gtk::Entry = realABVBuilderClone.get_object(&realABVFinalABVOutput).unwrap();
output.set_text("Starting brix must be greater than final brix"); output.set_text("Starting brix must be greater than final brix");
} else { } else {
realABVMaths(startingBrix, finalBrix, &realABVBuilderClone); realABVMaths(startingBrix, finalBrix, &realABVBuilderClone);
...@@ -37,21 +35,12 @@ pub fn realABVPrep(ref realABVBuilderClone: &gtk::Builder) { ...@@ -37,21 +35,12 @@ pub fn realABVPrep(ref realABVBuilderClone: &gtk::Builder) {
} }
} }
pub fn realABVMaths(startingBrix: f32, finalBrix: f32, ref realABVBuilderClone: &gtk::Builder) { fn realABVMaths(startingBrix: f32, finalBrix: f32, ref realABVBuilderClone: &gtk::Builder) {
let ref realABVRealAttenuationOutput: &gtk::Entry = &realABVBuilderClone.get_object("realABVRealAttenuationOutput").unwrap();
let ref realABVFinalABVOutput: &gtk::Entry = &realABVBuilderClone.get_object("realABVFinalABVOutput").unwrap(); let ref realABVFinalABVOutput: &gtk::Entry = &realABVBuilderClone.get_object("realABVFinalABVOutput").unwrap();
let originalGravity = (startingBrix / (258.6 - ((startingBrix / 258.2) * 227.1))) + 1.0; let finalGravity = 1.001843 - (0.002318474 * startingBrix) - (0.000007775 * startingBrix.powi(2)) - (0.000000034 * startingBrix.powi(3)) + (0.00574 * finalBrix) + (0.00003344 * finalBrix.powi(2)) + (0.000000086 * finalBrix.powi(3));
let finalGravity = (finalBrix / (258.6 - ((finalBrix / 258.2) * 227.1))) + 1.0; let refractiveIndex = 1.33302 + (0.001427193 * finalBrix) + (0.000005791157 * finalBrix.powi(2));
let originalExtract = (-668.962) + (1262.45 * originalGravity) - (776.43 * originalGravity.powi(2)) + (182.94 * originalGravity.powi(3)); let abw = 1017.5596 - (277.4 * finalGravity) + refractiveIndex * ((937.8135 * refractiveIndex) - 1805.1228);
let apparentExtract = (-668.962) + (1262.45 * finalGravity) - (776.43 * finalGravity.powi(2)) + (182.94 * finalGravity.powi(3)); let abv = format!("{:.2}%", abw * (finalGravity / 0.794));
let attenuationCoefficient = (0.22) + (0.001 * originalExtract);
let realExtract = (attenuationCoefficient * originalExtract + apparentExtract) / (1.0 + attenuationCoefficient);
let realAttenuation = ((originalExtract - realExtract) / originalExtract) * 100.0;
let attenuation = format!("{:.2}%", realAttenuation);
let estimatedABW = (originalExtract - realExtract) / ( 2.0665 - (0.010665 * originalExtract));
let finalABV = estimatedABW * (finalGravity / 0.794);
let abv = format!("{:.2}%", finalABV);
realABVRealAttenuationOutput.set_text(&attenuation);
realABVFinalABVOutput.set_text(&abv);