Calculate your way into a great e-juice mix!

published Aug 25, 2016

The geekiest way to prepare your e-liquid.

Today, we'll learn how to use Python, SymPy and Reinteract to calculate the proportions of nicotine base, flavoring, and PG/VG, directly on your computer.

Preparation and setup

You need to install three things on your computer:

  1. Python 2.7.
  2. Reinteract for Python 2.7.
  3. The SymPy library.

The links above show how to install these programs on Windows.  On a distribution like Fedora, all you have to do is (as root) type the command dnf install -y python reinteract sympy and that is it.

Now launch Reinteract from your computer's programs menu.

On the window that appears, type the command import sympy and hit Ctrl+Enter on your keyboard.  If you did everything right during installation, there will be no errors, and a small blue square will appear to the left of the command you just typed.

What you have installed right now is a computer program that will let you write programs and run them interactively.  Reinteract is a super fun way to program your computer, and it also has the advantage that it lets you see the results of what you input as you type — just hit Ctrl+Enter on your keyboard every time you want to run your program.

The program

Copy and paste the following listing to your Reinteract window (erasing what was there before):

# Calculate the ingredients for any e-liquid mixture.

# All computed figures in milliliters.
# mlmg() converts to permille.
# perc() converts to percent.

from sympy import Symbol as S
from sympy import Eq, Rational

from sympy.solvers import solve

def mgml(num): return Rational(num, 1000)
def perc(num): return Rational(num, 100)

def fix(eqs, **args):
    neqs = []
    for i, eq in enumerate(eqs):
        for k,v in args.items():
            eq = eq.subs(k, v)
    return neqs

# Let's define our equations.
eqs = [Eq( S('nicbase_volume') + S('zeronic_volume') + S('flavor_volume'), # = S('target_volume')), Eq( S('nicbase_concentration') * S('nicbase_volume') + S('zeronic_concentration') * S('zeronic_volume') + S('flavor_concentration') * S('flavor_volume'), # = S('target_concentration') * S('target_volume')), Eq( S('flavor_volume'), # = S('target_volume') * S('flavor_proportion'))] # Fix the concentrations of nicotine in each liquid. Mg/ml units. eqs = fix(eqs, zeronic_concentration=mgml(0), flavor_concentration=mgml(0), nicbase_concentration=mgml(20)) # Fix the desired target concentration. Mg/ml unit. eqs = fix(eqs, target_concentration=mgml(6)) # Fix the proportion of flavor to total volume. Percent (%) unit. eqs = fix(eqs, flavor_proportion=perc(5)) # Fix the target volume to tell the solver how many ml of liquid to make. Ml unit. eqs = fix(eqs, target_volume=20)
# Solve the equations! results = solve(eqs) if type(results) != list: results = [results] for n, result in enumerate(results): print "Result %s:" % (n + 1) if hasattr(result, 'items'): for k, v in result.items(): addendum = " ml" if str(k).endswith('volume') else "" try: print "%20s: %.2f%s" % (k, float(v), addendum) except TypeError: print "%20s: %s%s" % (k, v, addendum) else: if not results: print "No results."

If you'll note, in this program, we fix the concentrations of nicotine for each type of ingredient (the nic base in this example is set to 20 mg/ml) and then we fix both the desired concentration of the result (6 mg/ml) as well as how much flavor the result should have (5%) and, finally, the target volume (in this case, we say we want to make 20 ml — enough for a few days).

This program is about to compute the results of the equations defined with Eq.

Now hit Ctrl+Enter.

You should see, at the bottom, the results of this calculation.  Something like this:

Result 1:
      zeronic_volume: 13.00 ml
       flavor_volume: 1.00 ml
      nicbase_volume: 6.00 ml

Nice!  The program correctly solved the equations, and calculated that we need 13 ml of PG/VG, 6 ml of nicotine base at 1.8% (18 mg/ml) and, finally, a tiny squirt (1 ml) of flavoring.  Mix them up and you're ready to go.

Experiment with changing the program, directly in Reinteract, and hitting Ctrl+Enter to see your new results.  You can change the values of all the fixes — for example, upping the concentration of your base by changing the value of nicbase_concentration — or you can also try to fix a different target_volume to see the results change.  You are also not limited to fixing the target volume — for example, you can try fixing the nicbase_volume instead of the target_volume — that'll tell you how much of each ingredient to mix if you only have 10 ml of nicotine base to play with.

So what are we doing here?

We're just solving a system of equations that we defined first.  SymPy, which we installed before, is the code that is doing this magic of heavy lifting.  Once we have defined enough variables, SymPy can automatically merge and solve for the remaining variables.

The documentation for SymPy shows us that SymPy can do so much more.  If you have an interest in programming and math, I recommend you take a look at them.

Happy mixing!