• Please visit and share your knowledge at our sister communities:
  • If you have not, please join our official Homebrewing Facebook Group!

    Homebrewing Facebook Group

Water Chemistry Calculator pH Discrepancy

Homebrew Talk

Help Support Homebrew Talk:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
That seems to be harder to do than I had hoped.

Yes sir it has.

I’m hoping for a rough draft adaption if your functions into a formatted brewing sheet by the end of the month but it has been slow going.

Trying to eek out the time required has been a bit tough.
 
The Gen II approach (don't think we can glorify it to the extent of calling it a "specification") is to use robust models for everything in the mash (water, alkalinity, additions, grains) and thereby eliminate the inaccuracies that arise when corners are cut for simplicity and when empirical approaches are used or, at least, to do this to the extent possible. If we have not taken measurements on a grain, for example, we will have to use an empirical approach to obtaining the grain's characteristics such as comparing it to a similar grain or using measurements made by someone else. Thus practically we can seldom entirely eliminate empiricism in the grain model but we can eliminate it from the remainder of the process. Our results are thus improved relative to programs that model the grains empirically and use empirical or approximate models for the chemistry.

The acids, bases, water and alkalinity are all pretty straight forward so the whole thing turns on the
q = a1 * (pHz - DI pH) + a2 * (pHz - DI pH)^2 + a3 * (pHz - DI pH)^3
model for charge change on malt. I tried to handle this in the same way I handled the other elements i.e. by providing functions which can be entered into an Excell spreadsheet in the same way as the functions that come with Excel out of the box. The hope was that some person or persons who knew how to put a user friendly spreadsheet together would be able to take these "engine" functions and assemble a sheet the average brewer could benefit from. That seems to be harder to do than I had hoped.

I'll probably come off as an arse, and thanks for all of those functions BTW, but several things come to mind:

1.) Why can't/haven't you, AJDelange, made a user friendly spreadsheet using your own functions? (Write one yourself! Your functions aren't quite as usable/accessible as you might think!)
2.) Why are these functions tied to an Excel spreadsheet and not made generic enough to use from any programming environment? (Code the functions in an environment independent way... i.e. not tied to excel)
3.) The code itself is atrocious. Names with special meanings and one letter variables, unused functions, etc... (This just requires some practice with coding, preferably in an OOP language!)
4.) The basic algorithms and explanations for these function are not present and require knowledge of water chemistry. I know there's some explanation in the documentation and some comments but it's not enough. One has to go to your website and read and understand your alkalinity papers, etc... (Write a book such that a child could understand! Your 1990's era papers on Alkalinity are well written!)

There, I said it. Many and various apologies if I've offended you.
 
If you don't use color, how do you get the acidity of the grain?

Riffe's spreadsheet calculates the Grist pH by using an assumed DI pH (or in the case of the savvy, a weighted user input that sums all the DI pH values for at the very least the base malts) and the grist acidity, which comes from color and the grist fraction of each malt.

If you eliminate the latter, the Grist pH will just be the combined DI pH of the grist, which doesn't say much about how the malt will affect the Grist pH.
Derek the source of the confusion may stem from the fact that ezRecipe now has an option that relies on the input of valid DIpH values for each grain. It does not attempt to predict the DIpH of the grains based on AJ's voltmeter functions. Although you can enter those DIpH values as they become available. I agreed Riffe's spreadsheet uses an assumed DIpH value that is based solely on grain color. The override I mentioned lets you enter an alternate DIpH value when you feel the assumed DIpH value is too low or too high.

Keeping in mind that ezRecipe is meant to be a full-featured beer recipe design tool that is powerful and easy to use. I wanted it's brewing water and mash pH prediction feature to be as accurate as possible without overwhelming the end user. I guess it's fair to say that ezRecipe v2.01 is a consumer of Gen II DIpH values and of DIpH values confirmed by means of actual single or multi-point titration testing.
 
Last edited:
Derek the source of the confusion may stem from the fact that ezRecipe relies on valid DIpH values for each grain for input. It does not attempt to predict the DIpH of the grains. I agreed Riffe's spreadsheet uses an assumed DIpH value based on solely on grain color. The override I mentioned lets you enter a different DIpH value when you feel the assumed DIpH value is too low or too high.

Keeping in mind that ezRecipe is meant to be a full-featured beer recipe design tool that is powerful and easy to use. I wanted it's brewing water and mash pH prediction features to be as accurate as possible without overwhelming the end user.

I don't think there is really any confusion on my part. I don't mean to imply you are confused either but let's reference Riffe:

Grist pH = DI pH - (0.0337 * (∑ f * A))

So say for instance we have an all pilsner grain bill. Color is 2.0L. MpH assumes 5.72 for DI pH. For Riffe:

Grist pH = 5.72 - (0.0337 * (-1.9 + (1 *2))) = 5.717

Now let's assume we can input our own DI pH of 5.80 (which we can):

Grist pH = 5.80 - (0.0337 * (-1.9 + (1 *2))) = 5.797

Now let's remove the color based acidity proxy (which it sounds like you have implemented):

Grist pH = 5.80 - (0.0337 * 1) = 5.766

Is this going to be a huge discrepancy? not in this scenario, but what about when we add different malts?

Let's try the same grain bill but with 5% cara malt (11L at 5.19 D|I pH) and 5% roast malt (350L at 4.69 DI pH. First we use Riffe:

Grist pH = DI pH - (0.0337 * (∑ f * A))

f * A (Pilsner) = 0.9 * (-1.9 + (1 * 2)) = 0.09
f * A (Cara) = 0.05 * (5 + (0.453*11)) = 0.5
f * A (Roast) = 0.05 * 42 = 2.1

Grist pH = 5.72 - (0.0337 * 2.69) = 5.629

Now let's assume we can input our own DI pH of 5.71 (which we can):

Grist pH = 5.71 - (0.0337 * 2.69) = 5.623

Now let's remove the color based acidity proxy (which it sounds like you have implemented):

Grist pH = 5.71- (0.0337 * 1) = 5.680


I certainly don't want to misrepresent what you are doing. I'm just trying to help and make sure you aren't missing a key element.
 
Last edited:
Derek, I appreciate your taking the time to help me check out the calculations. I think I've entered your test scenario correctly in both ezRecipe and Brewers Friend which I am using to regression test my new changes. For my results, I used 12 gallons of strike water and 100% RO water with an alkalinity of 13 ppm as CaCO3 without any salt or acid additions.

I'm sure I've read here in several threads that Brewers Friend has implemented the brewing water chemistry correctly. That's why I chose to use it to compare my calculations with.

ez pH Test Batch1.jpg

ez pH Test Batch2.jpg



ez pH Test Batch4.jpg

ez pH Test Batch3.jpg
 
Last edited:
Derek, I appreciate your taking the time to help me check out the calculations. I think I've entered your test scenario correctly in both ezRecipe and Brewers Friend which I am using to regression test my new changes. For my results, I used 12 gallons of strike water and 100% RO water with an alkalinity of 13 ppm as CaCO3 without any salt or acid additions.

I'm sure I've read here in several threads that Brewers Friend has implemented the brewing water chemistry correctly. That's why I chose to use it to compare my calculations with.

View attachment 607265
View attachment 607268


View attachment 607270
View attachment 607269

Here is what I got with similar parameters:

1.JPG
2.JPG
3.JPG
 
Here is what I got with similar parameters:
Ah ok rounded up I see you have 5.71 pH where ezRecipe and Brewers Friend have 5.76 pH. There's that pesky 0.05 pH discrepancy again. I'd like to know your thoughts on what is causing the difference between your mash pH prediction and Brewers Friend's prediction? I enter my RO water at pH 7 as having 8 ppm sodium, 4 ppm calcium chloride and 1 ppm sulfate with 13 ppm as CaCO3 total alkalinity.
 
Last edited:
Ah ok rounded up I see you have 5.71 pH where ezRecipe and Brewers Friend have 5.76 pH. There's that pesky 0.05 pH discrepancy again. I'd like to know your thoughts on what is causing the difference between your mash pH prediction and Brewers Friend's prediction? I enter my RO water at pH 7 as having 8 ppm sodium, 4 ppm calcium chloride and 1 ppm sulfate with 13 ppm as CaCO3 total alkalinity.

I think you are missing an acidity term in the malt parameters. Any equation that tries to predict mash pH is going to directly calculate or approximate malt acidity as well as use it’s DI pH.

I look a little deeper into the brewers friend calcs later.
 
I think you are missing an acidity term in the malt parameters. Any equation that tries to predict mash pH is going to directly calculate or approximate malt acidity as well as use it’s DI pH.

I look a little deeper into the brewers friend calcs later.
Ok sounds good Derek thank you.
 
Yes indeed they can when the full understanding and/or application of the chemistry is not incorporated.

In other words, if you've got a great and factual calculation for a part of the chemical reaction and haven't accounted for other aspects of that reaction, then you are no better off than an empirical estimate.

Sorry guys, I'm just in this thread to clean up some nastiness, but I'd like to comment on the statements above. In the past, I've been in the embarrassing position of defending a mathematical solution to some real-world measurements, when ultimately the empirically-derived table lookup was just better. I now know that in the real world there are confounding variables that the math doesn't appreciate, but the measured data certainly does :)

It's possible I'm misinterpreting the convo here, and if so sorry.
 
Sorry guys, I'm just in this thread to clean up some nastiness, but I'd like to comment on the statements above. In the past, I've been in the embarrassing position of defending a mathematical solution to some real-world measurements, when ultimately the empirically-derived table lookup was just better. I now know that in the real world there are confounding variables that the math doesn't appreciate, but the measured data certainly does :)

It's possible I'm misinterpreting the convo here, and if so sorry.

The only aspect of pH estimation that is going to be influenced negatively by the user is grain input and water source input.

The math is bulletproof and if fed good information, will be spot on all the time, much more so than empirically derived formulas.

What I mean by that is that we can estimate, with neglible error, the acid/base characteristics of the malt, source water, dilution water, sparge water, Ca and Mg salts, Baking Soda, and liquid acids.

This issue is getting good info for malts and source water and then getting someone to enter it correctly.
 
Last edited:
Any equation that tries to predict mash pH is going to directly calculate or approximate malt acidity as well as use it’s DI pH.

Unless it exclusively uses base 10 logs for malt to malt and grain to grain pH interactions, in which case it has no need for either calculating or approximating malt acidity. The proof that this works is that my spreadsheet, which involves zero malt acidities and has no need for them, comes up with mash pH solutions that are quite highly in line with the solutions of those that require the difficult and often questionable calculation and interaction of malt acidities.
 
Unless it exclusively uses base 10 logs for malt to malt and grain to grain pH interactions, in which case it has no need for either calculating or approximating malt acidity. The proof that this works is that my spreadsheet, which involves zero malt acidities and has no need for them, comes up with mash pH solutions that are quite highly in line with the solutions of those that require the difficult and often questionable calculation and interaction of malt acidities.

How do you estimate each malts DI pH? The answer is color. By you, I mean you personally, and MME, not the royal we.

If I don’t input a malt color to your sheet it has no valid output. That means it’s color based and estimates the malts acidity using color. That’s not a dig at you or your sheet. It’s a fact.

Your base 10 log thing is a fancy way of finding the weighted contribution to DI pH for each grain. I went over this in some previous post. No offense to you but your log base 10 thing is smoke and mirrors. It doesn’t do what you think it does.

I’m going to start a new thread tomorrow and post some sheet to sheet analysis and try to put to bed some misconceptions and try to make some comments on what works and why different sheets give the results they do.
 
I like your description of what a grain color driven calculation is. If color is involved in a calculation your talking a color based formula.

We should compare our results using 3 recipes. For a light, a dark and a medium colored beer. Then see what our mash pH predictions look like. We’d have to all use the same water profiles in our recipes.
 
Last edited:
Derek please include me I’m anxious to put ezRecipe v2.01 up against each other’s predictions.

Will do.

The plan will be to decide on 2 sets of theoretical input data. They will mimic what I ran through today: a base only and base, Cara, and roast grain bill.

I’ll get an unaltered output from each spreadsheet. Then I normalize all outputs for a specific set of DI pH values for each grain.

It will be a Grist pH only data set. We’ll see how everyone stacks up analytically and run some basic analysis on the outputs. See who is similar stock and see how altering DI pH user inputs brings everyone together.
 
I like your description of what a grain color driven calculation is. If color is involved in a calculation your talking color based.

That’s the long and short of it. If your sheet doesn’t work without a grain color input, it uses color as an acidity proxy in some way shape or form.
 
Will do.

The plan will be to decide on 2 sets of theoretical input data. They will mimic what I ran through today: a base only and base, Cara, and roast grain bill.

I’ll get an unaltered output from each spreadsheet. Then I normalize all outputs for a specific set of DI pH values for each grain.

It will be a Grist pH only data set. We’ll see how everyone stacks up analytically and run some basic analysis on the outputs. See who is similar stock and see how altering DI pH user inputs brings everyone together.
This is going to be fun.
 
That’s the long and short of it. If your sheet doesn’t work without a grain color input, it uses color as an acidity proxy in some way shape or form.

Let's try the same grain bill but with 5% cara malt (11L at 5.19 D|I pH) and 5% roast malt (350L at 4.69 DI pH. First, we use Riffe:

Grist pH = DI pH - (0.0337 * (∑ f * A))

f * A (Pilsner) = 0.9 * (-1.9 + (1 * 2)) = 0.09
f * A (Cara) = 0.05 * (5 + (0.453*11)) = 0.5
f * A (Roast) = 0.05 * 42 = 2.1

Grist pH = 5.72 - (0.0337 * 2.69) = 5.629

Now let's assume we can input our own DI pH of 5.71 (which we can):

Grist pH = 5.71 - (0.0337 * 2.69) = 5.623

Now let's remove the color based acidity proxy (which it sounds like you have implemented):

Grist pH = 5.71- (0.0337 * 1) = 5.680
So @RPIScotty as you have been saying eliminate color from the equation completely and it's no longer color based. Then Gen II mash pH predictions will be able to work without any influence from color. This shouldn't be too hard to get in with the next release.
 
So @RPIScotty as you have been saying eliminate color from the equation completely and it's no longer color based. Then Gen II mash pH predictions will be able to work without any influence from color. This shouldn't be too hard to get in with the next release.

Well you eliminate color based acidity but you can’t eliminate malt acidity altogether.

You either use color or you find q based around DI pH, a1, a2, a3.

I’m having a hard time finding a simple implementation of the latter. I love the solver based version I use but people have been having issues with it and I have not been able to simplify A.J. Iterative solution into something I can easily adapt.
 
Well you eliminate color based acidity but you can’t eliminate malt acidity altogether.
The malt acidty and buffering would come from single point titration or Andrew's voltmeter. Assuming one of us knows how to use it correctly.

You either use color or you find q based around DI pH, a1, a2, a3.
You list a multipoint titration here. I will do at least a single point titration I have the citric acid and plastic syringes to measure in cc or ml.

I’m having a hard time finding a simple implementation of the latter. I love the solver based version I use but people have been having issues with it and I have not been able to simplify A.J. Iterative solution into something I can easily adapt.
Yes I agree supporting ezRecipe is one thing but supporting Solver is up to Microsoft as far as I'm concerned.
 
The malt acidty and buffering would come from single point titration or Andrew's voltmeter. Assuming one of us knows how to use it correctly.

You list a multipoint titration here. I will do at least a single point titration I have the citric acid and plastic syringes to measure in cc or ml.


Yes I agree supporting ezRecipe is one thing but supporting Solver is up to Microsoft as far as I'm concerned.

Why don’t we talk offline and I can give you the info from my malt classes. I have a whole sheets worth of single, double and triple point titration data from A.J. and Riffe. I made my malt data table from this info.
 
How do you estimate each malts DI pH? The answer is color. By you, I mean you personally, and MME, not the royal we.

If I don’t input a malt color to your sheet it has no valid output. That means it’s color based and estimates the malts acidity using color. That’s not a dig at you or your sheet. It’s a fact.

Many malts and/or grains in MME have fully fixed (albeit end-user overrideable) DI_pH values that are not color correlated at all, and many others have highly range bound DI_pH's that are color correlated, some linearly, and some exponentially, so your presumption of absolute fact is not at all totally factual.

Your base 10 log thing is a fancy way of finding the weighted contribution to DI pH for each grain. I went over this in some previous post. No offense to you but your log base 10 thing is smoke and mirrors. It doesn’t do what you think it does.

From this I don't believe you understand it at all. The base 10 Logarithm itself is the very basis of pH. There is no need to weight anything beyond the weight contribution of each grist component, as presumably must be done at some level for all mash pH assistant software. Downstream of the initial determination of each grist components DI_pH, base 10 Logs accomplish literally everything within my spreadsheet that is involved in the process of determining the grists overall "pre-adjustment" mash pH, so how can they not be accomplishing specifically what I think they do, since what they accomplish can clearly be seen within the very output of the spreadsheet? How then can this be demeaned as merely smoke and mirrors?
 
Many malts and/or grains in MME have fully fixed (albeit end-user overrideable) DI_pH values that are not color correlated at all, and many others have highly range bound DI_pH's that are color correlated, some linearly, and some exponentially, so your presumption of absolute fact is not at all totally factual.



From this I don't believe you understand it at all. The base 10 Logarithm itself is the very basis of pH. There is no need to weight anything beyond the weight contribution of each grist component, as presumably must be done at some level for all mash pH assistant software. Downstream of the initial determination of each grist components DI_pH, base 10 Logs accomplish literally everything within my spreadsheet that is involved in the process of determining the grists overall "pre-adjustment" mash pH, so how can they not be accomplishing specifically what I think they do, since what they accomplish can clearly be seen within the very output of the spreadsheet? How then can this be demeaned as merely smoke and mirrors?

Larry, I would never, ever disclose anything about your sheet to anyone. You have my word on that but I have seen behind the scenes.
 
Last edited:
Larry, I would never, ever disclose anything about your sheet to anyone. You have my word on that but I have seen behind the scenes. I know exactly how it works.

How then can you state that it is merely smoke and mirrors? Only the later generations of my software have transitioned to a system based purely upon logarithms. Earlier versions did not use logs at all. Then there were attempted hybrid engines mixing logs and other methods. Then lastly the pure log based engine.
 
How then can you state that it is merely smoke and mirrors? Only the later generations of my software have transitioned to a system based purely upon logarithms. Earlier versions did not use logs at all. Then there were attempted hybrid engines mixing logs and other methods. Then lastly the pure log based engine.

I’ve seen your latest sheet.

I am going to include your sheet in my analysis tomorrow. Again, I will never disclose any behind the scenes details. You should know that opening a protected sheet in Google sheets bypasses all protection. There is no way around it. I don’t bother with sheet protection anymore for that reason.

It part of the reason I went to Macros and the solver.

I can explain to you privately why I think the log thing is smoke and mirrors and a dead end. Also, like I told Vince, thinking you’ve bypassed color based prediction because you jettison color based acidity proxies altogether is not realistic. Either you base a malts acidity on a color proxy or it’s titration characteristics. Sidestepping it altogether and just using a malts DI pH is not a complete picture.

I don’t have anything against you personally Larry. I do find it a bit annoying how you market MME with vieled digs at other programs, Brun Water in particular, without fully understanding your own, but that in no way shape or form means I don’t think you’re a nice guy. I’ve interacted enough in private conversation to know that you mean well.

Tomorrow it’s my hope that we will all learn a lot about how these things receive equal inputs and how playing around with them a little can tighten the spread between them. I think, at least as far as the color based sheets are concerned, you see a parity that may not otherwise be obvious.

Keep in mind that I’m only going to analyze Grist pH, as I feel differences between how sheets model the other parameters is not interesting. It’s so easy to use the right calcs for Source Water, Minerals, Acids, Bases, etc. that there should really be no difference between all the known sheets.

Grist modeling is where the disparities and interesting bits lie.
 
Last edited:
The only arbiter of software validity is actual end user testing of mash pH results for actual batches followed by comparison to the predicted results of said software.

Where I have primarily exposed error in BW is with regard to how it makes oddly radical output changes (mash pH predictions) with respect to the water to grist ratio alteration, which is in no way different from how A.J. and dmr have similarly railed against it. Dmr even recently offered the clear path by which BW can correct for this. That you fail to similarly complain of their railing against discovered errors within BW while complaining of my similar findings somewhat confuses and concerns me, but I understand this as your means of expressing respect for them.

Other than that, I have primarily railed against a wave of end users who give blind faith to a belief that software can be and to them factually is more precise and error free than real world mash pH measurement, to the extent where they no longer bother to perform such measurement, or they endlessly and mainly blindly parrot 0.01 pH accuracy of measurement compared to software. And I have railed against the blind leading the blind and parroting the mantra that software has the power to be superior to measurement. I.E., most of my railing is against "confirmation bias".
 
The only arbiter of software validity is actual end user testing of mash pH results for actual batches followed by comparison to the predicted results of said software.

Where I have primarily exposed error in BW is with regard to how it makes oddly radical output changes (mash pH predictions) with respect to the water to grist ratio alteration, which is in no way different from how A.J. and dmr have similarly railed against it. Dmr even recently offered the clear path by which BW can correct for this. That you fail to similarly complain of their railing against discovered errors within BW while complaining of my similar findings somewhat confuses and concerns me, but I understand this as your means of expressing respect for them.

Other than that, I have primarily railed against a wave of end users who give blind faith to a belief that software can be and to them factually is more precise and error free than real world mash pH measurement, to the extent where they no longer bother to perform such measurement, or they endlessly and mainly blindly parrot 0.01 pH accuracy of measurement compared to software. And I have railed against the blind leading the blind and parroting the mantra that software has the power to be superior to measurement. I.E., most of my railing is against "confirmation bias".

We should first be concerned with actual mash pH measurements. I agree.

We should then also be concerned with how software predicts and why others match it or differ from it.

So predict, measure, compare.

Lastly, we should be concerned with how software claims to predict, assure its ground in the proper scientific background, and expose certain aspects of it that are wonky, both in our software and in others. How we do that is important. Why we do that is important as well.

If I seem to unfairly malign you it’s because I don’t think you fully understand what you are doing, which is contrary to someone like A.J. who I think more than understands the factual basis for what he talks about. That’s neither here nor there at this point.

This isn’t solving world hunger, I’ll grant anyone that, and maybe I take the discussion of it too seriously, but it’s important to be genuine, to understand what you are recommending, and to ensure the factual and scientific basis for YOUR prediction is solid.

I think I’m done speaking to this topic in particular in this thread. I’ll start a new one shortly.
 
Last edited:
1.) Why can't/haven't you, AJDelange, made a user friendly spreadsheet using your own functions? (Write one yourself! Your functions aren't quite as usable/accessible as you might think!)
Because I'm not skilled at such things. The whole intent of the project was to make the science accessible to those who are. I have prepared a spreadsheet using them mostly as a demo platform and find it extremely useful and easy to use relative to previous spreadsheets I have done but am well aware that someone who does this for a living could doubtless do it much better.

2.) Why are these functions tied to an Excel spreadsheet and not made generic enough to use from any programming environment? (Code the functions in an environment independent way... i.e. not tied to excel)
Because everybody has got Excel. If you can't figure out how to port the meat functions to any other programming language you are a worse programmer than I. The exceptions here would be the functions that gather up the data from the spreadsheet i.e. get what the user enters to the bits that do the actual computation. That is, of course, going to depend on the UI and that in turn will depend on the environment.

3.) The code itself is atrocious. Names with special meanings and one letter variables, unused functions, etc...
It was never intended to be elegant - just functional. My original intent was that it would be hidden in and Excel Add-In (or whatever they are called). The user would not be exposed to the actual code behind Qcarb any more than he is exposed to the code for VLOOKUP.
(This just requires some practice with coding, preferably in an OOP language!)
Visual Basic is an OOP language.

4.) The basic algorithms and explanations for these function are not present and require knowledge of water chemistry.
As is manifestly clear in this thread and others water chemistry is not something that is comprehensible to the average home brewer (nor to most commercial brewers either).

I know there's some explanation in the documentation and some comments but it's not enough.
Given the last comment, one of the goals here was to make functions that would, for example, return the charge on a liter of water or the charge on a killogram of malt available to the user without explaining how they are computed or why. The job of pH estimation then becomes that of setting things up so that the net sum gain in charge over a mash is 0. Given that only perhaps two or three people here understand that it appears that this approach is not going to lead to success.

One has to go to your website and read and understand your alkalinity papers, etc...
Though the "manual" is not complete the chemistry is in the Appendix.


(Write a book such that a child could understand!
Impossible. For some reason this particular area of chemistry is very hard to understand.


Your 1990's era papers on Alkalinity are well written!)
Alkalinity is a very simple concept when considered in the context of a water supply. It is only when you generalize the concept to solve any problem involving the mixing of buffers that you lose 99% of readers.


Many and various apologies if I've offended you.
No worries. The endeavour to this point is certainly a torso undertaken by a FORTRAN programming engineer more interested in algorithms than pretty code. As before, I encourage anyone with real programming skills to run with it.
 
Last edited:
Back
Top