-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from brewerwall/feature/spirit
Distillate Unit Type and Spirt Calculations
Showing
8 changed files
with
471 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?php | ||
|
||
namespace Unitz\Calculate; | ||
|
||
use InvalidArgumentException; | ||
use Unitz\Distillate; | ||
use Unitz\Volume; | ||
|
||
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 | ||
* @return \Unitz\Volume | ||
* @throws \RuntimeException | ||
*/ | ||
public static function diluteDownToDesiredProof( | ||
Distillate $current, | ||
Distillate $desired, | ||
Volume $distillateVolume | ||
): Volume { | ||
if ($current->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) | ||
); | ||
} | ||
|
||
/** | ||
* 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 $stillEfficiencyPercent | ||
* @return \Unitz\Volume | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public static function distilledAlcoholVolume( | ||
Volume $volume, | ||
Distillate $wash, | ||
float $stillEfficiencyPercent | ||
): Volume { | ||
if ($stillEfficiencyPercent === 0.0) { | ||
throw new InvalidArgumentException('Still Efficiency cannot be zero.'); | ||
} | ||
|
||
return new Volume( | ||
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() | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
|
||
namespace Unitz; | ||
|
||
use InvalidArgumentException; | ||
|
||
class Distillate extends AbstractUnitz | ||
{ | ||
private float $proof; | ||
private float $percentAlcohol; | ||
|
||
public function __construct( | ||
?float $proof = null, | ||
?float $percentAlcohol = null, | ||
?float $userValue = null, | ||
array $preferences = [] | ||
) { | ||
if (!$this->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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
namespace Tests\Calculate; | ||
|
||
use InvalidArgumentException; | ||
use PHPUnit\Framework\TestCase; | ||
use Unitz\Calculate\Spirit; | ||
use Unitz\Distillate; | ||
use Unitz\Volume; | ||
|
||
class SpiritTest extends TestCase | ||
{ | ||
public function testDiluteDownToDesiredProofCalculatesCorrectly(): void | ||
{ | ||
$distillateVolume = new Volume(liter: 2); | ||
$current = new Distillate(percentAlcohol: 75); | ||
$desired = new Distillate(percentAlcohol: 40); | ||
$expected = new Volume(liter: 1.75); | ||
|
||
$actual = Spirit::diluteDownToDesiredProof($current, $desired, $distillateVolume); | ||
$this->assertEquals($expected, $actual); | ||
} | ||
|
||
public function testDiluteDownToDesiredProofThrowsInvalidArgumentExceptionWithReverseDistillateValues(): 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); | ||
} | ||
|
||
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); | ||
} | ||
|
||
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); | ||
} | ||
} |
Oops, something went wrong.