If it were me, I'd write the transpose of this loop for better striding and vector lengths on the assumption that the number of phases is (much) smaller than the number of cells (we only really support two or three phases).  Something along the lines of
```C++
std::vector<double>
convertSaturations(const std::vector< std::vector<double> >& sat)
{
    typedef std::vector< std::vector<double> >::size_type sz_t;

    const sz_t np = sat.size();
    const sz_t nc = sat[0].size();

    std::vector<double> s(nc * np);

    for (sz_t p = 0; p < np; ++p) {
        const std::vector<double>& sat_p = sat[p];

        for (sz_t c = 0; c < nc; ++c) {
            s[c*np + p] = sat_p[c];
        }
    }

    return s;
}
```
This gives "`np`"-strided access to the destination (`s`), but as `np` is small, I'm betting that advanced branch prediction and similar technologies will reduce the cost of computing the induction variable.  On the other hand, we won't really know until we measure...

Note: I initially outlined an implementation using iterators but the overall syntax became too wordy and grotesque so I went back to using indices.