Static, pure catalog of GNSS analysis centers and the rules that turn a product specification into a canonical filename and a full archive URL.
Everything here is deterministic and network-free: GPS-week and day-of-year arithmetic, the IGS long-name filename convention, and the per-center archive layout. The fetch pipeline derives all network hosts and cache filenames from this module, which is what keeps the layer safe against SSRF (only known hosts are ever contacted) and path traversal (cache names come only from a validated canonical filename).
Analysis centers
Each center maps to a transfer protocol (:https or :ftp), an archive host,
the product token it publishes, and the directory layout for each content
type. Only centers and paths that resolve against a live, anonymous archive
are listed; every entry below has been checked against its server.
| Code | Center | Protocol | Host |
|---|---|---|---|
:gfz | GFZ Potsdam (operational rapid) | HTTPS | isdc-data.gfz.de |
:cod | CODE / University of Bern (MGEX) | FTP | gssc.esa.int |
:grg | CNES/CLS (MGEX, final) | FTP | gssc.esa.int |
:wum | Wuhan University (MGEX, final) | FTP | gssc.esa.int |
:igs | IGS combined (broadcast / IONEX) | FTP | gssc.esa.int |
The ESA Galileo Science Support Centre (gssc.esa.int) mirrors the IGS/MGEX
archive over anonymous FTP and is the source for the MGEX precise products,
the merged broadcast navigation file, and the global ionosphere maps. GFZ's
own HTTPS server (isdc-data.gfz.de) carries its operational rapid SP3/CLK.
Content types and what each center serves
:sp3,:clk— precise orbits and clocks.:gfz(operational rapid),:cod,:grg,:wum(MGEX). The GFZ token isGFZ0OPSRAP; the MGEX tokens areCOD0MGXFIN,GRG0MGXFIN,WUM0MGXFIN.:nav— the IGS merged multi-GNSS broadcast navigation file (BRDC00IGS_R_..._MN.rnx). Only:igspublishes it.:ionex— the global ionosphere TEC map (..._GIM.INX).:igsserves the combinedIGS0OPSFINmap;:codservesCOD0OPSFIN. IONEX cadence is sub-daily, so the default sampling is01H/02H, not01D.
Filename conventions
Precise products and IONEX follow the IGS long-name convention
AAAVPPPTTT_YYYYDDDHHMM_LEN_SMP_CNT.EXT (e.g.
GFZ0OPSRAP_20201760000_01D_15M_ORB.SP3). Broadcast navigation uses the
RINEX long-name SSSSMRCCC_R_YYYYDDDHHMM_LEN_CNT.fmt with no sampling
field and a lowercase extension (e.g. BRDC00IGS_R_20201770000_01D_MN.rnx).
Summary
Functions
The set of hosts the layer is permitted to contact.
Build the full, compressed (.gz) archive URL for a product.
Build the canonical IGS long-name filename for a product.
Look up a center's static definition.
Human-readable center name, or nil if the code is unknown.
All supported analysis-center codes.
The content-type descriptor (%{code:, ext:, kind:}) for a content type.
All supported content-type codes.
The day-of-year (001–366) for a calendar date.
The GPS day-of-week for a calendar date (0 = Sunday … 6 = Saturday).
The GPS week number for a calendar date.
The transfer protocol (:https or :ftp) for a center.
Build the canonical IGS long-name filename for a daily station observation
product (RINEX 3 CRINEX), e.g.
ESBC00DNK_R_20201770000_01D_30S_MO.crx.
The transfer protocol for the daily station observation archive (:ftp on the
ESA GSSC mirror).
Build the full, compressed (.gz) archive URL for a daily station observation
product on the ESA GSSC anonymous archive (the same daily data tree the
broadcast navigation file uses).
Functions
The set of hosts the layer is permitted to contact.
Used by the download path as an allow-list so a malformed or unexpected URL can never cause a request to an off-catalog host.
@spec archive_url(atom(), atom(), Date.t(), String.t()) :: {:ok, String.t()} | {:error, {:unsupported_product, term()}}
Build the full, compressed (.gz) archive URL for a product.
The directory follows the center/content layout; the filename is the canonical
long-name plus a .gz suffix. The host is always one of the catalog hosts,
never caller-supplied input.
Returns {:ok, url} or an {:error, {:unsupported_product, _}} tuple.
Examples
iex> Orbis.GnssData.Catalog.archive_url(:gfz, :sp3, ~D[2020-06-24], "15M")
{:ok, "https://isdc-data.gfz.de/gnss/products/rapid/w2111/GFZ0OPSRAP_20201760000_01D_15M_ORB.SP3.gz"}
iex> Orbis.GnssData.Catalog.archive_url(:igs, :nav, ~D[2020-06-25], "01D")
{:ok, "ftp://gssc.esa.int/gnss/data/daily/2020/177/BRDC00IGS_R_20201770000_01D_MN.rnx.gz"}
@spec canonical_filename(atom(), atom(), Date.t(), String.t()) :: {:ok, String.t()} | {:error, {:unsupported_product, term()}}
Build the canonical IGS long-name filename for a product.
Precise products and IONEX use AAAVPPPTTT_YYYYDDDHHMM_LEN_SMP_CNT.EXT;
broadcast navigation uses the no-sampling RINEX form
SSSSMRCCC_R_YYYYDDDHHMM_LEN_CNT.ext. The center must actually publish the
requested content type.
Returns {:ok, filename} or an {:error, {:unsupported_product, _}} tuple.
Examples
iex> Orbis.GnssData.Catalog.canonical_filename(:gfz, :sp3, ~D[2020-06-24], "15M")
{:ok, "GFZ0OPSRAP_20201760000_01D_15M_ORB.SP3"}
iex> Orbis.GnssData.Catalog.canonical_filename(:igs, :nav, ~D[2020-06-25], "01D")
{:ok, "BRDC00IGS_R_20201770000_01D_MN.rnx"}
Look up a center's static definition.
Returns {:ok, map} or {:error, {:unsupported_product, {:center, code}}}.
Human-readable center name, or nil if the code is unknown.
@spec centers() :: [atom()]
All supported analysis-center codes.
The content-type descriptor (%{code:, ext:, kind:}) for a content type.
Returns {:ok, map} or {:error, {:unsupported_product, {:content, type}}}.
@spec content_types() :: [atom()]
All supported content-type codes.
@spec day_of_year(Date.t()) :: 1..366
The day-of-year (001–366) for a calendar date.
Examples
iex> Orbis.GnssData.Catalog.day_of_year(~D[2020-06-24])
176
@spec gps_day_of_week(Date.t()) :: 0..6
The GPS day-of-week for a calendar date (0 = Sunday … 6 = Saturday).
Examples
iex> Orbis.GnssData.Catalog.gps_day_of_week(~D[2020-06-24])
3
@spec gps_week(Date.t()) :: non_neg_integer()
The GPS week number for a calendar date.
GPS week 0 began on 1980-01-06. Uses exact integer day arithmetic, so it is leap-second-agnostic (week numbering is a calendar count, not a clock count).
Examples
iex> Orbis.GnssData.Catalog.gps_week(~D[2020-06-24])
2111
The transfer protocol (:https or :ftp) for a center.
@spec station_obs_filename(String.t(), Date.t(), String.t()) :: {:ok, String.t()} | {:error, {:unsupported_product, term()}}
Build the canonical IGS long-name filename for a daily station observation
product (RINEX 3 CRINEX), e.g.
ESBC00DNK_R_20201770000_01D_30S_MO.crx.
Station observation files are keyed by a 9-character site id, not an analysis-center token, so they have their own builder.
Examples
iex> Orbis.GnssData.Catalog.station_obs_filename("ESBC00DNK", ~D[2020-06-25], "30S")
{:ok, "ESBC00DNK_R_20201770000_01D_30S_MO.crx"}
@spec station_obs_protocol() :: :ftp
The transfer protocol for the daily station observation archive (:ftp on the
ESA GSSC mirror).
@spec station_obs_url(String.t(), Date.t(), String.t()) :: {:ok, String.t()} | {:error, {:unsupported_product, term()}}
Build the full, compressed (.gz) archive URL for a daily station observation
product on the ESA GSSC anonymous archive (the same daily data tree the
broadcast navigation file uses).
Examples
iex> Orbis.GnssData.Catalog.station_obs_url("ESBC00DNK", ~D[2020-06-25], "30S")
{:ok, "ftp://gssc.esa.int/gnss/data/daily/2020/177/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz"}