Non-diffusive atmospheric flow #14: Markov matrix calculations
This is going to be the last substantive post of this series (which is probably as much of a relief to you as it is to me...). In this article, we’re going to look at phase space partitioning for our dimension-reduced
Phase space partitioning
We need to divide the phase space we’re working in (the unit sphere parameterised by




In each case, the “compartments” of the partition are each of the same area on the unit sphere. For Partitions 1 and 2, we find the angle
where
Assigning points in our time series on the unit sphere to partitions is then done by this code (as usual, the code is in a Gist):
-- Partition component: theta range, phi range. data Component = C { thmin :: Double, thmax :: Double , phmin :: Double, phmax :: Double } deriving Show -- A partition is a list of components that cover the unit sphere. type Partition = [Component] -- Angle for 1-4-1 partition. th4 :: Double th4 = acos $ 2.0 / 3.0 -- Partitions. partitions :: [Partition] partitions = [ [ C 0 (pi/3) 0 (2*pi) , C (pi/3) (2*pi/3) 0 pi , C (pi/3) (2*pi/3) pi (2*pi) , C (2*pi/3) pi 0 (2*pi) ] , [ C 0 th4 0 (2*pi) , C th4 (pi-th4) 0 (pi/2) , C th4 (pi-th4) (pi/2) pi , C th4 (pi-th4) pi (3*pi/2) , C th4 (pi-th4) (3*pi/2) (2*pi) , C (pi-th4) pi 0 (2*pi) ] , [ C 0 (pi/2) 0 pi , C 0 (pi/2) pi (2*pi) , C (pi/2) pi 0 pi , C (pi/2) pi pi (2*pi) ] , [ C 0 (pi/2) (pi/4) (5*pi/4) , C 0 (pi/2) (5*pi/4) (pi/4) , C (pi/2) pi (pi/4) (5*pi/4) , C (pi/2) pi (5*pi/4) (pi/4) ] ] npartitions :: Int npartitions = length partitions -- Convert list of (theta, phi) coordinates to partition component -- numbers for a given partition. convert :: Partition -> [(Double, Double)] -> [Int] convert part pts = map (convOne part) pts where convOne comps (th, ph) = 1 + length (takeWhile not $ map isin comps) where isin (C thmin thmax ph1 ph2) = if ph1 < ph2 then th >= thmin && th < thmax && ph >= ph1 && ph < ph2 else th >= thmin && th < thmax && (ph >= ph1 || ph < ph2)
The only thing we need to be careful about is dealing with partitions that extend across the zero of
What we’re doing here is really another kind of dimensionality reduction. We’ve gone from our original spatial maps of
We can now use this discrete data to construct empirical Markov transition matrices.
Markov matrix calculations
Once we’ve generated the partition time series described in the previous section, calculating the empirical Markov transition matrices is fairly straightforward. We need to be careful to avoid counting transitions from the end of one winter to the beginning of the next, but apart from that little wrinkle, it’s just a matter of counting how many times there’s a transition from partition component
transMatrix :: Int -> SV.Vector Int -> (M, Int) transMatrix n pm = (accum (konst 0.0 (n, n)) (+) $ zip steps (repeat 1.0), ns) where allSteps = [((pm SV.! (i + 1)) - 1, (pm SV.! i) - 1) | i <- [0..SV.length pm - 2], (i + 1) `mod` 21 /= 0] steps0 = map (\k -> filter (\(i, j) -> i == k) allSteps) [0..n-1] ns = minimum $ map length steps0 steps = concat $ map (take ns) steps0
Once we have
splitMarkovMatrix :: M -> (M, M) splitMarkovMatrix mm = (a, s) where s = scale 0.5 $ mm + tr mm a = scale 0.5 $ mm - tr mm
We can then calculate the
Let’s look at the results for the four partitions we showed earlier. In each case, we’ll show the
For partition #1, we find:
For partition #2:
For partition #3:
And for partition #4:
So, what conclusions can we draw from these results? First, the results we get here are rather different from those in Crommelin’s paper. This isn’t all that surprising–as we’ve followed along with the analysis in the paper, our results have become more and more different, mostly because the later parts of the analysis are more dependent on smaller details in the data, and we’re using a longer time series of data than Crommelin did. The plots below represent that contents of the




We’re only going to be able to draw relatively weak conclusions from these results. Let’s take a look at the apparent dynamics for partitions #1 and #2 shown above. In both cases, there is a highly significant flow from the right hand side of the plot to the left, presumably mostly representing transitions from the higher probability density regions on the right (around
I’ll freely admit that this isn’t terrible convincing, and for partitions #3 and #4, the situation is less clear.
For me, one of the lessons to take away from this is that even though we started with quite a lot of data (daily
It’s difficult to tell, but if I was doing this analysis “for real”, rather than just as an exercise to play with data analysis in Haskell, I’d probably do two additional things:
Use a truncated version of the data set to attempt to the replicate the results from Crommelin (2004) as closely as possible. This would give better confidence that I’ve not made a mistake.
Randomly generate partitions of the unit sphere for calculating the Markov transition matrices and use some sort of bootstrapping to get a better idea of how robust the “significant” transitions really are. (Generating random partitions of the sphere would be kind of interesting–I’d probably sample a bunch of random points uniformly on the sphere, then use some kind of spring-based relaxation to spread the points out and use the Voronoi polygons around the relaxed points as the components of the partition.)
However, I think that that’s quite enough about atmospheric flow regimes for now...