Two Bad Solvents

Quick Start

One of the key uses of Hansen Solubility Parameters is in creating a good solvent from a blend of two bad solvents. This often works very well but sometimes results are disappointing. For the first time via stat therm we have a way to see what does and doesn't work. The app assumes some basic knowledge of KB theory and KBIs that you can read in other apps.

Credits

The app is based on Shimizu and Matubayasi's Synergistic Solvation as the Enhancement of Local Mixing, J Phys Chem, doi.org/10.1021/acs.jpcb.4c01582 .

Two Bad Solvents

χ0 A0 B0 Sol. Increase Max/1 Sol. Increase Max/2
Convert from ...
... to χ0calc
Calculated Data
//One universal basic required here to get things going once loaded
window.onload = function () {
    //restoreDefaultValues(); //Un-comment this if you want to start with defaults
    Main();
};
//Any global variables go here


//Main is hard wired as THE place to start calculating when input changes
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
    saveSettings();

    //Send all the inputs as a structured object
    //If you need to convert to, say, SI units, do it here!
    const inputs = {
        Chi0: sliders.SlideChi0.value,
        A0: sliders.SlideA0.value,
        B0: sliders.SlideB0.value,
        From: document.getElementById('From').value
    }

    //Send inputs off to CalcIt where the names are instantly available
    //Get all the resonses as an object, result
    const result = CalcIt(inputs)

    //Set all the text box outputs
    document.getElementById('Max1').value = result.Max1
    document.getElementById('Max2').value = result.Max2
    document.getElementById('ChiCalc').value = result.ChiCalc
    document.getElementById('Comments').value = result.Comments
    //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //plotIt is part of the app infrastructure in app.new.js
    if (result.plots) {
        for (let i = 0; i < result.plots.length; i++) {
            plotIt(result.plots[i], result.canvas[i]);
        }
    }

    //You might have some other stuff to do here, but for most apps that's it for CalcIt!
}

//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ A0, B0, Chi0, From }) {
    let SolCurve = []
    const x2Max = 1 / (2 * Chi0 - B0 / A0)
    let Comments = "x2Max = " + x2Max.toFixed(2) + ", B0 - 2A0χ0 = ", C = 0
    const Max = Math.exp(A0 / 2 * 1 / (2 * Chi0 - B0 / A0))
    const FS = From.trim().toUpperCase().split(/:| |;|,/)
    let Ns = []
    for (let i = 1; i < FS.length; i++) {
        if (FS[i] != "" && !isNaN(FS[i])) Ns.push(parseFloat(FS[i]))
    }
    let Conv = "Can't convert"
    if (FS[0] == "M") {
        if (Ns.length == 1) Conv = (2 * Ns[0]).toFixed(2)
        if (Ns.length == 2) Conv = (2 * Ns[0] - Ns[1]).toFixed(2)
    }
    if (FS[0] == "V") {
        if (Ns.length == 2) Conv = (2 * Ns[1] * Ns[1] / Ns[0]).toFixed(2)
    }
    if (FS[0] == "W") {
        if (Ns.length == 2) Conv = (2 * ((1 - Ns[1] * Ns[1]) / 2 + (1 - Ns[0]) / Ns[0])).toFixed(2)
    }
    const ChiCalc = Conv
    for (let x2 = 0; x2 <= 1; x2 += 0.01) {
        C = Math.exp(A0 * x2 + 0.5 * (B0 - 2 * A0 * Chi0) * x2 * x2)
        SolCurve.push({ x: x2, y: C })
    }
    const Max1 = Max.toFixed(2) 
    const Max2 = (Max / Math.exp(A0 + 0.5 * (B0 - 2 * A0 * Chi0))).toFixed(2)
    //Now set up all the graphing data detail by detail.
    Comments += (B0 - 2 * A0 * Chi0).toFixed(2)
    Comments += ", B0/A0 = " + (B0 / A0).toFixed(2)
    Comments += ", B0/A0+A0-2χ0 = " + (B0 / A0 + A0 - 2 * Chi0).toFixed(2)
    const prmap = {
        plotData: [SolCurve],
        lineLabels: ["RelSol"],
        hideLegend: true,
        xLabel: "x2&", //Label for the x axis, with an & to separate the units
        yLabel: "C/C0&", //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [0, 1], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'F2', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'F2', //F for Fixed, P for Precision, E for exponential
    };

    //Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot

    return {
        Comments: Comments,
        ChiCalc: ChiCalc,
        Max1: Max1,
        Max2: Max2,
        plots: [prmap],
        canvas: ['canvas'],
    };

}

        

The standard story from HSP is that if the HSP of a blend of two bad solvents is the same as that of a good solvent, the solute will be as soluble in the blend as it is in the pure solvent.

The idea is based on classic regular solution theory via Flory-Huggins χ parameters. It often works well, but we often get disappointing results. For reasons we shall see shortly, it's clear that the classic theory cannot explain why.

If we call the first solvent 1, the second 2 and the solute u and think things through using assumption-free statistical thermodyanmics we could attempt to measure 6 different KB parameters across the solubility range and understand good or bad results in terms of the balance of u-u, u-1, u-2, 1-1, 1-2 and 2-2 interactions. After a vast amount of work we could see in what ways the classic theory fails, given that it only understands u-u, u-M and M-M interactions (M is mean-field average of the two solvents). But that's too much work for most of us.

Instead, we fit the (relative) solubility curve, C/C0 across the range 0 < x2 < 1, where x2 is the mole fraction of solvent 2 and C0 is the concentration of u in pure solvent 1. The fit is via 3 parameters that are deeply rooted in assumption-free stat therm. Here's the equation:

`ln(C/C_0)=A_0x_2+1/2(B_0-2A_0χ_0)x_2^2`

From the parameters we can calculate the maximum solubility, relative to 1, and its x2 value.

`ln(C_(max)/C_0)=A_0/2(1/(2χ_0-B_0/A_0)) " at "x_2=1/(2χ_0-B_0/A_0)`

We also need to calculate the solubility with respect to solvent 2. Why two values? We are probably interested in starting with a specific solvent (greener, cheaper, ...) and getting more solubility via a co-solvent. If we used the (worse) co-solvent as our reference we will get a deceptively large solubility increase.

So now we have the key questions:

  • What can we do to get the maximum solubility boost?
  • How do we relate A0, B0, χ0 to the real world?

It's mostly about A0

All 3 parameters matter, but to get large increases, A0 is the best place to start. Or, to put it another way, when you don't get large effects from a solvent blend, it's mostly likely to be an A0 issues. If you happened to have lots of KB data (which is unlikely) you would be able to calculate it via:

`A_0=[c_1(G_(u2)-G_(u1))]_0`

The c1 term, the concentration of the pure solvent, is of some interest. Larger solvent molecules have a lower c1 (mol/l) so if you can choose 1 to be a smaller molecule, that helps. More precisely, a lower MVol is a distinct advantage; halving MVol doubles A0. The more interesting part is the comparison of the two KBIs Gu2 and Gu1 at low concentrations of 2 in 1. Let's unpack that. The KBIs tell us how much more of something (say 2) we have around something (in this case u) than we would expect from the average. If a lone 2 is strongly attracted to a u sitting in 1, then Gu2 will be large. If there's no strong attraction is will be small. Gu1 will always be small because there's so much 1 anyway, that it can't differ much from the average.

So, for strong synergy you need strong u-2 attraction. But wait, if it's a strong attraction, doesn't that mean that it's a strong solvent? No! When we have lots of 2 then there's a competition between u-2 and 2-2, and if the solubility is low then 2-2 is more powerful than u-2. So, to understand solvent blends we have to think how the 2nd solvent will interact with the solute in the presence of a large amount of 1. This is an unusual way of thinking, but if these effects could have been explained by normal thinking, we wouldn't have these puzzling failures of solvent blends when normal theory predicts success.

What about χ0?

The equation for χ0 involves 3 KBIs and is a Kirkwood Buff χ, capturing the difference between 1-1+2-2 interactions and 1-2 interactions, again at low concentration of 2:

`χ_0=[(⟨N_1⟩)/V(G_(11)+G_(22)-2G_(12))]_0`

The initial term is, again, a fancy concentration term which we can ignore, and we just look at mutual (in)compatibilities. Fortunately we don't have to measure the KBIs, we can derive χ0 from standard activity coefficient measures, often known for typical solvent pairs, via Margules, Van Laar or Wilson parameters. For example, if you just have a single Margules α then `χ_0=2α`. If you have 1 or 2 parameter Margules or 2 parameter Van Laar or Wilson, just type M:, V: or W: at the start of the Convert box then your parameters separated by a comma or a space, e.g. W:0.822, 0.0853 and press return - the calculated χ0 will appear.

It turns out that the maximum solubility enhancement over that in pure 1 is given by `A_0/2(1/(2χ_0-B_0/A_0))`. So, yes, χ0 is significant, but it also plays a role in how solubility changes from 1 to 2, and if solubility in 2 is much lower or higher, we have some different issues: if lower, why are we using it as it's unlikely to help much; if higher, why not use that as 1 and find a different co-solvent?

What about B0?

The formula for B0 shows some interesting new ideas:

`B_0=Ke^2⟨N_1⟩_u(χ_u+1)-⟨N_1⟩(χ_0+1)]_0`

Forgetting constants like Ke and ⟨N1⟩, this captures the difference of χ values of the solvents in the presence (χu) and absence (χ0) of the solute. In principle we could spend a lot of time thinking about what this means, but happily the B0value although important isn't as critical as A0 so we can note its existence and discuss the details if they turn out to be critical.

Getting the data

How do you get A0, B0 and χ0? We saw how to get χ0 from activity coefficient data. We get everything else by fitting the solubility data as we change x2. It turns out to be simple/efficient to fit to the plot of ln(C/C0), giving A0 and B0-2A0χ0 directly. Knowing χ0 independently, B0 can be extracted. That's great - deriving deep thermodynamic understanding from relatively simple solubility data. But it's not what most of us want.

Choosing the best two bad solvents

Knowing the HSP of the solute (or of the good solvent we wish to replace because it's no longer acceptable) and choosing one "not so good" solvent for reasons of cost, greenness etc. we might find a small range of "not so good" or bad solvents that, via simple mixing criteria, should give a good blend. How do we select the one most likely to give a large boost?

Because A0 is the single most important factor, think of the solute surrounded by Solvent 1 and then think which of your potential Solvent 2s will, at low concentration, show a strong attraction to the solute. This is especially easy if 1 is not very H-bonding, u likes H-bonding and a potential 2 offers H-bonding. When H-bonding isn't an obvious approach just think "from u's perspective, what does 2 have that 1 lacks?" If the answer is "not much" then the pair are unlikely to be much good. If the answer is something like "1 is dull, u is a bit like a polar aprotic molecule and 2 is polar aprotic" then you might be on to something.

Which brings us back to HSP. When trying to find an effective blend, it's often the case that you find one solvent that is lower in, say δD while higher in δP or δH, and automatically a solvent with the opposite tendencies will allow a good mixture to be created. Those are precisely the circumstances where the A0 effect might work. Blends of solvents that both lack distinctive features are less likely to provide the desired effect.

Co-nonsolvency

After release of the first version of the app, the question was asked whether co-nonsolvency was possible. The app, at that time, said "no" but that is because A0 was not allowed to go negative. After an update, you can show the effect. How common this is in reality remains to be explored.