Wednesday, March 28, 2018

Fantasy Weather: How to Create a Temperature Algorithm in Just 16 Easy Steps!

Or at least I'm going to tell you how I did it for THE ALMANAC of FANTASY WEATHER.

I'm not a computer programmer. The last (and only) programming language I learned was Fortran, as a college sophomore in 1982. (Yes, Fortran. Is it still around?) But I've always enjoyed working with numbers and logic puzzles. So, I've ended up spending a fair amount of time "programming" in Microsoft Excel. I'm not an expert, nor even close, but I've learned enough Excel to help me do what I want to do for both my real-world job and gaming projects.

I also knew almost nothing about weather or climate science (at least in any formal, courses-in-school way) before beginning the SEVEN YEARS of FANTASY WEATHER and THE ALMANAC of FANTASY WEATHER projects.

In a sense, this post is a companion post to my Editing Batten post of a few years ago. It tracks the progress of an amateur (or more accurately, quasi-ignoramus) in "learning" a new thing.

I don't want to sound falsely modest. I do think I am pretty good with numbers. But as far as I can tell, 80%+ of OSR people are pretty  good (or better than pretty good) with numbers. My impression is that many of you are IT or programming people. One of my favorite gaming blogs - Delta's D&D Hotspot - is written by a professional mathematician.

As with Batten, what's notable is not that I did it, but that I did it. Or to put it another way, If I did it, then you can probably do it, too. We're all nerds here.

Whether you would ever want to do it is, of course, another question...    

The problem: Given a particular real-world model - say, Jerusalem - create an algorithm for realistically simulating the temperature for 365 days or 730 twelve-hour day/night periods over the course of a typical year.

1. Find a data source. For temperature, I used Weatherbase and Weather Spark almost exclusively. Most online weather data sources feature both the Fahrenheit and Celsius temperature scales. I used Fahrenheit for all data entry and internal calculations, but presented the temperature using both scales on the actual weather charts. Here is some of the data from Weatherbase:

And here is some of the data from Weatherspark:

I should note that the overall weather data would often differ from source to source. The average number of days with precipitation was notoriously variable, for example,  presumably because the definition of "precipitation" differed from site to site (and many sites wouldn't explicitly tell you which definition they used). However, for temperature  this wasn't a huge problem.

2. Determine base temperature ranges and probabilities for each season or month. I began, following the suggestions in Lisa Cabala's 1988 Dragon magazine article, "Weathering the Storms," with three seasons - Winter, Summer and Spring/Fall - each broken down into four sets of ranges. Here is what I started with for a "South Temperate Coastal Hot" climate type, similar to that of Jerusalem:

But in redesigning SEVEN YEARS of FANTASY WEATHER to create THE ALMANAC of FANTASY WEATHER I made things more granular - in this case, going from seasons to months, and from four ranges to eight ranges - and made the data specific to the location I was trying to model:

The lows and highs were taken from Weatherbase, but the ranges within the percentile chances were taken from the Weatherspark charts for the middle day of each month, using the values at the time of day that contained the peak day temperature. "Eyeballing" the values for the shades was initially annoying, but after a while I got pretty fast at it. 

3. Smooth things out. As you can see, unsurprisingly, the ranges can shift up or down pretty dramatically from month to month. For example, they shift up about 8 points or so from April to May. Rather than have these shifts suddenly happen, so to speak, on the 1st of each month, I smoothed these transitions from "peak" - the middle of each month - to peak. You just take the difference between peaks and divide them by 30 or so to get the incremental change for each day. If you think about it, one problem with this method is that it might smooth things out too much - a peak is not necessarily the same as an average. I'll talk about how I addressed that problem in #16, below. Here are the smoothed numbers for the first five days of January for Jersusalem:

Why are the lows (0.0) here 10° higher than the lows under "Lowest Recorded Temperature" in the Weatherbase data? Because, these are the base day temperatures. The evening temperatures will be, for January, an average of 10° points lower.

Why is the first "1/1" cell red, and what is that "J" and "x" in the upper right-hand cells? Don't ask. My "programming" is filled with that sort of cryptic stuff. I often forget myself what some of it means myself. 

4. Determine how "sticky" the base temperature is. Generally temperature doesn't suddenly "re-set" every 12-hours. You might get a sudden major rise or drop, but on average you don't. Early on, I settled on a 90% "stickiness chance." That is, as you go from one 12-hour period to the next, there is a 90% chance that the base temperature will remain the same and a 10% chance it will re-set. This means that a particular base temperature phase will last an average of 5 days. Of course, even if the base temperature does re-set after, say, 5 days, this might not be noticeable - it might re-set to a value close to the previous one. So even in climes and seasons with quite wide potential temperature ranges, relatively consistent warm or cold spells might persist for some time.

Is 90%, or an average of 5 days, realistic? I have no idea - whatever "realistic" might even mean in the context of this sort of model. But it seemed about right.

5. Determine the relationship between day and evening temperatures. In virtually every climate, the day temperature is on average higher than the evening temperature, though, how much it might be higher, on average, will depend on climate and season. Weatherspark provides the average high (day) and low (eve) temperature averages for each day throughout the year. In Jerusalem, these high and lows differ by anywhere from 10° in the Winter to 18° in the Summer. In other words, if the afternoon temperature reaches, say, 90° F for a particular day in July, it will, on average, drop to a low of 72° F during the coldest part of the evening. This is, again, an average, however - the algorithm randomly determines a different actual variance each time. I settled on a variance (from the variance) of 20%. That is, the actual variance will be between 80% and 120% of the average variance. Thus, in July, the temperature might drop anywhere from 14° to 22° from day to evening. Of course, it won't always drop, since it's possible the temperature might re-set to a higher base during the transition from day to evening, an increase potentially higher than the average day/eve decrease. But this will be infrequent.

6. Add a completely random variance to the base. I went back and forth between 1° and 2°, and I think I settled on 1°. (Weirdly, 2° made things look too swingy to me.) That would mean a base of 80° F could yield an actual temperature with whopping variance of anywhere from 79° F to 81° F. Why go to the trouble of doing this since this would obviously have virtually no effect on play? Well, so the charts would look more "realistic," of course - like real weather as opposed to made-up weather, and thus trick the reader into thinking it was real. Here, as in many other places, "realism," for me, would actually mean "apparent realism."  

7. Add an additional quasi-random small "step" cycle to the base. In the real-world, you often notice small up or down temperature trends over the course of days. It's not quite a random-walk, in that once you've started to go up or down, there's a greater chance that you will continue than that you will stop or reverse. But a stop or reverse is always possible, and once you get to a peak of 3 or 4 above or below the trend line, you go back in the other direction. This adds further variance and "apparent realism" to an otherwise constant base.

Here is a (very rainy) first nine days of January. Can you tell which temperature changes happen around the same base and which are "re-sets"?

8. Add in the possibility of "exogenous" shocks. In the real world, sometimes particularly cold or hot years are completely random within the internal parameters of the system. But other times, some external factor - sunspots, ash from a volcano, etc. - will shift the whole system one way or another. In THE ALMANAC, every 50 days there's a chance for such a shock, which at the limit could move the ranges up or down by as much as 8° (though 8° would be very rare). Like the base temperature, these shocks have a 75% chance of sticking from one 50-day phase to the next. Also, as with base temperature, the shocks are often not shocks - the transitions are smoothed - though occasionally they are.

I thought it would be fun to indicate on the charts whether a particular month or year was unusually cold or hot. The player-characters or NPC inhabitants of the area would presumably know this, and it might prompt adventure or plot hooks perhaps involving higher level NPC's, monsters or even gods messing around with things.

Or it could just be sunspots. 

9. Optional: Create ceilings or floors for record highs and lows. This is sort of a question of taste, but in THE ALMANAC, once you get to within 3 or 4 points of a record high or low for the month (based on real-world weather data often going back many years), a mechanism kicks in that will randomly re-assign you to a point also within 3 or 4 points of that high or low but in a manner that makes actually hitting the high or low less likely than getting a few points from it. That's a confusing way of saying that if you have ceilings and floors, you don't want temperatures to "bunch up" at the identical extremes. This would look odd and "unrealistic" on the charts.     

10. Determine temperature minimums and maximums for precipitation events. This is a basic insight, and it's sort of obvious, but as with many otherwise obvious things, I was alerted to it by David Axler's Dragon article, "Weather in the World of Greyhawk". I initially cribbed the values from Axler, but would later modify some of them. The idea is that you always have a chance for precipitation event - determined by the climate type and month - but the range of which precipitation events you might get will depend on the temperature. 

Thus, it needs to be at least 30° F for Drizzle, 40° F for a Gale and 55° F for a Cyclone. It must be below 35° F for a Light Snowstorm and below 20° F for a Light Blizzard. For Light Fog, it has to be between 30° F and 70° F. For Freezing Rain or Sleet, it has to be between 25° F and 35° F. And so on:

11. Make sure that the temperature won't exceed the maximums or fall below the minimums during the precipitation event. Many precipitation events only last a few hours, and thus will only take up one 12-hour period, but some will last longer. You don't want to temperature to suddenly shoot up to 50° F during a blizzard.

12. Create a mechanism for possibly lowering the temperature if a particular precipitation event happens. This is different from 10, above. The idea is that temperature is the base engine that influences everything that happens - from precipitation to windspeed. If the temperature is 100° F, you can still get a rainstorm, but that rainstorm would then lower the temperature - at least while it was raining. I went around and around on this, and had a difficult time finding information for how this worked in the real world. But it just seemed sensible that rain would "cool things off," somewhat. Can it be 100° F during a rainstorm? 90° F? 85° F? I came up with some values but am still not sure whether they were "realistic".

Also, as with #10, above, you have to come up with a way to "fuzz" things, otherwise any lowered temperatures will bunch at the maximums and look dumb.    

13. Create the possibility of temperature shifts - warm fronts or cold fronts - caused by or associated with precipitation events. This is different from 12 - not a temporary shift in apparent temperature, but an actual change in the base. In THE ALMANAC, there's a 50% chance that "mild" precipitation events - Drizzle, Light Rainstorm, etc. - will cause the base temperature to shift up 1 to 3 steps, and "harsh" events - Thunderstorms, Blizzards - will cause the temperature to shift down by 1 to 3 steps. I think this is quasi-realistic, based on the information I could find.

Writing this into the algorithm was tricky for me as it potentially created circular references (utter doom in Excel) - temperature determining possible precipitation which in turn possibly determined temperature - but eventually I figured it out. To be honest, I don't remember how.

Here's a case where a Light Rainstorm rode in on a (minor) warm front:

14. Add in wind-chill. In the Introduction to SEVEN YEARS of FANTASY WEATHER: Indea, I argued against this, but then I changed my mind, perhaps due to suffering through another unpleasant Chicago Winter - a Winter (still not over) made much more unpleasant by the wind. But I thought it would be too fussy to put two temperatures - the actual one and the "feels like" wind-chill one - on the chart. Thus, my wind-chill measurement is hidden, but it does determine the "C" rating - C-1, C-2 and C-3 - for rating the effect of cold temperatures. The effects of wind-chill are particularly noticeable in the Southern Mountains:

15. Add humidity and a heat-index. The internal algorithm for THE ALMANAC of FANTASY WEATHER generates relative humidity for each 12-hour period, based on the climate type, temperature, season, cloud cover and precipitation status. But, as with wind-chill, I decided it would be too busy to list relative humidity on the charts, except in a general way on the yearly summaries. But the relative humidity does help to determine my own heat index, represented, as with cold, with three ratings - H+1, H+2 and H+3 - on the charts. Along with temperature and relative humidity, the rating also incorporates wind speed - which at very high temperatures may actually make things feel hotter - as well as sun intensity. Thus, cloud cover could go both ways - more clouds might mean more relative humidity, but they also might mean that direct sunlight is less intense.

16. Adjust the monthly weather ranges to approximate the desired averages. Because of the peaks vs. averages thing and the sometime bias caused by the warm and cold front adjustments, as well as other factors - some of which remained admittedly somewhat opaque to me - the average monthly temperature averages I ended up with for a particular climate template were sometimes "off" the real-world model averages (as listed on Weatherbase) by a number of degrees. (The average averages were taken from 80 simulated years. Don't worry - once you set things up, simulating up to eight years at a time takes about five  seconds.) Here, I suppose, was another place where it's unlikely anyone would have noticed or cared, but it still bugged me. To have gotten this far, so to speak, and then to end up with, say, February off by an average of 6° was annoying. Fortunately, the problem was easily fixed by simply adding a constant (a plus or minus value) to the original monthly temperature ranges.

There's something satisfying about designing a completely artificial simulation which nevertheless appears to get the averages, as well as the highs and lows, variance frequencies and so on, right or at least apparently right.

Maybe I need to get out more.

Here is the final product - January of Year 1 for "Jerusalem":

As I mentioned in the Introduction of THE ALMANAC, while Climate Template 101: Southern Temperate may have been modeled on Jerusalem, it ended up diverging from the model in a few significant aspects. Perhaps most obviously, I added a coastal cyclone season in the Fall.

Did those violent cyclones (or those gales caused by Storm Giants or the occasionally marauding cluster of possibly malign whirlwinds, etc.) kill all of the meticulously averaged averages previously mentioned? Actually, they didn't:

See, for fantasy weather Year 1, the average temperature in Temperate South is 60° F, while Weatherbase tells us that the average temperature for Jerusalem is - oh, damn!

61° F.

It must have been one of those exogenous factors.    


  1. Not gonna lie, I wasn't too impressed with the "Seven Years of Fantasy Weather," but this... this is brilliant. This is worth paying for. I will be mining this for everything it's worth. (And if there's a way I can contribute, please let me know.)

    1. No, thanks! I really appreciate your feedback!

      I think some found the "historicity" of SEVEN YEARS to be annoying, while others liked it. Though, really that was more a question of tone or marketing than anything else.

      And I did make what I thought were various improvements here and there.

      But by far the greatest difference is one of length/diversity - 10 climates x 8 years in ALMANAC versus 1 climate x 7 years in SEVEN YEARS. You get roughly four times the weather for your dollar, as well as the ability to cover a world-spanning area. So, I assume that's what you are referring to?

    2. Maybe.

      I bought Seven Years, opened it up and started going through the tables... and put it down, thinking, "Yeah, this isn't going to help me."

      I think what I was looking for is a means of creating my own weather system. The thing is, weather is rather difficult to account for. You can have vast territories where the weather is largely homogenous ~ take the great plains of America ~ and you can have smaller areas where the weather is different just over the next hill ~ which pretty much describes the whole Appalachian region.

      The Almanac would certainly offer more options, but it's the methodology that will help more than anything else.