Showing posts with label Wind. Show all posts
Showing posts with label Wind. Show all posts

August 10, 2022

Weather Engine

Way back when I first started coding up this project (several years ago now), one of the first things I implemented was Alexis' weather generator.

It works pretty well. Working with real-world data as the seed input is easy. I've extended the system a little bit to make it more versatile throughout the year.

The only bits of data I need are: minimum and maximum monthly temperature in Fahrenheit (high and low), and the months in which the high occurs. I also collect high and lows for the precipitation (in mm) and the month in which that high occurs.

"climate": {
	"temperature": {
		"minimum": {
			"high": 77,
			"low": 47,
			"highMonth": 7
		},
		"maximum": {
			"high": 89,
			"low": 62,
			"highMonth": 7
		}
	},
	"precipitation": {
		"high": 126,
		"low": 70,
		"highMonth": 7
	}
}

With these numbers, it's a simple enough matter to fit a sinusoidal curve to give me the monthly average high and low for any given month. Admittedly, very few places on earth have a perfectly balanced summer/winter cycle, but this can be forgiven, and the players are unlikely to notice in any case (particularly across such a relatively small area).

A whole year of temperatures

I've incorporated a few extra bits into my version of the weather engine. The first is apparent temperature. At higher temperatures (80F+), high humidity makes the air seem hotter. This is usually reported as Heat Index. Conversely, when the air is cold, wind can make it feel even colder (Wind Chill).

Next, I used a IDW algorithm (my go-to) to spoof data for all hexes based on just a few inputs. I grabbed a few stations from around the State, but with this method, I don't need to worry about researching all 170+ points.

On one of the original weather posts, Vlad made a comment about how much rain it generates. These are some good thoughts for possible mods. I don't see that problem cropping up at the moment, but it's something I'll keep an eye on.

As another potential update, I could use a Gaussian distribution to generate the temperature for each day, or calculate the daily drift differently. But for now this works well.

July 22, 2020

Wind VIII: Over the Land to Skye

Once we have established the wind pattern over the sea, we can determine the effect that the topography has on those winds.

First, I get a list of all winds blowing on or near the coasts. For each of those, I take the projected vector of the wind onto each neighboring hex. If the angle of the projected vector is $<90^\circ$, I know that it's at least in the right direction to catch a bit of that wind.

From there, I determine $dh$, which is the difference between the heights of the two hexes, source and target. If $dh$ is downhill ($dh<0$), there's no change. Otherwise, the turnaside angle $\theta$ is calculated as \[\theta = \frac{90 \exp\left(r \cdot \mathit{dh}\right)}{90 + \left(\exp\left(r \cdot \mathit{dh}\right) - 1\right)}\], where $r=2\log(89)/5000$ is calculated such that the wind will be totally turned aside $90^\circ$ when the slope is 5000 ft or more.

This is one of those areas that I've still not managed to tweak completely to my satisfaction, but it will be good enough to use for precipitation.

Angle of wind vectors (not speed) in summer

Wind VII

I'm looking over my old code and wondering what on earth I actually did to make this work.

Or whether it worked at all.

Allegedly, I used a curl function to boil the pressure down into a wind value (wind rotates around pressure centers, this makes sense). But I had gotten that initial pressure from a hand-drawn map on GIMP, and that's what I'm trying to get away from in this latest attack.

I tried to fiddle with getting the gradient but the implementation of a discrete gradient on a hex grid was somewhat problematic. However, this value may be useful later on in determining the length of the wind vector - winds on a steep pressure gradient will naturally be stronger.

The angle is another matter. This is where I really thought the gradient would help (and maybe it would on a different grid or even map layout). I ended up doing something much simpler: "walk" around the edge of the major pressure cells, correcting for direction based on the Coriolis effect, then (predictably) use IDW to fill in the rest of the map.

a quarter million objects has more of an effect on performance than you might think

For now, I am not box-blurring these values, so the transitions are still a little choppy. My plan is to apply the effect of the topography on the wind vectors and then smooth it out, so that everything lines up more nicer.

June 27, 2020

All Together Now

As I revisit my generation process from top to bottom (as I do every few quarters), it might be helpful to have a flowchart or at least a process list, both for my own reference and the general welfare of the public.
  1. Terrain generation, either from code or manually input (do not recommend)
  2. Derive currents by a) determining major trade currents at 0 and 45 latitudes, b) extending these currents and splitting them where they hit landforms, and c) interpolating these currents via IDW to make a nice smooth surface. I also have found that d) applying a Gaussian smooth filter to the results is even nicer.
  3. Assign sea surface temperature (SST) and measure the effect of the currents on that temperature: currents from the poles bringing cooler water down to the equator and vice versa.
  4. Generate areas of high and low pressure
  5. From the pressure map, obtain wind direction and speeds
  6. Determine the effect of topography on wind
  7. Apply base precipitation and use the on-shore winds to blow that moisture across the continents
  8. Use the coastal current temperatures and on-shore winds to determine areas of coastal climate influence
  9. Apply base temperature, then modify it according to the coastal climates
  10. Lapse the temperature up mountain slopes
  11. Run Koppen and Holdridge algorithms
At this point, social simulation can take over.

November 26, 2018

Wind VI: Wind Pun

Getting the wind model to work is the easy part.

Figuring out what parameters to use is the hard part.

One issue that I ran into last time is the fact that if wind starts going in the same direction from a bunch of sources, simple vector addition can add up fast.

That's because I've been treating my wind collisions as elastic collisions. There are two major kinds: elastic and inelastic. In an elastic collision, no energy is lost to heat, etc. So two (or more) winds enter a hex, one wind leaves. The following formula is used:
\[m_0 v_0 + m_1 v_1 + \cdots + m_n v_n = m_f v_f\]
This is essentially what we've been doing, in two dimensions, treating all masses as equal (even the final mass). Because I'm ignoring masses, this isn't really a physically correct description of an elastic collision.

The other option is inelastic. I think this is better, because we can think of the input winds "sticking" together into a new mass of air. This is not how fluids really mix, however, but it will be good enough. This formula is (ignoring masses again):
\[v_f = {v_0 + v_1 + \cdots + v_n \over n}\]
Which is simply the average.

So let's try a few combos of parameters. \[g\] is the ratio of decrease between each successive push, and \[z\] is the slope change (in feet) at which the wind is deflected by 45 degrees.

g=0.7, z=5000, elastic
g=0.7, z=5000, inelastic
g=0.7, z=2500, inelastic
g=0.8, z=2500, inelastic
g=0.9, z=2500, inelastic
g=0.99, z=2500, inelastic
Overall, the inelastic collision seems much more accurate. I also need to take a look at the downhill slope speed increase, which is not set for these simulations. The wind is still modulating into bands of 60 degrees, even with Gaussian blurring. Scott has trouble with straight bands, I have trouble in an additional dimension!

Also, I need to develop some better representation for topography. The heightmap is huge overkill here, but its difficult to see the effect of altitude when height is not shown at all. Something for a rainy day (of which there are many upcoming).

November 21, 2018

Wind V: Clearer Winds

As often happens, I'll publish an initial post on some subject, then add bells and whistles on to my code, then post the "finished" product with a few quips, and expect the audience to have insight into the chaos of my workflow.

So I've decided to put the wind model down on blog-paper, at least to make it clearer to myself and others. I was inspired by Here Dragons Abound, who also revisited his wind model and arrived at the same method that I did (just with better pictures)! So this post is essentially the same, just with some different words and pictures, for my own reference.

Getting the initial wind values at the coast was the easy part, really. But what to do once I have them?

Ideally, I could use some kind of iterative finite element method to solve for the flow across the surface. But that's pretty complicated and if I can find something simpler, I will.

There are a few things to keep in mind as we create this model.

  • Wind slows as it drags across the ground
  • Wind picks up speed when going downhill and slows uphill
  • Wind is turned aside by mountains
So there are (in the most simple representation) 3 parameters that can be tuned. I'll call them $g$ for ground drag, $s$ for slope change (where $\Delta$ can represent the different in height of the hexes), and $\theta(\rho, \Delta)$ for the change in direction by a mountain (or hill, etc), where $\rho$ is the sensitivity of the wind.

Let's begin with a single wind vector.

The basic method of propagation is along the vector projection of the direction between the two hexes. I refer you to this diagram from the post on tectonics. We are interested in the $d_{\perp f}$ vector.


Projecting the vectors:

One downside of this approach is that eventually, every initial vector gets binned into one of the 6 hex directions, so the wind map becomes much more West Marches-esque, with strictly defined angles in increments of 60 degrees. But let's propagate each of these three resultants.

Next, we add the vectors (simply adding the $x$ and $y$ components) for E and B.

And of course, E and B will project onto D, and so on. But I'll ignore that for now.

So what about mountains, or other obstacles? How much is it affected? Let us assume that A represents a high mountain at 10,000 ft, and that the other hexes are 1 ft. We can then define $\theta$ in terms of $\Delta$ as:
\[\theta = {90 \exp\left(\rho\Delta\right) \over 90 + \left(\exp\left(\rho\Delta\right) - 1\right)}\]

The value $\rho={\ln(89) \over 5000}$ indicates that the wind is turned aside 45$^\circ$ at a slope of 5000 ft. So for our Mountain A, it will be 89$^\circ$. I have no idea what number will work best here. The relative direction of change is to the right in the northern hemisphere, and to the left in the southern hemisphere.

And so it continues (I haven't actually propagated A out fully).

As far as picking up speed goes, I have $s = g$ if $\Delta < 0$ else $1$. But I want to do some tweaking of this anyway (I also see a lot of stuff that I want to update/clean up, just from going through this exercise). I've been using $g = 0.946$ after my initial experiments.

So the final model for the effect of wind from Hex 0 to Hex 1 (where $h_{01}$ represents the vector from 0 to 1):
\[w_{01} = g \cdot s \cdot {w_0 \cdot h_{01} \over |h_{01}|^2} h_{01} + \angle \theta(\rho, \Delta)\]
I guess that looks kinda complicated. If you can't wow them with facts, dazzle them with bullshit.

There is also a choice to be made in the algorithm for propagating vectors. Either we can view this as an expanding frontier, where the next set of hexes to be solved is defined by where the vectors in the current frontier are pointing (projection is only ever positive for 3 hexes at most), or we can fully propagate each vector from each source (which are all coastal hexes) and then average them at the end. Right now I'm using source-propagation since its a little faster, but I'd like to take another look at frontier-propagation.

I'll save the good stuff (the actual application on the map) for another post.

September 26, 2018

Wind IV: Rain I: Water is Wet

So I've gotten the wind working more or less how I want. Now I need to push water (in the form of rain) across the landscape.

The initial inputs are observed from the current influences. Cold currents are dry, mild currents are half-wet, and warm currents are the wettest. These begin at the coasts. Then, based on the wind map, the rain moves across the landscape. It drops more water (and exhausts itself faster) when a positive slope is encountered.

Some of the code isn't working exactly like I want it. There are too many straight lines here, but overall I'm able to avoid a lot of ad hoc, and in the end, that's on the right track.

July
January

The wind is altered both by the existing terrain and by the natural winds which are the sole product of the pressure zones. These are the default where nothing else exists. Eventually, though, the air runs out of moisture, leading to the large arid areas in the center of the larger continents.

September 19, 2018

Wind III: Swirls

I needed to redo the wind algorithm, but I want to avoid solving the Reynolds equation over the surface, because that's dangerously close to my real-world research.

So instead of pushing it along hex vector directions, I propagate each wind cell to every neighbor, and then add the vectors in inelastic collisions.

This puts me on the right track, but there's still something missing. For one, the code is ignorant of the hexmap layout, and so it's unaware that there are 60 degree turns at the folds, and the equator is also a problem (notice the big black splotch below). However, I'm getting much more simulated flow this time, and so I think I'm close.

I'm also using a box blur here on the values to make them smoother. If you do this a few times, it approximates a Gaussian blur, so that's easy to do. I'm not sure if I'll stick with this for the final iteration or just use it for display.


Another interesting effect is that the wind dies out going up a mountain slope, but increases to gale-like proportions on the other side. Hm. Some experimentation will be necessary but I can tweak that after I fix the actual propagation.

August 31, 2018

Winds II: Better Winds

Inverse distance weighting is working well. So I decided to apply it to the sea winds as well. It gives nice smooth interpolation, even if there are some places that are a bit odd. But that's ok. Nothing is perfect...yet.


Once both season (hot and cold) have been calculated, I can use the areas near the coast to define the boundary conditions for the existing land wind model. For the coastal currents only, I've categorized them as cold, hot, or mild. These aren't absolute values, just relative ones. This feeds into the precipitation model, which will be used to give better results for erosion. I'm waiting to put the finishing touches on the erosion model until I can staple these parts to it.

August 6, 2018

Wind I: Spirit of the Wind

I love what Here Dragons Abound did with wind. I want to do that, perhaps adding it to my pressure model.

Mainly, this will help with my move away from hand-drawing the rain. If I know where the wind is blowing, I can model the rain, yielding better results.

Once again, the primary source of my frustration is the sector rotation. It's hard to think in polar coordinates sometimes.

I applied a constant wind at an angle of 135$^\circ$, just for testing. The velocity is 25 knots, which is pretty high. I found a source showing a sea breeze strength of a max of 5 knots. No matter.

There are a few more rules for spreading the wind across land:
  • Every time a wind is propagated, it loses 10% of its strength
  • If it goes downhill, it gains some of that back depending on the slope
  • If it goes uphill, it's deflected up to 90 degrees. I use a logistic function to make a nice smooth transition, using $K=90$, $P_0 = 1$, and $r={\ln(89)\over 2400}$. The rate is one of the settings I'm playing with to get a good result. The 2400 is the change in altitude where the deflection angle is 45$^\circ$. So if I want winds to make it higher up a slope, I make this number bigger.
  • I talked about vector projection/rejection here, and I found that the best model for the wind is to use this to project the wind along the direction of the target hex. This "splits" the wind between the three hexes it's pointed toward the most.
  • Everything gets added up using vector notation. At first I thought this propagated stuff forward too much but it seems ok after a few bugs were worked out. And I'm not using real data so that can affect things.


The wind barb notation shows the direction and strength of the local wind:


It's off to a good start. I'm going to think a bit more about the pressure systems so that maybe I can figure out how to integrate those into the model. There's also much tweaking to be done to get results I'm happy with.

Once that's done, I can move on to pushing moisture around.