Time Sketch #4: Calculating People Receiving Sunlight

Rovelli in his book “The Order of Time” spent a whole chapter talking about how there is no “one present”. Each point in the universe move through space in their own time and has their own “present”. But in practice, we as humans have observed this “one present” ever since we can observe time.

We know that at any point, roughly half of the surface of the earth is receiving sunlight, while the other half is blanketed by darkness. One may assume, that at any one time, half of the world’s population is receiving sunlight, while the other is not. But the world’s population is not distributed evenly. We, humans, have a tendency to gather together, forming cities. I wanted to create a tool to measure how many people are receiving sunlight at any given time.

General Workflow

Here are the steps I used to calculate the number of people receiving sunlight at any given time:

  1. Split the earth into a 360 by 180 “grid” where each cell is the size of 1-degree longitude by 1-degree latitude, and calculate how many people are residing in each cell.
  2. Figure out which cells are receiving daylight at any given time.
  3. Calculate the number of people receiving daylight by adding up the population on the cells that receive daylight.

Step 1 – Gathering Population Data

Fortunately, I happened upon NASA’s Dataset of Gridded Population of The World. However, the dataset is extremely large (it’s a 3.5 GB CSV file). It would take a long time to calculate if I am to use this dataset directly. So I had this idea of aggregating the data into a 360 by 180 “grid” where each cell is the size of 1-degree longitude by 1-degree latitude, and calculate how many people are residing in each cell.

I used the Node.js script below to aggregate the data:

const Fs = require('fs');
const CsvReadableStream = require('csv-reader');
const AutoDetectDecoderStream = require('autodetect-decoder-stream');

let inputStream = Fs.createReadStream('source.csv')
  .pipe(new AutoDetectDecoderStream({ defaultEncoding: '1255' })); // If failed to guess encoding, default to 1255

// The AutoDetectDecoderStream will know if the stream is UTF8, windows-1255, windows-1252 etc.
// It will pass a properly decoded data to the CsvReader.

const result = [];
for (let i = 0; i < 180; i++) {
  const row = []
  for (let j = 0; j < 360; j++) {
    row.push(0)
  }
  result.push(row)
}

let n = 0
inputStream
  .pipe(new CsvReadableStream({ parseNumbers: true, parseBooleans: true, trim: true, asObject: true }))
  .on('data', function (row) {
    n++
    const population = row['UN_2020_E']

    if (population > 0) {
      const lng = Math.floor(row['CENTROID_X'])
      const lat = Math.floor(row['CENTROID_Y'])
      const lngIdx = lng + 180;
      const latIdx = -lat + 90;

      result[latIdx][lngIdx] += population
    }
  }).on('end', function (data) {
    console.log(JSON.stringify(result, null, 2))
  });

Using this method, I was able to reduce down the 3.5 GB CSV file into a 400KB JSON file, and reduced the lookup time from over 3 minutes to mere milliseconds.

Step 2 – Generate a GeoJSON Polygon of Darkness in the Earth

So before I could calculate the population, I first need to know which section of the earth is receiving sunlight at any given time.

Thankfully, someone did this for me already. I found a GitHub repository of someone creating a night-time overlay on Google Maps API v3. Through some complex math that I don’t particularly understand, they were able to calculate the exact position where the sun is perpendicular to the earth at any given time. Using that point, they then calculate where the centroid of the “darkness” is. Then they used that position to cast a circle on the surface of the earth’s sphere using some rudimentary geometric calculation.

I adapted their code a little bit because I wanted to use GeoJSON format instead of Google Map’s API. I mainly used turf.js to perform the necessary transformations.

Here’s the javascript module that I ended up with to obtain a GeoJSON polygon of where the earth is experiencing darkness.

Step 3 – Calculation

I was yet again lucky enough that turf.js has a helper method called booleanPointInPolygon which determines whether or not a geographical coordinate exists within a GeoJSON polygon.

This makes it relatively easy for me. All I had to do then is to just iterate over all the cells and add up the population of the cells where it doesn’t fit inside the darkness polygon. Here’s the javascript module that I ended up with.

Caveats

Since the data is aggregated on a 1-degree longitude by 1-degree latitude grid, there was some level of resolution loss. The earth rotates 1-degree every four minutes, and at the equator, it amounts to about 100 kilometers. Therefore the largest cell would be about 10,000 kilometers squared.

Result

As I’m writing this at 8:47 PM, Oct 19th, 2020, there are roughly 4,036,211,821 people experiencing daylight. It consists of half of North America, half of Asia, and all of Australia.

I will use this library for my midterm project which is an interactive visualization of sunlight all over the world.

Leave a Reply

Your email address will not be published. Required fields are marked *