 |
01-12-2011, 09:36 PM
|
#1
|
|
Feedback Score: 0 reviews
Join Date: Mar 2009
Location: Denver, CO
Posts: 261
Liked 5 Times on 2 Posts Likes Given: 5
|
Script to calculate water salt additions
|
|
I wrote this script to calculate the optimal amount of brewing salts to add to your water profile to end up with a target profile. I grabbed most of my numbers from ProMash, and so far this seems to be working well for me.
It is a python script, so you'll need the python interpreter with numpy, and the PyIMSL numerical libraries (freely available here: http://www.imslaps.com/products/imsl/pyimsl/)
Code:
from numpy import *
from imsl.math.linLsqLinConstraints import linLsqLinConstraints
from imsl.math.writeMatrix import writeMatrix
from imsl.math.vectorNorm import vectorNorm
#Replace the values in base_water with your water profile
base_water = [26.0, 3.6, 13.2, 28.0, 12.2, 68]
#################Values taken from ProMash################
burton_on_trent = [268., 62., 30., 638., 36., 141.]
calistoga_mineral = [11.1, 62., 30., 638., 36., 141.]
distilled_water = [0.,0.,0.,0.,0.,0.]
dortmund = [260.,23.,69.,240.,206.,270.]
dublin = [118., 4., 12., 54., 19., 319.]
edinburgh = [140., 36., 92., 231., 60., 270.]
london = [90., 4., 24., 58., 18., 123.]
marin_county_ca = [12., 10., 15., 17., 13., 74.]
munich = [76., 18., 1., 10., 2., 152.]
pilsen = [7., 3., 3.2, 5.8, 5., 9.]
vienna = [200., 60., 8., 125., 12., 120.]
yorkshire = [105., 17., 23., 66., 30., 153.]
###########################################################
target = burton_on_trent
#Salt contents (PPM / (grams per gallon))
caso4 = [61.5, 0.0, 0.0, 147.4, 0.0, 0.0]
mgso4 = [0.0, 26.1, 0.0, 103.0, 0.0, 0.0]
nacl = [0.0, 0.0, 103.9, 0.0, 160.3, 0.0]
nahco3 = [0.0, 0.0, 72.0, 0.0, 0.0, 189.0]
cacl2 = [72.0, 0.0, 0.0, 0.0, 127.4, 0.0]
caco3 = [105.8, 0.0, 0.0, 0.0, 0.0, 158.4]
# The overall goal here is to find x ST:
# Ax =~ b
# x >= 0
a = transpose([caso4, mgso4, nacl, nahco3, cacl2, caco3])
b = array(target) - array(base_water)
xlb = [0.] * 6
xub = [-1.0e30] * 6
c = []
con_type = []
bu = []
bl = []
residual = []
x = linLsqLinConstraints(a, b, c, bl, bu, con_type, xlb, xub, residual=residual)
ion_labels = ['', 'Ca', 'Mg', 'Na', 'SO4', 'Cl', 'HCO3']
salt_labels = ['', 'CaSO4', 'MgSO4', 'NaCl', 'NaHCO3', 'CaCl2', 'CaCO3']
writeMatrix("Salt amounts to add \n(Grams per Gallon)", x, colLabels=salt_labels)
writeMatrix("Target Profile \n(PPM)", target, colLabels=ion_labels)
writeMatrix("Base Water + Recomended Salt Additions \n(PPM)", dot(a,x) + array(base_water), colLabels=ion_labels)
writeMatrix("Residuals \n(PPM)", residual, colLabels=ion_labels)
print ("\nNorm of residual = %f" % (vectorNorm(residual)))
Here's a run calculating additions from my water to Burton on Trent. Plugging these numbers back into ProMash I get these exact totals.
Code:
ryan@ubuntu-desktop:~/Desktop$ python water.py
Salt amounts to add
(Grams per Gallon)
CaSO4 MgSO4 NaCl NaHCO3 CaCl2 CaCO3
2.888 1.817 0.106 0.000 0.083 0.489
Target Profile
(PPM)
Ca Mg Na SO4 Cl HCO3
268 62 30 638 36 141
Base Water + Recomended Salt Additions
(PPM)
Ca Mg Na SO4 Cl HCO3
261.3 51.0 24.2 640.8 39.8 145.5
Residuals
(PPM)
Ca Mg Na SO4 Cl HCO3
-6.67 -10.98 -5.81 2.78 3.77 4.45
Norm of residual = 15.513117
Hope somebody finds this useful! 
|
|
|
09-07-2012, 05:29 AM
|
#2
|
|
Feedback Score: 0 reviews
Join Date: Oct 2010
Location: Potosi, Missouri
Posts: 62
Liked 4 Times on 3 Posts Likes Given: 2
|
This is the first calculator I've found that (supposedly) calculates the proper additions to reach a desired water profile, rather than calculating the profile based on my additions. The first problem is that the link above for the python interpreter doesn't work. The second problem is that I have no idea what "python" or "numpy" are. Help please.
__________________
Part of me says I need to stop drinking like this. The other part says "Don't listen to him, he's drunk."
|
|
|
09-11-2012, 07:11 PM
|
#3
|
|
Senior Member
Feedback Score: 0 reviews
Join Date: Sep 2011
Location: Healdsburg, CA
Posts: 1,381
Liked 39 Times on 35 Posts Likes Given: 6
|
Got an 500 Error.. Internal Server on the link
__________________
Cheers, Bill
Hop Song Brewing
A fine beer may be judged with only one sip, but it's better to be thoroughly sure.
Bottled n Kegged 2 APA's, Milk Stout
Brewing: zippo
Up Next: APA, Dry Stout
|
|
|
09-16-2012, 03:50 AM
|
#4
|
|
Feedback Score: 1 reviews
Join Date: Jan 2010
Location: Cincinnat, OH
Posts: 235
Liked 7 Times on 7 Posts Likes Given: 3
|
I'd love to be able to use this. Unfortunately, like a previous poster, I don't know how exactly. I've used a python script a couple times for something I was doing about a year ago, but I had no idea what I was doing. Could you (would you?) put together a "How-To" of getting the proper software/program and actually running the script? That would make this uber-helpful. Thanks so much.
|
|
|
09-19-2012, 09:33 PM
|
#5
|
|
Feedback Score: 0 reviews
Join Date: Oct 2010
Location: Potosi, Missouri
Posts: 62
Liked 4 Times on 3 Posts Likes Given: 2
|
^^^^=awesome!
__________________
Part of me says I need to stop drinking like this. The other part says "Don't listen to him, he's drunk."
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
|
|
|