A walkthrough of one file

You downloaded this. Here is what it is.

Every cell of a 3,600 × 1,800 grid covering the whole planet, holding an estimate for 30 min on 30 September 2025.

3B-HHR.MS.MRG.3IMERG.20250930-S113000-E115959.0690.V07B.HDF5

When11:30 UTC30 Sep 2025
Processing levelLevel 3Gridded
LayoutGrida regular lattice
What is inside19 arrays10 of them are data

Nothing below assumes you have worked with satellite data before. Terms with a dotted underline carry their own definition. A panel on a tinted background was read out of your file or its name; a panel with an orange edge is an inference this guide made, flagged so you can check it.

Start
01

First, the unit you are holding

One file is a slice, not a dataset

A dataset is the record. A granule is one file out of it. Almost every confusing thing about Earthdata follows from that distinction.

NASA does not hand you a dataset. It hands you granules — the smallest slice it is willing to distribute. Download a year of this product and you have 17,520 files that are individually meaningless and collectively a scientific record.

This is the first thing that trips people up. You go looking for data and you get a file with a name like the one above, which is one slice out of a record running for years. The collection identifier names the whole record; the granule is one slice of it.

in your file

This granule covers 11:30:00 to 12:00:00 UTC on 30 September 2025 — 30 min.

00:0006:0012:0018:0024:00

One day of this product, sliced into 48 granules. Yours is the lit one.

Collection
GPM_3IMERGHH
Version
V07B
The full record
One file every half hour, without gaps. The Final run reaches back to January 1998 (extended from June 2000 in late 2024); Early and Late begin June 2000. Half a million granules and counting.
02

Second, the container

What kind of file is this, really?

HDF5, netCDF-4, HDF4 and GeoTIFF are containers, not data. Which one you have decides which software will open it.

The file extension is a label someone typed. It is not enforced by anything, and renaming a file does not change what is inside it. So the honest first question is: what container is this actually written in, and what will open it?

HDF5

yours

A filesystem inside a single file.

Holds folders (groups), arrays (datasets), and labelled notes attached to either (attributes). One file can carry a dozen variables, their coordinate axes, and a paragraph describing each, with no separate header to lose.

Opened by h5py, xarray, Panoply, HDFView, MATLAB, IDL

netCDF-4

HDF5 with the rules turned on.

Every netCDF-4 file is valid HDF5. The reverse is not true. netCDF-4 forbids some HDF5 features and requires coordinate axes to be declared a particular way, which is what lets xarray open a file and immediately know which dimension is time.

Opened by xarray, netCDF4-python, NCO, CDO, Panoply, QGIS

netCDF

The classic, flat version.

No groups, no compression, no nesting. Simple and extremely portable. Common for model output and station records.

Opened by netCDF4-python, xarray, NCO, CDO

HDF4 (legacy)

The previous generation. Not compatible with HDF5.

Despite the name, HDF4 and HDF5 are different formats with different libraries. Older MODIS and AIRS products still ship this way. If h5py refuses a .hdf file, this is why.

Opened by pyhdf, GDAL, HDFView

GeoTIFF

An image that knows where it is.

A raster with a coordinate reference system baked into its tags. Excellent in GIS software, awkward for anything with a time dimension.

Opened by GDAL, rasterio, QGIS, ArcGIS

HDF5
netCDF-4

Every netCDF-4 file is a valid HDF5 file. The reverse is not true, which is why a file can be perfectly well formed and still refuse to open in xarray.

in your file

Your file was opened twice: once through the HDF5 library and once through the netCDF-4 library. Both worked, which means xarray, Panoply, QGIS and the HDF5 tools will all read it without special handling.

03

Third, and most important

Nobody measured most of these cells

Level 3 means gridded. Gridded means an algorithm filled the space between what the satellites actually saw.

Here is the idea that changes how you read every number in this file.

Nobody measured the quantity in those 6,480,000 cells. Satellites do not see a grid. A satellite sees a swath — a strip of ground traced out underneath it as it orbits. Between one pass and the next, that patch of ground is not being watched at all. A grid covering the whole planet with no holes in it is something an algorithm produced from those strips.

the grid you were given what was actually observed

Two satellite passes over one grid. Everything the strips miss has to be filled some other way — which is the next chapter.

NASA labels how far a product has travelled from the raw signal. The number appears in the filename of almost every Earthdata product, and it is the fastest way to know what you are dealing with.

1724089113362205441782911687raw counts, in the order the instrument sent them

Level 0 — Raw

Instrument counts, straight off the downlink. Nobody outside the mission team works with these.

the same counts, now in physical units and pinned to the groundstill one pass, still curved

Level 1 — Calibrated and located

Counts converted to physical units and tagged with where and when the sensor was looking. Still organised by satellite pass, not by map.

a real one you could downloadGPM_1CGMI Brightness temperatures from the GMI radiometer on the GPM Core Observatory, along its own swath.

each sample turned into a quantity — rain rate, temperature, fireeverything off the track is still unknown

Level 2 — Retrieved

A geophysical quantity derived from Level 1, still laid out along the satellite's own ground track.

a real one you could downloadGPM_2AGPROFGPMGMI Rain rate retrieved from those temperatures — still only where GMI was looking.

one regular grid, no holessolid cells were observed; pale cells were filled in by the algorithm

Level 3 — Gridded

Level 2 from many passes and many satellites, resampled onto one regular grid over one fixed time window.

a real one you could downloadGPM_3IMERGHH This file. Every Level 2 retrieval from every satellite in the constellation, merged onto one grid.

a model has taken over; values now come from physics, not observation

Level 4 — Modelled

Output of a model that ingested observations. No longer a measurement of anything.

a real one you could downloadMERRA-2 A reanalysis: a weather model run backwards over the record, ingesting observations like these along the way.

Every panel shows the same stretch of ground. Step through the rungs to watch one satellite pass become a map.

what this means for you

IMERG stands for Integrated Multi-satellitE Retrievals for GPM. The name is the method: it takes what a constellation of satellites saw, and stitches it into one continuous rainfall field covering the whole planet, with no gaps.

No single satellite can watch everywhere at once. IMERG exists so that you can ask “how much rain fell here, then” without first working out which satellites happened to be overhead.

A cell reading 0.4 is the algorithm’s best estimate for that cell, not a reading from an instrument that looked at it. Some cells were observed directly seconds before the window closed. Others were last seen an hour ago and have been carried forward on modelled winds. The next chapter is how to tell which.

04

Fourth, how it was made

Your file shows its working

Every array in here is the output of a step. Knowing the steps is how you know what the numbers mean.

IMERG stands for Integrated Multi-satellitE Retrievals for GPM. The name is the method: it takes what a constellation of satellites saw, and stitches it into one continuous rainfall field covering the whole planet, with no gaps.

This is the part worth slowing down for, because the steps below are not background reading — several of them left their output in your file, in the arrays named beside them. Most people take the headline variable and never look. But if you want to know why a value is what it is, the working is right there.

  1. Passive microwave

    Radiometers on roughly a dozen satellites see through cloud and estimate rain rate directly. Best estimate available, but each satellite only passes over a given spot every few hours.

    visible in your file asMWprecipitationMWobservationTimeMWprecipSource

  2. Morphing

    Between passes, the last observation is pushed along using winds from a weather reanalysis, so a storm keeps moving on the grid even when nothing is watching it. The Early run can only push forward in time; Late and Final also interpolate backward from the next pass, which is more accurate.

    changes the other fields in place; leaves no variable behind

  3. Infrared fill

    Geostationary satellites watch continuously but only see cloud-top temperature, a weak proxy for rain. Used where microwave and morphing leave a gap.

    visible in your file asIRprecipitationIRinfluence

  4. Merge

    The sources are combined into one field, weighted by how trustworthy each is at that place and time. This is the finished product for the Early and Late runs.

    visible in your file asprecipitationUncal

  5. Gauge calibration

    Final run only. Once a month of ground rain-gauge records has been collected and quality-controlled, the merged field is adjusted to agree with it. This is why Final takes months to appear, and why it is the one to use for anything you publish.

    visible in your file asprecipitation

in your file

This granule is the Final version, published about 3.5 months after observation. Everything Late does, plus adjustment against ground rain gauges. Research grade, and the one to cite.

These versions are not corrections of each other and do not replace each other in the archive. They are different trade-offs between speed and accuracy, and mixing them in one analysis produces a discontinuity you will spend a day chasing.

AvailableWhat it is
Earlyabout 4 hours after observationForward morphing only, no gauge adjustment. Built for flood warning, where a number now beats a better number later.
Lateabout 14 hours after observationForward and backward morphing, still no gauge adjustment.
Finalabout 3.5 months after observationEverything Late does, plus adjustment against ground rain gauges. Research grade, and the one to cite.
05

Fifth, the label on the outside

The filename is a fingerprint

Every character is doing a job. Nothing in the name is arbitrary and nothing repeats by accident.

An Earthdata filename is not decoration. It is a structured record, and it is the only part of the file you can read without opening anything. Once you can decode it you can sort, filter and sanity-check a directory of ten thousand granules from the shell.

The catch: the key to reading it is not inside the file. It lives in a specification document on a different server, nowhere linked from the download page. That is the gap this whole exercise exists to close.

3B-HHRProduct and cadence
MSSource
MRGMerge
3IMERGAlgorithm
20250930Date
113000Start
115959End
0690Sequence
V07BVersion
HDF5Extension

Product and cadence 3B-HHR

3B is Level 3B. HHR is half-hourly, DAY is daily, MO is monthly. A trailing -E or -L marks the Early or Late run; Final carries no letter.

Source MS

MS: multi-satellite, as opposed to a single sensor.

Merge MRG

MRG: the sources have been merged.

Algorithm 3IMERG

The name of the algorithm that built this.

Date 20250930

Year, month, day. UTC.

Start 113000

Hours, minutes, seconds the observation window opens.

End 115959

The last second inside the window, not the first second of the next one - E115959 means the window runs through 12:00:00. Consecutive granules butt up without overlapping, and this guide adds the second back when it reports the duration.

Sequence 0690

Minutes elapsed since midnight. Redundant with the start time, which makes it a free consistency check.

Version V07B

Algorithm version. Variable names changed between V06 and V07, so older tutorials will mislead you.

Extension HDF5

The claimed container format.

Hover or tap a piece of the filename above.

in your file

Consistency check: the sequence field says 0690, and 11:30 is minute 690 of the day. They agree, so the name was assembled correctly.

06

Sixth, the stamp inside

The extension can lie; the opening bytes cannot

Renaming a file changes its label and nothing else. Formats identify themselves from the inside.

Every file format stamps its identity into its opening bytes. The stamp is written by whatever program created the file, and unlike the extension, it does not survive being renamed. Reading it is how a program knows what it is holding before it commits to a parser.

89‹‹
48H
44D
46F
0DCR
0ALF
1ASUB
0ALF

The opening bytes this format always writes, regardless of what is inside.

Bytes two through four spell HDF in plain ASCII, so a damaged file often still announces what it was trying to be. The bytes either side are deliberate traps: they are chosen to get mangled if the file crosses a connection that “helpfully” converts line endings, which turns a silent corruption into an obvious one.

in your file

The extension claimed HDF5. The opening bytes say HDF5. They agree, so the name is telling the truth.

07

Seventh, what else you need

One file is rarely the whole answer

Products come in families. The one you downloaded may be a piece of a set, and useless on its own.

Related products, before you write a loop. NASA splits products along lines that make sense to the production system and are invisible from the download page. Knowing which sibling you actually want saves more time than any amount of clever code.

GPM_3IMERGDF

The daily accumulation, built from these half-hours. Reach for it before you write a loop over 48 files.

GPM_3IMERGM

Monthly. No Early or Late variant exists, because a monthly product needs the gauge data that defines Final.

IMERG GIS (GeoTIFF)

The same estimates repackaged by PPS as GeoTIFF plus WorldFile, at 30-minute through monthly spans. If your destination is a map program, download this and skip the HDF5 entirely.

One boundary to respect: the V07 Final record stops in September 2025 while the upstream products move to V08, and a full V08 reprocessing of the record follows. Treat a version change exactly like a collection change — never mix versions in one analysis.

08

Opening it up

Inside is a folder tree

Groups, arrays and notes. Once you can see the shape of it, the file stops being opaque.

Open the container and you find something laid out like the folders on your computer. A group is a folder. Inside it are arrays. Attached to each array are attributes — short labelled notes saying what the array is and what to watch out for.

in your file

19 arrays in /Grid and /Grid/Intermediate: 10 data, 6 axes, 3 bounds.

ArrayKind TypeShapeUnitsDescriptionFill
IRinfluence /Grid/Intermediate data int161 × 3600 × 1800 Relative influence of infrared precipitation in the merged microwave-infrared precipitation estimate -9999
IRprecipitation /Grid/Intermediate data float321 × 3600 × 1800 mm/hr Infrared precipitation estimate -9999.9
MWobservationTime /Grid/Intermediate data int161 × 3600 × 1800 minutes Observed merged microwave observation time after dataset start time; formerly HQobservationTime -9999
MWprecipSource /Grid/Intermediate data int161 × 3600 × 1800 Observed merged microwave satellite source; formerly HQprecipSource -9999
MWprecipitation /Grid/Intermediate data float321 × 3600 × 1800 mm/hr Observed merged microwave precipitation estimate; formerly HQprecipitation -9999.9
precipitationUncal /Grid/Intermediate data float321 × 3600 × 1800 mm/hr Merged microwave-infrared precipitation estimate -9999.9
lat /Grid axis float321800 degrees_north Latitude at the center of 0.10 degree grid intervals of latitude from -90 to 90.
lat_bnds /Grid bounds float321800 × 2 degrees_north
latv /Grid axis int322 Number of latitude bounds.
lon /Grid axis float323600 degrees_east Longitude at the center of 0.10 degree grid intervals of longitude from -180 to 180.
lon_bnds /Grid bounds float323600 × 2 degrees_east
lonv /Grid axis int322 Number of longitude bounds.
nv /Grid axis int322 Number of time bounds.
precipitation /Grid data float321 × 3600 × 1800 mm/hr Complete merged microwave-infrared (gauge-adjusted) precipitation estimate; formerly precipitationCal -9999.9
precipitationQualityIndex /Grid data float321 × 3600 × 1800 Precipitation quality index; qualitative indicator of skill based on the microwave-infrared merging process -9999.9
probabilityLiquidPrecipitation /Grid data int161 × 3600 × 1800 percent Probability of liquid precipitation; estimated with a diagnostic parameterization using ancillary data -9999
randomError /Grid data float321 × 3600 × 1800 mm/hr Root-mean-square error estimate for complete merged microwave-infrared (gauge-adjusted) precipitation -9999.9
time /Grid axis int321 seconds since 1980-01-06 00:00:00 UTC Representative time of data in seconds since 1980-01-06 00:00:00 UTC. The calculation of time does not add leap seconds. The difference due to leap seconds grows with time and in 2019 is less than 30 seconds.
time_bnds /Grid bounds int321 × 2 seconds since 1980-01-06 00:00:00 UTC
09

The notes on the arrays

The sticky notes are the documentation

Units, descriptions, missing-data markers. This is the metadata everyone tells you to read, and here is what is in it.

The notes attached to an array are where a self-describing file earns the name. They are also where the traps are, because a note that is missing does not raise an error — software just carries on without it.

in your file

Every note attached to /Grid/Intermediate/IRinfluence, the largest data array in this file.

NoteValue What it is for
DimensionNamestime,lon,latWhich dimension of the array is which. Read this before you plot anything.
coordinatestime lon latWhich variables hold the latitude, longitude and time for this array.
_FillValue-9999The number written into cells with no estimate. Not a measurement; remove it before doing arithmetic.
CodeMissingValue-9999no standard meaning — product-specific
LongNameRelative influence of infrared precipitation in the merged microwave-infrared precipitatio…A sentence describing the variable, written for a human.
DIMENSION_LIST<3 HDF5 internal reference(s)>no standard meaning — product-specific
10

The one that catches everybody

−9999.9 is not a rainfall measurement

Every product has a way of being silently wrong. This is this product’s.

The algorithm cannot always produce an estimate. Those cells still need a number written into them, because the array is a rectangle and rectangles do not have holes. A fill value goes in: chosen to be so far outside the plausible range that nobody could mistake it for rain. It works right up until somebody calls .mean().

What the average becomes if you forget

Drag to change how much of the array has no estimate. Assumes a true mean of 0.12 across the cells that do have one.

Reported by a.mean() −4,000
After masking 0.12

No error is raised. No warning appears. You get a number and it has the right units.

in your file

10 data arrays declare a fill value. Here is what catches people who did everything else right:

What the documentation says -9999.9
What is actually stored -9999.900390625

These are 32-bit floating point numbers, and 32 bits cannot represent -9999.9 exactly. Writing a == -9999.9 matches nothing, masks nothing, and reports success. Compare with a tolerance instead.

fill = ds[path].attrs['_FillValue']
a = ds[path][:]
a = np.where(np.isclose(a, fill, rtol=0, atol=0.01), np.nan, a)
mean = np.nanmean(a)

No variable declares a valid_min or valid_max either, so you cannot mask by asking for “everything in the sensible range.” The exact fill value is the only handle available.

11

Onto a real map

Three maps walk in; one is right

A regular grid loads on the first try, which is the problem: wrong axis order and wrong row direction also load on the first try.

Sooner or later this file meets a map program. A gridded product is the easy case — a regular lattice is exactly what raster software expects — and that is precisely what makes it dangerous. The load succeeds either way. Whether the map is right depends on two conventions the software has to guess: which axis is which, and which way the rows run.

the same file, three loadsread as the docs describeaxes checked, rows top-downaxis order trusted blindly(time, lon, lat): sidewaysrow direction assumedbottom-up rows: flipped

Same granule, three loads. Only one of them is the planet.

Two specifics for this product. First, the grid is stored in (time, lon, lat) order — longitude varies along the first spatial axis, backwards from what raster tools expect, so a naive load renders sideways until you transpose. Second, common netCDF readers assume rows run bottom-up, which flips the world vertically. Neither raises an error; both produce a confident, wrong map. If your destination is QGIS or ArcGIS, skip the fight: PPS publishes a GIS-ready GeoTIFF version of every IMERG granule.

in your file

DimensionNames on /Grid/Intermediate/IRinfluence reads time,lon,lat — the axis order is written right there, which is exactly what a careful load checks first.

The tell is always geography. Before trusting any load, find one coastline you know and check it — a sideways or mirrored continent takes one second to spot and one line of code to fix, but only if you look.

12

When

The clock does not start in 1970

Time is a count of seconds since a reference date, and the reference is rarely the one your language assumes.

Time in a science data file is almost never a date. It is a count of seconds since some reference moment, and the reference is written in the array’s units string. Read the wrong reference and every timestamp you produce is confidently, consistently wrong. The one everyone assumes is 1 January 1970, the Unix epoch. Earth science products frequently do not use it.

in your file

The units string on /Grid/time reads:

seconds since 1980-01-06 00:00:00 UTC
Stored in the file 1,443,267,000
Counted from 06 January 1980
Correct answer 30 September 2025, 11:30:00 UTC
If you assume 1 Jan 1970 26 September 2015, 11:30:00 UTC out by about 10 years

Two more things to internalise while you are here. Everything is UTC, never local — a granule labelled 20:48 covers the evening in Lagos and the afternoon in Denver. And every product picks a convention for its end stamp: the last instant inside the window, or the first instant of the next one. Get it wrong and you double-count or drop a slice everywhere two granules meet. Where this guide knows the product’s convention it has already applied it — the times and durations shown above describe the true window, and the filename chapter explains the raw stamp.

13

House rules

Conventions, and which ones matter to you

Conformance checking sounds like paperwork. Some of it is. Some of it is the difference between a right and a wrong answer.

Now that you know what an attribute is, this will make sense. NASA publishes house rules — the DIWG recommendations — about how a data file should be built, so that software written by someone who has never seen your product can still read it. Alongside those sit the CF conventions, which fix the exact spelling of common attributes.

Files break these rules all the time, including files produced by NASA. That is not a scandal. What matters is which rule, because the consequences run from “a catalogue lists this slightly wrong” to “your average is off by three orders of magnitude.” Sorted that way, not by rule number:

Changes your answer

Reading the file the obvious way gives a wrong number, with no warning.

2.2

CF-compliant attribute names

Breaks the rule

Some attributes are capitalised ('Units', 'LongName') instead of the lowercase CF convention ('units', 'long_name'). CF-aware tools look for the lowercase names specifically, and won't error when they don't find them - they'll just treat the variable as if it carries no units or description at all. Some variables carry both the capitalised and lowercase version of the same attribute with matching values. Harmless today, but redundant fields are exactly what drifts apart when a file gets regenerated by a different code path later. Some variables don't declare a standard_name, so tools that look variables up by their CF standard meaning - rather than this file's own local name - won't find them. The variable still reads fine.

4.8

Fill value sits outside the valid range

Cannot be judged from this file

None of this file's variables say what their valid data range is, so there's nothing to compare the fill value against. This doesn't mean the file is wrong - it means the file gives you no way to confirm it's right. You still have to mask on the exact fill value, the way section 19 does, rather than on a range.

Breaks your tools

Something will refuse to open, refuse to decode, or run out of range.

2.1

Opens through the netCDF-4 interface

Follows the rule

This opens in both HDF5 and netCDF tools, so xarray, Panoply and most standard software will read it without special handling.

4.10

Time stored at double precision

Breaks the rule

Time is stored as int32 rather than double precision. Concretely: int32 maxes out at 2,147,483,647 seconds past the 1980-01-06 epoch, which lands on 2048-01-24. That's about 22 years out from this granule's own date. This granule's own stored value (1443267000) decodes to 2025-09-30 11:30:00 - correct today, just on a clock that eventually runs out of digits.

Neither

Worth knowing if you catalogue or cite this data. Otherwise ignore.

3.11

Date-time information in filenames

Follows the rule

The filename says this granule covers a 30-minute window starting 11:30 UTC on 30 Sep 2025. All times are UTC, not local.

3.8

Standardised file extension

Bends the rule, allowably

This is HDF5, so it will open fine - the extension just isn't the one NASA's own recommendation asks for. We opened it and confirmed it really is HDF5.

3.9

Filename carries dataset + release identifiers

Follows the rule

The filename identifies which dataset, which version, and when - so files from different releases can't be confused. Whether it's genuinely unique across the whole archive can't be determined from one file.

One habit worth taking away: when a tool says a file is non-conformant, the useful question is never is this bad. It is what would I have got wrong if nobody had told me. Most of the time the answer is nothing. Occasionally it is everything.

14

More than one file

The same product, packaged two ways

Checking a folder answers a question a single file cannot: is what you found true of this granule, or of the whole product?

One granule tells you about one granule. Run the same checks over a folder and a different question opens: does the answer change from file to file?

Mostly it should not. How a product is packaged is decided once, by the algorithm team, and applies to everything they publish. A row where every file agrees is telling you about the product. A row where they disagree is telling you that two different things are sitting in your folder.

in your folder

2 of 7 checks land differently across these 4 files. Only GPM IMERG files are compared here — a rule number means different things across products, so a mixed table would be meaningless. Different cadences of the same product are compared, because that is exactly where the interesting disagreements turn up.

3B-DAY-E.MS.MRG…-E235959.V07C.nc43B-DAY-L.MS.MRG…-E235959.V07C.nc43B-HHR.MS.MRG.3…59.0810.V07B.HDF53B-HHR.MS.MRG.3…59.0690.V07B.HDF5
2.1Opens through the netCDF-4 interfacesame
2.2CF-compliant attribute namesdiffers
3.8Standardised file extensionsame
3.9Filename carries dataset + release identifierssame
3.11Date-time information in filenamessame
4.8Fill value sits outside the valid rangesame
4.10Time stored at double precisiondiffers

Dwell on any row marked differs. It usually means mixed cadences or mixed containers — half-hourly HDF5 alongside daily netCDF-4, say. Same algorithm, same version, but written by different code, so they store time differently and spell their attributes differently. A loop that reads one correctly can quietly misread the other.