@welldot/core 0.1.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -52
- package/dist/index.cjs +878 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4948 -107
- package/dist/index.d.ts +4948 -107
- package/dist/index.js +836 -29
- package/dist/index.js.map +1 -1
- package/docs/profiles/.gitkeep +0 -0
- package/docs/reference/fgdc-textures.md +380 -0
- package/docs/schema/v1/.gitkeep +0 -0
- package/docs/schema/v2/profiles/.gitkeep +0 -0
- package/docs/schema/v2/well.schema.json +949 -0
- package/{well-specifications.md → docs/spec/v1/well-format.md} +160 -95
- package/docs/spec/v2/format-reference.md +534 -0
- package/docs/spec/v2/interoperability.md +177 -0
- package/docs/spec/v2/object-schemas.md +657 -0
- package/docs/spec/v2/overview.md +85 -0
- package/package.json +16 -12
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
# `.well` File Format Specification — Version 2.0: Format Reference
|
|
2
|
+
|
|
3
|
+
**See also:** [overview.md](./overview.md) · [object-schemas.md](./object-schemas.md) · [interoperability.md](./interoperability.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Top-level Structure
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"version": 2,
|
|
12
|
+
"@context": "https://welldot.org/context/v2.jsonld",
|
|
13
|
+
|
|
14
|
+
"well_id": [ ... ],
|
|
15
|
+
"location": { ... },
|
|
16
|
+
|
|
17
|
+
"name": "...",
|
|
18
|
+
"well_type": "...",
|
|
19
|
+
"well_driller": "...",
|
|
20
|
+
"construction_date": "YYYY-MM-DD",
|
|
21
|
+
"obs": "...",
|
|
22
|
+
|
|
23
|
+
"profiles": [ ... ],
|
|
24
|
+
|
|
25
|
+
"bore_hole": [ ... ],
|
|
26
|
+
"well_case": [ ... ],
|
|
27
|
+
"reduction": [ ... ],
|
|
28
|
+
"well_screen": [ ... ],
|
|
29
|
+
"surface_case": [ ... ],
|
|
30
|
+
"hole_fill": [ ... ],
|
|
31
|
+
"cement_pad": { ... },
|
|
32
|
+
|
|
33
|
+
"lithology": [ ... ],
|
|
34
|
+
"fractures": [ ... ],
|
|
35
|
+
"caves": [ ... ],
|
|
36
|
+
|
|
37
|
+
"hydrodynamic_events": [ ... ],
|
|
38
|
+
"aquifer_analysis": [ ... ],
|
|
39
|
+
"history_logs": [ ... ]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Versioning
|
|
46
|
+
|
|
47
|
+
| Version | Description |
|
|
48
|
+
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `1` | Initial release — constructive and geologic data only |
|
|
50
|
+
| `2` | Adds location, well_id (array), profiles, texture object, hydrodynamic_events, aquifer_analysis, history_logs, optional @context, \*\_precision fields, and extensibility conventions. Tightens unit semantics: all values are canonical SI, no per-file declaration. |
|
|
51
|
+
|
|
52
|
+
### Parser version handling
|
|
53
|
+
|
|
54
|
+
The `version` field is an integer and must always be present.
|
|
55
|
+
|
|
56
|
+
- A v2 parser encountering `version: 1` MUST apply the v1-to-v2 normalizations listed in the changes section and treat the document as v2-equivalent for all subsequent processing.
|
|
57
|
+
- A v1 parser encountering `version: 2` MUST reject the file with a clear error indicating an unsupported format version. v1 parsers MUST NOT attempt partial reads of v2 documents.
|
|
58
|
+
- Either parser encountering an unrecognized integer version MUST reject the file with a clear error.
|
|
59
|
+
- A file without a `version` field SHOULD be rejected. Parsers MAY emit a warning and attempt to read the file as v1 if all required v1 fields are present and no v2-specific blocks are detected, but this fallback behavior is implementation-specific and not guaranteed by the spec.
|
|
60
|
+
|
|
61
|
+
Files with `version: 1` MUST NOT contain any v2-only blocks (`hydrodynamic_events`, `aquifer_analysis`, `history_logs`, `profiles`, `well_id` as array, `location` object, `@context`). A v1 file containing such fields is malformed.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Deprecation Policy
|
|
66
|
+
|
|
67
|
+
The `.well` format evolves in two version dimensions:
|
|
68
|
+
|
|
69
|
+
- **Major versions** (`1`, `2`, `3`, …): may remove deprecated fields and introduce breaking changes. Each major version has its own canonical JSON Schema URL.
|
|
70
|
+
- **Minor revisions** within a major version (`2.0`, `2.1`, …): additive only. Minor revisions may introduce new fields, new vocabulary values, and **deprecation markers** for existing fields. Minor revisions MUST NOT remove fields, change field semantics, or break round-trip compatibility for files conforming to earlier minor revisions of the same major version.
|
|
71
|
+
|
|
72
|
+
### Field lifecycle
|
|
73
|
+
|
|
74
|
+
A field moves through three states:
|
|
75
|
+
|
|
76
|
+
1. **Active** — defined and recommended by the current minor revision.
|
|
77
|
+
2. **Deprecated** — still defined and still valid, but flagged for removal in the next major version. Deprecation is announced in a minor revision (e.g. introduced in v2.0, deprecated in v2.1).
|
|
78
|
+
3. **Removed** — no longer defined. May only occur in a new major version (e.g. removed in v3.0).
|
|
79
|
+
|
|
80
|
+
Each deprecation announcement MUST include, in the spec text for the relevant field:
|
|
81
|
+
|
|
82
|
+
- The minor revision in which the field was deprecated (e.g. _"Deprecated in v2.1"_).
|
|
83
|
+
- The major version in which the field will be removed (e.g. _"Will be removed in v3.0"_).
|
|
84
|
+
- The replacement field or pattern, when applicable.
|
|
85
|
+
- A v2-to-vNext normalization rule that parsers for the next major version MUST implement to read files using the deprecated field.
|
|
86
|
+
|
|
87
|
+
### Parser behavior
|
|
88
|
+
|
|
89
|
+
Parsers conformant to the version that introduced a deprecation:
|
|
90
|
+
|
|
91
|
+
- MUST accept the deprecated field as valid input.
|
|
92
|
+
- MUST preserve the deprecated field on round-trip unless explicitly migrating the document to a newer version.
|
|
93
|
+
- SHOULD emit a warning when encountering a deprecated field, naming the replacement.
|
|
94
|
+
- MAY offer a migration mode that rewrites the field to its replacement in place. Migration mode MUST be opt-in (e.g. an explicit flag passed to the parser), not the default behavior of read operations.
|
|
95
|
+
|
|
96
|
+
Parsers for the major version after removal:
|
|
97
|
+
|
|
98
|
+
- MUST apply the documented normalization when reading older files (e.g. a v3 parser reading a v2 file that used a v2-deprecated field).
|
|
99
|
+
- MUST NOT accept the removed field name in files declaring the new major version (e.g. a file with `version: 3` containing a v2-deprecated field is malformed).
|
|
100
|
+
|
|
101
|
+
### Vocabulary value promotion
|
|
102
|
+
|
|
103
|
+
When a vocabulary value previously available only with the `x-` prefix is promoted to canonical (e.g. `x-slug_test` becomes `slug_test`):
|
|
104
|
+
|
|
105
|
+
- The minor revision that performs the promotion MUST document both forms as equivalent.
|
|
106
|
+
- Parsers from that revision onward MUST treat both forms as equivalent for the remainder of the major version.
|
|
107
|
+
- The `x-` prefixed form is implicitly deprecated upon promotion and will be removed in the next major version, following the standard field lifecycle.
|
|
108
|
+
|
|
109
|
+
### Canonical deprecation registry
|
|
110
|
+
|
|
111
|
+
Each minor revision of this spec MUST include a "Deprecations" subsection in its changelog listing all fields and vocabulary values deprecated in that revision, with their replacement and removal timeline. The v2.0 release contains no deprecations.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Top-level Fields
|
|
116
|
+
|
|
117
|
+
### Core identity
|
|
118
|
+
|
|
119
|
+
| Field | Type | Required | Description |
|
|
120
|
+
| ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `version` | integer | yes | Format version. Must be `2` for this spec. |
|
|
122
|
+
| `well_type` | string | yes | Classification of the well. See vocabulary below. |
|
|
123
|
+
| `name` | string | no | Well name or local identifier. |
|
|
124
|
+
| `well_driller` | string | no | Name of the drilling company or individual. |
|
|
125
|
+
| `construction_date` | string | no | ISO 8601 calendar date of well completion (`YYYY-MM-DD`). Date-only by design — time of day for construction completion is not meaningful at the precision the well registry cares about. Interpreted as the local civil date at the well site. |
|
|
126
|
+
| `obs` | string | no | Free-text observations about the well. |
|
|
127
|
+
| `well_depth` | number | no | The well's current usable depth in meters from ground level, as measured or reported. May be less than the deepest constructive element (see `bore_hole`) due to siltation, debris, or partial backfill. |
|
|
128
|
+
|
|
129
|
+
### v2 additions
|
|
130
|
+
|
|
131
|
+
| Field | Type | Required | Description |
|
|
132
|
+
| ---------- | ------------------------- | -------- | ---------------------------------------------------------------------------- |
|
|
133
|
+
| `@context` | string \| array \| object | no | JSON-LD context. Reserved field; see § JSON-LD Context. |
|
|
134
|
+
| `well_id` | `WellId[]` | no | Array of authority-scoped identifiers. See § well_id. |
|
|
135
|
+
| `location` | `Location` | no | Geographic position and elevation. See § location. |
|
|
136
|
+
| `profiles` | string[] | no | Array of JSON Schema URLs declaring conformance to profiles. See § profiles. |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Datetime Conventions
|
|
141
|
+
|
|
142
|
+
The `.well` format distinguishes two kinds of temporal values:
|
|
143
|
+
|
|
144
|
+
**Calendar dates** — `YYYY-MM-DD`, no time, no offset. Used for `construction_date` only. Interpreted as the local civil date at the well site. The well site's timezone is not stored separately; calendar dates are sortable lexicographically and applications MUST NOT attempt to derive an instant from them.
|
|
145
|
+
|
|
146
|
+
**Instants** — RFC 3339 datetime strings with a mandatory UTC offset (e.g. `2006-03-14T08:00:00-03:00` or `2006-03-14T11:00:00Z`). Used for all event, analysis, and log timestamps:
|
|
147
|
+
|
|
148
|
+
- `hydrodynamic_events[].datetime`
|
|
149
|
+
- `aquifer_analysis[].datetime`
|
|
150
|
+
- `history_logs[].datetime`
|
|
151
|
+
- `history_logs[].updated_at`
|
|
152
|
+
|
|
153
|
+
A datetime without an offset (naked `YYYY-MM-DDTHH:MM:SS`) is malformed and parsers MUST reject it. Time zone abbreviations (`EST`, `BRT`) are not RFC 3339 and MUST NOT be used.
|
|
154
|
+
|
|
155
|
+
### Ordering and ties
|
|
156
|
+
|
|
157
|
+
Instants are ordered by absolute UTC instant, not by the lexical form of the string. The strings `2006-03-14T08:00:00-03:00` and `2006-03-14T11:00:00Z` represent the same instant and tie for ordering purposes.
|
|
158
|
+
|
|
159
|
+
When two events share the same instant, the optional `sequence` integer breaks the tie (lower values sort first). When two events share the same instant and no `sequence` is provided, ordering is implementation-defined; producers SHOULD provide `sequence` when authoring events with identical instants.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## `well_type` — Recommended values
|
|
164
|
+
|
|
165
|
+
The `well_type` field accepts any string. The values below are the recommended vocabulary for interoperability. Tools should treat unrecognized values gracefully.
|
|
166
|
+
|
|
167
|
+
| Value | Portuguese (BR) | Description |
|
|
168
|
+
| ---------------------- | ----------------------- | ---------------------------------------------- |
|
|
169
|
+
| `tubular` | Tubular | Conventional rotary or percussion drilled well |
|
|
170
|
+
| `artesian` | Artesiano | Free-flowing artesian well |
|
|
171
|
+
| `hand_dug` | Cacimba / poço escavado | Manually excavated well or cistern |
|
|
172
|
+
| `horizontal` | Horizontal | Horizontal or sub-horizontal well |
|
|
173
|
+
| `infiltration_gallery` | Galeria de infiltração | Horizontal subsurface infiltration gallery |
|
|
174
|
+
|
|
175
|
+
Non-canonical values SHOULD use the `x-` prefix (e.g. `x-radial_collector`).
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## `well_id`
|
|
180
|
+
|
|
181
|
+
Array of authority-scoped identifiers linking the well to external registries. A well may be registered in multiple national, regional, or institutional registries simultaneously.
|
|
182
|
+
|
|
183
|
+
| Field | Type | Required | Description |
|
|
184
|
+
| ----------- | ------- | -------- | --------------------------------------------------------------------------------- |
|
|
185
|
+
| `authority` | string | yes | Name of the issuing registry or institution (e.g. `"SIAGAS"`, `"ANA"`, `"NGWD"`). |
|
|
186
|
+
| `id` | string | yes | The identifier as issued by the authority. |
|
|
187
|
+
| `primary` | boolean | no | Marks the canonical identifier. At most one entry may have `primary: true`. |
|
|
188
|
+
|
|
189
|
+
When `primary` is omitted on all entries, the first entry is canonical. Parsers MUST warn when multiple entries have `primary: true`.
|
|
190
|
+
|
|
191
|
+
### Numeric ID conversion
|
|
192
|
+
|
|
193
|
+
All `id` values are strings. When the source identifier from an external system is an integer, the string representation MUST be the canonical base-10 representation with no leading zeros, no thousands separator, and no locale-specific formatting. The integer `42` becomes `"42"`, not `"042"` or `"42,"`.
|
|
194
|
+
|
|
195
|
+
When the source identifier is a fixed-width string with significant leading zeros (e.g. `"00042819"` from a registry where width carries meaning), the original string MUST be preserved verbatim. Composite identifiers containing significant leading zeros in their numeric portion (e.g. SIAGAS `"SP-0042819"`) MUST be preserved as-is.
|
|
196
|
+
|
|
197
|
+
### Uniqueness
|
|
198
|
+
|
|
199
|
+
The combination `(authority, id)` MUST be unique within the `well_id` array. See § Cross-reference and uniqueness rules for the duplicate-handling policy.
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
"well_id": [
|
|
203
|
+
{ "authority": "SIAGAS", "id": "SP-0042819", "primary": true },
|
|
204
|
+
{ "authority": "ANA", "id": "02000.001234/2006-78" },
|
|
205
|
+
{ "authority": "utility-internal", "id": "PP-01" }
|
|
206
|
+
]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## `location`
|
|
212
|
+
|
|
213
|
+
Geographic position and elevation of the wellhead. Supersedes the v1 top-level `lat`, `lng`, and `elevation` fields.
|
|
214
|
+
|
|
215
|
+
The three primary measurements — `lat`, `lng`, `elevation` — are top-level fields on the location object for ergonomics. All ancillary metadata (datum, CRS, precision, source CRS) lives under a nested `properties` object.
|
|
216
|
+
|
|
217
|
+
| Field | Type | Required | Description |
|
|
218
|
+
| ------------ | -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
219
|
+
| `lat` | number | yes | Latitude in decimal degrees. |
|
|
220
|
+
| `lng` | number | yes | Longitude in decimal degrees. |
|
|
221
|
+
| `elevation` | number | no | Wellhead elevation in meters above the WGS84 reference ellipsoid (or the datum named in `properties.elevation_datum`). |
|
|
222
|
+
| `properties` | `LocationProperties` | no | Ancillary metadata. When absent, all defaults apply. |
|
|
223
|
+
|
|
224
|
+
### `LocationProperties`
|
|
225
|
+
|
|
226
|
+
| Field | Type | Required | Description |
|
|
227
|
+
| --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
228
|
+
| `elevation_datum` | string | no | Reference datum for `elevation`. See vocabulary below. Default: `wgs84_ellipsoid`. |
|
|
229
|
+
| `crs` | string | no | EPSG code of the coordinate reference system. Must be a geographic (not projected) CRS. Default: `"EPSG:4326"` (WGS84). |
|
|
230
|
+
| `lat_precision` | number | no | One-sigma precision of `lat` in decimal degrees. |
|
|
231
|
+
| `lng_precision` | number | no | One-sigma precision of `lng` in decimal degrees. |
|
|
232
|
+
| `elevation_precision` | number | no | One-sigma precision of `elevation` in meters. |
|
|
233
|
+
| `original_crs` | string | no | EPSG code of the source CRS, preserved for traceability when source data was in a projected CRS that the converter transformed to geographic. Informational only. |
|
|
234
|
+
|
|
235
|
+
### `elevation_datum` — Recommended values
|
|
236
|
+
|
|
237
|
+
| Value | Description |
|
|
238
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
239
|
+
| `wgs84_ellipsoid` | WGS84 reference ellipsoidal height. Default. |
|
|
240
|
+
| `egm2008` | Earth Gravitational Model 2008 geoid |
|
|
241
|
+
| `egm96` | Earth Gravitational Model 1996 geoid |
|
|
242
|
+
| `local_msl` | Local mean sea level (imprecise; specific datum SHOULD be named via `x-` prefix, e.g. `x-imbituba` for Brazil's national vertical reference) |
|
|
243
|
+
|
|
244
|
+
When `elevation_datum` is omitted, parsers MUST assume `wgs84_ellipsoid`.
|
|
245
|
+
|
|
246
|
+
### CRS scope
|
|
247
|
+
|
|
248
|
+
Only geographic coordinate reference systems are permitted in `properties.crs`. Projected CRS values (e.g. UTM zones) are not valid. If source data uses a projected CRS, the converting application MUST transform to geographic coordinates before writing the file. The `original_crs` field MAY be populated with the source CRS for traceability.
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
"location": {
|
|
252
|
+
"lat": -1.4558,
|
|
253
|
+
"lng": -48.5039,
|
|
254
|
+
"elevation": 12.5,
|
|
255
|
+
"properties": {
|
|
256
|
+
"elevation_datum": "wgs84_ellipsoid",
|
|
257
|
+
"crs": "EPSG:4326",
|
|
258
|
+
"lat_precision": 0.0001,
|
|
259
|
+
"lng_precision": 0.0001,
|
|
260
|
+
"elevation_precision": 0.5,
|
|
261
|
+
"original_crs": "EPSG:31983"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Units
|
|
269
|
+
|
|
270
|
+
All numeric values in a `.well` file are in **SI**. The format does not encode unit declarations; the units below are the single, canonical interpretation for every field of the corresponding kind. No file may override these.
|
|
271
|
+
|
|
272
|
+
### Canonical units
|
|
273
|
+
|
|
274
|
+
| Quantity | Unit | UCUM | Stored as |
|
|
275
|
+
| ------------------------ | ------------------------ | ------ | ---------------------------------------- |
|
|
276
|
+
| Depth, length, elevation | meter | `m` | number |
|
|
277
|
+
| Diameter | millimeter | `mm` | number |
|
|
278
|
+
| Volumetric flow rate | cubic meter per hour | `m3/h` | number |
|
|
279
|
+
| Elapsed time, duration | minute | `min` | number |
|
|
280
|
+
| Transmissivity | square meter per second | `m2/s` | number |
|
|
281
|
+
| Hydraulic conductivity | meter per second | `m/s` | number |
|
|
282
|
+
| Pressure | kilopascal | `kPa` | number |
|
|
283
|
+
| Angle (azimuth, dip) | degree | `deg` | number (0–360 for azimuth, 0–90 for dip) |
|
|
284
|
+
| Geographic coordinates | decimal degree (WGS84) | `deg` | number |
|
|
285
|
+
| Calendar date | ISO 8601 | — | string `YYYY-MM-DD` |
|
|
286
|
+
| Instant | RFC 3339 with UTC offset | — | string |
|
|
287
|
+
|
|
288
|
+
UCUM is the **Unified Code for Units of Measure**, the international machine-parseable unit standard used by OGC SWE and the scientific community. The UCUM column above documents the canonical encoding of each unit for use in JSON-LD contexts, profile schemas, and downstream interoperability — it is not encoded in `.well` files themselves.
|
|
289
|
+
|
|
290
|
+
### Field-to-unit binding (normative)
|
|
291
|
+
|
|
292
|
+
**Meter (`m`)** — all depths, lengths, and elevations:
|
|
293
|
+
|
|
294
|
+
- `well_depth`
|
|
295
|
+
- `bore_hole[].from`, `bore_hole[].to`
|
|
296
|
+
- `well_case[].from`, `well_case[].to`
|
|
297
|
+
- `reduction[].from`, `reduction[].to`
|
|
298
|
+
- `well_screen[].from`, `well_screen[].to`
|
|
299
|
+
- `surface_case[].from`, `surface_case[].to`
|
|
300
|
+
- `hole_fill[].from`, `hole_fill[].to`
|
|
301
|
+
- `cement_pad.width`, `cement_pad.length`, `cement_pad.thickness`
|
|
302
|
+
- `lithology[].from`, `lithology[].to`
|
|
303
|
+
- `fractures[].depth`, `fractures[].depth_precision`
|
|
304
|
+
- `caves[].from`, `caves[].to`
|
|
305
|
+
- `hydrodynamic_events[].static_level`, `static_level_precision`
|
|
306
|
+
- `PumpingStep.readings[].depth`, `depth_precision`
|
|
307
|
+
- `RecoveryPhase.readings[].depth`, `depth_precision`
|
|
308
|
+
- `aquifer_analysis[].static_level`, `static_level_precision`
|
|
309
|
+
- `aquifer_analysis[].dynamic_level`, `dynamic_level_precision`
|
|
310
|
+
- `aquifer_analysis[].aquifer_thickness`
|
|
311
|
+
- `location.elevation`, `location.properties.elevation_precision`
|
|
312
|
+
|
|
313
|
+
**Millimeter (`mm`)** — all diameters and slot openings:
|
|
314
|
+
|
|
315
|
+
- `bore_hole[].diameter`
|
|
316
|
+
- `well_case[].diameter`
|
|
317
|
+
- `reduction[].diam_from`, `reduction[].diam_to`
|
|
318
|
+
- `well_screen[].diameter`, `well_screen[].screen_slot`
|
|
319
|
+
- `surface_case[].diameter`
|
|
320
|
+
- `hole_fill[].diameter`
|
|
321
|
+
|
|
322
|
+
**Cubic meter per hour (`m3/h`)** — all volumetric flow rates:
|
|
323
|
+
|
|
324
|
+
- `PumpingStep.rate`, `rate_precision`
|
|
325
|
+
- `aquifer_analysis[].flow_rate`, `flow_rate_precision`
|
|
326
|
+
- `recovery_only.pumping_rate`
|
|
327
|
+
|
|
328
|
+
**Minute (`min`)** — all elapsed times and durations:
|
|
329
|
+
|
|
330
|
+
- `PumpingStep.duration`
|
|
331
|
+
- `LevelReading.elapsed`
|
|
332
|
+
- `recovery_only.pumping_duration`
|
|
333
|
+
|
|
334
|
+
**Square meter per second (`m2/s`)** — transmissivity:
|
|
335
|
+
|
|
336
|
+
- `aquifer_analysis[].transmissivity`
|
|
337
|
+
|
|
338
|
+
**Meter per second (`m/s`)** — hydraulic conductivity:
|
|
339
|
+
|
|
340
|
+
- `aquifer_analysis[].hydraulic_conductivity`
|
|
341
|
+
|
|
342
|
+
**Kilopascal (`kPa`)** — pressure:
|
|
343
|
+
|
|
344
|
+
- `LevelReading.pressure`
|
|
345
|
+
|
|
346
|
+
**Degree (`deg`)** — angles and geographic coordinates:
|
|
347
|
+
|
|
348
|
+
- `fractures[].azimuth`, `fractures[].dip`
|
|
349
|
+
- `location.lat`, `location.lng`, `location.properties.lat_precision`, `location.properties.lng_precision`
|
|
350
|
+
|
|
351
|
+
**Unitless** — dimensionless or domain-specific values:
|
|
352
|
+
|
|
353
|
+
- `aquifer_analysis[].storativity` (dimensionless)
|
|
354
|
+
- `aquifer_analysis[].jacob_b`, `jacob_c` (composite units; treated as the units required to make the standard Jacob equation balance with stored `flow_rate` and `length`)
|
|
355
|
+
- `aquifer_analysis[].well_efficiency_pct` (percentage, 0–100)
|
|
356
|
+
- `aquifer_analysis[].specific_capacity` (derived ratio in m³/h per m, i.e. `m2/h`)
|
|
357
|
+
- Lithology `color` (CSS hex string)
|
|
358
|
+
|
|
359
|
+
### Diameter and the as-built convention
|
|
360
|
+
|
|
361
|
+
Diameters in casing, screens, surface case, and hole fill are stored as the **as-built outer diameter in millimeters**, not as nominal manufacturer designations. A casing sold as "6 inch" with a real outer diameter of 168.3 mm is recorded as `168.3`, not `152.4` (the literal conversion of 6 inches to mm). Nominal-to-actual mapping for common pipe and screen sizes is a market convention handled by applications — typically by the converter or input form — not by the file format.
|
|
362
|
+
|
|
363
|
+
### Screen slot
|
|
364
|
+
|
|
365
|
+
`well_screen[].screen_slot` is in millimeters like every other diameter field. US-market slot-number designations (e.g. "20 slot" = 0.020 inch = 0.508 mm) are an input convenience handled by applications, not encoded in the file. The v1 field name `screen_slot_mm` was a legacy artifact and is renamed to `screen_slot` in v2; the value is in millimeters before and after.
|
|
366
|
+
|
|
367
|
+
### Rationale
|
|
368
|
+
|
|
369
|
+
An interchange format with configurable units multiplies the number of valid encodings of the same well, complicates equality and comparison, and introduces a class of bugs where the declared units do not match the stored values. The `.well` format is designed to be a canonical machine representation: one well, one encoding. Display units, input units, and locale-specific notation are concerns of the applications that read and write `.well` files, not of the format itself. This separation matches the design of GeoJSON (WGS84 only), RFC 3339 (UTC offsets always present), and most modern interchange formats.
|
|
370
|
+
|
|
371
|
+
Producers receiving non-SI source data (imperial drilling reports, US gpm flow measurements, inch casing designations, slot-number screens) MUST convert to SI before writing. Consumers presenting the data to users in non-SI units MUST convert on read.
|
|
372
|
+
|
|
373
|
+
Conversion utilities for the common transformations are provided in `@welldot/core` under the `units` module — m ↔ ft, mm ↔ in, m³/h ↔ L/s, m³/h ↔ US gpm, m²/s ↔ m²/d, DD ↔ DMS, slot-number ↔ mm, and similar.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## `profiles`
|
|
378
|
+
|
|
379
|
+
An optional array of HTTPS URLs declaring formal extensions to the spec that the file conforms to. Each URL MUST resolve to a JSON Schema document.
|
|
380
|
+
|
|
381
|
+
```json
|
|
382
|
+
"profiles": [
|
|
383
|
+
"https://welldot.org/profiles/brazil-ana/v1/schema.json",
|
|
384
|
+
"https://inspire.ec.europa.eu/schemas/gwhyd/4.0/profile.json"
|
|
385
|
+
]
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Profile schema requirements
|
|
389
|
+
|
|
390
|
+
- Each URL MUST be an HTTPS URL resolving to a JSON Schema document (`Content-Type: application/schema+json` or `application/json`).
|
|
391
|
+
- The schema SHOULD extend the canonical `.well` v2 schema via `allOf` + `$ref`, but this is not required.
|
|
392
|
+
- The schema MAY link to human documentation via its `description` field or a custom `x-documentation` field pointing to a Markdown or PDF URL.
|
|
393
|
+
- Profiles MAY impose additional required fields, constrain vocabulary values, or mandate the use of specific `x-` extensions for a regulatory context.
|
|
394
|
+
|
|
395
|
+
### Profile validation
|
|
396
|
+
|
|
397
|
+
- If a profile URL is unreachable, returns a non-JSON document, or fails to parse as JSON Schema, the profile is silently ignored. Parsers MUST NOT reject files whose profile URLs are unavailable.
|
|
398
|
+
- A profile-aware parser SHOULD validate the file against each reachable profile schema and surface failures as **warnings**, not errors. Conformance is asserted by the author, not enforced by the spec.
|
|
399
|
+
- Profile URLs SHOULD be versioned via path segments or schema-internal `$id` to ensure stability.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Extensibility
|
|
404
|
+
|
|
405
|
+
### Custom fields — `x-` prefix
|
|
406
|
+
|
|
407
|
+
Any implementer may add custom fields to any object by prefixing the field name with `x-`. This convention is established by OpenAPI 3.x and JSON Schema. Parsers MUST preserve and ignore `x-` fields they do not recognize. Sub-properties within an `x-` object do not need to be prefixed.
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{
|
|
411
|
+
"id": "b2c3d4e5-...",
|
|
412
|
+
"type": "constant_rate",
|
|
413
|
+
"datetime": "2006-03-14T08:00:00-03:00",
|
|
414
|
+
"x-siagas": {
|
|
415
|
+
"registro": "SP-0042819",
|
|
416
|
+
"processo_ana": "02000.001234/2006-78"
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Fields without the `x-` prefix that are not defined in this spec are technically non-conformant. Parsers MUST NOT reject such files but SHOULD emit a warning.
|
|
422
|
+
|
|
423
|
+
### Custom top-level blocks — `x-` prefix required
|
|
424
|
+
|
|
425
|
+
Top-level blocks not defined in this spec MUST use the `x-` prefix. Parsers MUST preserve and ignore unrecognized top-level keys.
|
|
426
|
+
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"version": 2,
|
|
430
|
+
"x-water_quality": [ ... ],
|
|
431
|
+
"x-geophysical_logs": [ ... ]
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Custom vocabulary values — `x-` prefix
|
|
436
|
+
|
|
437
|
+
Open vocabulary fields in this spec (`type` in `hydrodynamic_events`, `category` in `history_logs`, `vocabulary` in `texture`, `method` in `aquifer_analysis`, `well_type`, and any other field documented as accepting any string) SHOULD use the `x-` prefix when the value is non-canonical — i.e. not listed in the recommended vocabulary of this spec.
|
|
438
|
+
|
|
439
|
+
Parsers MUST treat `x-` prefixed vocabulary values as valid. Promotion from `x-` form to canonical form follows the Deprecation Policy (see § Deprecation Policy — Vocabulary value promotion).
|
|
440
|
+
|
|
441
|
+
```json
|
|
442
|
+
{ "type": "x-slug_test" }
|
|
443
|
+
{ "category": "x-decommission" }
|
|
444
|
+
{ "method": "x-theis_recovery" }
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Cross-reference and Uniqueness Rules
|
|
450
|
+
|
|
451
|
+
The `.well` format uses string IDs to link records across arrays. This section is the single normative source for ID semantics.
|
|
452
|
+
|
|
453
|
+
### Uniqueness scope
|
|
454
|
+
|
|
455
|
+
Each ID-bearing array maintains its **own uniqueness scope**. The ID namespaces are independent:
|
|
456
|
+
|
|
457
|
+
- `hydrodynamic_events[].id` — unique within `hydrodynamic_events`
|
|
458
|
+
- `aquifer_analysis[].id` — unique within `aquifer_analysis`
|
|
459
|
+
- `history_logs[].id` — unique within `history_logs`
|
|
460
|
+
- `history_logs[].attachments[].id` — unique within the attachments array of the same log entry
|
|
461
|
+
- `well_id[]` — uniqueness is on the composite key `(authority, id)`, not on `id` alone
|
|
462
|
+
|
|
463
|
+
An ID value MAY repeat across different arrays without conflict (e.g. an event and an analysis MAY both use the ID `"001"`), though distinct values are recommended for clarity.
|
|
464
|
+
|
|
465
|
+
### Cross-array references
|
|
466
|
+
|
|
467
|
+
The following fields hold references to IDs in other arrays:
|
|
468
|
+
|
|
469
|
+
| Reference field | Points to | Resolution scope |
|
|
470
|
+
| ------------------------------------------- | -------------------------- | ---------------- |
|
|
471
|
+
| `aquifer_analysis[].source_event_ids[]` | `hydrodynamic_events[].id` | Same file only |
|
|
472
|
+
| `aquifer_analysis[].static_level_source_id` | `hydrodynamic_events[].id` | Same file only |
|
|
473
|
+
|
|
474
|
+
Cross-file references are not supported in v2.
|
|
475
|
+
|
|
476
|
+
### Dangling references
|
|
477
|
+
|
|
478
|
+
A **dangling reference** is a reference field whose value does not match any ID in the target array.
|
|
479
|
+
|
|
480
|
+
- Dangling references MUST emit a warning naming the referring field, the referring object's ID, and the missing target ID.
|
|
481
|
+
- Dangling references MUST NOT cause file rejection. Events may be legitimately deleted from history (regulatory retention rules, GDPR-style erasure) leaving analyses that reference them stranded.
|
|
482
|
+
- Applications SHOULD surface dangling references to the user as a data-integrity concern and offer to either (a) update the analysis to remove the reference, or (b) restore the missing event.
|
|
483
|
+
|
|
484
|
+
### Duplicate IDs within a scope
|
|
485
|
+
|
|
486
|
+
A **duplicate ID** occurs when two records in the same uniqueness scope share the same ID (or, for `well_id`, the same `(authority, id)` pair).
|
|
487
|
+
|
|
488
|
+
Duplicate IDs are **malformed but recoverable**:
|
|
489
|
+
|
|
490
|
+
- Parsers MUST NOT silently accept duplicate IDs. The file is considered malformed.
|
|
491
|
+
- Parsers MUST NOT silently rewrite duplicate IDs. Automatic renaming would change the object graph in a way that downstream references cannot detect.
|
|
492
|
+
- Interactive applications MUST surface the duplication to the user with sufficient context to decide:
|
|
493
|
+
- The IDs in conflict
|
|
494
|
+
- A summary of each conflicting record (datetime, type, key fields)
|
|
495
|
+
- The choices: **merge** (keep one, discard the other), **rename** (assign a new ID to one of them, updating any references in the same file), or **abort load**.
|
|
496
|
+
- Non-interactive parsers (batch importers, server-side validators) MUST reject the file with a clear error rather than guess.
|
|
497
|
+
- Any user-confirmed resolution MUST be logged as a `history_logs` entry with `category: "event"` describing what was changed.
|
|
498
|
+
|
|
499
|
+
The objective is deterministic load behavior: a `.well` file MUST produce the same object graph across all conformant parsers under default settings. User-mediated repair is the only path that can deviate from this, and it must be explicit.
|
|
500
|
+
|
|
501
|
+
### `id` field convention
|
|
502
|
+
|
|
503
|
+
All `id` fields are `string` type. UUID v4 is recommended for new records. Sequential strings (e.g. `"evt-001"`) are valid for manually authored files. Numeric IDs from external systems are converted per the rule documented in § well_id (Numeric ID conversion).
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Precision and Uncertainty
|
|
508
|
+
|
|
509
|
+
Optional one-sigma precision qualifiers are defined for the most consequential measurement fields. Parsers that do not recognize them ignore them per the foreign-members rule.
|
|
510
|
+
|
|
511
|
+
The precision field name is the measurement field name suffixed with `_precision`. The unit of the precision value is the unit of the measurement it qualifies.
|
|
512
|
+
|
|
513
|
+
### Supported precision fields
|
|
514
|
+
|
|
515
|
+
| Measurement | Precision field | Defined on |
|
|
516
|
+
| --------------- | ------------------------- | -------------------------- |
|
|
517
|
+
| `lat` | `lat_precision` | `LocationProperties` |
|
|
518
|
+
| `lng` | `lng_precision` | `LocationProperties` |
|
|
519
|
+
| `elevation` | `elevation_precision` | `LocationProperties` |
|
|
520
|
+
| `static_level` | `static_level_precision` | events, `AquiferAnalysis` |
|
|
521
|
+
| `dynamic_level` | `dynamic_level_precision` | `AquiferAnalysis` |
|
|
522
|
+
| `depth` | `depth_precision` | `LevelReading`, `Fracture` |
|
|
523
|
+
| `rate` | `rate_precision` | `PumpingStep` |
|
|
524
|
+
| `flow_rate` | `flow_rate_precision` | `AquiferAnalysis` |
|
|
525
|
+
|
|
526
|
+
All precision fields are optional. When omitted, the measurement value carries no documented precision. Precision is the one-sigma standard deviation in the same unit as the measurement.
|
|
527
|
+
|
|
528
|
+
```json
|
|
529
|
+
{ "depth": 44.8, "depth_precision": 0.01 }
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
_Draft — `.well` Format Specification v2.0_
|