Of the four stages in a TerraGear build, this is the one that goes wrong. Not because it is badly designed, because both of its traps look like something other than a failure. One looks like slowness. The other looks like success.
Failure one: it looks slow, it is stuck
You pass apt.dat.gz, because
that is what $FG_ROOT/Airports contains and because --help says
“Input files may be gzipped or left as plain text as required”.
What happens: the configuration banner prints, then nothing. One core at 100%, a few megabytes of memory, no output files, no error. It is reasonable to assume a world-scale airport database takes a while. It does not: this run was killed after 25 minutes and would not have finished.
The cause is two readers on one file. main.cxx:245 opens it with
sg_gzifstream, which handles gzip, and uses it for the version
check, so the .gz passes. The scheduler then reopens the same path
four times with a plain std::ifstream, which does not. It reads
compressed bytes as text, matches no airport record, never reaches the
end-of-file marker it is waiting for, and loops.
gunzip -k apt.dat.gz
genapts --input=apt.dat ...
Failure two: it looks finished, it is partial
This is the dangerous one. With several threads, the run ends early:
[ALRT]:general Error reading Index file .../w130n30/w123n37/chop.idx abort
corrupted size vs. prev_size while consolidating
Segmentation fault
Exit status 139. But the output directory is not empty: it holds real,
valid, loadable airports. Just not all of them. Nothing downstream complains,
tg-construct consumes what is there, and you get scenery with
airports quietly missing.
Every airport in a bucket writes the same chop.idx. Enough of
them at once and the writes interleave, the index is corrupted, the heap follows.
A single degree square is the worst case, because all its airports share one
bucket.
Forty-four runs of the same command, changing only the thread count:
--threads | Crashed | Airports written when it crashed | Time when clean |
|---|---|---|---|
| 1 | 0 / 8 | n/a | 19 s |
| 2 | 0 / 8 | n/a | 12 s |
| 4 | 0 / 8 | n/a | 11 s |
| 5 | 4 / 8 | varied | n/a |
| 6 | 0 / 8 | n/a | 11 s |
| 8 | 4 / 8 | varied | n/a |
| 10 | 12 / 12 | 0 to 24 of 31 | never |
It is a race, so those are probabilities and not a threshold; six came up
clean eight times while five and eight did not. What was consistent: plain
--threads, which takes your core count, failed every attempt on a
ten-core machine.
Use --threads=4, and check the exit status of
anything you script.
Running it once you know that
genapts --input=apt.dat --work=$WORK \
--min-lon=-123 --max-lon=-122 --min-lat=37 --max-lat=38 \
--threads=4
That produced 31 airports in 11 seconds: KSFO, KOAK, KPAO, KNUQ, KHWD, KHAF, KSQL, KCCR and 23 smaller fields, heliports and seaplane bases. A count of airports “in a square” is larger than a count of towered fields; most of those 31 are a single strip or pad.
Narrowing the work
genapts scans the whole input whatever your bounds; all 34,074
airports, 106 MB of text. Reading it is cheap: a bounding box over open
ocean, with no airport inside it, finishes in 0.55 s, and
that is the entire scan. The 19 seconds above were the 31 airports. Narrow the
region to narrow the work, not to skip the read.
--airport=KSFObuilds exactly one. The fastest way to check your setup works before committing to a region.--min-lon/--max-lon/--min-lat/--max-lattake every airport with a runway endpoint inside the rectangle.--start-id=abcdresumes from a given airport onward.
Where it looks for elevation
Airports have to sit on the ground, so it reads the terrain you prepared. It searches these subdirectories of the work directory, in order:
SRTM-1 SRTM-3 SRTM-30 SRTMGL1 SRTMGL3
Name your hgtchop output
as one of those, or pass --dem-path= explicitly.
--clear-dem-path empties the list first.
On the name
The binary is genapts. A good deal of documentation, including
the FlightGear wiki, calls it genapts850: after the 8.50 version of
the apt.dat format. That string occurs nowhere in the source tree, and has not
for as long as the git history goes back.