Skip to content

Instantly share code, notes, and snippets.

@erget
Last active April 5, 2016 15:32
Show Gist options
  • Save erget/26a1cbafa855136671ecfacddcf3f03b to your computer and use it in GitHub Desktop.
Save erget/26a1cbafa855136671ecfacddcf3f03b to your computer and use it in GitHub Desktop.
GRIB packing precision
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Packing in GRIB\n",
"\n",
"Moin moin,\n",
"\n",
"Da die Problematik etwas komplexer ist, hab ich auf eine Notebook zurückgegriffen um die Thematik übersichtlicher und reproduzierbarer zu schildern.\n",
"\n",
"Ich glaube nämlich, die Daten, die du mir gegeben hast, sind in Ordnung. Die Werte, die ich nämlich beobachte, machen nämlich Sinn.\n",
"\n",
"## TL;DR\n",
"\n",
"Vorausgesetzt, ich liege richtig in der Annahme, dass deine GRIBs richtig kodiert sind:\n",
"\n",
"* Deine Daten sind richtig kodiert (glaube ich).\n",
"* ``decimalPrecision`` ist nur zum Schreiben - sie wird immer als 0 gelesen.\n",
"* ``packingError`` kann man stattdessen lesen, wenn man den Fehler einer Message ermitteln will - aber nicht schreiben.\n",
"\n",
"Das heißt, du musst nichts tun - du kannst die Daten so schreiben, wie du jetzt tust. Ausführlicheres unten, falls du jetzt noch interessiert bist ;)\n",
"\n",
"## Annahme: Die GRIBs sind OK\n",
"\n",
"Ich habe mir nur ein paar GRIBs angeschaut. Wir gucken in diesem Beispiel ``/e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2`` an. Das sieht für mich nach plausiblen Konzentrationswerten in kg * kg aus."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"max min avg sd skew kurt const \r\n",
"4.83444e-05 0 3.44253e-10 6.95785e-08 509.685 309977 0 \r\n",
"1 of 1 grib messages in /e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"\r\n",
"1 of 1 total grib messages in 1 files\r\n"
]
}
],
"source": [
"example_grib=/e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\n",
"grib_ls -n statistics $example_grib"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Aber dabei sehen die Packvariablen komisch aus, wie du angemerkt hast. Warum? Wir gucken gleich rein."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"referenceValue decimalPrecision numberOfBits decimalScaleFactor binaryScaleFactor \r\n",
"0 0 24 0 -38 \r\n",
"1 of 1 grib messages in /e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"\r\n",
"1 of 1 total grib messages in 1 files\r\n"
]
}
],
"source": [
"grib_ls -p referenceValue,decimalPrecision,numberOfBits,decimalScaleFactor,binaryScaleFactor $example_grib"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Was ist denn hier eigentlich los?\n",
"\n",
"Die Werte im GRIB sind - soweit ich erkennen kann - in Ordnung. Auch ``numberOfBits`` scheint richtig gesetzt zu sein. Aber ``binaryScaleFactor`` sieht sehr komisch aus. Wie interagieren also die Keys, die wir uns oben angeschaut haben?\n",
"\n",
"Beim Kodieren von GRIBs haben wir das übliche Tradeoff zwischen Präzision und Länge. Wir wollen, dass die GRIBs möglichst klein sind, aber die Werte mit der gewünschten Genauigkeit speichern. Dabei gilt:\n",
"\n",
"* ``referenceValue`` ist immer das Minimum\n",
"* ``decimalScaleFactor`` stellt man ein um die Genauigkeit der eingespeicherten Werte zu beeinflussen. Dabei gibt man an, wie die Werte im Dezimalsystem skaliert werden um die gewünschte Genauigkeit zu erreichen. Die GRIB API setzt dabei ``binaryScaleFactor``, damit man genügend Bits hat um den Wertebereich zwischen ``referenceValue`` und ``max`` darzustellen. Wenn man das setzt, hat man gleiche Genauigkeit zwischen GRIBs, aber eventuell unterschiedliche Größen.\n",
"* ``binaryScaleFactor`` gibt dementsprechend etwa ``numberOfBits`` vor. Setzt man das, so hat man eine garantierte Größe je GRIB, aber die Genauigkeit schwankt von GRIB zu GRIB, abhängig vom Wertebereich, die die Message darstellen soll. Wenn man diesen Hebel benutzt, stellt die GRIB API ``decimalScaleFactor`` ein, so dass das zu den Werten passt.\n",
"* Die Werte, die tatsächlich in die Message geschrieben werden, sind also positive Deltas zwischen ``referenceValue`` und dem darzustellenden Wert.\n",
"\n",
"ECMWF empfiehlt, ``decimalPrecision`` nach den fachlichen Anforderungen einzustellen und alles Andere von der GRIB API erledigen zu lassen. Analog dazu kann man - wie du es gemacht hast - ``numberOfBits`` einstellen. Hauptsache, man stellt nur eins ein - sie sind alle Hebeln, die sich beeinflussen und entsprechend des darzustellenden Wertebereichs zusammen arbeiten müssen.\n",
"\n",
"## Anwendungsbeispiel\n",
"\n",
"Dein GRIB hat ein ``max`` von 4.83444e-05. In GRIB werden Werte wie folgt kodiert:\n",
"\n",
"$$ y * 10^D = R + x * 2^{38} $$\n",
"\n",
"mit ``x`` als Eingangswert und ``y`` als dem Wert, der eigentlich ins GRIB kommt.\n",
"\n",
"In unserem Fall ist laut ``D`` (``decimalScaleFactor``) 0 und ``R`` (``referenceValue``) ist 0. Das mit ``R`` ist ganz richtig - ``min`` ist 0 - und ``D`` wird entsprechend der Werte eingestellt. Für dein GRIB haben wir also\n",
"\n",
"$$ y = x * 2^E$$ bzw. $$x = y * 2^{-E} $$\n",
"\n",
"Was passiert, wenn wir so 4.83444e-05 kodieren wollen? Dann haben wir konkret:\n",
"\n",
"$$ x = 4.83444 \\times 10^{-5} * 2^{38} \\approx 13288807 $$\n",
"\n",
"``E`` ist also genau richtig gewählt, um in den Wertebereich zu passen:\n",
"\n",
"$$ 2^{23} < x < 2^{24} $$\n",
"\n",
"Wäre ein anderer ``decimalScaleFactor`` gewählt worden, hätte man Genauigkeit opfern müssen, und ein Größerer hätte gar nicht gepasst.\n",
"\n",
"\n",
"## Warum also die Verwirrung mit den Keys?\n",
"\n",
"Es ist verwirrend, dass ``decimalPrecision`` 0 zurückgibt. Das liegt daran, dass ``decimalPrecision`` zum *schreiben* gedacht ist. Natürlich könnte die GRIB API das auch ermitteln und ausgeben, aber eigentlich wäre das unpräzise, da man von der binären Enkodierung auf Dezimalzahlen umsteigen würde. Würde man dafür den nächsten Zehnerpotenz nehmen? Was ist das Sinnvollste an der Stelle? Deswegen geben sie das genauer an, und zwar mit dem Key ``packingError``:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"referenceValue decimalPrecision numberOfBits decimalScaleFactor binaryScaleFactor packingError \r\n",
"0 0 24 0 -38 1.81899e-12 \r\n",
"1 of 1 grib messages in /e/uscratch/jfoerstn/Pavlof/ASHC_l69.grb2\r\n",
"\r\n",
"1 of 1 total grib messages in 1 files\r\n"
]
}
],
"source": [
"grib_ls -p referenceValue,decimalPrecision,numberOfBits,decimalScaleFactor,binaryScaleFactor,packingError $example_grib"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Der gibt schließlich an, wie genau die Werte in der Message wirklich sind.\n",
"\n",
"Ich gebe zu, es ist nicht ganz intuitiv. ``decimalPrecision`` kann man setzen, aber schlecht lesen. ``packingError`` gibt genaue Auskunft, man kann den Key aber nur lesen. Hier wünsche ich mir häufig, die GRIB API hätte so was wie Lesekeys und Schreibkeys, aber das ist nun mal die Bibliothek, die wir haben :)\n",
"\n",
"Ich hoffe, das macht das Ganze durchdringbarer!"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Bash",
"language": "bash",
"name": "bash"
},
"language_info": {
"codemirror_mode": "shell",
"file_extension": ".sh",
"mimetype": "text/x-sh",
"name": "bash"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment