.well File Format Specification — Version 2.4: Interoperability
See also: overview.md · format-reference.md · object-schemas.md · water-quality.md
Overview
This part of the .well v2.4 specification covers how .well connects to other standards and tools: the reserved JSON-LD @context and its publication plan, how the format maps onto the OGC GroundWaterML 2 (GWML2) model, and validating files against the published JSON Schema.
Table of contents
JSON-LD Context (Reserved)
The @context top-level field is reserved for JSON-LD interoperability with semantic web tooling and external standards such as GWML2. See § Relationship to GWML2.
v2.0 parser requirements
- The
@contextfield is optional. - v2.0 parsers MUST preserve the
@contextfield on round-trip, per the foreign-members rule. - v2.0 parsers MUST NOT reject files that include or omit the field.
- v2.0 parsers are NOT required to interpret the field as JSON-LD. No semantic processing is mandated by this version of the spec.
Recommended usage
A .well file MAY include "@context": "https://welldot.org/context/v2.jsonld" to assert that the file's field names map to the canonical .well v2 JSON-LD context. Tools that understand JSON-LD can then transform the document into RDF for use with SPARQL, triple stores, or GWML2-conformant pipelines.
Context publication plan
The canonical context is staged across six phases (0–5). Each phase publishes a real, fetchable document at the canonical URL — at no phase is the URL a placeholder.
Phase 0 — Reservation (v2.0 ratification)
A minimal valid JSON-LD 1.1 document is published at https://welldot.org/context/v2.jsonld containing only the format-identity terms:
{
"@context": {
"@version": 1.1,
"well": "https://welldot.org/vocab/v2#",
"version": "well:version",
"name": "well:name",
"well_type": "well:well_type"
}
}
The document advertises itself as a draft via an x-welldot-status: reserved HTTP header and an in-band @version marker. This phase reserves the URL and proves it resolves; it does not yet enable meaningful RDF processing.
Phase 1 — Identity & location (v2.0 + 1 month)
Adds mappings for well_id, well_id.authority, well_id.id, well_id.primary, location, location.lat, location.lng, location.elevation, and construction_date. Aliases location.lat/lng to geo:lat/geo:long from the W3C Geo vocabulary; aliases construction_date to schema:dateCreated from Schema.org.
After Phase 1, a .well document round-trips to a minimal valid RDF graph representing the well's identity and position.
Phase 2 — Constructive blocks (v2.0 + 3 months)
Adds mappings for bore_hole, well_case, well_screen, reduction, surface_case, hole_fill, cement_pad and their fields. Where direct GWML2 alignment is verified against the published XSDs, terms alias to the GWML2-WellConstruction namespace; otherwise terms live under the welldot:vocab/v2# namespace with explanatory rdfs:comment annotations.
Phase 3 — Geological & hydrogeological (v2.0 + 6 months)
Adds mappings for lithology, fractures, caves, texture, texture.code, texture.vocabulary. Aliases lithology to gwml:GW_GeologyLogCoverage once the corresponding GWML2 class name is verified against the OGC schema documents.
Phase 4 — Hydrodynamic & analysis (v2.1)
Adds mappings for well_purpose, centralizers, hydrodynamic_events, aquifer_analysis, history_logs, and supporting types (PumpingStep, LevelReading, RecoveryPhase, Attachment). Maps event readings to O&M's OM_Observation pattern and time-series to TimeseriesML where alignment is verified. This phase ships alongside the v2.1 spec revision.
Phase 5 — Operational blocks (v2.3)
Adds mappings for attachments, Attachment.document_type, pump_installations, PumpInstallation and PumpElectrical fields (including installed_by and removed_by), permits (Permit, VolumeLimit, MonthlyGrant, PermitCondition, ConditionFulfillment, PermitHistoryEntry, and the administrative status), meters (Meter, including manufacturer, model, installed_by, removed_by and attachments), production (MeterReading, EstimatedVolume, with production[].corrects), operating_regime (OperatingRegime), the maintenance and status_change log fields, and hydrodynamic_events[].corrects. Permit dates map to xsd:date and condition durations to xsd:duration; supersedes is a succession relation between two instruments, distinct from corrects. corrects maps to a retraction relation between two observation or ledger records; installation, reading and regime instants map to xsd:dateTime; installed_by and removed_by map to the agent of the installation or removal activity (prov:wasAssociatedWith), kept as a plain literal; attachments alias to schema:MediaObject (uri → schema:contentUrl, media_type → schema:encodingFormat, sha256 → schema:sha256). Units bind to QUDT (unit:KiloW, unit:V, unit:MilliM2, unit:M3 for meter readings and volumes, unit:M3-PER-HR for regime flow rates, unit:HR for daily operating time, unit:MilliM for meter nominal diameter). This phase ships alongside the v2.3 spec revision.
The v2.3 water quality terms ship in the same phase: water_samples (WaterSample, SamplingPoint, Purge, PurgeReading, Laboratory, Result, Parameter, Filtration, Validation) and history_logs[].sample_ids. Collection, receipt, analysis and validation instants map to xsd:dateTime; a _resolution: "day" sibling maps the value to xsd:date semantics. Each welldot parameter code gets a term URI under https://welldot.org/vocab/water-quality/ (versioned with the published vocabulary), aligned where verified to the corresponding observable property in QUDT, ChEBI or the SOSA/SSN observable-property pattern. A cas parameter maps to the CAS Common Chemistry URI of its registry number, for example { "code": "71-43-2", "vocabulary": "cas" } → https://commonchemistry.cas.org/detail?cas_rn=71-43-2; a welldot code with a published CAS equivalence carries an owl:sameAs-style link to the same URI. x- vocabularies are left unmapped. Units bind to QUDT (unit:MilliGM-PER-L, unit:MicroS-PER-CentiM, unit:DEG_C, unit:MilliV, unit:BQ-PER-L, unit:MicroM); turbidity, color and microbiological count units without a QUDT term keep their UCUM code as a literal.
Versioning and stability
- The Phase-0 document is replaced in-place as phases ship, but term URIs under
welldot:vocab/v2#are append-only and never re-purposed within v2. - If a term needs to change meaning, it gets a new URI in
welldot:vocab/v3#. v2 consumers continue to resolve the old term. - Each phase increments an internal
versionmarker on the context document; client tools can detect which phase they're consuming. - A
CHANGELOG.mdis published alongside the context athttps://welldot.org/context/v2.changelog.mddocumenting every term added.
Optional fallback
If publishing infrastructure fails, files may inline the context object directly under @context instead of referencing the URL. This is supported by JSON-LD 1.1 and parsers MUST accept both forms.
Relationship to GWML2
GroundWaterML 2 (GWML2) is the OGC international standard for groundwater data exchange. It was developed and ratified by an international consortium that includes the Geological Survey of Canada (GSC), U.S. Geological Survey (USGS), CSIRO and the Bureau of Meteorology (Australia), BRGM (France), Federation University Australia, and Salzburg University, with contributing input from the British Geological Survey, the EU INSPIRE Joint Research Centre, the Polish and German geological surveys, and UNESCO's International Groundwater Resources Assessment Centre.
Two versions of the standard are currently in use:
- OGC 16-032r2 — WaterML 2: Part 4 — GroundWaterML 2 (GWML2), version 2.2, ratified in 2016 and published in 2017
- OGC 19-013 — GWML2 version 2.2.1, ratified in 2019 and published in 2021, which updates 16-032r2 by aligning with GeoSciML 4.1 and Observations & Measurements 2.0
GWML2 defines its model in three stages — a conceptual UML schema, a logical UML schema specialized for OGC standards, and an XML/GML encoding — and explicitly anticipates future JSON or RDF encodings. The standard is organized into six modular packages: GWML2-Main, GWML2-Constituent, GWML2-Flow, GWML2-Well, GWML2-WellConstruction, and GWML2-AquiferTest.
.well is a JSON-native format that scopes down to the static record plus operational history of a single well. It is not a competing conceptual model — it is an opinionated encoding for a subset of the GWML2 domain, designed for tooling and developer adoption. The optional JSON-LD @context (see § JSON-LD Context) is the technical bridge that allows a .well document to also be interpreted as a GWML2-aligned RDF graph.
Authoritative references
| Reference | Location |
|---|---|
| GWML2 v2.2 specification (16-032r2) | https://docs.ogc.org/is/16-032r2/16-032r2.html |
| GWML2 v2.2.1 specification (19-013) | https://docs.ogc.org/is/19-013/19-013.html |
| GWML2 XML schemas (XSD) | http://schemas.opengis.net/gwml/2.2/ |
| OGC Hydrology DWG GWML2 wiki | https://external.ogc.org/twiki_public/HydrologyDWG/ |
Scope correspondence
| GWML2 Module | Namespace | .well coverage |
|---|---|---|
| GWML2-Main | http://www.opengis.net/gwml-main/2.2 | Out of scope (aquifers, fluid bodies, hydrogeological units as standalone features) |
| GWML2-Constituent | http://www.opengis.net/gwml-constituent/2.2 | Partially covered (water_samples, v2.3): measured constituents and properties of sampled water |
| GWML2-Flow | http://www.opengis.net/gwml-flow/2.2 | Out of scope (recharge, discharge, inter-flow) |
| GWML2-Well | http://www.opengis.net/gwml-well/2.2 | Covered: top-level well identity, location, well_id, well-as-sampling-feature semantics |
| GWML2-WellConstruction | http://www.opengis.net/gwml-wellconstruction/2.2 | Covered: bore_hole, well_case, well_screen, reduction, surface_case, hole_fill, cement_pad |
| GWML2-AquiferTest | http://www.opengis.net/gwml-aquifertest/2.2 | Covered: hydrodynamic_events, aquifer_analysis |
Conceptual alignment
A .well document corresponds conceptually to a GWML2 GW_Well feature, which itself specializes O&M's SF_SamplingCurve — wells in GWML2 are modeled as sampling features along whose length observations are made. Boreholes (Borehole from GWML2-WellConstruction) are physical engineering artifacts distinct from wells in GWML2; in .well v2, both are collapsed into the constructive blocks of a single record since the format describes one composite well.
A .well Lithology array corresponds to a GWML2 GW_GeologyLogCoverage, which is a realization of CV_DiscreteCoverage over depth intervals. Each lithology interval references a GW_HydrogeologicalUnit — GWML2's specialization of GeoSciML's GeologicUnit — via the geologic_unit field; .well does not model the hydrogeological unit itself as a standalone feature.
Class mapping (informative)
The mapping below is informative, not normative. Class names in italics are verified against published GWML2 documentation (the OGC 16-032r2 specification, the Hydrogeology Journal and Open Geospatial Data, Software and Standards papers, and the OGC Hydrology DWG wiki). Class names marked with ? are approximate — they describe the GWML2 module a .well construct belongs to but the exact class name was not verified at the time of writing this draft. Implementers building converters should verify these against the authoritative XSDs at http://schemas.opengis.net/gwml/2.2/ before relying on them.
.well construct | GWML2 module | Class / property |
|---|---|---|
| Well (top-level) | GWML2-Well | GW_Well (specializes O&M:SF_SamplingCurve) |
well_id[] | GWML2-Well | GW_Well identifier property (?) |
location | GWML2-Well | GW_Well shape / position property (?) |
bore_hole[] | GWML2-WellConstruction | Borehole (?) |
well_case[] | GWML2-WellConstruction | Casing (?) |
surface_case[] | GWML2-WellConstruction | Casing with surface depth range (?) |
well_screen[] | GWML2-WellConstruction | Screen (?) |
reduction[] | GWML2-WellConstruction | No direct equivalent — casing transition |
hole_fill[] | GWML2-WellConstruction | Annular fill / gravel pack / seal (?) |
cement_pad | GWML2-WellConstruction | No direct equivalent — wellhead furniture |
centralizers[] | GWML2-WellConstruction | No verified equivalent — casing accessory (?) |
well_purpose[] | GWML2-Well | GW_Well purpose / use property (?) |
lithology[] | GWML2-Well | GW_GeologyLogCoverage (realizes CV_DiscreteCoverage) |
lithology[].geologic_unit | GWML2-Main | GW_HydrogeologicalUnit (specializes GeoSciML GeologicUnit) |
fractures[] | GWML2-Well | Fracture log interval (?) |
caves[] | GWML2-Well | Void / cavity log interval (?) |
hydrodynamic_events[] | GWML2-AquiferTest | GW_AquiferTest (?) plus OM_Observation series via TimeseriesML |
aquifer_analysis[] | GWML2-AquiferTest | Aquifer test result properties (?) |
history_logs[] | n/a | No direct equivalent — operational record outside GWML2 scope |
pump_installations[] | GWML2-WellConstruction | Pump / wellhead equipment (?) — pending check against the XSD |
permits[] | n/a | No direct equivalent — operational record outside GWML2 scope |
meters[] | n/a | No direct equivalent — operational record outside GWML2 scope |
production[] | n/a | No direct equivalent — operational record outside GWML2 scope |
operating_regime[] | n/a | No direct equivalent — operational record outside GWML2 scope |
attachments[] (root) | n/a | No direct equivalent — documents referenced by URL |
hydrodynamic_events[].corrects | n/a | No direct equivalent — ledger correction outside GWML2 scope |
water_samples[] | GWML2-Constituent | SF_Specimen (?) — the sample taken from the GW_Well |
water_samples[].results[] | GWML2-Constituent | OM_Measurement (?) on the specimen, observed property = parameter |
water_samples[].corrects | n/a | No direct equivalent — ledger correction outside GWML2 scope |
A complete, normative mapping will be published as a separate document once the GWML2 XSDs have been read directly and each verified class name and property path has been confirmed. Until then, this table is a structural guide and not a conversion specification.
Notes on the mapping
- Wells vs. boreholes in GWML2. GWML2 distinguishes a
GW_Well(the construction with hydrogeological purpose) from aBorehole(the physical hole). A single.welldocument conflates both since it describes one composite installation. A.well → GWML2converter must emit both features and link them; aGWML2 → .wellconverter must merge them. - Aquifer tests in GWML2. GWML2-AquiferTest uses TimeseriesML (OGC 15-042r2) for time-series readings and O&M's
OM_Observationpattern for individual measurements. The.wellevent types (spot_measurement,constant_rate,step_drawdown,airlift,recovery_onlyand, since v2.4,logger_series) are pragmatic field-record categories with no direct GWML2 counterpart; a converter must decompose each into one or moreGW_AquiferTestfeatures with appropriateOM_Observationresults. Alogger_seriesis not a test: a converter maps it to a TimeseriesML series ofOM_Observationresults on the well, without aGW_AquiferTest. - Hydrogeological units.
.wellstoreslithology[].geologic_unitandaquifer_unitas free-text strings. In GWML2 these resolve to references toGW_HydrogeologicalUnitfeatures, which in real GWML2 deployments are typically catalogued in national registries (e.g. French BDLISA, Canadian GIN). A.well → GWML2converter SHOULD resolve these strings to authoritative unit URIs when a national vocabulary is available; absent that, it emits inlineGW_HydrogeologicalUnitfeatures withgml:nameset to the string value. - Water samples as specimens. A
water_samplesentry corresponds to an O&MSF_Specimentaken from the well (the sampled feature), withdatetimeas the sampling time andsampling_pointas the sampling location along the well. Each result is anOM_Measurementwhose observed property is the parameter (a CAS orwelldotterm URI), whose result is the value in the code's canonical unit, and whose procedure ismethod. GWML2-Constituent describes the constituents of a fluid body rather than individual analyses, so a converter maps.wellresults to O&M observations on the specimen and derives constituent statements only when needed. Censoring (qualifier), detection and quantification limits,lab_flagsandvalidationhave no direct GWML2 counterpart and travel as result quality metadata orx-extensions. Field QA/QC links (parent_sample_id), purge data and chain of custody are outside GWML2 scope. Limits and exceedances are never part of the file and have no mapping. - History logs are outside GWML2 scope. GWML2 models the well as a static feature and its observations as a time-series. Maintenance interventions, incidents, status changes (
status_change), permit condition fulfillment, and operational events are not represented. The same holds for the v2.3 operational blocks (permits,meters,production,operating_regime): metered production is an abstraction record, not an aquifer observation. A converter SHOULD preserve.wellhistory_logsin a GeoSciML observation event sequence or as anx-extension on the GWML2 side, but full lossless round-trip is not guaranteed.
Profiles for regulatory adoption
National regulators with existing data models (Brazil SIAGAS, French BSS / BDLISA, EU INSPIRE hydrogeology) can publish .well profiles that constrain the format to their required fields and vocabularies. Profile schemas may extend the canonical .well v2 schema with regulator-specific requirements (e.g. mandatory well_id entries for the relevant national authority, restricted enums for casing materials, required precision fields) without breaking interoperability with the core spec.
Schema Validation
The canonical JSON Schema for .well v2 is published at:
https://welldot.org/schema/v2/well.schema.json
The schema conforms to JSON Schema 2020-12 (https://json-schema.org/draft/2020-12/schema). Implementers SHOULD use a JSON Schema validator that supports this draft (Ajv 8+, python-jsonschema 4+, NetworkNT json-schema-validator). Earlier-draft validators may work for most fields but are not officially supported.
Files MAY include a $schema field referencing this URL:
{
"$schema": "https://welldot.org/schema/v2/well.schema.json",
"version": "2.4",
...
}
The schema is generated from the Zod validators in @welldot/core to prevent drift between runtime validation and published schema. The generated file lives at spec/schema/v2/well.schema.json in the repository root, is published at https://welldot.org/schema/v2/well.schema.json and ships in @welldot/core as @welldot/core/well.schema.json. Profile schemas SHOULD extend this canonical schema via allOf + $ref.
.well Format Specification v2.4