Getting water chemistry in the ballpark given the limited number of salts that are typically used in brewing is basically a "Linear Programming" problem. You'd try to minimize additions to the water while keeping the number of ions of various types as close as possible to the levels in whatever water you're trying to emulate.
There's a nice package that's open source called "glpk" that exists for various operating systems. You could grab it and use it under the GPL if you aren't making any modifications to the source without putting your source in danger.
Here's a sample of an input file using the GMPL syntax that I used to get the amount of salts to add to my water from Washington, DC to get it into the ballpark of Dublin, Ireland's water:
It should be fairly explanatory. The output of this is the grams per gallon of each salt that you'd need to add to get to the Dublin, Ireland profile. The output for the tap water variable is the percentage of tap to total water (distilled plus tap). In this model I have every salt and tap water weighted evenly, but if you decided you didn't care about Chlorine, for instance, or wanted it totally gone you could do that too. Or if you wanted to emphasize one salt over others you'd increase the weight to a number greater than 1. The coefficients on each salt in the constraint equations are the ppm that 1 gram in 1 gallon of water will give you for each ion.
Anyway, this basically works out even though you're not technically minimizing the difference between the achieved water profile and your target, by minimizing the total amount of salt used you're basically doing the same thing...
There's a nice package that's open source called "glpk" that exists for various operating systems. You could grab it and use it under the GPL if you aren't making any modifications to the source without putting your source in danger.
Here's a sample of an input file using the GMPL syntax that I used to get the amount of salts to add to my water from Washington, DC to get it into the ballpark of Dublin, Ireland's water:
Code:
var caso4 >= 0;
var nacl >= 0;
var mgso4 >= 0;
var cacl >= 0;
var nahco3 >= 0;
var caco3 >= 0;
var tap >= 0, <= 1;
minimize additions: 1*caso4 + 1*nacl + 1*mgso4 + 1*cacl + 1*nahco3 + 1*caco3 + 1*tap;
s.t. ca: 78*caso4 + 140*cacl + 88*caco3 + 38*tap >= 115;
s.t. mg: 53*mgso4 + 9.4*tap >= 4;
s.t. na: 104*nacl + 72*nahco3 + 19.4*tap >= 12;
s.t. s04: 186*caso4 + 32.7*tap >= 55;
s.t. cl: 160*nacl + 124*cacl + 35.6*tap >= 19;
s.t. hco3: 192*nahco3 + 176*caco3 + 10*tap >= 200;
end;
It should be fairly explanatory. The output of this is the grams per gallon of each salt that you'd need to add to get to the Dublin, Ireland profile. The output for the tap water variable is the percentage of tap to total water (distilled plus tap). In this model I have every salt and tap water weighted evenly, but if you decided you didn't care about Chlorine, for instance, or wanted it totally gone you could do that too. Or if you wanted to emphasize one salt over others you'd increase the weight to a number greater than 1. The coefficients on each salt in the constraint equations are the ppm that 1 gram in 1 gallon of water will give you for each ion.
Anyway, this basically works out even though you're not technically minimizing the difference between the achieved water profile and your target, by minimizing the total amount of salt used you're basically doing the same thing...