From c3cecf2d1ad195ab45d2629f5bd744af4b14dae3 Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Mon, 11 Sep 2023 22:59:53 -0500 Subject: [PATCH 1/6] Distillate Unit Type and start of Spirt Calculations --- src/BaseUnitz.php | 1 + src/Calculate/Spirit.php | 31 ++++++++++ src/Distillate.php | 106 +++++++++++++++++++++++++++++++++ src/UnitzService.php | 14 +++++ tests/Calculate/SpiritTest.php | 35 +++++++++++ tests/DistillateTest.php | 92 ++++++++++++++++++++++++++++ tests/UnitzServiceTest.php | 31 ++++++++++ 7 files changed, 310 insertions(+) create mode 100644 src/Calculate/Spirit.php create mode 100644 src/Distillate.php create mode 100644 tests/Calculate/SpiritTest.php create mode 100644 tests/DistillateTest.php diff --git a/src/BaseUnitz.php b/src/BaseUnitz.php index 839433e..5508aef 100644 --- a/src/BaseUnitz.php +++ b/src/BaseUnitz.php @@ -12,6 +12,7 @@ class BaseUnitz 'Weight' => 'Pound', 'Color' => 'Srm', 'Time' => 'Minute', + 'Distillate' => 'Proof' ]; private array $preferences; diff --git a/src/Calculate/Spirit.php b/src/Calculate/Spirit.php new file mode 100644 index 0000000..1de57bd --- /dev/null +++ b/src/Calculate/Spirit.php @@ -0,0 +1,31 @@ +getPercentAlcohol() < $desired->getPercentAlcohol()) { + throw new InvalidArgumentException('Current distillate cannot be less than desired distillate.'); + } + + return new Volume( + liter: $distillateVolume->getLiter() * (($current->getPercentAlcohol() / $desired->getPercentAlcohol()) - 1) + ); + } +} \ No newline at end of file diff --git a/src/Distillate.php b/src/Distillate.php new file mode 100644 index 0000000..12f4185 --- /dev/null +++ b/src/Distillate.php @@ -0,0 +1,106 @@ +hasOnlyOneValue([$proof, $percentAlcohol, $userValue])) { + throw new InvalidArgumentException('Only one Distillate type can be set at a time.'); + } + + parent::__construct($preferences); + + if (is_numeric($proof)) { + $this->setProof($proof); + } + + if (is_numeric($percentAlcohol)) { + $this->setPercentAlcohol($percentAlcohol); + } + + if (is_numeric($userValue)) { + $this->setValue($userValue); + } + } + + /** + * @param float $proof + * @return $this + * @throws \InvalidArgumentException + */ + public function setProof(float $proof): self + { + if ($proof > 200) { + throw new InvalidArgumentException('Proof cannot be greater than 200'); + } + + $this->proof = $proof; + $this->percentAlcohol = self::convertProofToPercentAlcohol($proof); + + return $this; + } + + /** + * @param ?int $round + * @return float + */ + public function getProof(?int $round = null): float + { + return $round ? round($this->proof, $round) : $this->proof; + } + + /** + * @param float $percentAlcohol + * @return $this + * @throws \InvalidArgumentException + */ + public function setPercentAlcohol(float $percentAlcohol): self + { + if ($percentAlcohol > 100) { + throw new InvalidArgumentException('Percent alcohol cannot be greater than 100'); + } + + $this->percentAlcohol = $percentAlcohol; + $this->proof = self::convertPercentAlcoholToProof($percentAlcohol); + + return $this; + } + + /** + * @param ?int $round + * @return float + */ + public function getPercentAlcohol(?int $round = null): float + { + return $round ? round($this->percentAlcohol, $round) : $this->percentAlcohol; + } + + /** + * @param float $proof + * @return float + */ + public static function convertProofToPercentAlcohol(float $proof): float + { + return $proof / 2; + } + + /** + * @param float $percentAlcohol + * @return float + */ + public static function convertPercentAlcoholToProof(float $percentAlcohol): float + { + return $percentAlcohol * 2; + } +} \ No newline at end of file diff --git a/src/UnitzService.php b/src/UnitzService.php index c5c4794..28fd6c5 100644 --- a/src/UnitzService.php +++ b/src/UnitzService.php @@ -146,4 +146,18 @@ public function makeTime( $this->getPreferences() ); } + + /** + * @param float|null $proof + * @param float|null $percentAlcohol + * @param float|null $userValue + * @return \Unitz\Distillate + */ + public function makeDistillate( + ?float $proof = null, + ?float $percentAlcohol = null, + ?float $userValue = null + ): Distillate { + return new Distillate($proof, $percentAlcohol, $userValue, $this->getPreferences()); + } } \ No newline at end of file diff --git a/tests/Calculate/SpiritTest.php b/tests/Calculate/SpiritTest.php new file mode 100644 index 0000000..cfd4453 --- /dev/null +++ b/tests/Calculate/SpiritTest.php @@ -0,0 +1,35 @@ +assertEquals($expected, $actual); + } + + public function testDiluteDownToDesiredProofThrowsRuntimeExceptionWithReverseDistillateValues(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Current distillate cannot be less than desired distillate.'); + + $distillateVolume = new Volume(liter: 2); + $current = new Distillate(percentAlcohol: 35); + $desired = new Distillate(percentAlcohol: 40); + + Spirit::diluteDownToDesiredProof($current, $desired, $distillateVolume); + } +} \ No newline at end of file diff --git a/tests/DistillateTest.php b/tests/DistillateTest.php new file mode 100644 index 0000000..bacf3e1 --- /dev/null +++ b/tests/DistillateTest.php @@ -0,0 +1,92 @@ +getValue(); + $expected = self::TEST_PROOF; + + $this->assertEquals($expected, $actual); + } + + public function testSetProofWillReturnProofWithGetProof(): void + { + $distillate = new Distillate(proof: self::TEST_PROOF); + $actual = $distillate->getProof(); + $expected = self::TEST_PROOF; + + $this->assertEquals($expected, $actual); + } + + public function testSetProofWillReturnPercentAlcoholWithGetPercentAlcohol(): void + { + $distillate = new Distillate(proof: self::TEST_PROOF); + $actual = $distillate->getPercentAlcohol(); + $expected = self::TEST_PERCENT_ALCOHOL; + + $this->assertEquals($expected, $actual); + } + + public function testSetProofWillThrowInvalidArgumentExceptionWithOutOfRangeProof(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Proof cannot be greater than 200'); + + new Distillate(proof: 201); + } + + public function testSetPercentAlcoholWillReturnProofWithGetValueAndDefaultPreferences(): void + { + $distillate = new Distillate(percentAlcohol: self::TEST_PERCENT_ALCOHOL); + $actual = $distillate->getValue(); + $expected = self::TEST_PROOF; + + $this->assertEquals($expected, $actual); + } + + public function testSetPercentAlcoholWillReturnProofWithGetProof(): void + { + $distillate = new Distillate(percentAlcohol: self::TEST_PERCENT_ALCOHOL); + $actual = $distillate->getProof(); + $expected = self::TEST_PROOF; + + $this->assertEquals($expected, $actual); + } + + public function testSetPercentAlcoholWillReturnPercentAlcoholWithGetPercentAlcohol(): void + { + $distillate = new Distillate(percentAlcohol: self::TEST_PERCENT_ALCOHOL); + $actual = $distillate->getPercentAlcohol(); + $expected = self::TEST_PERCENT_ALCOHOL; + + $this->assertEquals($expected, $actual); + } + + public function testSetUserValueWillReturnProofWithGetValueAndDefaultPreferences(): void + { + $distillate = new Distillate(userValue: self::TEST_PROOF); + $actual = $distillate->getValue(); + $expected = self::TEST_PROOF; + + $this->assertEquals($expected, $actual); + } + + public function testSetPercentAlcoholWillThrowInvalidArgumentExceptionWithOutOfRangeProof(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Percent alcohol cannot be greater than 100'); + + new Distillate(percentAlcohol: 101); + } +} \ No newline at end of file diff --git a/tests/UnitzServiceTest.php b/tests/UnitzServiceTest.php index 18615a9..4e7146c 100644 --- a/tests/UnitzServiceTest.php +++ b/tests/UnitzServiceTest.php @@ -218,4 +218,35 @@ public function testMakeTimeWillSetTimeWithPreferenceAndNewSetValueAndReturnTheS $actual = $time->getHour(); $this->assertEquals($expected, $actual); } + + public function testMakeProofWillReturnProofWithPreference(): void + { + $proof = 60; + $distillate = $this->makeUnitService(['Distillate' => 'Proof'])->makeDistillate( + proof: $proof + ); + $expected = $proof; + $actual = $distillate->getValue(); + $this->assertEquals($expected, $actual); + } + + public function testMakeProofWillSetProofWithPreferenceAndReturnTheSame(): void + { + $proof = 60; + $distillate = $this->makeUnitService(['Distillate' => 'Proof'])->makeDistillate(userValue: $proof); + $expected = $proof; + $actual = $distillate->getValue(); + $this->assertEquals($expected, $actual); + } + + public function testMakeProofWillSetProofWithPreferenceAndNewSetValueAndReturnTheSame(): void + { + $proof = 60; + $newProof = 70; + $distillate = $this->makeUnitService(['Distillate' => 'Proof'])->makeDistillate(userValue: $proof); + $distillate->setValue($newProof); + $expected = $newProof; + $actual = $distillate->getProof(); + $this->assertEquals($expected, $actual); + } } \ No newline at end of file From 2ab43c8dce486b4513293dc865083dc564cd9a52 Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Wed, 13 Sep 2023 22:51:11 -0500 Subject: [PATCH 2/6] Add distilledAlcoholVolume to Spirit Calculation --- src/Calculate/Spirit.php | 26 ++++++++++++++++++++++++++ tests/Calculate/SpiritTest.php | 25 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Calculate/Spirit.php b/src/Calculate/Spirit.php index 1de57bd..f5358a8 100644 --- a/src/Calculate/Spirit.php +++ b/src/Calculate/Spirit.php @@ -9,6 +9,8 @@ class Spirit { /** + * The amount of water you need to add to a distillate to dilute it down to a desired distillate. + * * @param \Unitz\Distillate $current * @param \Unitz\Distillate $desired * @param \Unitz\Volume $distillateVolume @@ -28,4 +30,28 @@ public static function diluteDownToDesiredProof( liter: $distillateVolume->getLiter() * (($current->getPercentAlcohol() / $desired->getPercentAlcohol()) - 1) ); } + + /** + * Determines the Volume of distillate you will get with a specific wash abv and still efficiency. + * + * Source - https://www.hillbillystills.com/distilling-calculator + * + * @param \Unitz\Volume $volume + * @param \Unitz\Distillate $wash + * @param float $stillEfficiency + * @return \Unitz\Volume + */ + public static function distilledAlcoholVolume( + Volume $volume, + Distillate $wash, + float $stillEfficiencyPercent + ): Volume { + if ($stillEfficiency === 0.0) { + throw new InvalidArgumentException('Still Efficiency cannot be zero.'); + } + + return new Volume( + liter: ((0.95 * $volume->getLiter() * $wash->getPercentAlcohol() / $stillEfficiencyPercent) * 100) / 100 + ); + } } \ No newline at end of file diff --git a/tests/Calculate/SpiritTest.php b/tests/Calculate/SpiritTest.php index cfd4453..5b66eec 100644 --- a/tests/Calculate/SpiritTest.php +++ b/tests/Calculate/SpiritTest.php @@ -21,7 +21,7 @@ public function testDiluteDownToDesiredProofCalculatesCorrectly(): void $this->assertEquals($expected, $actual); } - public function testDiluteDownToDesiredProofThrowsRuntimeExceptionWithReverseDistillateValues(): void + public function testDiluteDownToDesiredProofThrowsInvalidArgumentExceptionWithReverseDistillateValues(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Current distillate cannot be less than desired distillate.'); @@ -32,4 +32,27 @@ public function testDiluteDownToDesiredProofThrowsRuntimeExceptionWithReverseDis Spirit::diluteDownToDesiredProof($current, $desired, $distillateVolume); } + + public function testDistilledAlcoholVolumeCalculatesCorrectly(): void + { + $volume = new Volume(liter: 20); + $wash = new Distillate(percentAlcohol: 9); + $stillEfficiencyPercent = 92; + $expected = new Volume(liter: 1.858695652173913); + + $actual = Spirit::distilledAlcoholVolume($volume, $wash, $stillEfficiencyPercent); + $this->assertEquals($expected, $actual); + } + + public function testDistilledAlcoholVolumeThrowsInvalidArgumentExceptionWithZeroStillEfficiency(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Still Efficiency cannot be zero.'); + + $volume = new Volume(liter: 20); + $wash = new Distillate(percentAlcohol: 9); + $stillEfficiencyPercent = 0; + + Spirit::distilledAlcoholVolume($volume, $wash, $stillEfficiencyPercent); + } } \ No newline at end of file From 10abf4b307eeeafa416ce025c788dfe262e9e522 Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Wed, 13 Sep 2023 23:03:23 -0500 Subject: [PATCH 3/6] Spirit and Proof documentation in README --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 49c2a58..7c72271 100644 --- a/README.md +++ b/README.md @@ -99,10 +99,11 @@ $temperature->getFahrenheit(); // 76 | Gravity | Plato
SpecificGravity
Brix | | Pressure | Psi
Bar | | Temperature | Celsius
Fahrenheit | -| Volumne | Ounce
Gallon
Barrel
Milliliter
Liter
Hectoliter | +| Volume | Ounce
Gallon
Barrel
Milliliter
Liter
Hectoliter | | Weight | Ounce
Pound
Gram
Kilogram | | Color | Srm
Ebc
Lovibond | | Time | Millisecond
Second
Minute
Hour
Day
Week
Month
Year | +| Distillate | Proof
Alcohol Percent | ### Preferences @@ -120,6 +121,7 @@ preference set, but can be overridden when instantiating a new unit. 'Weight' => 'Pound', 'Color' => 'Srm', 'Time' => 'Minute', + 'Distillate' => 'Proof', ]; ``` @@ -380,3 +382,47 @@ Beer::gravityCorrection(Gravity $gravity, Temperature $temperature, Temperature ##### Returns - `Gravity` - Corrected Gravity of Sample + +### Spirit + +This class will calculate Spirit related calculations. +___ + +#### Dilute Down To Desired Proof + +Dilute Down To Desired Proof is a calculation to determine how much water to add to a spirit to get to a desired proof. + +```php +Spirit::diluteDownToDesiredProof(Proof $currentProof, Proof $desiredProof, Volume $currentVolume): Volume +``` + +##### Arguments + +- `Proof $currentProof` - Current Proof of the spirit +- `Proof $desiredProof` - Desired Proof of the spirit +- `Volume $currentVolume` - Current Volume of the spirit + +##### Returns + +- `Volume` - Volume of water to add to the spirit + +--- + +#### Distilled Alcohol Volume + +Distilled Alcohol Volume is a calculation to determine the volume of alcohol distilled depending on the wash abv and +still efficiency. + +```php +Spirit::distilledAlcoholVolume(Volume $volume, Distillate $wash, float $stillEfficiencyPercent): Volume +``` + +##### Arguments + +- `Volume $volume` - Volume of the wash +- `Distillate $wash` - Distillate of the wash +- `float $stillEfficiencyPercent` - Still efficiency percentage + +##### Returns + +- `Volume` - Volume of the distilled alcohol \ No newline at end of file From 1b04dfc3d6dbd7cc646ccc727e162df0597dffda Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Wed, 13 Sep 2023 23:22:33 -0500 Subject: [PATCH 4/6] Variable name refactor miss in Spirit::distilledAlcoholVolume --- src/Calculate/Spirit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Calculate/Spirit.php b/src/Calculate/Spirit.php index f5358a8..760052b 100644 --- a/src/Calculate/Spirit.php +++ b/src/Calculate/Spirit.php @@ -46,7 +46,7 @@ public static function distilledAlcoholVolume( Distillate $wash, float $stillEfficiencyPercent ): Volume { - if ($stillEfficiency === 0.0) { + if ($stillEfficiencyPercent === 0.0) { throw new InvalidArgumentException('Still Efficiency cannot be zero.'); } From 8c1809659f98ce8c54303c84c0d6be646f713221 Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Wed, 13 Sep 2023 23:23:14 -0500 Subject: [PATCH 5/6] Spirit::distilledAlcoholVolume Update DocBlock Variable Name --- src/Calculate/Spirit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Calculate/Spirit.php b/src/Calculate/Spirit.php index 760052b..6c2422d 100644 --- a/src/Calculate/Spirit.php +++ b/src/Calculate/Spirit.php @@ -38,7 +38,7 @@ public static function diluteDownToDesiredProof( * * @param \Unitz\Volume $volume * @param \Unitz\Distillate $wash - * @param float $stillEfficiency + * @param float $stillEfficiencyPercent * @return \Unitz\Volume */ public static function distilledAlcoholVolume( From 3d25f08ecf7493755b11c77ebfd95855c4c986b9 Mon Sep 17 00:00:00 2001 From: Ben Griffith Date: Sun, 17 Sep 2023 21:54:23 -0500 Subject: [PATCH 6/6] Distilled Remaining Water Volume --- README.md | 22 +++++++++++++++++++++- src/Calculate/Spirit.php | 22 ++++++++++++++++++++++ tests/Calculate/SpiritTest.php | 23 +++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c72271..134207f 100644 --- a/README.md +++ b/README.md @@ -425,4 +425,24 @@ Spirit::distilledAlcoholVolume(Volume $volume, Distillate $wash, float $stillEff ##### Returns -- `Volume` - Volume of the distilled alcohol \ No newline at end of file +- `Volume` - Volume of the distilled alcohol + +--- + +#### Distilled Remaining Water Volume + +Distilled Remaining Water Volume is a calculation to determine the volume of water remaining after distilling a spirit. + +```php +Spirit::distilledRemainingWaterVolume(Volume $volume, Distillate $wash, float $stillEfficiencyPercent): Volume +``` + +##### Arguments + +- `Volume $volume` - Volume of the wash +- `Distillate $wash` - Distillate of the wash +- `float $stillEfficiencyPercent` - Still efficiency percentage + +##### Returns + +- `Volume` - Volume of the remaining water \ No newline at end of file diff --git a/src/Calculate/Spirit.php b/src/Calculate/Spirit.php index 6c2422d..ddfe8b0 100644 --- a/src/Calculate/Spirit.php +++ b/src/Calculate/Spirit.php @@ -40,6 +40,7 @@ public static function diluteDownToDesiredProof( * @param \Unitz\Distillate $wash * @param float $stillEfficiencyPercent * @return \Unitz\Volume + * @throws \InvalidArgumentException */ public static function distilledAlcoholVolume( Volume $volume, @@ -54,4 +55,25 @@ public static function distilledAlcoholVolume( liter: ((0.95 * $volume->getLiter() * $wash->getPercentAlcohol() / $stillEfficiencyPercent) * 100) / 100 ); } + + /** + * @param \Unitz\Volume $volume + * @param \Unitz\Distillate $wash + * @param float $stillEfficiencyPercent + * @return \Unitz\Volume + * @throws \InvalidArgumentException + */ + public static function distilledRemainingWaterVolume( + Volume $volume, + Distillate $wash, + float $stillEfficiencyPercent + ): Volume { + return new Volume( + liter: $volume->getLiter() - self::distilledAlcoholVolume( + $volume, + $wash, + $stillEfficiencyPercent + )->getLiter() + ); + } } \ No newline at end of file diff --git a/tests/Calculate/SpiritTest.php b/tests/Calculate/SpiritTest.php index 5b66eec..4919f07 100644 --- a/tests/Calculate/SpiritTest.php +++ b/tests/Calculate/SpiritTest.php @@ -55,4 +55,27 @@ public function testDistilledAlcoholVolumeThrowsInvalidArgumentExceptionWithZero Spirit::distilledAlcoholVolume($volume, $wash, $stillEfficiencyPercent); } + + public function testDistilledRemainingWaterVolumeCalculatesCorrectly(): void + { + $volume = new Volume(liter: 20); + $wash = new Distillate(percentAlcohol: 9); + $stillEfficiencyPercent = 92; + $expected = new Volume(liter: 18.141304347826086); + + $actual = Spirit::distilledRemainingWaterVolume($volume, $wash, $stillEfficiencyPercent); + $this->assertEquals($expected, $actual); + } + + public function testDistilledRemainingWaterVolumeThrowsInvalidArgumentExceptionWithZeroStillEfficiency(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Still Efficiency cannot be zero.'); + + $volume = new Volume(liter: 20); + $wash = new Distillate(percentAlcohol: 9); + $stillEfficiencyPercent = 0; + + Spirit::distilledRemainingWaterVolume($volume, $wash, $stillEfficiencyPercent); + } } \ No newline at end of file