Where Can Pregnant Women Go?

metadata

Recently I travelled to Colorado with a pregnant woman. The NHS guidance on exercise in pregnancy says:

Don’t exercise at heights over 2,500m above sea level until you have acclimatised: this is because you and your baby are at risk of altitude sickness.

This led to some interesting discussions, particularly because a lot of Colorado is above 2,500m ASL due to the fact that the Rocky Mountains run straight through the state. One day, whilst visiting Rocky Mountain National Park we found a valley that was less than 2,500m ASL (specifically Moraine Park at 8,160ft ASL or 2,487m ASL) but the road to the valley briefly went over 2,500m ASL. In the end, we decided to still drive to the valley but it got me thinking: how common is it for there to be places that are less than 2,500m ASL but which you cannot access on land/water without going over 2,500m ASL to get there? Obviously you could cheat by flying there in a pressurised cabin - but that isn’t a fun programming project.

To solve this problem I wrote WCPWG (Where Can Pregnant Women Go?), which uses FORTRAN for the hardcore searching and Python for data conversion and pretty output. The basic method is:

  1. load elevation data provided by the GLOBE project
  2. set the top-left corner (the North Pole) as ‘accessible’
  3. loop over all pixels and set them as ‘accessible’ too if they are less than or equal to 2,500m ASL and if one of the (up to) eight surrounding pixels is also ‘accessible’
  4. continue looping over the world until no more pixels are marked as ‘accessible’

This method can be seen in action in the animation below. You can see that the first pass (which goes left-to-right scanning down each column one-by-one) finds most of the accessible places in the world and that subsequent passes just refine some very particular places (the north-western edge of the Tibetan Plateau is perhaps the most obvious).

Download:
  1. 512 px × 256 px (0.1 Mpx; 17.0 KiB)
  2. 1,024 px × 512 px (0.5 Mpx; 30.9 KiB)
  3. 2,048 px × 1,024 px (2.1 Mpx; 55.0 KiB)
  4. 2,160 px × 1,080 px (2.3 Mpx; 57.4 KiB)

Pretty quickly it became apparent that it was going to take ages to find all of the accessible places. You can see that the first pass found the vast majority of the accessible places, but that some nooks and crannies were going to take an awfully long time to converge. It seemed silly to keep on scanning the whole world if only a few small places weren’t yet converged. I therefore wrote a second version that split the world up into small tiles and iterated each one separately. I still needed a global pass to ensure that accessible regions could cross across tile boundaries, but it certainly seemed to help. The convergence of the two different strategies can be downloaded: the CSV file for global-only and the CSV file for global and tiled.

I then wrote a simple Python script to plot the CSV files (shown below).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

#!/usr/bin/env python3

# Use the proper idiom in the main module ...
# NOTE: See https://docs.python.org/3.11/library/multiprocessing.html#the-spawn-and-forkserver-start-methods
if __name__ == "__main__":
    # Import special modules ...
    try:
        import matplotlib
        matplotlib.rcParams.update(
            {
                       "backend" : "Agg",                                       # NOTE: See https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
                    "figure.dpi" : 300,
                "figure.figsize" : (9.6, 7.2),                                  # NOTE: See https://github.com/Guymer/misc/blob/main/README.md#matplotlib-figure-sizes
                     "font.size" : 8,
            }
        )
        import matplotlib.pyplot
    except:
        raise Exception("\"matplotlib\" is not installed; run \"pip install --user matplotlib\"") from None
    try:
        import numpy
    except:
        raise Exception("\"numpy\" is not installed; run \"pip install --user numpy\"") from None

    # Import my modules ...
    try:
        import pyguymer3
        import pyguymer3.image
    except:
        raise Exception("\"pyguymer3\" is not installed; you need to have the Python module from https://github.com/Guymer/PyGuymer3 located somewhere in your $PYTHONPATH") from None

    # **************************************************************************

    # Create figure ...
    fg = matplotlib.pyplot.figure()

    # Create axis ...
    ax = fg.add_subplot()

    # Load data and plot it ...
    i, n = numpy.loadtxt(
        "createMask1.csv",
        delimiter = ",",
            dtype = numpy.uint32,
         skiprows = 1,
           unpack = True,
    )
    ax.plot(
        i,
        100.0 * n.astype(numpy.float64) / 43200.0 / 21600.0,
        label = "global-only",
    )

    # Load data and plot it ...
    i, n = numpy.loadtxt(
        "createMask2.csv",
        delimiter = ",",
            dtype = numpy.uint32,
         skiprows = 1,
           unpack = True,
    )
    ax.plot(
        i,
        100.0 * n.astype(numpy.float64) / 43200.0 / 21600.0,
        label = "global and tiled",
    )

    # Configure axis ...
    ax.grid()
    ax.legend(loc = "lower right")
    ax.set_xlabel("Step Number")
    ax.set_xlim(0, 200)
    ax.set_ylabel("Fraction Of Dataset That Is Accessible [%]")

    # Configure figure ...
    fg.tight_layout()

    # Save figure ...
    fg.savefig("convergence.png")
    matplotlib.pyplot.close(fg)

    # Optimize PNG ...
    pyguymer3.image.optimize_image(
        "convergence.png",
        strip = True,
    )

              
You may also download “convergence.py” directly or view “convergence.py” on GitHub Gist (you may need to manually checkout the “main” branch).

As you can see in the plot below it was going to take ages to find them all if I did not split the world up into tiles every step.

Download:
  1. 512 px × 384 px (0.2 Mpx; 22.8 KiB)
  2. 1,024 px × 768 px (0.8 Mpx; 57.2 KiB)
  3. 2,048 px × 1,536 px (3.1 Mpx; 147.6 KiB)
  4. 2,880 px × 2,160 px (6.2 Mpx; 124.0 KiB)

The FORTRAN program created a nice map of the mountains in Colorado (shown below). You can see all of the places that are forbidden in red and accessible in green. If you look very carefully on the eastern edge of the Rockies (just to the west of Denver and Boulder) there are one or two orange pixels - these are places which are less than 2,500m ASL but which cannot be accessed by land/water without going over 2,500m ASL. There is a particularly large orange region on the west of the Rockies (north-east of Glenwood Springs).

Download:
  1. 512 px × 512 px (0.3 Mpx; 94.3 KiB)
  2. 1,024 px × 1,024 px (1.0 Mpx; 245.0 KiB)
  3. 2,048 px × 2,048 px (4.2 Mpx; 533.9 KiB)
  4. 2,700 px × 2,700 px (7.3 Mpx; 291.0 KiB)

These orange regions are perhaps more easily observed in the black-and-white plot below.

Download:
  1. 512 px × 512 px (0.3 Mpx; 27.2 KiB)
  2. 1,024 px × 1,024 px (1.0 Mpx; 70.5 KiB)
  3. 2,048 px × 2,048 px (4.2 Mpx; 170.1 KiB)
  4. 2,700 px × 2,700 px (7.3 Mpx; 141.9 KiB)

Finally, when I looked at the whole world as a 43,200 px × 21,600 px (933.1 Mpx) image (which is included at the very bottom of this blog post) one region jumped out in particular: Salar de Atacama. This is a large salt flat in the Atacama Desert and it is the largest salt flat in Chile. The average elevation is about 2,300m ASL which means that the surrounding mountains don’t have to be that much taller for it to be blocked off and marked as inaccessible. You can see this clearly in the plot below.

Download:
  1. 512 px × 512 px (0.3 Mpx; 146.9 KiB)
  2. 1,024 px × 1,024 px (1.0 Mpx; 479.3 KiB)
  3. 2,048 px × 2,048 px (4.2 Mpx; 1.2 MiB)
  4. 2,700 px × 2,700 px (7.3 Mpx; 1.2 MiB)

Or perhaps even more easily in the black-and-white plot below.

Download:
  1. 512 px × 512 px (0.3 Mpx; 131.1 KiB)
  2. 1,024 px × 1,024 px (1.0 Mpx; 435.5 KiB)
  3. 2,048 px × 2,048 px (4.2 Mpx; 1.1 MiB)
  4. 2,700 px × 2,700 px (7.3 Mpx; 1.1 MiB)

In conclusion, there are a few places in the world that are less than 2,500m ASL but which are not accessible without going over 2,500m ASL if you are travelling by land/water. Most of these are tiny, with the odd exception of a valley or two in a high mountain range such as those found in Colorado. The largest contiguous region by far that is inaccessible is the Salar de Atacama in Chile with an area of around 3,000km2. For completeness I have included the two different types of maps for the entire globe below:

Download:
  1. 512 px × 256 px (0.1 Mpx; 11.8 KiB)
  2. 1,024 px × 512 px (0.5 Mpx; 30.8 KiB)
  3. 2,048 px × 1,024 px (2.1 Mpx; 83.3 KiB)
  4. 4,096 px × 2,048 px (8.4 Mpx; 227.3 KiB)
  5. 8,192 px × 4,096 px (33.6 Mpx; 633.8 KiB)
  6. 43,200 px × 21,600 px (933.1 Mpx; 681.8 KiB)
Download:
  1. 512 px × 256 px (0.1 Mpx; 456.0 B)
  2. 1,024 px × 512 px (0.5 Mpx; 1.3 KiB)
  3. 2,048 px × 1,024 px (2.1 Mpx; 4.8 KiB)
  4. 4,096 px × 2,048 px (8.4 Mpx; 15.3 KiB)
  5. 8,192 px × 4,096 px (33.6 Mpx; 46.8 KiB)
  6. 43,200 px × 21,600 px (933.1 Mpx; 123.2 KiB)

As a curious aside: this exact same algorithm could be used to answer the question of “which valleys wouldn’t be filled in by water if the sea level rose by 2,500 metres”; stay tuned …