Files
nrlmsise00/scripts/generate-msis-cases.sh
T

118 lines
5.0 KiB
Bash
Executable File

#!/bin/sh
# Generates tests/fixtures/nrlmsise00-cases.json: the seventeen standard NRLMSISE-00 test
# cases, with inputs and outputs at full precision, for a port to be validated against.
#
# Fetches Dominik Brodowski's C translation of the NRL Fortran, compiles it with a driver
# that prints more digits than its own test does, runs it, and throws the source away. What
# is committed is the numbers, which are facts about the model rather than anyone's code.
#
# The model itself is the work of Picone, Hedin and Drob at the US Naval Research
# Laboratory. Needs a C compiler and network access; rerun it only to regenerate.
#
# Usage: scripts/generate-msis-cases.sh
set -e
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
out="$root/tests/fixtures/nrlmsise00-cases.json"
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
base="https://raw.githubusercontent.com/magnific0/nrlmsise-00/master"
echo "fetching the reference from $base"
for f in nrlmsise-00.c nrlmsise-00.h nrlmsise-00_data.c; do
curl -sS --fail --max-time 120 -L "$base/$f" -o "$work/$f"
done
digest=$(cat "$work/nrlmsise-00.c" "$work/nrlmsise-00_data.c" | sha256sum | cut -d' ' -f1)
echo "source digest $digest"
cat > "$work/driver.c" <<'DRIVER'
/* Prints the seventeen standard cases as JSON, at seventeen significant digits.
*
* The cases are those of the reference distribution's own test_gtd7, which varies one
* input at a time from a common baseline: day 172, 29000 s UT, 400 km, 60 N, 70 W, local
* solar time 16 h, F10.7 and its average 150, ap 4. Cases 15 and 16 use the seven-element
* ap history instead of the daily value, which is the mode a real propagation runs in. */
#include <stdio.h>
#include "nrlmsise-00.h"
int main(void) {
struct nrlmsise_output output[17];
struct nrlmsise_input input[17];
struct nrlmsise_flags flags;
struct ap_array aph;
int i, j;
for (i = 0; i < 7; i++) aph.a[i] = 100;
flags.switches[0] = 0;
for (i = 1; i < 24; i++) flags.switches[i] = 1;
for (i = 0; i < 17; i++) {
input[i].doy = 172; input[i].year = 0; input[i].sec = 29000;
input[i].alt = 400; input[i].g_lat = 60; input[i].g_long = -70;
input[i].lst = 16; input[i].f107A = 150; input[i].f107 = 150; input[i].ap = 4;
}
input[1].doy = 81;
input[2].sec = 75000; input[2].alt = 1000;
input[3].alt = 100;
input[10].alt = 0; input[11].alt = 10; input[12].alt = 30;
input[13].alt = 50; input[14].alt = 70; input[16].alt = 100;
input[4].g_lat = 0;
input[5].g_long = 0;
input[6].lst = 4;
input[7].f107A = 70;
input[8].f107 = 180;
input[9].ap = 40;
input[15].ap_a = &aph; input[16].ap_a = &aph;
for (i = 0; i < 15; i++) gtd7(&input[i], &flags, &output[i]);
flags.switches[9] = -1;
for (i = 15; i < 17; i++) gtd7(&input[i], &flags, &output[i]);
printf("[\n");
for (i = 0; i < 17; i++) {
printf(" {\"case\": %d,\n", i);
printf(" \"day_of_year\": %d, \"seconds_of_day\": %.17e,\n",
input[i].doy, input[i].sec);
printf(" \"altitude_km\": %.17e, \"latitude_deg\": %.17e, \"longitude_deg\": %.17e,\n",
input[i].alt, input[i].g_lat, input[i].g_long);
printf(" \"local_solar_time_h\": %.17e,\n", input[i].lst);
printf(" \"f107_average\": %.17e, \"f107\": %.17e, \"ap_daily\": %.17e,\n",
input[i].f107A, input[i].f107, input[i].ap);
printf(" \"ap_history\": %s,\n", i >= 15 ? "[100,100,100,100,100,100,100]" : "null");
printf(" \"densities\": [");
for (j = 0; j < 9; j++) printf("%s%.17e", j ? ", " : "", output[i].d[j]);
printf("],\n \"temperatures\": [%.17e, %.17e]\n", output[i].t[0], output[i].t[1]);
printf(" }%s\n", i == 16 ? "" : ",");
}
printf("]\n");
return 0;
}
DRIVER
cc -O2 -o "$work/driver" "$work/nrlmsise-00.c" "$work/nrlmsise-00_data.c" "$work/driver.c" -lm
mkdir -p "$(dirname "$out")"
{
echo "{"
echo " \"what\": \"The seventeen standard NRLMSISE-00 test cases, for validating a port.\","
echo " \"model\": \"NRLMSISE-00, by Picone, Hedin and Drob at the US Naval Research Laboratory\","
echo " \"reference\": \"$base, Dominik Brodowski's C translation of the NRL Fortran\","
echo " \"reference_sha256\": \"$digest\","
echo " \"generated\": \"$(date -u +%Y-%m-%d)\","
echo " \"generated_by\": \"scripts/generate-msis-cases.sh\","
echo " \"densities\": \"He, O, N2, O2, Ar, total mass, H, N, anomalous O. Number densities in cm^-3 and the total in g/cm^3, which is what the model returns unless its metric switch is set; convert at the boundary.\","
echo " \"temperatures\": \"exospheric, then at the altitude asked for, in K.\","
echo " \"cases\":"
"$work/driver" | sed 's/^/ /'
echo "}"
} > "$out"
python3 -c "
import json, sys
cases = json.load(open('$out'))['cases']
assert len(cases) == 17, len(cases)
print(f'wrote tests/fixtures/nrlmsise00-cases.json: {len(cases)} cases')
for c in (0, 3, 16):
d = cases[c]
print(f\" case {d['case']:>2}: {d['altitude_km']:>6.0f} km -> total mass {d['densities'][5]:.6e} g/cm^3\")
"