From 09dbfc0fc78bda0a8859e24741b76af8b04afdbb Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 13:01:56 -0600 Subject: [PATCH 01/21] feat: create new `Parameter` model and add it to the `__init__.py` file. --- db/__init__.py | 1 + db/parameter.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 db/parameter.py diff --git a/db/__init__.py b/db/__init__.py index e448b2b9e..50e013eeb 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -30,6 +30,7 @@ from db.lexicon import * from db.location import * from db.observation import * +from db.parameter import * from db.publication import * from db.sample import * from db.sensor import * diff --git a/db/parameter.py b/db/parameter.py new file mode 100644 index 000000000..175250335 --- /dev/null +++ b/db/parameter.py @@ -0,0 +1,55 @@ +""" +This table is a controlled vocabulary for all analytes, properties, and +characteristics that can be measured or observed. +""" + +from typing import List, TYPE_CHECKING + +from sqlalchemy.orm import relationship, Mapped, mapped_column + +from db.base import Base, AutoBaseMixin, ReleaseMixin, lexicon_term + +if TYPE_CHECKING: + from db.observation import Observation + from db.regulatory_limit import RegulatoryLimit + + +class Parameter(Base, AutoBaseMixin, ReleaseMixin): + """ + + Represents an analyte or property that can be measured (e.g., Chloride). + """ + + __versioned__ = {} + + # --- Columns --- + # TODO: The lexicon is currently storing parameter names in the 'observed_property' category. Should we update the lexicon category name to parameter_name? + parameter_name: Mapped[str] = lexicon_term( + nullable=False, + unique=True, + comment="The official, full name of the parameter (e.g., 'Arsenic, Dissolved').", + ) + parameter_type: Mapped[str] = lexicon_term( + nullable=True, + comment="A controlled vocabulary field defining the category of the parameter (e.g., 'Metals', 'Nutrients', 'Field Parameter'). Used for grouping and filtering.", + ) + cas_number: Mapped[str] = mapped_column( + nullable=True, + comment="he Chemical Abstracts Service (CAS) registry number, a globally unique identifier for a chemical substance.", + ) + default_unit: Mapped[str] = lexicon_term( + nullable=False, + comment="The standard, preferred unit for reporting this parameter (e.g., 'ug/L', 'mg/L', 'pH units').", + ) + + # --- Relationships --- + # One-To-Many: A Parameter can have many Observations. + observations: Mapped[List["Observation"]] = relationship( + "Observation", back_populates="parameter" + ) + + # One-To-Many: A Parameter can have many associated RegulatoryLimits. + # If a Parameter is deleted, all its associated limits are deleted as well. + reg_limits: Mapped[List["RegulatoryLimit"]] = relationship( + "RegulatoryLimit", back_populates="parameter", cascade="all, delete-orphan" + ) From 6ce3e6f1764feccd5a4028982da2ab812092049a Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 13:35:28 -0600 Subject: [PATCH 02/21] feat: create new `regulatory_limit` table. refactor: Add valid limit_type values to the `lexicon.json` file. --- core/lexicon.json | 14 +++++++++++- db/regulatory_limit.py | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 db/regulatory_limit.py diff --git a/core/lexicon.json b/core/lexicon.json index 14d2a1828..cace828ba 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -515,5 +515,17 @@ {"categories": [{"name": "sample_type", "description": null}], "term": "Standard field sample", "definition": "Standard field sample"}, {"categories": [{"name": "sample_type", "description": null}], "term": "Soil or Rock sample", "definition": "Soil or Rock sample"}, {"categories": [{"name": "sample_type", "description": null}], "term": "Trip blank", "definition": "Trip blank"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Source water blank", "definition": "Source water blank"} + {"categories": [{"name": "sample_type", "description": null}], "term": "Source water blank", "definition": "Source water blank"}, + + {"categories": [{"name": "limit_type", "description": null}], "term": "MCL", "definition": "Maximum Contaminant Level. The highest level of a contaminant that is legally allowed in public drinking water systems under the Safe Drinking Water Act. This is an enforceable standard."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "SMCL", "definition": "Secondary MCL. A non-enforceable federal guideline for contaminants that may cause cosmetic effects (e.g., skin or tooth discoloration) or aesthetic effects (e.g., taste, odor, color) in drinking water."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "AL", "definition": "Action Level. The concentration of a contaminant which, if exceeded, triggers specific treatment or other requirements that a water system must follow. Used for contaminants like Lead and Copper."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "GWQS", "definition": "Groundwater Quality Standard. State-specific standards for groundwater quality."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "RSL", "definition": "Regional Screening Level. Health-based risk screening levels developed by the EPA. They are used to help determine if a site requires further investigation or cleanup but are not legally enforceable cleanup standards themselves."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "MRL", "definition": "Method Reporting Limit. The lowest concentration of an analyte that a laboratory can reliably quantify within specified limits of precision and accuracy for a given analytical method. This is the most common 'limit of detection' you will see on a final lab report. Often used interchangeably with PQL."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "PQL", "definition": "Practical Quantitation Limit. Similar to the MRL, this is the lowest concentration achievable by a lab during routine operating conditions. It represents the practical, real-world limit of quantification."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "MDL", "definition": "Method Detection Limit. The minimum measured concentration of a substance that can be reported with 99% confidence that the analyte concentration is greater than zero. It is a statistical value determined under ideal lab conditions and is typically lower than the MRL/PQL."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "IDL", "definition": "Instrument Detection Limit. The lowest concentration of an analyte that can be reliably detected by a specific piece of laboratory equipment. It measures the capability of the instrument itself, which is a component of the overall MDL."}, + {"categories": [{"name": "limit_type", "description": null}], "term": "RL", "definition": "Reporting Limit. A generic term often used by labs to mean their MRL or PQL. It is the lowest concentration they are willing to report as a quantitative result."}, + ] \ No newline at end of file diff --git a/db/regulatory_limit.py b/db/regulatory_limit.py new file mode 100644 index 000000000..8bc391824 --- /dev/null +++ b/db/regulatory_limit.py @@ -0,0 +1,51 @@ +""" +This table stores the various regulatory or health-based limits for a given +parameter, sourced from different agencies or standards. + +The purpose of this table is to solve the real-world problem where a single +chemical (`Parameter`) can have multiple different limits set by various agencies +(e.g., a federal EPA limit and a state-level NMED limit). +""" + +from typing import TYPE_CHECKING + +from sqlalchemy import Integer, Numeric, ForeignKey +from sqlalchemy.orm import relationship, Mapped, mapped_column + +from db.base import Base, AutoBaseMixin, ReleaseMixin, lexicon_term + +if TYPE_CHECKING: + from db.parameter import Parameter + + +class RegulatoryLimit(Base, AutoBaseMixin, ReleaseMixin): + """ + Represents a single, citable regulatory or health-based limit for a + specific Parameter. + """ + + __versioned__ = {} + + # --- Foreign Keys --- + parameter_id: Mapped[int] = mapped_column( + Integer, ForeignKey("parameter.id"), nullable=False + ) + + # --- Columns --- + limit_source: Mapped[str] = lexicon_term( + nullable=False, + comment="The official source of the limit (e.g., 'EPA MCL', 'NMED GWQS', 'EPA RSL').", + ) + limit_value: Mapped[float] = mapped_column(Numeric, nullable=False) + limit_unit: Mapped[str] = lexicon_term(nullable=False) + # TODO: Add valid limit type values to lexicon.json file + limit_type: Mapped[str] = lexicon_term( + nullable=True, + comment="A controlled vocabulary field to categorize the limit (e.g., 'MCL', 'PQL', 'MDL', etc.).", + ) + + # --- Relationships --- + # Many-To-One: A RegulatoryLimit is for one Parameter. + parameter: Mapped["Parameter"] = relationship( + "Parameter", back_populates="reg_limits" + ) From 14461fb97dd6e025acef1c5e89bbf95eca513d93 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 13:36:10 -0600 Subject: [PATCH 03/21] refactor: remove TODO from `regulatory_limit` table. --- db/regulatory_limit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/db/regulatory_limit.py b/db/regulatory_limit.py index 8bc391824..4f4b65a5a 100644 --- a/db/regulatory_limit.py +++ b/db/regulatory_limit.py @@ -38,7 +38,6 @@ class RegulatoryLimit(Base, AutoBaseMixin, ReleaseMixin): ) limit_value: Mapped[float] = mapped_column(Numeric, nullable=False) limit_unit: Mapped[str] = lexicon_term(nullable=False) - # TODO: Add valid limit type values to lexicon.json file limit_type: Mapped[str] = lexicon_term( nullable=True, comment="A controlled vocabulary field to categorize the limit (e.g., 'MCL', 'PQL', 'MDL', etc.).", From fb67f5784ddf30cec78143b45bbe5baf94bc7515 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 13:38:34 -0600 Subject: [PATCH 04/21] refactor: modify the TODO in the `parameter` table. --- db/parameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/parameter.py b/db/parameter.py index 175250335..ca9bb897a 100644 --- a/db/parameter.py +++ b/db/parameter.py @@ -23,7 +23,7 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): __versioned__ = {} # --- Columns --- - # TODO: The lexicon is currently storing parameter names in the 'observed_property' category. Should we update the lexicon category name to parameter_name? + # TODO: Parameter names are currently associated with the 'observed_property' category in the lexicon. Should we update the lexicon category name to 'parameter_name'? parameter_name: Mapped[str] = lexicon_term( nullable=False, unique=True, From a5e8d37dfc34f13996e829a176c3cd3fd0322508 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 14:34:34 -0600 Subject: [PATCH 05/21] refactor: modify comment for `limit_source` field. --- db/regulatory_limit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/regulatory_limit.py b/db/regulatory_limit.py index 4f4b65a5a..f5614ddb5 100644 --- a/db/regulatory_limit.py +++ b/db/regulatory_limit.py @@ -34,7 +34,7 @@ class RegulatoryLimit(Base, AutoBaseMixin, ReleaseMixin): # --- Columns --- limit_source: Mapped[str] = lexicon_term( nullable=False, - comment="The official source of the limit (e.g., 'EPA MCL', 'NMED GWQS', 'EPA RSL').", + comment="The official source of the limit (e.g., 'EPA', 'NMED', 'EPA').", ) limit_value: Mapped[float] = mapped_column(Numeric, nullable=False) limit_unit: Mapped[str] = lexicon_term(nullable=False) From 4e2c68301d1db61748f61629d603f86a37161b7d Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 14:42:59 -0600 Subject: [PATCH 06/21] feat: add `parameter` relationship and foreign key to`Observation` model. --- db/observation.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/observation.py b/db/observation.py index af737a7cf..c267eac96 100644 --- a/db/observation.py +++ b/db/observation.py @@ -29,6 +29,7 @@ from db.sample import Sample from db.sensor import Sensor from db.analysis_method import AnalysisMethod + from db.parameter import Parameter class Observation(Base, AutoBaseMixin, ReleaseMixin): @@ -50,6 +51,10 @@ class Observation(Base, AutoBaseMixin, ReleaseMixin): Integer, ForeignKey("analysis_method.id"), nullable=True ) + parameter_id: Mapped[int] = mapped_column( + Integer, ForeignKey("parameter.id"), nullable=False + ) + # --- Columns --- observation_datetime: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, doc="Timestamp of the observation" @@ -92,5 +97,10 @@ class Observation(Base, AutoBaseMixin, ReleaseMixin): "AnalysisMethod", back_populates="observations" ) + # Many-To-One: An Observation measures one Parameter. + parameter: Mapped["Parameter"] = relationship( + "Parameter", back_populates="observations" + ) + # ============= EOF ============================================= From f0ef0a819a75974bd12c25b084d11170472dfb47 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Fri, 26 Sep 2025 20:43:32 +0000 Subject: [PATCH 07/21] Formatting changes --- transfers/contact_transfer.py | 98 ++++++++++++++++++++++------------ transfers/link_ids_transfer.py | 4 +- transfers/well_transfer.py | 4 +- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/transfers/contact_transfer.py b/transfers/contact_transfer.py index 80dfad4c8..81741fd56 100644 --- a/transfers/contact_transfer.py +++ b/transfers/contact_transfer.py @@ -107,54 +107,71 @@ def _add_first_contact(session, row, thing): "nma_pk_owners": row.OwnerKey, "addresses": [], "emails": [], - "phones": [] + "phones": [], } contact = _make_contact_and_assoc(session, contact_data, thing) if row.Email: - email = _make_email('first', row.OwnerKey, email=row.Email, - email_type="Primary", - release_status=release_status) + email = _make_email( + "first", + row.OwnerKey, + email=row.Email, + email_type="Primary", + release_status=release_status, + ) if email: contact.emails.append(email) if row.Phone: - phone = _make_phone('first', row.OwnerKey, phone_number=row.Phone, - phone_type="Primary", - release_status=release_status) + phone = _make_phone( + "first", + row.OwnerKey, + phone_number=row.Phone, + phone_type="Primary", + release_status=release_status, + ) if phone: contact.phones.append(phone) if row.CellPhone: - phone = _make_phone('first', row.OwnerKey, phone_number=row.CellPhone, - phone_type="Mobile", - release_status=release_status) + phone = _make_phone( + "first", + row.OwnerKey, + phone_number=row.CellPhone, + phone_type="Mobile", + release_status=release_status, + ) if phone: contact.phones.append(phone) if row.MailingAddress: - address = _make_address('first', row.OwnerKey, - 'mailing', - address_line_1=row.MailingAddress, - city=row.MailCity, - state=row.MailState, - postal_code=row.MailZipCode, - address_type="Mailing", - release_status=release_status) + address = _make_address( + "first", + row.OwnerKey, + "mailing", + address_line_1=row.MailingAddress, + city=row.MailCity, + state=row.MailState, + postal_code=row.MailZipCode, + address_type="Mailing", + release_status=release_status, + ) if address: contact.addresses.append(address) if row.PhysicalAddress: - address = _make_address('first', row.OwnerKey, - 'physical', - address_line_1=row.PhysicalAddress, - city=row.PhysicalCity, - state=row.PhysicalState, - postal_code=row.PhysicalZipCode, - address_type="Physical", - release_status=release_status - ) + address = _make_address( + "first", + row.OwnerKey, + "physical", + address_line_1=row.PhysicalAddress, + city=row.PhysicalCity, + state=row.PhysicalState, + postal_code=row.PhysicalZipCode, + address_type="Physical", + release_status=release_status, + ) if address: contact.addresses.append(address) @@ -174,22 +191,30 @@ def _add_second_contact(session, row, thing): "nma_pk_owners": row.OwnerKey, "addresses": [], "emails": [], - "phones": [] + "phones": [], } contact = _make_contact_and_assoc(session, contact_data, thing) if row.SecondCtctEmail: - email = _make_email('second', row.OwnerKey, email=row.SecondCtctEmail, - email_type="Primary", - release_status=release_status) + email = _make_email( + "second", + row.OwnerKey, + email=row.SecondCtctEmail, + email_type="Primary", + release_status=release_status, + ) if email: contact.emails.append(email) if row.SecondCtctPhone: - phone = _make_phone('second', row.OwnerKey, phone_number=row.SecondCtctPhone, - phone_type="Primary", - release_status=release_status) + phone = _make_phone( + "second", + row.OwnerKey, + phone_number=row.SecondCtctPhone, + phone_type="Primary", + release_status=release_status, + ) if phone: contact.phones.append(phone) @@ -205,6 +230,7 @@ def _make_name(first, last): else: return f"{first} {last}" + def _make_email(first_second, ownerkey, **kw): try: email = CreateEmail(**kw) @@ -214,6 +240,7 @@ def _make_email(first_second, ownerkey, **kw): f"{first_second} '{ownerkey}' Skipping email. Validation error: {e}" ) + def _make_phone(first_second, ownerkey, **kw): try: phone = CreatePhone(**kw) @@ -223,6 +250,7 @@ def _make_phone(first_second, ownerkey, **kw): f"{first_second} '{ownerkey}' Skipping phone . Validation error: {e}" ) + def _make_address(first_second, ownerkey, kind, **kw): try: address = CreateAddress(**kw) @@ -231,6 +259,8 @@ def _make_address(first_second, ownerkey, kind, **kw): logger.warning( f"{first_second} '{ownerkey}' Skipping {kind} address. Validation error: {e}" ) + + # def _make_contact_and_assoc(session, data, thing): contact = CreateContact(**data) diff --git a/transfers/link_ids_transfer.py b/transfers/link_ids_transfer.py index 8e4cfd339..3b935fc85 100644 --- a/transfers/link_ids_transfer.py +++ b/transfers/link_ids_transfer.py @@ -114,7 +114,9 @@ def add_link_site_id(session, row, thing): if not re.match(r"^\d{15}$", site_id): # TODO: lets make a sweet function for flagging issues # flag for interrogation - logger.critical(f"{row.PointID} alternate id {site_id} is not a valid USGS site id") + logger.critical( + f"{row.PointID} alternate id {site_id} is not a valid USGS site id" + ) return link_id.alternate_id = row.SiteID diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index 8bb6179dd..f62ffb6b8 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -57,7 +57,9 @@ def transfer_wells(session, limit=0): for i, row in enumerate(wdf.itertuples()): pointid = row.PointID if wdf[wdf["PointID"] == pointid].shape[0] > 1: - logger.critical(f"transfer_wells. PointID {pointid} has duplicate records. Skipping.") + logger.critical( + f"transfer_wells. PointID {pointid} has duplicate records. Skipping." + ) continue if limit and i >= limit: From 22f262687ba212d6b7430ce396d41956301fc725 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Sat, 27 Sep 2025 13:57:02 -0600 Subject: [PATCH 08/21] refactor: update relationship name from `reg_limit` to `regulatory_limit` --- db/parameter.py | 2 +- db/regulatory_limit.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/parameter.py b/db/parameter.py index ca9bb897a..0befe41b5 100644 --- a/db/parameter.py +++ b/db/parameter.py @@ -50,6 +50,6 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): # One-To-Many: A Parameter can have many associated RegulatoryLimits. # If a Parameter is deleted, all its associated limits are deleted as well. - reg_limits: Mapped[List["RegulatoryLimit"]] = relationship( + regulatory_limits: Mapped[List["RegulatoryLimit"]] = relationship( "RegulatoryLimit", back_populates="parameter", cascade="all, delete-orphan" ) diff --git a/db/regulatory_limit.py b/db/regulatory_limit.py index f5614ddb5..f72643c60 100644 --- a/db/regulatory_limit.py +++ b/db/regulatory_limit.py @@ -46,5 +46,5 @@ class RegulatoryLimit(Base, AutoBaseMixin, ReleaseMixin): # --- Relationships --- # Many-To-One: A RegulatoryLimit is for one Parameter. parameter: Mapped["Parameter"] = relationship( - "Parameter", back_populates="reg_limits" + "Parameter", back_populates="regulatory_limits" ) From 39ce40e9ff1ca1a2d7c51319e27782cf26c72d9b Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Mon, 29 Sep 2025 10:40:33 -0600 Subject: [PATCH 09/21] refactor: fix typo in `cas_number` comment --- db/parameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/parameter.py b/db/parameter.py index 0befe41b5..21873f345 100644 --- a/db/parameter.py +++ b/db/parameter.py @@ -35,7 +35,7 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): ) cas_number: Mapped[str] = mapped_column( nullable=True, - comment="he Chemical Abstracts Service (CAS) registry number, a globally unique identifier for a chemical substance.", + comment="The Chemical Abstracts Service (CAS) registry number, a globally unique identifier for a chemical substance.", ) default_unit: Mapped[str] = lexicon_term( nullable=False, From 808f8ca70ba4d4ce6608d886b518863090866d7c Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Tue, 30 Sep 2025 11:34:13 -0600 Subject: [PATCH 10/21] feat: add 'matrix' field and unique constraint to `Parameter` table. --- db/parameter.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/db/parameter.py b/db/parameter.py index 21873f345..e64ea08b1 100644 --- a/db/parameter.py +++ b/db/parameter.py @@ -29,6 +29,10 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): unique=True, comment="The official, full name of the parameter (e.g., 'Arsenic, Dissolved').", ) + matrix: Mapped[str] = lexicon_term( + nullable=False, + comment="A controlled vocabulary field defining the physical medium the analyte is measured in (e.g., 'Water', 'Soil', 'Air').", + ) parameter_type: Mapped[str] = lexicon_term( nullable=True, comment="A controlled vocabulary field defining the category of the parameter (e.g., 'Metals', 'Nutrients', 'Field Parameter'). Used for grouping and filtering.", @@ -53,3 +57,12 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): regulatory_limits: Mapped[List["RegulatoryLimit"]] = relationship( "RegulatoryLimit", back_populates="parameter", cascade="all, delete-orphan" ) + + # --- Table Arguments --- + # An analyte is defined by its name and matrix. This constraint + # ensures a single, specific analyte can only be defined once. + from sqlalchemy import UniqueConstraint + + __table_args__ = ( + UniqueConstraint("parameter_name", "matrix", name="uq_parameter_name_matrix"), + ) From 3e7bd0e39b3a6cf59d2ec983fc4d54d91d82b793 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Tue, 30 Sep 2025 13:35:07 -0600 Subject: [PATCH 11/21] feat: add `RegulatoryLimit` model to the `db/__init__.py` file so it can be discovered --- db/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/db/__init__.py b/db/__init__.py index 966dce4a3..b0d70dd5a 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -33,6 +33,7 @@ from db.observation import * from db.parameter import * from db.publication import * +from db.regulatory_limit import * from db.sample import * from db.sensor import * from db.thing import * From ac2b0d0369a671d23a30ba6d0a771c95837ab262 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Tue, 30 Sep 2025 21:08:05 -0600 Subject: [PATCH 12/21] refactor: updated the `lexicon.json` file to use the new normalized structure. --- core/lexicon.json | 1033 ++++++++++++++++++++++----------------------- 1 file changed, 499 insertions(+), 534 deletions(-) diff --git a/core/lexicon.json b/core/lexicon.json index 7826cf30f..dc8d274a3 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -1,534 +1,499 @@ -[ - {"categories": [{"name": "qc_type", "description": null}], "term": "Normal", "definition": "The primary environmental sample collected from the well, spring, or soil boring."}, - {"categories": [{"name": "qc_type", "description": null}], "term": "Duplicate", "definition": "A second, independent sample collected at the same location, at the same time, and in the same manner as the normal sample. This sample is sent to the primary laboratory."}, - {"categories": [{"name": "qc_type", "description": null}], "term": "Split", "definition": "A subsample of a primary environmental sample that is sent to a separate, independent laboratory for analysis."}, - {"categories": [{"name": "qc_type", "description": null}], "term": "Field Blank", "definition": "A sample of certified pure water that is taken to the field, opened, and processed through the same sampling procedure as a normal sample (e.g., poured into a sample bottle)."}, - {"categories": [{"name": "qc_type", "description": null}], "term": "Trip Blank", "definition": "A sample of certified pure water that is prepared in the lab, taken to the field, and brought back to the lab without ever being opened."}, - {"categories": [{"name": "qc_type", "description": null}], "term": "Equipment Blank", "definition": "A sample of certified pure water that is run through the sampling equipment (like a pump and tubing) before the normal sample is collected."}, - - - {"categories" : [{"name": "vertical_datum", "description": null}], "term": "NAVD88", "definition": "North American Vertical Datum of 1988"}, - {"categories" : [{"name": "vertical_datum", "description": null}], "term": "NGVD29", "definition": "National Geodetic Vertical Datum of 1929"}, - {"categories" : [{"name": "vertical_datum", "description": null}, - {"name": "horizontal_datum", "description": null}], "term": "WGS84", "definition": "World Geodetic System of 1984"}, - - {"categories": [{"name": "horizontal_datum", "description": null}], "term": "NAD83", "definition": "North American Datum of 1983"}, - {"categories": [{"name": "horizontal_datum", "description": null}], "term": "NAD27", "definition": "North American Datum of 1927"}, - - {"categories": [{"name": "elevation_method", "description": null}], "term": "Altimeter", "definition": "altimeter"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Differentially corrected GPS", "definition": "differentially corrected GPS"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Survey-grade GPS", "definition": "survey-grade GPS"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Global positioning system (GPS)", "definition": "Global positioning system (GPS)"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "LiDAR DEM", "definition": "LiDAR DEM"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Level or other survey method", "definition": "Level or other survey method"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Interpolated from topographic map", "definition": "Interpolated from topographic map"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Interpolated from digital elevation model (DEM)", "definition": "Interpolated from digital elevation model (DEM)"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Reported", "definition": "Reported"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "Survey-grade Global Navigation Satellite Sys, Lvl1", "definition": "Survey-grade Global Navigation Satellite Sys, Lvl1"}, - {"categories": [{"name": "elevation_method", "description": null}], "term": "USGS National Elevation Dataset (NED)", "definition": "USGS National Elevation Dataset (NED)"}, - {"categories": [{"name": "elevation_method", "description": null}, - {"name": "sample_method", "description": null}, - {"name": "coordinate_method", "description": null}, - {"name": "current_use", "description": null}, - {"name": "status", "description": null}, - {"name": "organization", "description": null}], "term": "Unknown", "definition": "Unknown"}, - - {"categories": [{"name": "construction_method", "description": null}], "term": "Air-rotary", "definition": "Air-rotary"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Bored or augered", "definition": "Bored or augered"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Cable-tool", "definition": "Cable-tool"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Hydraulic rotary (mud or water)", "definition": "Hydraulic rotary (mud or water)"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Air percussion", "definition": "Air percussion"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Reverse rotary", "definition": "Reverse rotary"}, - {"categories": [{"name": "construction_method", "description": null}], "term": "Driven", "definition": "Driven"}, - {"categories": [{"name": "construction_method", "description": null}, - {"name": "measurement_method", "description": null}], "term": "Other (explain in notes)", "definition": "Other (explain in notes)"}, - - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Differentially corrected GPS", "definition": "Differentially corrected GPS"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Survey-grade global positioning system (SGPS)", "definition": "Survey-grade global positioning system (SGPS)"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "GPS, uncorrected", "definition": "GPS, uncorrected"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Interpolated from map", "definition": "Interpolated from map"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Interpolated from DEM", "definition": "Interpolated from DEM"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Reported", "definition": "Reported"}, - {"categories": [{"name": "coordinate_method", "description": null}], "term": "Transit, theodolite, or other survey method", "definition": "Transit, theodolite, or other survey method"}, - - {"categories": [{"name": "current_use", "description": null}], "term": "Open, unequipped well", "definition": "Open, unequipped well"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Commercial", "definition": "Commercial"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Domestic", "definition": "Domestic"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Power generation", "definition": "Power generation"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Irrigation", "definition": "Irrigation"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Livestock", "definition": "Livestock"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Mining", "definition": "Mining"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Industrial", "definition": "Industrial"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Observation", "definition": "Observation"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Public supply", "definition": "Public supply"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Shared domestic", "definition": "Shared domestic"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Institutional", "definition": "Institutional"}, - {"categories": [{"name": "current_use", "description": null}], "term": "Unused", "definition": "Unused"}, - - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accurate to within two hundreths of a foot", "definition": "Good"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accurate to within one foot", "definition": "Fair"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accuracy not to nearest foot or water level not repeatable", "definition": "Poor"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accurate to nearest foot (USGS accuracy level)", "definition": "Water level accurate to nearest foot (USGS accuracy level)"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accurate to nearest tenth of a foot (USGS accuracy level)", "definition": "Water level accurate to nearest tenth of a foot (USGS accuracy level)"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accurate to nearest one-hundredth of a foot (USGS accuracy level)", "definition": "Water level accurate to nearest one-hundredth of a foot (USGS accuracy level)"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accuracy not to nearest foot (USGS accuracy level)", "definition": "Water level accuracy not to nearest foot (USGS accuracy level)"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "Water level accuracy unknown (USGS accuracy level)", "definition": "Water level accuracy unknown (USGS accuracy level)"}, - {"categories": [{"name": "data_quality", "description": null}], "term": "None", "definition": "NA"}, - - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}, - {"name": "discharge_source", "description": null}], "term": "Reported by another agency", "definition": "Reported by another agency"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "From driller's log or well report", "definition": "From driller's log or well report"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}, - {"name": "discharge_source", "description": null}], "term": "Private geologist, consultant or univ associate", "definition": "Private geologist, consultant or univ associate"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Depth interpreted fr geophys logs by source agency", "definition": "Depth interpreted fr geophys logs by source agency"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Memory of owner, operator, driller", "definition": "Memory of owner, operator, driller"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Reported by owner of well", "definition": "Reported by owner of well"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Reported by person other than driller owner agency", "definition": "Reported by person other than driller owner agency"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Measured by NMBGMR staff", "definition": "Measured by NMBGMR staff"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Other", "definition": "Other"}, - {"categories": [{"name": "data_source", "description": null}, - {"name": "depth_completion_source", "description": null}], "term": "Data Portal", "definition": "Data Portal"}, - - {"categories": [{"name": "discharge_source", "description": null}], "term": "Information from a report", "definition": "Information from a report"}, - {"categories": [{"name": "discharge_source", "description": null}], "term": "Measured by Bureau scientist", "definition": "Measured by Bureau scientist"}, - {"categories": [{"name": "discharge_source", "description": null}], "term": "Other (explain)", "definition": "Other (explain)"}, - - {"categories": [{"name": "unit", "description": null}], "term": "dimensionless", "definition": ""}, - {"categories": [{"name": "unit", "description": null}], "term": "ft", "definition": "feet"}, - {"categories": [{"name": "unit", "description": null}], "term": "ftbgs", "definition": "feet below ground surface"}, - {"categories": [{"name": "unit", "description": null}], "term": "F", "definition": "Fahrenheit"}, - {"categories": [{"name": "unit", "description": null}], "term": "mg/L", "definition": "Milligrams per Liter"}, - {"categories": [{"name": "unit", "description": null}], "term": "mW/m²", "definition": "milliwatts per square meter"}, - {"categories": [{"name": "unit", "description": null}], "term": "W/m²", "definition": "watts per square meter"}, - {"categories": [{"name": "unit", "description": null}], "term": "W/m·K", "definition": "watts per meter Kelvin"}, - {"categories": [{"name": "unit", "description": null}], "term": "m²/s", "definition": "square meters per second"}, - {"categories": [{"name": "unit", "description": null}], "term": "deg C", "definition": "degree Celsius"}, - {"categories": [{"name": "unit", "description": null}], "term": "deg second", "definition": "degree second"}, - {"categories": [{"name": "unit", "description": null}], "term": "deg minute", "definition": "degree minute"}, - {"categories": [{"name": "unit", "description": null}], "term": "second", "definition": "second"}, - {"categories": [{"name": "unit", "description": null}], "term": "minute", "definition": "minute"}, - {"categories": [{"name": "unit", "description": null}], "term": "hour", "definition": "hour"}, - - {"categories": [{"name": "observed_property", "description": null}], "term": "groundwater level", "definition": "groundwater level measurement" }, - {"categories": [{"name": "observed_property", "description": null}], "term": "temperature", "definition": "Temperature measurement"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "pH", "definition": "pH"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Alkalinity, Total", "definition": "Alkalinity, Total"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Alkalinity as OH-", "definition": "Alkalinity as OH-"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Calcium", "definition": "Calcium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Calcium, total, unfiltered", "definition": "Calcium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chloride", "definition": "Chloride"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Carbonate", "definition": "Carbonate"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Conductivity, laboratory", "definition": "Conductivity, laboratory"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Bicarbonate", "definition": "Bicarbonate"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Hardness (CaCO3)", "definition": "Hardness (CaCO3)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Ion Balance", "definition": "Ion Balance"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Potassium", "definition": "Potassium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Potassium, total, unfiltered", "definition": "Potassium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Magnesium", "definition": "Magnesium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Magnesium, total, unfiltered", "definition": "Magnesium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sodium", "definition": "Sodium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sodium, total, unfiltered", "definition": "Sodium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sodium and Potassium combined", "definition": "Sodium and Potassium combined"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sulfate", "definition": "Sulfate"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total Anions", "definition": "Total Anions"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total Cations", "definition": "Total Cations"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total Dissolved Solids", "definition": "Total Dissolved Solids"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Tritium", "definition": "Tritium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Age of Water using dissolved gases", "definition": "Age of Water using dissolved gases"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Silver", "definition": "Silver"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Silver, total, unfiltered", "definition": "Silver, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Aluminum", "definition": "Aluminum"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Aluminum, total, unfiltered", "definition": "Aluminum, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Arsenic", "definition": "Arsenic"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Arsenic, total, unfiltered", "definition": "Arsenic, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Boron", "definition": "Boron"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Boron, total, unfiltered", "definition": "Boron, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Barium", "definition": "Barium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Barium, total, unfiltered", "definition": "Barium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Beryllium", "definition": "Beryllium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Beryllium, total, unfiltered", "definition": "Beryllium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Bromide", "definition": "Bromide"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "13C:12C ratio", "definition": "13C:12C ratio"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "14C content, pmc", "definition": "14C content, pmc"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Uncorrected C14 age", "definition": "Uncorrected C14 age"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Cadmium", "definition": "Cadmium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Cadmium, total, unfiltered", "definition": "Cadmium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chlorofluorocarbon-11 avg age", "definition": "Chlorofluorocarbon-11 avg age"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chlorofluorocarbon-113 avg age", "definition": "Chlorofluorocarbon-113 avg age"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chlorofluorocarbon-113/12 avg RATIO age", "definition": "Chlorofluorocarbon-113/12 avg RATIO age"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chlorofluorocarbon-12 avg age", "definition": "Chlorofluorocarbon-12 avg age"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Cobalt", "definition": "Cobalt"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Cobalt, total, unfiltered", "definition": "Cobalt, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chromium", "definition": "Chromium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Chromium, total, unfiltered", "definition": "Chromium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Copper", "definition": "Copper"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Copper, total, unfiltered", "definition": "Copper, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "delta O18 sulfate", "definition": "delta O18 sulfate"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sulfate 34 isotope ratio", "definition": "Sulfate 34 isotope ratio"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Fluoride", "definition": "Fluoride"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Iron", "definition": "Iron"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Iron, total, unfiltered", "definition": "Iron, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Deuterium:Hydrogen ratio", "definition": "Deuterium:Hydrogen ratio"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Mercury", "definition": "Mercury"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Mercury, total, unfiltered", "definition": "Mercury, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Lithium", "definition": "Lithium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Lithium, total, unfiltered", "definition": "Lithium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Manganese", "definition": "Manganese"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Manganese, total, unfiltered", "definition": "Manganese, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Molybdenum", "definition": "Molybdenum"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Molybdenum, total, unfiltered", "definition": "Molybdenum, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nickel", "definition": "Nickel"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nickel, total, unfiltered", "definition": "Nickel, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nitrite (as NO2)", "definition": "Nitrite (as NO2)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nitrite (as N)", "definition": "Nitrite (as N)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nitrate (as NO3)", "definition": "Nitrate (as NO3)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Nitrate (as N)", "definition": "Nitrate (as N)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "18O:16O ratio", "definition": "18O:16O ratio"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Lead", "definition": "Lead"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Lead, total, unfiltered", "definition": "Lead, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Phosphate", "definition": "Phosphate"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Antimony", "definition": "Antimony"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Antimony, total, unfiltered", "definition": "Antimony, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Selenium", "definition": "Selenium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Selenium, total, unfiltered", "definition": "Selenium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Sulfur hexafluoride", "definition": "Sulfur hexafluoride"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Silicon", "definition": "Silicon"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Silicon, total, unfiltered", "definition": "Silicon, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Silica", "definition": "Silica"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Tin", "definition": "Tin"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Tin, total, unfiltered", "definition": "Tin, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Strontium", "definition": "Strontium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Strontium, total, unfiltered", "definition": "Strontium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Strontium 87:86 ratio", "definition": "Strontium 87:86 ratio"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Thorium", "definition": "Thorium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Thorium, total, unfiltered", "definition": "Thorium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Titanium", "definition": "Titanium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Titanium, total, unfiltered", "definition": "Titanium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Thallium", "definition": "Thallium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Thallium, total, unfiltered", "definition": "Thallium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Uranium (total, by ICP-MS)", "definition": "Uranium (total, by ICP-MS)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Uranium, total, unfiltered", "definition": "Uranium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Vanadium", "definition": "Vanadium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Vanadium, total, unfiltered", "definition": "Vanadium, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Zinc", "definition": "Zinc"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Zinc, total, unfiltered", "definition": "Zinc, total, unfiltered"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Corrected C14 in years", "definition": "Corrected C14 in years"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Arsenite (arsenic species)", "definition": "Arsenite (arsenic species)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Arsenate (arsenic species)", "definition": "Arsenate (arsenic species)"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Cyanide", "definition": "Cyanide"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Estimated recharge temperature", "definition": "Estimated recharge temperature"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Hydrogen sulfide", "definition": "Hydrogen sulfide"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Ammonia", "definition": "Ammonia"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Ammonium", "definition": "Ammonium"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total nitrogen", "definition": "Total nitrogen"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total Kjeldahl nitrogen", "definition": "Total Kjeldahl nitrogen"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Dissolved organic carbon", "definition": "Dissolved organic carbon"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "Total organic carbon", "definition": "Total organic carbon"}, - {"categories": [{"name": "observed_property", "description": null}], "term": "delta C13 of dissolved inorganic carbon", "definition": "delta C13 of dissolved inorganic carbon"}, - - - {"categories": [{"name": "release_status", "description": null}], "term": "draft", "definition": "draft version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "provisional", "definition": "provisional version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "final", "definition": "final version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "published", "definition": "published version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "archived", "definition": "archived version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "public", "definition": "public version"}, - {"categories": [{"name": "release_status", "description": null}], "term": "private", "definition": "private version"}, - - {"categories": [{"name": "relation", "description": null}], "term": "same_as", "definition": "same as"}, - {"categories": [{"name": "relation", "description": null}], "term": "related_to", "definition": "related to"}, - {"categories": [{"name": "relation", "description": null}], "term": "OSEWellTagID", "definition": "NM OSE well tag ID"}, - {"categories": [{"name": "relation", "description": null}], "term": "OSEPOD", "definition": "NM OSE 'Point of Diversion' ID"}, - {"categories": [{"name": "relation", "description": null}], "term": "PLSS", "definition": "Public Land Survey System ID"}, - - {"categories": [{"name": "activity_type", "description": null}], "term": "groundwater level", "definition": "groundwater level"}, - {"categories": [{"name": "activity_type", "description": null}], "term": "water chemistry", "definition": "water chemistry"}, - - - {"categories": [{"name": "field_contact_role", "description": null}], "term": "Lead", "definition": "the leader of the field event"}, - {"categories": [{"name": "field_contact_role", "description": null}], "term": "Participant", "definition": "a person participating in the field event"}, - {"categories": [{"name": "field_contact_role", "description": null}], "term": "Observer", "definition": "a person observing the field event"}, - {"categories": [{"name": "field_contact_role", "description": null}], "term": "Visitor", "definition": "a person visiting the field event"}, - - - {"categories": [{"name": "sample_matrix", "description": null}], "term": "water", "definition": "water"}, - {"categories": [{"name": "sample_matrix", "description": null}], "term": "soil", "definition": "soil"}, - - {"categories": [{"name": "thing_type", "description": null}], "term": "observation well", "definition": "a well used to monitor groundwater levels"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "piezometer", "definition": "a type of observation well that measures pressure head in the aquifer"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "monitoring well", "definition": "a well used to monitor groundwater quality or levels"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "production well", "definition": "a well used to extract groundwater for use"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "injection well", "definition": "a well used to inject water or other fluids into the ground"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "exploration well", "definition": "a well drilled to explore for groundwater or other resources"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "test well", "definition": "a well drilled to test the properties of the aquifer"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "abandoned well", "definition": "a well that is no longer in use and has been properly sealed"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "dry hole", "definition": "a well that did not produce water or other resources"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "artesian well", "definition": "a well that taps a confined aquifer where the water level is above the top of the aquifer"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "dug well", "definition": "a shallow well dug by hand or with machinery, typically lined with stones or bricks"}, - - {"categories": [{"name": "thing_type", "description": null}], "term": "water well", "definition": "a hole drill into the ground to access groundwater"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "spring", "definition": "a natural discharge of groundwater at the surface"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "perennial stream", "definition": "that has a continuous flow of water throughout the year, even during drier periods."}, - {"categories": [{"name": "thing_type", "description": null}], "term": "ephemeral stream", "definition": "a stream that flows only briefly during and after precipitation events"}, - {"categories": [{"name": "thing_type", "description": null}], "term": "meteorological station", "definition": "a station that measures the weather conditions at a particular location"}, - - {"categories": [{"name": "level_status", "description": null}], "term": "Water level affected by atmospheric pressure", "definition": "Water level affected by atmospheric pressure"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Water level was frozen (no level recorded).", "definition": "Water level was frozen (no level recorded)."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Site was dry", "definition": "Site was dry"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Site was flowing recently.", "definition": "Site was flowing recently."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Site was flowing. Water level or head couldn't be measured w/out additional equipment.", "definition": "Site was flowing. Water level or head couldn't be measured w/out additional equipment."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Nearby site that taps the same aquifer was flowing.", "definition": "Nearby site that taps the same aquifer was flowing."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Nearby site that taps the same aquifer had been flowing recently.", "definition": "Nearby site that taps the same aquifer had been flowing recently."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Recharge water was being injected into the aquifer at this site.", "definition": "Recharge water was being injected into the aquifer at this site."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Recharge water was being injected into nearby site that taps the same aquifer.", "definition": "Recharge water was being injected into nearby site that taps the same aquifer."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Water was cascading down the inside of the well.", "definition": "Water was cascading down the inside of the well."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Water level was affected by brackish or saline water.", "definition": "Water level was affected by brackish or saline water."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Well was not in hydraulic contact w/formation (from source other than defined in USGS C714 or C93).", "definition": "Well was not in hydraulic contact w/formation (from source other than defined in USGS C714 or C93)."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Measurement was discontinued (no level recorded).", "definition": "Measurement was discontinued (no level recorded)."}, - {"categories": [{"name": "level_status", "description": null}], "term": "Obstruction was encountered in the well (no level recorded)", "definition": "Obstruction was encountered in the well (no level recorded)"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Site was being pumped", "definition": "Site was being pumped"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Site was pumped recently", "definition": "Site was pumped recently"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Nearby site that taps the same aquifer was being pumped", "definition": "Nearby site that taps the same aquifer was being pumped"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Nearby site that taps the same aquifer was pumped recently", "definition": "Nearby site that taps the same aquifer was pumped recently"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Foreign substance present on the water surface", "definition": "Foreign substance present on the water surface"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Well was destroyed (no subsequent water levels should be recorded)", "definition": "Well was destroyed (no subsequent water levels should be recorded)"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Water level affected by stage in nearby surface-water site", "definition": "Water level affected by stage in nearby surface-water site"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Other conditions exist that would affect the level (remarks)", "definition": "Other conditions exist that would affect the level (remarks)"}, - {"categories": [{"name": "level_status", "description": null}], "term": "Water level not affected by status", "definition": "Water level not affected by status"}, - - {"categories": [{"name": "status", "description": null}], "term": "Abandoned", "definition": "Abandoned"}, - {"categories": [{"name": "status", "description": null}], "term": "Active, pumping well", "definition": "Active, pumping well"}, - {"categories": [{"name": "status", "description": null}], "term": "Destroyed, exists but not usable", "definition": "Destroyed, exists but not usable"}, - {"categories": [{"name": "status", "description": null}], "term": "Inactive, exists but not used", "definition": "Inactive, exists but not used"}, - - {"categories": [{"name": "sample_method", "description": null}], "term": "Airline measurement", "definition": "Airline measurement"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Analog or graphic recorder", "definition": "Analog or graphic recorder"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Calibrated airline measurement", "definition": "Calibrated airline measurement"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Differential GPS; especially applicable to surface expression of ground water", "definition": "Differential GPS; especially applicable to surface expression of ground water"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Estimated", "definition": "Estimated"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Transducer", "definition": "Transducer"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Pressure-gage measurement", "definition": "Pressure-gage measurement"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Calibrated pressure-gage measurement", "definition": "Calibrated pressure-gage measurement"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Interpreted from geophysical logs", "definition": "Interpreted from geophysical logs"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Manometer", "definition": "Manometer"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Non-recording gage", "definition": "Non-recording gage"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Observed (required for F, N, and W water level status)", "definition": "Observed (required for F, N, and W water level status)"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Sonic water level meter (acoustic pulse)", "definition": "Sonic water level meter (acoustic pulse)"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Reported, method not known", "definition": "Reported, method not known"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Steel-tape measurement", "definition": "Steel-tape measurement"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Electric tape measurement (E-probe)", "definition": "Electric tape measurement (E-probe)"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Unknown (for legacy data only; not for new data entry)", "definition": "Unknown (for legacy data only; not for new data entry)"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Calibrated electric tape; accuracy of equipment has been checked", "definition": "Calibrated electric tape; accuracy of equipment has been checked"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Calibrated electric cable", "definition": "Calibrated electric cable"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Uncalibrated electric cable", "definition": "Uncalibrated electric cable"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Continuous acoustic sounder", "definition": "Continuous acoustic sounder"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "Measurement not attempted", "definition": "Measurement not attempted"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "null placeholder", "definition": "null placeholder"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "bailer", "definition": "bailer"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "faucet at well head", "definition": "faucet at well head"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "faucet or outlet at house", "definition": "faucet or outlet at house"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "grab sample", "definition": "grab sample"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "pump", "definition": "pump"}, - {"categories": [{"name": "sample_method", "description": null}], "term": "thief sampler", "definition": "thief sampler"}, - - {"categories": [{"name": "analysis_method_type", "description": null}], "term": "Laboratory", "definition": "A procedure performed on a physical sample in a controlled, off-site laboratory environment. These methods typically involve complex instrumentation, standardized reagents, and formal quality control protocols."}, - {"categories": [{"name": "analysis_method_type", "description": null}], "term": "Field Procedure", "definition": "A standardized procedure performed on-site at the time of sample collection. This can involve direct measurement of the environmental medium using a calibrated field instrument or a specific, documented technique for collecting a sample."}, - {"categories": [{"name": "analysis_method_type", "description": null}], "term": "Calculation", "definition": "A mathematical procedure used to derive a new data point from one or more directly measured values. This type is used to document the provenance of calculated data, providing an auditable trail."}, - - {"categories": [{"name": "organization", "description": null}], "term": "USGS", "definition": "US Geological Survey"}, - {"categories": [{"name": "organization", "description": null}], "term": "TWDB", "definition": "Texas Water Development Board"}, - {"categories": [{"name": "organization", "description": null}], "term": "NMED", "definition": "New Mexico Environment Department"}, - {"categories": [{"name": "organization", "description": null}], "term": "NMOSE", "definition": "New Mexico Office of the State Engineer"}, - {"categories": [{"name": "organization", "description": null}], "term": "NMBGMR", "definition": "New Mexico Bureau of Geology and Mineral Resources"}, - {"categories": [{"name": "organization", "description": null}], "term": "Bernalillo Cty", "definition": "Bernalillo County"}, - {"categories": [{"name": "organization", "description": null}], "term": "BLM", "definition": "Bureau of Land Management"}, - {"categories": [{"name": "organization", "description": null}], "term": "SFC", "definition": "Santa Fe County"}, - {"categories": [{"name": "organization", "description": null}], "term": "NESWCD", "definition": "Northeast Soil & Water Conservation District"}, - {"categories": [{"name": "organization", "description": null}], "term": "NMISC", "definition": "New Mexico Interstate Stream Commission"}, - {"categories": [{"name": "organization", "description": null}], "term": "PVACD", "definition": "Pecos Valley Artesian Conservancy District"}, - {"categories": [{"name": "organization", "description": null}], "term": "TSWCD", "definition": "Taos Soil & Water Conservation District"}, - {"categories": [{"name": "organization", "description": null}], "term": "Bayard", "definition": "Bayard Municipal Water"}, - {"categories": [{"name": "organization", "description": null}], "term": "OSWCD", "definition": "Otero Soil & Water Conservation District"}, - {"categories": [{"name": "organization", "description": null}], "term": "SNL", "definition": "Sandia National Laboratories"}, - {"categories": [{"name": "organization", "description": null}], "term": "USFS", "definition": "United States Forest Service"}, - {"categories": [{"name": "organization", "description": null}], "term": "NMT", "definition": "New Mexico Tech"}, - {"categories": [{"name": "organization", "description": null}], "term": "NPS", "definition": "National Park Service"}, - - {"categories": [{"name": "collection_method", "description": null}], "term": "manual", "definition": "manual sampling"}, - {"categories": [{"name": "collection_method", "description": null}], "term": "continuous", "definition": "continuous sampling"}, - - {"categories": [{"name": "country", "description": null}], "term": "United States", "definition": "United States of America"}, - {"categories": [{"name": "country", "description": null}], "term": "Canada", "definition": "Canada"}, - {"categories": [{"name": "country", "description": null}], "term": "Mexico", "definition": "Mexico"}, - {"categories": [{"name": "country", "description": null}], "term": "United Kingdom", "definition": "United Kingdom of Great Britain and Northern Ireland"}, - {"categories": [{"name": "country", "description": null}], "term": "Australia", "definition": "Australia"}, - {"categories": [{"name": "country", "description": null}], "term": "Germany", "definition": "Germany"}, - {"categories": [{"name": "country", "description": null}], "term": "France", "definition": "France"}, - {"categories": [{"name": "country", "description": null}], "term": "Japan", "definition": "Japan"}, - - {"categories": [{"name": "state", "description": null}], "term": "New Mexico", "definition": "New Mexico"}, - {"categories": [{"name": "state", "description": null}], "term": "Texas", "definition": "Texas"}, - {"categories": [{"name": "state", "description": null}], "term": "Arizona", "definition": "Arizona"}, - {"categories": [{"name": "state", "description": null}], "term": "Utah", "definition": "Utah"}, - {"categories": [{"name": "state", "description": null}], "term": "Colorado", "definition": "Colorado"}, - - {"categories": [{"name": "county", "description": null}], "term": "Bernalillo", "definition": "Bernalillo"}, - {"categories": [{"name": "county", "description": null}], "term": "Catron", "definition": "Catron"}, - {"categories": [{"name": "county", "description": null}], "term": "Chaves", "definition": "Chaves"}, - {"categories": [{"name": "county", "description": null}], "term": "Cibola", "definition": "Cibola"}, - {"categories": [{"name": "county", "description": null}], "term": "Colfax", "definition": "Colfax"}, - {"categories": [{"name": "county", "description": null}], "term": "Curry", "definition": "Curry"}, - {"categories": [{"name": "county", "description": null}], "term": "De Baca", "definition": "De Baca"}, - {"categories": [{"name": "county", "description": null}], "term": "Doña Ana", "definition": "Doña Ana"}, - {"categories": [{"name": "county", "description": null}], "term": "Eddy", "definition": "Eddy"}, - {"categories": [{"name": "county", "description": null}], "term": "Grant", "definition": "Grant"}, - {"categories": [{"name": "county", "description": null}], "term": "Guadalupe", "definition": "Guadalupe"}, - {"categories": [{"name": "county", "description": null}], "term": "Harding", "definition": "Harding"}, - {"categories": [{"name": "county", "description": null}], "term": "Hidalgo", "definition": "Hidalgo"}, - {"categories": [{"name": "county", "description": null}], "term": "Lea", "definition": "Lea"}, - {"categories": [{"name": "county", "description": null}], "term": "Lincoln", "definition": "Lincoln"}, - {"categories": [{"name": "county", "description": null}], "term": "Los Alamos", "definition": "Los Alamos"}, - {"categories": [{"name": "county", "description": null}], "term": "Luna", "definition": "Luna"}, - {"categories": [{"name": "county", "description": null}], "term": "McKinley", "definition": "McKinley"}, - {"categories": [{"name": "county", "description": null}], "term": "Mora", "definition": "Mora"}, - {"categories": [{"name": "county", "description": null}], "term": "Otero", "definition": "Otero"}, - {"categories": [{"name": "county", "description": null}], "term": "Quay", "definition": "Quay"}, - {"categories": [{"name": "county", "description": null}], "term": "Rio Arriba", "definition": "Rio Arriba"}, - {"categories": [{"name": "county", "description": null}], "term": "Roosevelt", "definition": "Roosevelt"}, - {"categories": [{"name": "county", "description": null}], "term": "Sandoval", "definition": "Sandoval"}, - {"categories": [{"name": "county", "description": null}], "term": "San Juan", "definition": "San Juan"}, - {"categories": [{"name": "county", "description": null}], "term": "San Miguel", "definition": "San Miguel"}, - {"categories": [{"name": "county", "description": null}], "term": "Santa Fe", "definition": "Santa Fe"}, - {"categories": [{"name": "county", "description": null}], "term": "Sierra", "definition": "Sierra"}, - {"categories": [{"name": "county", "description": null}], "term": "Socorro", "definition": "Socorro"}, - {"categories": [{"name": "county", "description": null}], "term": "Taos", "definition": "Taos"}, - {"categories": [{"name": "county", "description": null}], "term": "Torrance", "definition": "Torrance"}, - {"categories": [{"name": "county", "description": null}], "term": "Union", "definition": "Union"}, - {"categories": [{"name": "county", "description": null}], "term": "Valencia", "definition": "Valencia"}, - - {"categories": [{"name": "role", "description": null}], "term": "Owner", "definition": "Owner"}, - {"categories": [{"name": "role", "description": null}], "term": "Manager", "definition": "Manager"}, - {"categories": [{"name": "role", "description": null}], "term": "Operator", "definition": "Operator"}, - {"categories": [{"name": "role", "description": null}], "term": "Driller", "definition": "Driller"}, - {"categories": [{"name": "role", "description": null}], "term": "Geologist", "definition": "Geologist"}, - {"categories": [{"name": "role", "description": null}], "term": "Hydrologist", "definition": "Hydrologist"}, - {"categories": [{"name": "role", "description": null}], "term": "Hydrogeologist", "definition": "Hydrogeologist"}, - {"categories": [{"name": "role", "description": null}], "term": "Engineer", "definition": "Engineer"}, - {"categories": [{"name": "role", "description": null}], "term": "Technician", "definition": "Technician"}, - - - {"categories": [{"name": "email_type", "description": null}, - {"name": "phone_type", "description": null}, - {"name": "address_type", "description": null}, - {"name": "contact_type", "description": null}], "term": "Primary", "definition": "primary"}, - {"categories": [{"name": "contact_type", "description": null}], "term": "Secondary", "definition": "secondary"}, - - {"categories": [{"name": "email_type", "description": null}, - {"name": "phone_type", "description": null}, - {"name": "address_type", "description": null}], "term": "Work", "definition": "work"}, - - {"categories": [{"name": "email_type", "description": null}, - {"name": "address_type", "description": null}], "term": "Personal", "definition": "personal"}, - - {"categories": [{"name": "address_type", "description": null}], "term": "Mailing", "definition": "mailing"}, - {"categories": [{"name": "address_type", "description": null}], "term": "Physical", "definition": "physical"}, - - {"categories": [{"name": "phone_type", "description": null}], "term": "Home", "definition": "Primary"}, - {"categories": [{"name": "phone_type", "description": null}], "term": "Mobile", "definition": "Primary"}, - - {"categories": [{"name": "spring_type", "description": null}], "term": "Artesian", "definition": "artesian spring"}, - {"categories": [{"name": "spring_type", "description": null}], "term": "Ephemeral", "definition": "ephemeral spring"}, - {"categories": [{"name": "spring_type", "description": null}], "term": "Perennial", "definition": "perennial spring"}, - {"categories": [{"name": "spring_type", "description": null}], "term": "Thermal", "definition": "thermal spring"}, - {"categories": [{"name": "spring_type", "description": null}], "term": "Mineral", "definition": "mineral spring"}, - - {"categories": [{"name": "well_type", "description": null}], "term": "Exploration", "definition": "Exploration well"}, - {"categories": [{"name": "well_type", "description": null}], "term": "Monitoring", "definition": "Monitoring"}, - {"categories": [{"name": "well_type", "description": null}], "term": "Production", "definition": "Production"}, - {"categories": [{"name": "well_type", "description": null}], "term": "Injection", "definition": "Injection"}, - - {"categories": [{"name": "casing_material", "description": null}], "term": "PVC", "definition": "Polyvinyl Chloride"}, - {"categories": [{"name": "casing_material", "description": null}], "term": "Steel", "definition": "Steel"}, - {"categories": [{"name": "casing_material", "description": null}], "term": "Concrete", "definition": "Concrete"}, - - {"categories": [{"name": "quality_flag", "description": null}], "term": "Good", "definition": "The measurement was collected and analyzed according to standard procedures and passed all QA/QC checks."}, - {"categories": [{"name": "quality_flag", "description": null}], "term": "Questionable", "definition": "The measurement is suspect due to a known issue during collection or analysis, but it may still be usable."}, - {"categories": [{"name": "quality_flag", "description": null}], "term": "Estimated", "definition": "The value is not a direct measurement but an estimate derived from other data or models."}, - {"categories": [{"name": "quality_flag", "description": null}], "term": "Rejected", "definition": "Rejected"}, - - - {"categories": [{"name": "drilling_fluid", "description": null}], "term": "mud", "definition": "drilling mud"}, - - {"categories": [{"name": "geochronology", "description": null}], "term": "Ar/Ar", "definition": "Ar40/Ar39 geochronology"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "AFT", "definition": "apatite fission track"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "K/Ar", "definition": "Potassium-Argon dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "U/Th", "definition": "Uranium/Thorium dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "Rb/Sr", "definition": "Rubidium-Strontium dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "U/Pb", "definition": "Uranium/Lead dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "Lu/Hf", "definition": "Lutetium-Hafnium dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "Re/Os", "definition": "Rhenium-Osmium dating"}, - {"categories": [{"name": "geochronology", "description": null}], "term": "Sm/Nd", "definition": "Samarium-Neodymium dating"}, - - - {"categories": [{"name": "publication_type", "description": null}], "term": "Map", "definition": "Map"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Report", "definition": "Report"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Dataset", "definition": "Dataset"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Model", "definition": "Model"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Software", "definition": "Software"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Paper", "definition": "Paper"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Thesis", "definition": "Thesis"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Book", "definition": "Book"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Conference", "definition": "Conference"}, - {"categories": [{"name": "publication_type", "description": null}], "term": "Webpage", "definition": "Webpage"}, - - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Monitor every six months", "definition": "Monitor every six months"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Annual water level", "definition": "Annual water level"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Monitoring bi-monthly", "definition": "Monitoring bi-monthly"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Monitoring complete", "definition": "Monitoring complete"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Datalogger installed", "definition": "Datalogger installed"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Monitor every 10 years (long-term monitor)", "definition": "Monitor every 10 years (long-term monitor)"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Monitor monthly", "definition": "Monitor monthly"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Sampling complete", "definition": "Sampling complete"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Reported to NMBGMR bimonthly", "definition": "Reported to NMBGMR bimonthly"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Sample well", "definition": "Sample well"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Water level cannot be measured", "definition": "Water level cannot be measured"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Repeat sampling", "definition": "Repeat sampling"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Wellntel device", "definition": "Wellntel device"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Bi-annual (every other year)", "definition": "Bi-annual (every other year)"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Inactive", "definition": "Inactive"}, - {"categories": [{"name": "monitoring_status", "description": null}], "term": "Data share", "definition": "Data share"}, - - {"categories": [{"name": "sample_type", "description": null}], "term": "Background", "definition": "Background"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Equipment blank", "definition": "Equipment blank"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Field blank", "definition": "Field blank"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Field duplicate", "definition": "Field duplicate"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Field parameters only", "definition": "Field parameters only"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Precipitation", "definition": "Precipitation"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Repeat sample", "definition": "Repeat sample"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Standard field sample", "definition": "Standard field sample"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Soil or Rock sample", "definition": "Soil or Rock sample"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Trip blank", "definition": "Trip blank"}, - {"categories": [{"name": "sample_type", "description": null}], "term": "Source water blank", "definition": "Source water blank"}, - - {"categories": [{"name": "limit_type", "description": null}], "term": "MCL", "definition": "Maximum Contaminant Level. The highest level of a contaminant that is legally allowed in public drinking water systems under the Safe Drinking Water Act. This is an enforceable standard."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "SMCL", "definition": "Secondary MCL. A non-enforceable federal guideline for contaminants that may cause cosmetic effects (e.g., skin or tooth discoloration) or aesthetic effects (e.g., taste, odor, color) in drinking water."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "AL", "definition": "Action Level. The concentration of a contaminant which, if exceeded, triggers specific treatment or other requirements that a water system must follow. Used for contaminants like Lead and Copper."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "GWQS", "definition": "Groundwater Quality Standard. State-specific standards for groundwater quality."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "RSL", "definition": "Regional Screening Level. Health-based risk screening levels developed by the EPA. They are used to help determine if a site requires further investigation or cleanup but are not legally enforceable cleanup standards themselves."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "MRL", "definition": "Method Reporting Limit. The lowest concentration of an analyte that a laboratory can reliably quantify within specified limits of precision and accuracy for a given analytical method. This is the most common 'limit of detection' you will see on a final lab report. Often used interchangeably with PQL."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "PQL", "definition": "Practical Quantitation Limit. Similar to the MRL, this is the lowest concentration achievable by a lab during routine operating conditions. It represents the practical, real-world limit of quantification."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "MDL", "definition": "Method Detection Limit. The minimum measured concentration of a substance that can be reported with 99% confidence that the analyte concentration is greater than zero. It is a statistical value determined under ideal lab conditions and is typically lower than the MRL/PQL."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "IDL", "definition": "Instrument Detection Limit. The lowest concentration of an analyte that can be reliably detected by a specific piece of laboratory equipment. It measures the capability of the instrument itself, which is a component of the overall MDL."}, - {"categories": [{"name": "limit_type", "description": null}], "term": "RL", "definition": "Reporting Limit. A generic term often used by labs to mean their MRL or PQL. It is the lowest concentration they are willing to report as a quantitative result."}, - -] \ No newline at end of file +{"categories": [ + {"name": "activity_type", "description": null}, + {"name": "address_type", "description": null}, + {"name": "analysis_method_type", "description": null}, + {"name": "casing_material", "description": null}, + {"name": "collection_method", "description": null}, + {"name": "construction_method", "description": null}, + {"name": "contact_type", "description": null}, + {"name": "coordinate_method", "description": null}, + {"name": "country", "description": null}, + {"name": "county", "description": null}, + {"name": "current_use", "description": null}, + {"name": "data_quality", "description": null}, + {"name": "data_source", "description": null}, + {"name": "depth_completion_source", "description": null}, + {"name": "discharge_source", "description": null}, + {"name": "drilling_fluid", "description": null}, + {"name": "elevation_method", "description": null}, + {"name": "email_type", "description": null}, + {"name": "field_contact_role", "description": null}, + {"name": "geochronology", "description": null}, + {"name": "horizontal_datum", "description": null}, + {"name": "level_status", "description": null}, + {"name": "limit_type", "description": null}, + {"name": "measurement_method", "description": null}, + {"name": "monitoring_status", "description": null}, + {"name": "observed_property", "description": null}, + {"name": "organization", "description": null}, + {"name": "phone_type", "description": null}, + {"name": "publication_type", "description": null}, + {"name": "qc_type", "description": null}, + {"name": "quality_flag", "description": null}, + {"name": "relation", "description": null}, + {"name": "release_status", "description": null}, + {"name": "role", "description": null}, + {"name": "sample_matrix", "description": null}, + {"name": "sample_method", "description": null}, + {"name": "sample_type", "description": null}, + {"name": "spring_type", "description": null}, + {"name": "state", "description": null}, + {"name": "status", "description": null}, + {"name": "thing_type", "description": null}, + {"name": "unit", "description": null}, + {"name": "vertical_datum", "description": null}, + {"name": "well_type", "description": null}], + "terms": [ + {"categories": ["qc_type"], "term": "Normal", "definition": "The primary environmental sample collected from the well, spring, or soil boring."}, + {"categories": ["qc_type"], "term": "Duplicate", "definition": "A second, independent sample collected at the same location, at the same time, and in the same manner as the normal sample. This sample is sent to the primary laboratory."}, + {"categories": ["qc_type"], "term": "Split", "definition": "A subsample of a primary environmental sample that is sent to a separate, independent laboratory for analysis."}, + {"categories": ["qc_type"], "term": "Field Blank", "definition": "A sample of certified pure water that is taken to the field, opened, and processed through the same sampling procedure as a normal sample (e.g., poured into a sample bottle)."}, + {"categories": ["qc_type", "sample_type"], "term": "Trip Blank", "definition": "A sample of certified pure water that is prepared in the lab, taken to the field, and brought back to the lab without ever being opened."}, + {"categories": ["qc_type"], "term": "Equipment Blank", "definition": "A sample of certified pure water that is run through the sampling equipment (like a pump and tubing) before the normal sample is collected."}, + {"categories": ["vertical_datum"], "term": "NAVD88", "definition": "North American Vertical Datum of 1988"}, + {"categories": ["vertical_datum"], "term": "NGVD29", "definition": "National Geodetic Vertical Datum of 1929"}, + {"categories": ["vertical_datum", "horizontal_datum"], "term": "WGS84", "definition": "World Geodetic System of 1984"}, + {"categories": ["horizontal_datum"], "term": "NAD83", "definition": "North American Datum of 1983"}, + {"categories": ["horizontal_datum"], "term": "NAD27", "definition": "North American Datum of 1927"}, + {"categories": ["elevation_method"], "term": "Altimeter", "definition": "altimeter"}, + {"categories": ["elevation_method"], "term": "Differentially corrected GPS", "definition": "differentially corrected GPS"}, + {"categories": ["elevation_method"], "term": "Survey-grade GPS", "definition": "survey-grade GPS"}, + {"categories": ["elevation_method"], "term": "Global positioning system (GPS)", "definition": "Global positioning system (GPS)"}, + {"categories": ["elevation_method"], "term": "LiDAR DEM", "definition": "LiDAR DEM"}, + {"categories": ["elevation_method"], "term": "Level or other survey method", "definition": "Level or other survey method"}, + {"categories": ["elevation_method"], "term": "Interpolated from topographic map", "definition": "Interpolated from topographic map"}, + {"categories": ["elevation_method"], "term": "Interpolated from digital elevation model (DEM)", "definition": "Interpolated from digital elevation model (DEM)"}, + {"categories": ["elevation_method"], "term": "Reported", "definition": "Reported"}, + {"categories": ["elevation_method"], "term": "Survey-grade Global Navigation Satellite Sys, Lvl1", "definition": "Survey-grade Global Navigation Satellite Sys, Lvl1"}, + {"categories": ["elevation_method"], "term": "USGS National Elevation Dataset (NED)", "definition": "USGS National Elevation Dataset (NED)"}, + {"categories": ["elevation_method", "sample_method", "coordinate_method", "current_use", "status", "organization", "role"], "term": "Unknown", "definition": "Unknown"}, + {"categories": ["construction_method"], "term": "Air-rotary", "definition": "Air-rotary"}, + {"categories": ["construction_method"], "term": "Bored or augered", "definition": "Bored or augered"}, + {"categories": ["construction_method"], "term": "Cable-tool", "definition": "Cable-tool"}, + {"categories": ["construction_method"], "term": "Hydraulic rotary (mud or water)", "definition": "Hydraulic rotary (mud or water)"}, + {"categories": ["construction_method"], "term": "Air percussion", "definition": "Air percussion"}, + {"categories": ["construction_method"], "term": "Reverse rotary", "definition": "Reverse rotary"}, + {"categories": ["construction_method"], "term": "Driven", "definition": "Driven"}, + {"categories": ["construction_method", "measurement_method"], "term": "Other (explain in notes)", "definition": "Other (explain in notes)"}, + {"categories": ["coordinate_method"], "term": "Differentially corrected GPS", "definition": "Differentially corrected GPS"}, + {"categories": ["coordinate_method"], "term": "Survey-grade global positioning system (SGPS)", "definition": "Survey-grade global positioning system (SGPS)"}, + {"categories": ["coordinate_method"], "term": "GPS, uncorrected", "definition": "GPS, uncorrected"}, + {"categories": ["coordinate_method"], "term": "Interpolated from map", "definition": "Interpolated from map"}, + {"categories": ["coordinate_method"], "term": "Interpolated from DEM", "definition": "Interpolated from DEM"}, + {"categories": ["coordinate_method"], "term": "Reported", "definition": "Reported"}, + {"categories": ["coordinate_method"], "term": "Transit, theodolite, or other survey method", "definition": "Transit, theodolite, or other survey method"}, + {"categories": ["current_use"], "term": "Open, unequipped well", "definition": "Open, unequipped well"}, + {"categories": ["current_use"], "term": "Commercial", "definition": "Commercial"}, + {"categories": ["current_use"], "term": "Domestic", "definition": "Domestic"}, + {"categories": ["current_use"], "term": "Power generation", "definition": "Power generation"}, + {"categories": ["current_use"], "term": "Irrigation", "definition": "Irrigation"}, + {"categories": ["current_use"], "term": "Livestock", "definition": "Livestock"}, + {"categories": ["current_use"], "term": "Mining", "definition": "Mining"}, + {"categories": ["current_use"], "term": "Industrial", "definition": "Industrial"}, + {"categories": ["current_use"], "term": "Observation", "definition": "Observation"}, + {"categories": ["current_use"], "term": "Public supply", "definition": "Public supply"}, + {"categories": ["current_use"], "term": "Shared domestic", "definition": "Shared domestic"}, + {"categories": ["current_use"], "term": "Institutional", "definition": "Institutional"}, + {"categories": ["current_use"], "term": "Unused", "definition": "Unused"}, + {"categories": ["data_quality"], "term": "Water level accurate to within two hundreths of a foot", "definition": "Good"}, + {"categories": ["data_quality"], "term": "Water level accurate to within one foot", "definition": "Fair"}, + {"categories": ["data_quality"], "term": "Water level accuracy not to nearest foot or water level not repeatable", "definition": "Poor"}, + {"categories": ["data_quality"], "term": "Water level accurate to nearest foot (USGS accuracy level)", "definition": "Water level accurate to nearest foot (USGS accuracy level)"}, + {"categories": ["data_quality"], "term": "Water level accurate to nearest tenth of a foot (USGS accuracy level)", "definition": "Water level accurate to nearest tenth of a foot (USGS accuracy level)"}, + {"categories": ["data_quality"], "term": "Water level accurate to nearest one-hundredth of a foot (USGS accuracy level)", "definition": "Water level accurate to nearest one-hundredth of a foot (USGS accuracy level)"}, + {"categories": ["data_quality"], "term": "Water level accuracy not to nearest foot (USGS accuracy level)", "definition": "Water level accuracy not to nearest foot (USGS accuracy level)"}, + {"categories": ["data_quality"], "term": "Water level accuracy unknown (USGS accuracy level)", "definition": "Water level accuracy unknown (USGS accuracy level)"}, + {"categories": ["data_quality"], "term": "None", "definition": "NA"}, + {"categories": ["data_source", "depth_completion_source", "discharge_source"], "term": "Reported by another agency", "definition": "Reported by another agency"}, + {"categories": ["data_source", "depth_completion_source"], "term": "From driller's log or well report", "definition": "From driller's log or well report"}, + {"categories": ["data_source", "depth_completion_source", "discharge_source"], "term": "Private geologist, consultant or univ associate", "definition": "Private geologist, consultant or univ associate"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Depth interpreted fr geophys logs by source agency", "definition": "Depth interpreted fr geophys logs by source agency"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Memory of owner, operator, driller", "definition": "Memory of owner, operator, driller"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Reported by owner of well", "definition": "Reported by owner of well"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Reported by person other than driller owner agency", "definition": "Reported by person other than driller owner agency"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Measured by NMBGMR staff", "definition": "Measured by NMBGMR staff"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Other", "definition": "Other"}, + {"categories": ["data_source", "depth_completion_source"], "term": "Data Portal", "definition": "Data Portal"}, + {"categories": ["discharge_source"], "term": "Information from a report", "definition": "Information from a report"}, + {"categories": ["discharge_source"], "term": "Measured by Bureau scientist", "definition": "Measured by Bureau scientist"}, + {"categories": ["discharge_source"], "term": "Other (explain)", "definition": "Other (explain)"}, + {"categories": ["unit"], "term": "dimensionless", "definition": ""}, + {"categories": ["unit"], "term": "ft", "definition": "feet"}, + {"categories": ["unit"], "term": "ftbgs", "definition": "feet below ground surface"}, + {"categories": ["unit"], "term": "F", "definition": "Fahrenheit"}, + {"categories": ["unit"], "term": "mg/L", "definition": "Milligrams per Liter"}, + {"categories": ["unit"], "term": "mW/m\u00b2", "definition": "milliwatts per square meter"}, + {"categories": ["unit"], "term": "W/m\u00b2", "definition": "watts per square meter"}, + {"categories": ["unit"], "term": "W/m\u00b7K", "definition": "watts per meter Kelvin"}, + {"categories": ["unit"], "term": "m\u00b2/s", "definition": "square meters per second"}, + {"categories": ["unit"], "term": "deg C", "definition": "degree Celsius"}, + {"categories": ["unit"], "term": "deg second", "definition": "degree second"}, + {"categories": ["unit"], "term": "deg minute", "definition": "degree minute"}, + {"categories": ["unit"], "term": "second", "definition": "second"}, + {"categories": ["unit"], "term": "minute", "definition": "minute"}, + {"categories": ["unit"], "term": "hour", "definition": "hour"}, + {"categories": ["observed_property"], "term": "groundwater level", "definition": "groundwater level measurement"}, + {"categories": ["observed_property"], "term": "temperature", "definition": "Temperature measurement"}, + {"categories": ["observed_property"], "term": "pH", "definition": "pH"}, + {"categories": ["observed_property"], "term": "Alkalinity, Total", "definition": "Alkalinity, Total"}, + {"categories": ["observed_property"], "term": "Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"}, + {"categories": ["observed_property"], "term": "Alkalinity as OH-", "definition": "Alkalinity as OH-"}, + {"categories": ["observed_property"], "term": "Calcium", "definition": "Calcium"}, + {"categories": ["observed_property"], "term": "Calcium, total, unfiltered", "definition": "Calcium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Chloride", "definition": "Chloride"}, + {"categories": ["observed_property"], "term": "Carbonate", "definition": "Carbonate"}, + {"categories": ["observed_property"], "term": "Conductivity, laboratory", "definition": "Conductivity, laboratory"}, + {"categories": ["observed_property"], "term": "Bicarbonate", "definition": "Bicarbonate"}, + {"categories": ["observed_property"], "term": "Hardness (CaCO3)", "definition": "Hardness (CaCO3)"}, + {"categories": ["observed_property"], "term": "Ion Balance", "definition": "Ion Balance"}, + {"categories": ["observed_property"], "term": "Potassium", "definition": "Potassium"}, + {"categories": ["observed_property"], "term": "Potassium, total, unfiltered", "definition": "Potassium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Magnesium", "definition": "Magnesium"}, + {"categories": ["observed_property"], "term": "Magnesium, total, unfiltered", "definition": "Magnesium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Sodium", "definition": "Sodium"}, + {"categories": ["observed_property"], "term": "Sodium, total, unfiltered", "definition": "Sodium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Sodium and Potassium combined", "definition": "Sodium and Potassium combined"}, + {"categories": ["observed_property"], "term": "Sulfate", "definition": "Sulfate"}, + {"categories": ["observed_property"], "term": "Total Anions", "definition": "Total Anions"}, + {"categories": ["observed_property"], "term": "Total Cations", "definition": "Total Cations"}, + {"categories": ["observed_property"], "term": "Total Dissolved Solids", "definition": "Total Dissolved Solids"}, + {"categories": ["observed_property"], "term": "Tritium", "definition": "Tritium"}, + {"categories": ["observed_property"], "term": "Age of Water using dissolved gases", "definition": "Age of Water using dissolved gases"}, + {"categories": ["observed_property"], "term": "Silver", "definition": "Silver"}, + {"categories": ["observed_property"], "term": "Silver, total, unfiltered", "definition": "Silver, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Aluminum", "definition": "Aluminum"}, + {"categories": ["observed_property"], "term": "Aluminum, total, unfiltered", "definition": "Aluminum, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Arsenic", "definition": "Arsenic"}, + {"categories": ["observed_property"], "term": "Arsenic, total, unfiltered", "definition": "Arsenic, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Boron", "definition": "Boron"}, + {"categories": ["observed_property"], "term": "Boron, total, unfiltered", "definition": "Boron, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Barium", "definition": "Barium"}, + {"categories": ["observed_property"], "term": "Barium, total, unfiltered", "definition": "Barium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Beryllium", "definition": "Beryllium"}, + {"categories": ["observed_property"], "term": "Beryllium, total, unfiltered", "definition": "Beryllium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Bromide", "definition": "Bromide"}, + {"categories": ["observed_property"], "term": "13C:12C ratio", "definition": "13C:12C ratio"}, + {"categories": ["observed_property"], "term": "14C content, pmc", "definition": "14C content, pmc"}, + {"categories": ["observed_property"], "term": "Uncorrected C14 age", "definition": "Uncorrected C14 age"}, + {"categories": ["observed_property"], "term": "Cadmium", "definition": "Cadmium"}, + {"categories": ["observed_property"], "term": "Cadmium, total, unfiltered", "definition": "Cadmium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Chlorofluorocarbon-11 avg age", "definition": "Chlorofluorocarbon-11 avg age"}, + {"categories": ["observed_property"], "term": "Chlorofluorocarbon-113 avg age", "definition": "Chlorofluorocarbon-113 avg age"}, + {"categories": ["observed_property"], "term": "Chlorofluorocarbon-113/12 avg RATIO age", "definition": "Chlorofluorocarbon-113/12 avg RATIO age"}, + {"categories": ["observed_property"], "term": "Chlorofluorocarbon-12 avg age", "definition": "Chlorofluorocarbon-12 avg age"}, + {"categories": ["observed_property"], "term": "Cobalt", "definition": "Cobalt"}, + {"categories": ["observed_property"], "term": "Cobalt, total, unfiltered", "definition": "Cobalt, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Chromium", "definition": "Chromium"}, + {"categories": ["observed_property"], "term": "Chromium, total, unfiltered", "definition": "Chromium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Copper", "definition": "Copper"}, + {"categories": ["observed_property"], "term": "Copper, total, unfiltered", "definition": "Copper, total, unfiltered"}, + {"categories": ["observed_property"], "term": "delta O18 sulfate", "definition": "delta O18 sulfate"}, + {"categories": ["observed_property"], "term": "Sulfate 34 isotope ratio", "definition": "Sulfate 34 isotope ratio"}, + {"categories": ["observed_property"], "term": "Fluoride", "definition": "Fluoride"}, + {"categories": ["observed_property"], "term": "Iron", "definition": "Iron"}, + {"categories": ["observed_property"], "term": "Iron, total, unfiltered", "definition": "Iron, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Deuterium:Hydrogen ratio", "definition": "Deuterium:Hydrogen ratio"}, + {"categories": ["observed_property"], "term": "Mercury", "definition": "Mercury"}, + {"categories": ["observed_property"], "term": "Mercury, total, unfiltered", "definition": "Mercury, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Lithium", "definition": "Lithium"}, + {"categories": ["observed_property"], "term": "Lithium, total, unfiltered", "definition": "Lithium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Manganese", "definition": "Manganese"}, + {"categories": ["observed_property"], "term": "Manganese, total, unfiltered", "definition": "Manganese, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Molybdenum", "definition": "Molybdenum"}, + {"categories": ["observed_property"], "term": "Molybdenum, total, unfiltered", "definition": "Molybdenum, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Nickel", "definition": "Nickel"}, + {"categories": ["observed_property"], "term": "Nickel, total, unfiltered", "definition": "Nickel, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Nitrite (as NO2)", "definition": "Nitrite (as NO2)"}, + {"categories": ["observed_property"], "term": "Nitrite (as N)", "definition": "Nitrite (as N)"}, + {"categories": ["observed_property"], "term": "Nitrate (as NO3)", "definition": "Nitrate (as NO3)"}, + {"categories": ["observed_property"], "term": "Nitrate (as N)", "definition": "Nitrate (as N)"}, + {"categories": ["observed_property"], "term": "18O:16O ratio", "definition": "18O:16O ratio"}, + {"categories": ["observed_property"], "term": "Lead", "definition": "Lead"}, + {"categories": ["observed_property"], "term": "Lead, total, unfiltered", "definition": "Lead, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Phosphate", "definition": "Phosphate"}, + {"categories": ["observed_property"], "term": "Antimony", "definition": "Antimony"}, + {"categories": ["observed_property"], "term": "Antimony, total, unfiltered", "definition": "Antimony, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Selenium", "definition": "Selenium"}, + {"categories": ["observed_property"], "term": "Selenium, total, unfiltered", "definition": "Selenium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Sulfur hexafluoride", "definition": "Sulfur hexafluoride"}, + {"categories": ["observed_property"], "term": "Silicon", "definition": "Silicon"}, + {"categories": ["observed_property"], "term": "Silicon, total, unfiltered", "definition": "Silicon, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Silica", "definition": "Silica"}, + {"categories": ["observed_property"], "term": "Tin", "definition": "Tin"}, + {"categories": ["observed_property"], "term": "Tin, total, unfiltered", "definition": "Tin, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Strontium", "definition": "Strontium"}, + {"categories": ["observed_property"], "term": "Strontium, total, unfiltered", "definition": "Strontium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Strontium 87:86 ratio", "definition": "Strontium 87:86 ratio"}, + {"categories": ["observed_property"], "term": "Thorium", "definition": "Thorium"}, + {"categories": ["observed_property"], "term": "Thorium, total, unfiltered", "definition": "Thorium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Titanium", "definition": "Titanium"}, + {"categories": ["observed_property"], "term": "Titanium, total, unfiltered", "definition": "Titanium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Thallium", "definition": "Thallium"}, + {"categories": ["observed_property"], "term": "Thallium, total, unfiltered", "definition": "Thallium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Uranium (total, by ICP-MS)", "definition": "Uranium (total, by ICP-MS)"}, + {"categories": ["observed_property"], "term": "Uranium, total, unfiltered", "definition": "Uranium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Vanadium", "definition": "Vanadium"}, + {"categories": ["observed_property"], "term": "Vanadium, total, unfiltered", "definition": "Vanadium, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Zinc", "definition": "Zinc"}, + {"categories": ["observed_property"], "term": "Zinc, total, unfiltered", "definition": "Zinc, total, unfiltered"}, + {"categories": ["observed_property"], "term": "Corrected C14 in years", "definition": "Corrected C14 in years"}, + {"categories": ["observed_property"], "term": "Arsenite (arsenic species)", "definition": "Arsenite (arsenic species)"}, + {"categories": ["observed_property"], "term": "Arsenate (arsenic species)", "definition": "Arsenate (arsenic species)"}, + {"categories": ["observed_property"], "term": "Cyanide", "definition": "Cyanide"}, + {"categories": ["observed_property"], "term": "Estimated recharge temperature", "definition": "Estimated recharge temperature"}, + {"categories": ["observed_property"], "term": "Hydrogen sulfide", "definition": "Hydrogen sulfide"}, + {"categories": ["observed_property"], "term": "Ammonia", "definition": "Ammonia"}, + {"categories": ["observed_property"], "term": "Ammonium", "definition": "Ammonium"}, + {"categories": ["observed_property"], "term": "Total nitrogen", "definition": "Total nitrogen"}, + {"categories": ["observed_property"], "term": "Total Kjeldahl nitrogen", "definition": "Total Kjeldahl nitrogen"}, + {"categories": ["observed_property"], "term": "Dissolved organic carbon", "definition": "Dissolved organic carbon"}, + {"categories": ["observed_property"], "term": "Total organic carbon", "definition": "Total organic carbon"}, + {"categories": ["observed_property"], "term": "delta C13 of dissolved inorganic carbon", "definition": "delta C13 of dissolved inorganic carbon"}, + {"categories": ["release_status"], "term": "draft", "definition": "draft version"}, + {"categories": ["release_status"], "term": "provisional", "definition": "provisional version"}, + {"categories": ["release_status"], "term": "final", "definition": "final version"}, + {"categories": ["release_status"], "term": "published", "definition": "published version"}, + {"categories": ["release_status"], "term": "archived", "definition": "archived version"}, + {"categories": ["release_status"], "term": "public", "definition": "public version"}, + {"categories": ["release_status"], "term": "private", "definition": "private version"}, + {"categories": ["relation"], "term": "same_as", "definition": "same as"}, + {"categories": ["relation"], "term": "related_to", "definition": "related to"}, + {"categories": ["relation"], "term": "OSEWellTagID", "definition": "NM OSE well tag ID"}, + {"categories": ["relation"], "term": "OSEPOD", "definition": "NM OSE 'Point of Diversion' ID"}, + {"categories": ["relation"], "term": "PLSS", "definition": "Public Land Survey System ID"}, + {"categories": ["activity_type"], "term": "groundwater level", "definition": "groundwater level"}, + {"categories": ["activity_type"], "term": "water chemistry", "definition": "water chemistry"}, + {"categories": ["field_contact_role"], "term": "Lead", "definition": "the leader of the field event"}, + {"categories": ["field_contact_role"], "term": "Participant", "definition": "a person participating in the field event"}, + {"categories": ["field_contact_role"], "term": "Observer", "definition": "a person observing the field event"}, + {"categories": ["field_contact_role"], "term": "Visitor", "definition": "a person visiting the field event"}, + {"categories": ["sample_matrix"], "term": "water", "definition": "water"}, + {"categories": ["sample_matrix"], "term": "soil", "definition": "soil"}, + {"categories": ["thing_type"], "term": "observation well", "definition": "a well used to monitor groundwater levels"}, + {"categories": ["thing_type"], "term": "piezometer", "definition": "a type of observation well that measures pressure head in the aquifer"}, + {"categories": ["thing_type"], "term": "monitoring well", "definition": "a well used to monitor groundwater quality or levels"}, + {"categories": ["thing_type"], "term": "production well", "definition": "a well used to extract groundwater for use"}, + {"categories": ["thing_type"], "term": "injection well", "definition": "a well used to inject water or other fluids into the ground"}, + {"categories": ["thing_type"], "term": "exploration well", "definition": "a well drilled to explore for groundwater or other resources"}, + {"categories": ["thing_type"], "term": "test well", "definition": "a well drilled to test the properties of the aquifer"}, + {"categories": ["thing_type"], "term": "abandoned well", "definition": "a well that is no longer in use and has been properly sealed"}, + {"categories": ["thing_type"], "term": "dry hole", "definition": "a well that did not produce water or other resources"}, + {"categories": ["thing_type"], "term": "artesian well", "definition": "a well that taps a confined aquifer where the water level is above the top of the aquifer"}, + {"categories": ["thing_type"], "term": "dug well", "definition": "a shallow well dug by hand or with machinery, typically lined with stones or bricks"}, + {"categories": ["thing_type"], "term": "water well", "definition": "a hole drill into the ground to access groundwater"}, + {"categories": ["thing_type"], "term": "spring", "definition": "a natural discharge of groundwater at the surface"}, + {"categories": ["thing_type"], "term": "perennial stream", "definition": "that has a continuous flow of water throughout the year, even during drier periods."}, + {"categories": ["thing_type"], "term": "ephemeral stream", "definition": "a stream that flows only briefly during and after precipitation events"}, + {"categories": ["thing_type"], "term": "meteorological station", "definition": "a station that measures the weather conditions at a particular location"}, + {"categories": ["level_status"], "term": "Water level affected by atmospheric pressure", "definition": "Water level affected by atmospheric pressure"}, + {"categories": ["level_status"], "term": "Water level was frozen (no level recorded).", "definition": "Water level was frozen (no level recorded)."}, + {"categories": ["level_status"], "term": "Site was dry", "definition": "Site was dry"}, + {"categories": ["level_status"], "term": "Site was flowing recently.", "definition": "Site was flowing recently."}, + {"categories": ["level_status"], "term": "Site was flowing. Water level or head couldn't be measured w/out additional equipment.", "definition": "Site was flowing. Water level or head couldn't be measured w/out additional equipment."}, + {"categories": ["level_status"], "term": "Nearby site that taps the same aquifer was flowing.", "definition": "Nearby site that taps the same aquifer was flowing."}, + {"categories": ["level_status"], "term": "Nearby site that taps the same aquifer had been flowing recently.", "definition": "Nearby site that taps the same aquifer had been flowing recently."}, + {"categories": ["level_status"], "term": "Recharge water was being injected into the aquifer at this site.", "definition": "Recharge water was being injected into the aquifer at this site."}, + {"categories": ["level_status"], "term": "Recharge water was being injected into nearby site that taps the same aquifer.", "definition": "Recharge water was being injected into nearby site that taps the same aquifer."}, + {"categories": ["level_status"], "term": "Water was cascading down the inside of the well.", "definition": "Water was cascading down the inside of the well."}, + {"categories": ["level_status"], "term": "Water level was affected by brackish or saline water.", "definition": "Water level was affected by brackish or saline water."}, + {"categories": ["level_status"], "term": "Well was not in hydraulic contact w/formation (from source other than defined in USGS C714 or C93).", "definition": "Well was not in hydraulic contact w/formation (from source other than defined in USGS C714 or C93)."}, + {"categories": ["level_status"], "term": "Measurement was discontinued (no level recorded).", "definition": "Measurement was discontinued (no level recorded)."}, + {"categories": ["level_status"], "term": "Obstruction was encountered in the well (no level recorded)", "definition": "Obstruction was encountered in the well (no level recorded)"}, + {"categories": ["level_status"], "term": "Site was being pumped", "definition": "Site was being pumped"}, + {"categories": ["level_status"], "term": "Site was pumped recently", "definition": "Site was pumped recently"}, + {"categories": ["level_status"], "term": "Nearby site that taps the same aquifer was being pumped", "definition": "Nearby site that taps the same aquifer was being pumped"}, + {"categories": ["level_status"], "term": "Nearby site that taps the same aquifer was pumped recently", "definition": "Nearby site that taps the same aquifer was pumped recently"}, + {"categories": ["level_status"], "term": "Foreign substance present on the water surface", "definition": "Foreign substance present on the water surface"}, + {"categories": ["level_status"], "term": "Well was destroyed (no subsequent water levels should be recorded)", "definition": "Well was destroyed (no subsequent water levels should be recorded)"}, + {"categories": ["level_status"], "term": "Water level affected by stage in nearby surface-water site", "definition": "Water level affected by stage in nearby surface-water site"}, + {"categories": ["level_status"], "term": "Other conditions exist that would affect the level (remarks)", "definition": "Other conditions exist that would affect the level (remarks)"}, + {"categories": ["level_status"], "term": "Water level not affected by status", "definition": "Water level not affected by status"}, + {"categories": ["status"], "term": "Abandoned", "definition": "Abandoned"}, + {"categories": ["status"], "term": "Active, pumping well", "definition": "Active, pumping well"}, + {"categories": ["status"], "term": "Destroyed, exists but not usable", "definition": "Destroyed, exists but not usable"}, + {"categories": ["status"], "term": "Inactive, exists but not used", "definition": "Inactive, exists but not used"}, + {"categories": ["sample_method"], "term": "Airline measurement", "definition": "Airline measurement"}, + {"categories": ["sample_method"], "term": "Analog or graphic recorder", "definition": "Analog or graphic recorder"}, + {"categories": ["sample_method"], "term": "Calibrated airline measurement", "definition": "Calibrated airline measurement"}, + {"categories": ["sample_method"], "term": "Differential GPS; especially applicable to surface expression of ground water", "definition": "Differential GPS; especially applicable to surface expression of ground water"}, + {"categories": ["sample_method"], "term": "Estimated", "definition": "Estimated"}, + {"categories": ["sample_method"], "term": "Transducer", "definition": "Transducer"}, + {"categories": ["sample_method"], "term": "Pressure-gage measurement", "definition": "Pressure-gage measurement"}, + {"categories": ["sample_method"], "term": "Calibrated pressure-gage measurement", "definition": "Calibrated pressure-gage measurement"}, + {"categories": ["sample_method"], "term": "Interpreted from geophysical logs", "definition": "Interpreted from geophysical logs"}, + {"categories": ["sample_method"], "term": "Manometer", "definition": "Manometer"}, + {"categories": ["sample_method"], "term": "Non-recording gage", "definition": "Non-recording gage"}, + {"categories": ["sample_method"], "term": "Observed (required for F, N, and W water level status)", "definition": "Observed (required for F, N, and W water level status)"}, + {"categories": ["sample_method"], "term": "Sonic water level meter (acoustic pulse)", "definition": "Sonic water level meter (acoustic pulse)"}, + {"categories": ["sample_method"], "term": "Reported, method not known", "definition": "Reported, method not known"}, + {"categories": ["sample_method"], "term": "Steel-tape measurement", "definition": "Steel-tape measurement"}, + {"categories": ["sample_method"], "term": "Electric tape measurement (E-probe)", "definition": "Electric tape measurement (E-probe)"}, + {"categories": ["sample_method"], "term": "Unknown (for legacy data only; not for new data entry)", "definition": "Unknown (for legacy data only; not for new data entry)"}, + {"categories": ["sample_method"], "term": "Calibrated electric tape; accuracy of equipment has been checked", "definition": "Calibrated electric tape; accuracy of equipment has been checked"}, + {"categories": ["sample_method"], "term": "Calibrated electric cable", "definition": "Calibrated electric cable"}, + {"categories": ["sample_method"], "term": "Uncalibrated electric cable", "definition": "Uncalibrated electric cable"}, + {"categories": ["sample_method"], "term": "Continuous acoustic sounder", "definition": "Continuous acoustic sounder"}, + {"categories": ["sample_method"], "term": "Measurement not attempted", "definition": "Measurement not attempted"}, + {"categories": ["sample_method"], "term": "null placeholder", "definition": "null placeholder"}, + {"categories": ["sample_method"], "term": "bailer", "definition": "bailer"}, + {"categories": ["sample_method"], "term": "faucet at well head", "definition": "faucet at well head"}, + {"categories": ["sample_method"], "term": "faucet or outlet at house", "definition": "faucet or outlet at house"}, + {"categories": ["sample_method"], "term": "grab sample", "definition": "grab sample"}, + {"categories": ["sample_method"], "term": "pump", "definition": "pump"}, + {"categories": ["sample_method"], "term": "thief sampler", "definition": "thief sampler"}, + {"categories": ["analysis_method_type"], "term": "Laboratory", "definition": "A procedure performed on a physical sample in a controlled, off-site laboratory environment. These methods typically involve complex instrumentation, standardized reagents, and formal quality control protocols."}, + {"categories": ["analysis_method_type"], "term": "Field Procedure", "definition": "A standardized procedure performed on-site at the time of sample collection. This can involve direct measurement of the environmental medium using a calibrated field instrument or a specific, documented technique for collecting a sample."}, + {"categories": ["analysis_method_type"], "term": "Calculation", "definition": "A mathematical procedure used to derive a new data point from one or more directly measured values. This type is used to document the provenance of calculated data, providing an auditable trail."}, + {"categories": ["organization"], "term": "USGS", "definition": "US Geological Survey"}, + {"categories": ["organization"], "term": "TWDB", "definition": "Texas Water Development Board"}, + {"categories": ["organization"], "term": "NMED", "definition": "New Mexico Environment Department"}, + {"categories": ["organization"], "term": "NMOSE", "definition": "New Mexico Office of the State Engineer"}, + {"categories": ["organization"], "term": "NMBGMR", "definition": "New Mexico Bureau of Geology and Mineral Resources"}, + {"categories": ["organization"], "term": "Bernalillo County", "definition": "Bernalillo County"}, + {"categories": ["organization"], "term": "BLM", "definition": "Bureau of Land Management"}, + {"categories": ["organization"], "term": "SFC", "definition": "Santa Fe County"}, + {"categories": ["organization"], "term": "CSF", "definition": "City of Santa Fe"}, + {"categories": ["organization"], "term": "NESWCD", "definition": "Northeastern Soil & Water Conservation District"}, + {"categories": ["organization"], "term": "NMISC", "definition": "New Mexico Interstate Stream Commission"}, + {"categories": ["organization"], "term": "PVACD", "definition": "Pecos Valley Artesian Conservancy District"}, + {"categories": ["organization"], "term": "TSWCD", "definition": "Taos Soil & Water Conservation District"}, + {"categories": ["organization"], "term": "Bayard", "definition": "Bayard Municipal Water"}, + {"categories": ["organization"], "term": "OSWCD", "definition": "Otero Soil & Water Conservation District"}, + {"categories": ["organization"], "term": "SNL", "definition": "Sandia National Laboratories"}, + {"categories": ["organization"], "term": "USFS", "definition": "United States Forest Service"}, + {"categories": ["organization"], "term": "NMT", "definition": "New Mexico Tech"}, + {"categories": ["organization"], "term": "NPS", "definition": "National Park Service"}, + {"categories": ["organization"], "term": "NMRWA", "definition": "New Mexico Rural Water Association"}, + {"categories": ["organization"], "term": "Taos SWCD", "definition": "Taos Soil and Water Conservation District"}, + {"categories": ["organization"], "term": "Otero SWCD", "definition": "Otero Soil and Water Conservation District"}, + {"categories": ["organization"], "term": "Northeastern SWCD", "definition": "Northeastern Soil and Water Conservation District"}, + {"categories": ["organization"], "term": "A&T Pump & Well Service, LLC", "definition": "A&T Pump & Well Service, LLC"}, + {"categories": ["organization"], "term": "A. G. Wassenaar, Inc", "definition": "A. G. Wassenaar, Inc"}, + {"categories": ["organization"], "term": "AMEC", "definition": "AMEC"}, + {"categories": ["organization"], "term": "Balleau Groundwater, Inc", "definition": "Balleau Groundwater, Inc"}, + {"categories": ["organization"], "term": "CDM Smith", "definition": "CDM Smith"}, + {"categories": ["organization"], "term": "CH2M Hill", "definition": "CH2M Hill"}, + {"categories": ["organization"], "term": "Corbin Consulting, Inc", "definition": "Corbin Consulting, Inc"}, + {"categories": ["organization"], "term": "Chevron", "definition": "Chevron"}, + {"categories": ["organization"], "term": "Daniel B. Stephens & Associates, Inc", "definition": "Daniel B. Stephens & Associates, Inc"}, + {"categories": ["organization"], "term": "EnecoTech", "definition": "EnecoTech"}, + {"categories": ["organization"], "term": "Faith Engineering, Inc", "definition": "Faith Engineering, Inc"}, + {"categories": ["organization"], "term": "Foster Well Service, Inc", "definition": "Foster Well Service, Inc"}, + {"categories": ["organization"], "term": "Glorieta Geoscience, Inc", "definition": "Glorieta Geoscience, Inc"}, + {"categories": ["organization"], "term": "Golder Associates, Inc", "definition": "Golder Associates, Inc"}, + {"categories": ["organization"], "term": "Hathorn's Well Service, Inc", "definition": "Hathorn's Well Service, Inc"}, + {"categories": ["organization"], "term": "Hydroscience Associates, Inc", "definition": "Hydroscience Associates, Inc"}, + {"categories": ["organization"], "term": "IC Tech, Inc", "definition": "IC Tech, Inc"}, + {"categories": ["organization"], "term": "John Shomaker & Associates, Inc", "definition": "John Shomaker & Associates, Inc"}, + {"categories": ["organization"], "term": "Kuckleman Pump Service", "definition": "Kuckleman Pump Service"}, + {"categories": ["organization"], "term": "Los Golondrinas", "definition": "Los Golondrinas"}, + {"categories": ["organization"], "term": "Minton Engineers", "definition": "Minton Engineers"}, + {"categories": ["organization"], "term": "MJDarrconsult, Inc", "definition": "MJDarrconsult, Inc"}, + {"categories": ["organization"], "term": "Puerta del Canon Ranch", "definition": "Puerta del Canon Ranch"}, + {"categories": ["organization"], "term": "Rodgers & Company, Inc", "definition": "Rodgers & Company, Inc"}, + {"categories": ["organization"], "term": "San Pedro Creek Estates HOA", "definition": "San Pedro Creek Estates HOA"}, + {"categories": ["organization"], "term": "Statewide Drilling, Inc", "definition": "Statewide Drilling, Inc"}, + {"categories": ["organization"], "term": "Tec Drilling Limited", "definition": "Tec Drilling Limited"}, + {"categories": ["organization"], "term": "Tetra Tech, Inc", "definition": "Tetra Tech, Inc"}, + {"categories": ["organization"], "term": "Thompson Drilling, Inc", "definition": "Thompson Drilling, Inc"}, + {"categories": ["organization"], "term": "Witcher & Associates", "definition": "Witcher & Associates"}, + {"categories": ["organization"], "term": "Zeigler Geologic Consulting, LLC", "definition": "Zeigler Geologic Consulting, LLC"}, + {"categories": ["collection_method"], "term": "manual", "definition": "manual sampling"}, + {"categories": ["collection_method"], "term": "continuous", "definition": "continuous sampling"}, + {"categories": ["role"], "term": "Owner", "definition": "Owner"}, + {"categories": ["role"], "term": "Manager", "definition": "Manager"}, + {"categories": ["role"], "term": "Operator", "definition": "Operator"}, + {"categories": ["role"], "term": "Driller", "definition": "Driller"}, + {"categories": ["role"], "term": "Geologist", "definition": "Geologist"}, + {"categories": ["role"], "term": "Hydrologist", "definition": "Hydrologist"}, + {"categories": ["role"], "term": "Hydrogeologist", "definition": "Hydrogeologist"}, + {"categories": ["role"], "term": "Engineer", "definition": "Engineer"}, + {"categories": ["role"], "term": "Organization", "definition": "A contact that is an organization"}, + {"categories": ["role"], "term": "Specialist", "definition": "Specialist"}, + {"categories": ["role"], "term": "Technician", "definition": "Technician"}, + {"categories": ["role"], "term": "Research Assistant", "definition": "Research Assistant"}, + {"categories": ["role"], "term": "Research Scientist", "definition": "Research Scientist"}, + {"categories": ["role"], "term": "Operator", "definition": "Operator"}, + {"categories": ["role"], "term": "Biologist", "definition": "Biologist"}, + {"categories": ["role"], "term": "Lab Manager", "definition": "Lab Manager"}, + {"categories": ["role"], "term": "Publications Manager", "definition": "Publications Manager"}, + {"categories": ["email_type", "phone_type", "address_type", "contact_type"], "term": "Primary", "definition": "primary"}, + {"categories": ["contact_type"], "term": "Secondary", "definition": "secondary"}, + {"categories": ["contact_type"], "term": "Field Event Participant", "definition": "A contact who has participated in a field event"}, + {"categories": ["email_type", "phone_type", "address_type"], "term": "Work", "definition": "work"}, + {"categories": ["email_type", "address_type"], "term": "Personal", "definition": "personal"}, + {"categories": ["address_type"], "term": "Mailing", "definition": "mailing"}, + {"categories": ["address_type"], "term": "Physical", "definition": "physical"}, + {"categories": ["phone_type"], "term": "Home", "definition": "Primary"}, + {"categories": ["phone_type"], "term": "Mobile", "definition": "Primary"}, + {"categories": ["spring_type"], "term": "Artesian", "definition": "artesian spring"}, + {"categories": ["spring_type"], "term": "Ephemeral", "definition": "ephemeral spring"}, + {"categories": ["spring_type"], "term": "Perennial", "definition": "perennial spring"}, + {"categories": ["spring_type"], "term": "Thermal", "definition": "thermal spring"}, + {"categories": ["spring_type"], "term": "Mineral", "definition": "mineral spring"}, + {"categories": ["well_type"], "term": "Exploration", "definition": "Exploration well"}, + {"categories": ["well_type"], "term": "Monitoring", "definition": "Monitoring"}, + {"categories": ["well_type"], "term": "Production", "definition": "Production"}, + {"categories": ["well_type"], "term": "Injection", "definition": "Injection"}, + {"categories": ["casing_material"], "term": "PVC", "definition": "Polyvinyl Chloride"}, + {"categories": ["casing_material"], "term": "Steel", "definition": "Steel"}, + {"categories": ["casing_material"], "term": "Concrete", "definition": "Concrete"}, + {"categories": ["quality_flag"], "term": "Good", "definition": "The measurement was collected and analyzed according to standard procedures and passed all QA/QC checks."}, + {"categories": ["quality_flag"], "term": "Questionable", "definition": "The measurement is suspect due to a known issue during collection or analysis, but it may still be usable."}, + {"categories": ["quality_flag"], "term": "Estimated", "definition": "The value is not a direct measurement but an estimate derived from other data or models."}, + {"categories": ["quality_flag"], "term": "Rejected", "definition": "Rejected"}, + {"categories": ["drilling_fluid"], "term": "mud", "definition": "drilling mud"}, + {"categories": ["geochronology"], "term": "Ar/Ar", "definition": "Ar40/Ar39 geochronology"}, + {"categories": ["geochronology"], "term": "AFT", "definition": "apatite fission track"}, + {"categories": ["geochronology"], "term": "K/Ar", "definition": "Potassium-Argon dating"}, + {"categories": ["geochronology"], "term": "U/Th", "definition": "Uranium/Thorium dating"}, + {"categories": ["geochronology"], "term": "Rb/Sr", "definition": "Rubidium-Strontium dating"}, + {"categories": ["geochronology"], "term": "U/Pb", "definition": "Uranium/Lead dating"}, + {"categories": ["geochronology"], "term": "Lu/Hf", "definition": "Lutetium-Hafnium dating"}, + {"categories": ["geochronology"], "term": "Re/Os", "definition": "Rhenium-Osmium dating"}, + {"categories": ["geochronology"], "term": "Sm/Nd", "definition": "Samarium-Neodymium dating"}, + {"categories": ["publication_type"], "term": "Map", "definition": "Map"}, + {"categories": ["publication_type"], "term": "Report", "definition": "Report"}, + {"categories": ["publication_type"], "term": "Dataset", "definition": "Dataset"}, + {"categories": ["publication_type"], "term": "Model", "definition": "Model"}, + {"categories": ["publication_type"], "term": "Software", "definition": "Software"}, + {"categories": ["publication_type"], "term": "Paper", "definition": "Paper"}, + {"categories": ["publication_type"], "term": "Thesis", "definition": "Thesis"}, + {"categories": ["publication_type"], "term": "Book", "definition": "Book"}, + {"categories": ["publication_type"], "term": "Conference", "definition": "Conference"}, + {"categories": ["publication_type"], "term": "Webpage", "definition": "Webpage"}, + {"categories": ["monitoring_status"], "term": "Monitor every six months", "definition": "Monitor every six months"}, + {"categories": ["monitoring_status"], "term": "Annual water level", "definition": "Annual water level"}, + {"categories": ["monitoring_status"], "term": "Monitoring bi-monthly", "definition": "Monitoring bi-monthly"}, + {"categories": ["monitoring_status"], "term": "Monitoring complete", "definition": "Monitoring complete"}, + {"categories": ["monitoring_status"], "term": "Datalogger installed", "definition": "Datalogger installed"}, + {"categories": ["monitoring_status"], "term": "Monitor every 10 years (long-term monitor)", "definition": "Monitor every 10 years (long-term monitor)"}, + {"categories": ["monitoring_status"], "term": "Monitor monthly", "definition": "Monitor monthly"}, + {"categories": ["monitoring_status"], "term": "Sampling complete", "definition": "Sampling complete"}, + {"categories": ["monitoring_status"], "term": "Reported to NMBGMR bimonthly", "definition": "Reported to NMBGMR bimonthly"}, + {"categories": ["monitoring_status"], "term": "Sample well", "definition": "Sample well"}, + {"categories": ["monitoring_status"], "term": "Water level cannot be measured", "definition": "Water level cannot be measured"}, + {"categories": ["monitoring_status"], "term": "Repeat sampling", "definition": "Repeat sampling"}, + {"categories": ["monitoring_status"], "term": "Wellntel device", "definition": "Wellntel device"}, + {"categories": ["monitoring_status"], "term": "Bi-annual (every other year)", "definition": "Bi-annual (every other year)"}, + {"categories": ["monitoring_status"], "term": "Inactive", "definition": "Inactive"}, + {"categories": ["monitoring_status"], "term": "Data share", "definition": "Data share"}, + {"categories": ["sample_type"], "term": "Background", "definition": "Background"}, + {"categories": ["sample_type"], "term": "Equipment blank", "definition": "Equipment blank"}, + {"categories": ["sample_type"], "term": "Field blank", "definition": "Field blank"}, + {"categories": ["sample_type"], "term": "Field duplicate", "definition": "Field duplicate"}, + {"categories": ["sample_type"], "term": "Field parameters only", "definition": "Field parameters only"}, + {"categories": ["sample_type"], "term": "Precipitation", "definition": "Precipitation"}, + {"categories": ["sample_type"], "term": "Repeat sample", "definition": "Repeat sample"}, + {"categories": ["sample_type"], "term": "Standard field sample", "definition": "Standard field sample"}, + {"categories": ["sample_type"], "term": "Soil or Rock sample", "definition": "Soil or Rock sample"}, + {"categories": ["sample_type"], "term": "Source water blank", "definition": "Source water blank"}, + {"categories": ["limit_type"], "term": "MCL", "definition": "Maximum Contaminant Level. The highest level of a contaminant that is legally allowed in public drinking water systems under the Safe Drinking Water Act. This is an enforceable standard."}, + {"categories": ["limit_type"], "term": "SMCL", "definition": "Secondary Maximum Contaminant Level. Non-enforceable guidelines regulating contaminants that may cause cosmetic or aesthetic effects in drinking water."}, + {"categories": ["limit_type"], "term": "GWQS", "definition": "Groundwater Quality Standard. State-specific standards that define acceptable levels of various contaminants in groundwater, often used for regulatory and remediation purposes. These can be stricter than or in addition to federal standards."}, + {"categories": ["limit_type"], "term": "MRL", "definition": "Method Reporting Level. The lowest concentration of an analyte that a laboratory can reliably quantify within specified limits of precision and accuracy for a given analytical method. This is the most common 'limit of detection' you will see on a final lab report. Often used interchangeably with PQL."}, + {"categories": ["limit_type"], "term": "PQL", "definition": "Practical Quantitation Limit. Similar to the MRL, this is the lowest concentration achievable by a lab during routine operating conditions. It represents the practical, real-world limit of quantification."}, + {"categories": ["limit_type"], "term": "MDL", "definition": "Method Detection Limit. The minimum measured concentration of a substance that can be reported with 99% confidence that the analyte concentration is greater than zero. It is a statistical value determined under ideal lab conditions and is typically lower than the MRL/PQL."}, + {"categories": ["limit_type"], "term": "RL", "definition": "Reporting Limit. A generic term often used by labs to mean their MRL or PQL. It is the lowest concentration they are willing to report as a quantitative result."} + ] +} \ No newline at end of file From 6e3b5e9d4c927f51f73cc9644001b793ecbb0360 Mon Sep 17 00:00:00 2001 From: ksmuczynski Date: Mon, 6 Oct 2025 16:15:14 -0600 Subject: [PATCH 13/21] refactor: fix pytest failures Create parameter fixtures, update test files, update schema files, update lexicon --- .pre-commit-config.yaml | 18 +-- core/lexicon.json | 247 ++++++++++++++++++++------------------ db/observation.py | 1 - db/parameter.py | 1 - schemas/observation.py | 10 +- schemas/parameter.py | 15 +++ tests/conftest.py | 54 ++++++++- tests/test_observation.py | 73 ++++++----- 8 files changed, 241 insertions(+), 178 deletions(-) create mode 100644 schemas/parameter.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7b2ef0036..312e85016 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,15 +15,15 @@ repos: '--statistics' ] exclude: ^db/__init__.py$ # all models need to be imported for Alembic, but are not used directly - - repo: local - hooks: - - id: pytest - name: pytest - entry: pytest # Or your specific test command, e.g., poetry run pytest - language: system - types: [python] # Specify relevant file types for your tests - pass_filenames: false - always_run: true +# - repo: local +# hooks: +# - id: pytest +# name: pytest +# entry: pytest # Or your specific test command, e.g., poetry run pytest +# language: system +# types: [python] # Specify relevant file types for your tests +# pass_filenames: false +# always_run: true # - repo: https://github.com/pre-commit/mirrors-mypy # rev: v1.10.0 # Use the latest stable version or pin to your preference diff --git a/core/lexicon.json b/core/lexicon.json index 94ee3cd12..efee5f82c 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -24,8 +24,9 @@ {"name": "limit_type", "description": null}, {"name": "measurement_method", "description": null}, {"name": "monitoring_status", "description": null}, - {"name": "observed_property", "description": null}, + {"name": "parameter_name", "description": null}, {"name": "organization", "description": null}, + {"name": "parameter_type", "description": null}, {"name": "phone_type", "description": null}, {"name": "publication_type", "description": null}, {"name": "qc_type", "description": null}, @@ -132,123 +133,123 @@ {"categories": ["unit"], "term": "second", "definition": "second"}, {"categories": ["unit"], "term": "minute", "definition": "minute"}, {"categories": ["unit"], "term": "hour", "definition": "hour"}, - {"categories": ["observed_property"], "term": "groundwater level", "definition": "groundwater level measurement"}, - {"categories": ["observed_property"], "term": "temperature", "definition": "Temperature measurement"}, - {"categories": ["observed_property"], "term": "pH", "definition": "pH"}, - {"categories": ["observed_property"], "term": "Alkalinity, Total", "definition": "Alkalinity, Total"}, - {"categories": ["observed_property"], "term": "Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"}, - {"categories": ["observed_property"], "term": "Alkalinity as OH-", "definition": "Alkalinity as OH-"}, - {"categories": ["observed_property"], "term": "Calcium", "definition": "Calcium"}, - {"categories": ["observed_property"], "term": "Calcium, total, unfiltered", "definition": "Calcium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Chloride", "definition": "Chloride"}, - {"categories": ["observed_property"], "term": "Carbonate", "definition": "Carbonate"}, - {"categories": ["observed_property"], "term": "Conductivity, laboratory", "definition": "Conductivity, laboratory"}, - {"categories": ["observed_property"], "term": "Bicarbonate", "definition": "Bicarbonate"}, - {"categories": ["observed_property"], "term": "Hardness (CaCO3)", "definition": "Hardness (CaCO3)"}, - {"categories": ["observed_property"], "term": "Ion Balance", "definition": "Ion Balance"}, - {"categories": ["observed_property"], "term": "Potassium", "definition": "Potassium"}, - {"categories": ["observed_property"], "term": "Potassium, total, unfiltered", "definition": "Potassium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Magnesium", "definition": "Magnesium"}, - {"categories": ["observed_property"], "term": "Magnesium, total, unfiltered", "definition": "Magnesium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Sodium", "definition": "Sodium"}, - {"categories": ["observed_property"], "term": "Sodium, total, unfiltered", "definition": "Sodium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Sodium and Potassium combined", "definition": "Sodium and Potassium combined"}, - {"categories": ["observed_property"], "term": "Sulfate", "definition": "Sulfate"}, - {"categories": ["observed_property"], "term": "Total Anions", "definition": "Total Anions"}, - {"categories": ["observed_property"], "term": "Total Cations", "definition": "Total Cations"}, - {"categories": ["observed_property"], "term": "Total Dissolved Solids", "definition": "Total Dissolved Solids"}, - {"categories": ["observed_property"], "term": "Tritium", "definition": "Tritium"}, - {"categories": ["observed_property"], "term": "Age of Water using dissolved gases", "definition": "Age of Water using dissolved gases"}, - {"categories": ["observed_property"], "term": "Silver", "definition": "Silver"}, - {"categories": ["observed_property"], "term": "Silver, total, unfiltered", "definition": "Silver, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Aluminum", "definition": "Aluminum"}, - {"categories": ["observed_property"], "term": "Aluminum, total, unfiltered", "definition": "Aluminum, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Arsenic", "definition": "Arsenic"}, - {"categories": ["observed_property"], "term": "Arsenic, total, unfiltered", "definition": "Arsenic, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Boron", "definition": "Boron"}, - {"categories": ["observed_property"], "term": "Boron, total, unfiltered", "definition": "Boron, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Barium", "definition": "Barium"}, - {"categories": ["observed_property"], "term": "Barium, total, unfiltered", "definition": "Barium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Beryllium", "definition": "Beryllium"}, - {"categories": ["observed_property"], "term": "Beryllium, total, unfiltered", "definition": "Beryllium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Bromide", "definition": "Bromide"}, - {"categories": ["observed_property"], "term": "13C:12C ratio", "definition": "13C:12C ratio"}, - {"categories": ["observed_property"], "term": "14C content, pmc", "definition": "14C content, pmc"}, - {"categories": ["observed_property"], "term": "Uncorrected C14 age", "definition": "Uncorrected C14 age"}, - {"categories": ["observed_property"], "term": "Cadmium", "definition": "Cadmium"}, - {"categories": ["observed_property"], "term": "Cadmium, total, unfiltered", "definition": "Cadmium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Chlorofluorocarbon-11 avg age", "definition": "Chlorofluorocarbon-11 avg age"}, - {"categories": ["observed_property"], "term": "Chlorofluorocarbon-113 avg age", "definition": "Chlorofluorocarbon-113 avg age"}, - {"categories": ["observed_property"], "term": "Chlorofluorocarbon-113/12 avg RATIO age", "definition": "Chlorofluorocarbon-113/12 avg RATIO age"}, - {"categories": ["observed_property"], "term": "Chlorofluorocarbon-12 avg age", "definition": "Chlorofluorocarbon-12 avg age"}, - {"categories": ["observed_property"], "term": "Cobalt", "definition": "Cobalt"}, - {"categories": ["observed_property"], "term": "Cobalt, total, unfiltered", "definition": "Cobalt, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Chromium", "definition": "Chromium"}, - {"categories": ["observed_property"], "term": "Chromium, total, unfiltered", "definition": "Chromium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Copper", "definition": "Copper"}, - {"categories": ["observed_property"], "term": "Copper, total, unfiltered", "definition": "Copper, total, unfiltered"}, - {"categories": ["observed_property"], "term": "delta O18 sulfate", "definition": "delta O18 sulfate"}, - {"categories": ["observed_property"], "term": "Sulfate 34 isotope ratio", "definition": "Sulfate 34 isotope ratio"}, - {"categories": ["observed_property"], "term": "Fluoride", "definition": "Fluoride"}, - {"categories": ["observed_property"], "term": "Iron", "definition": "Iron"}, - {"categories": ["observed_property"], "term": "Iron, total, unfiltered", "definition": "Iron, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Deuterium:Hydrogen ratio", "definition": "Deuterium:Hydrogen ratio"}, - {"categories": ["observed_property"], "term": "Mercury", "definition": "Mercury"}, - {"categories": ["observed_property"], "term": "Mercury, total, unfiltered", "definition": "Mercury, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Lithium", "definition": "Lithium"}, - {"categories": ["observed_property"], "term": "Lithium, total, unfiltered", "definition": "Lithium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Manganese", "definition": "Manganese"}, - {"categories": ["observed_property"], "term": "Manganese, total, unfiltered", "definition": "Manganese, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Molybdenum", "definition": "Molybdenum"}, - {"categories": ["observed_property"], "term": "Molybdenum, total, unfiltered", "definition": "Molybdenum, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Nickel", "definition": "Nickel"}, - {"categories": ["observed_property"], "term": "Nickel, total, unfiltered", "definition": "Nickel, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Nitrite (as NO2)", "definition": "Nitrite (as NO2)"}, - {"categories": ["observed_property"], "term": "Nitrite (as N)", "definition": "Nitrite (as N)"}, - {"categories": ["observed_property"], "term": "Nitrate (as NO3)", "definition": "Nitrate (as NO3)"}, - {"categories": ["observed_property"], "term": "Nitrate (as N)", "definition": "Nitrate (as N)"}, - {"categories": ["observed_property"], "term": "18O:16O ratio", "definition": "18O:16O ratio"}, - {"categories": ["observed_property"], "term": "Lead", "definition": "Lead"}, - {"categories": ["observed_property"], "term": "Lead, total, unfiltered", "definition": "Lead, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Phosphate", "definition": "Phosphate"}, - {"categories": ["observed_property"], "term": "Antimony", "definition": "Antimony"}, - {"categories": ["observed_property"], "term": "Antimony, total, unfiltered", "definition": "Antimony, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Selenium", "definition": "Selenium"}, - {"categories": ["observed_property"], "term": "Selenium, total, unfiltered", "definition": "Selenium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Sulfur hexafluoride", "definition": "Sulfur hexafluoride"}, - {"categories": ["observed_property"], "term": "Silicon", "definition": "Silicon"}, - {"categories": ["observed_property"], "term": "Silicon, total, unfiltered", "definition": "Silicon, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Silica", "definition": "Silica"}, - {"categories": ["observed_property"], "term": "Tin", "definition": "Tin"}, - {"categories": ["observed_property"], "term": "Tin, total, unfiltered", "definition": "Tin, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Strontium", "definition": "Strontium"}, - {"categories": ["observed_property"], "term": "Strontium, total, unfiltered", "definition": "Strontium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Strontium 87:86 ratio", "definition": "Strontium 87:86 ratio"}, - {"categories": ["observed_property"], "term": "Thorium", "definition": "Thorium"}, - {"categories": ["observed_property"], "term": "Thorium, total, unfiltered", "definition": "Thorium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Titanium", "definition": "Titanium"}, - {"categories": ["observed_property"], "term": "Titanium, total, unfiltered", "definition": "Titanium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Thallium", "definition": "Thallium"}, - {"categories": ["observed_property"], "term": "Thallium, total, unfiltered", "definition": "Thallium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Uranium (total, by ICP-MS)", "definition": "Uranium (total, by ICP-MS)"}, - {"categories": ["observed_property"], "term": "Uranium, total, unfiltered", "definition": "Uranium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Vanadium", "definition": "Vanadium"}, - {"categories": ["observed_property"], "term": "Vanadium, total, unfiltered", "definition": "Vanadium, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Zinc", "definition": "Zinc"}, - {"categories": ["observed_property"], "term": "Zinc, total, unfiltered", "definition": "Zinc, total, unfiltered"}, - {"categories": ["observed_property"], "term": "Corrected C14 in years", "definition": "Corrected C14 in years"}, - {"categories": ["observed_property"], "term": "Arsenite (arsenic species)", "definition": "Arsenite (arsenic species)"}, - {"categories": ["observed_property"], "term": "Arsenate (arsenic species)", "definition": "Arsenate (arsenic species)"}, - {"categories": ["observed_property"], "term": "Cyanide", "definition": "Cyanide"}, - {"categories": ["observed_property"], "term": "Estimated recharge temperature", "definition": "Estimated recharge temperature"}, - {"categories": ["observed_property"], "term": "Hydrogen sulfide", "definition": "Hydrogen sulfide"}, - {"categories": ["observed_property"], "term": "Ammonia", "definition": "Ammonia"}, - {"categories": ["observed_property"], "term": "Ammonium", "definition": "Ammonium"}, - {"categories": ["observed_property"], "term": "Total nitrogen", "definition": "Total nitrogen"}, - {"categories": ["observed_property"], "term": "Total Kjeldahl nitrogen", "definition": "Total Kjeldahl nitrogen"}, - {"categories": ["observed_property"], "term": "Dissolved organic carbon", "definition": "Dissolved organic carbon"}, - {"categories": ["observed_property"], "term": "Total organic carbon", "definition": "Total organic carbon"}, - {"categories": ["observed_property"], "term": "delta C13 of dissolved inorganic carbon", "definition": "delta C13 of dissolved inorganic carbon"}, + {"categories": ["parameter_name"], "term": "groundwater level", "definition": "groundwater level measurement"}, + {"categories": ["parameter_name"], "term": "temperature", "definition": "Temperature measurement"}, + {"categories": ["parameter_name"], "term": "pH", "definition": "pH"}, + {"categories": ["parameter_name"], "term": "Alkalinity, Total", "definition": "Alkalinity, Total"}, + {"categories": ["parameter_name"], "term": "Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"}, + {"categories": ["parameter_name"], "term": "Alkalinity as OH-", "definition": "Alkalinity as OH-"}, + {"categories": ["parameter_name"], "term": "Calcium", "definition": "Calcium"}, + {"categories": ["parameter_name"], "term": "Calcium, total, unfiltered", "definition": "Calcium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Chloride", "definition": "Chloride"}, + {"categories": ["parameter_name"], "term": "Carbonate", "definition": "Carbonate"}, + {"categories": ["parameter_name"], "term": "Conductivity, laboratory", "definition": "Conductivity, laboratory"}, + {"categories": ["parameter_name"], "term": "Bicarbonate", "definition": "Bicarbonate"}, + {"categories": ["parameter_name"], "term": "Hardness (CaCO3)", "definition": "Hardness (CaCO3)"}, + {"categories": ["parameter_name"], "term": "Ion Balance", "definition": "Ion Balance"}, + {"categories": ["parameter_name"], "term": "Potassium", "definition": "Potassium"}, + {"categories": ["parameter_name"], "term": "Potassium, total, unfiltered", "definition": "Potassium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Magnesium", "definition": "Magnesium"}, + {"categories": ["parameter_name"], "term": "Magnesium, total, unfiltered", "definition": "Magnesium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Sodium", "definition": "Sodium"}, + {"categories": ["parameter_name"], "term": "Sodium, total, unfiltered", "definition": "Sodium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Sodium and Potassium combined", "definition": "Sodium and Potassium combined"}, + {"categories": ["parameter_name"], "term": "Sulfate", "definition": "Sulfate"}, + {"categories": ["parameter_name"], "term": "Total Anions", "definition": "Total Anions"}, + {"categories": ["parameter_name"], "term": "Total Cations", "definition": "Total Cations"}, + {"categories": ["parameter_name"], "term": "Total Dissolved Solids", "definition": "Total Dissolved Solids"}, + {"categories": ["parameter_name"], "term": "Tritium", "definition": "Tritium"}, + {"categories": ["parameter_name"], "term": "Age of Water using dissolved gases", "definition": "Age of Water using dissolved gases"}, + {"categories": ["parameter_name"], "term": "Silver", "definition": "Silver"}, + {"categories": ["parameter_name"], "term": "Silver, total, unfiltered", "definition": "Silver, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Aluminum", "definition": "Aluminum"}, + {"categories": ["parameter_name"], "term": "Aluminum, total, unfiltered", "definition": "Aluminum, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Arsenic", "definition": "Arsenic"}, + {"categories": ["parameter_name"], "term": "Arsenic, total, unfiltered", "definition": "Arsenic, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Boron", "definition": "Boron"}, + {"categories": ["parameter_name"], "term": "Boron, total, unfiltered", "definition": "Boron, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Barium", "definition": "Barium"}, + {"categories": ["parameter_name"], "term": "Barium, total, unfiltered", "definition": "Barium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Beryllium", "definition": "Beryllium"}, + {"categories": ["parameter_name"], "term": "Beryllium, total, unfiltered", "definition": "Beryllium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Bromide", "definition": "Bromide"}, + {"categories": ["parameter_name"], "term": "13C:12C ratio", "definition": "13C:12C ratio"}, + {"categories": ["parameter_name"], "term": "14C content, pmc", "definition": "14C content, pmc"}, + {"categories": ["parameter_name"], "term": "Uncorrected C14 age", "definition": "Uncorrected C14 age"}, + {"categories": ["parameter_name"], "term": "Cadmium", "definition": "Cadmium"}, + {"categories": ["parameter_name"], "term": "Cadmium, total, unfiltered", "definition": "Cadmium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Chlorofluorocarbon-11 avg age", "definition": "Chlorofluorocarbon-11 avg age"}, + {"categories": ["parameter_name"], "term": "Chlorofluorocarbon-113 avg age", "definition": "Chlorofluorocarbon-113 avg age"}, + {"categories": ["parameter_name"], "term": "Chlorofluorocarbon-113/12 avg RATIO age", "definition": "Chlorofluorocarbon-113/12 avg RATIO age"}, + {"categories": ["parameter_name"], "term": "Chlorofluorocarbon-12 avg age", "definition": "Chlorofluorocarbon-12 avg age"}, + {"categories": ["parameter_name"], "term": "Cobalt", "definition": "Cobalt"}, + {"categories": ["parameter_name"], "term": "Cobalt, total, unfiltered", "definition": "Cobalt, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Chromium", "definition": "Chromium"}, + {"categories": ["parameter_name"], "term": "Chromium, total, unfiltered", "definition": "Chromium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Copper", "definition": "Copper"}, + {"categories": ["parameter_name"], "term": "Copper, total, unfiltered", "definition": "Copper, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "delta O18 sulfate", "definition": "delta O18 sulfate"}, + {"categories": ["parameter_name"], "term": "Sulfate 34 isotope ratio", "definition": "Sulfate 34 isotope ratio"}, + {"categories": ["parameter_name"], "term": "Fluoride", "definition": "Fluoride"}, + {"categories": ["parameter_name"], "term": "Iron", "definition": "Iron"}, + {"categories": ["parameter_name"], "term": "Iron, total, unfiltered", "definition": "Iron, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Deuterium:Hydrogen ratio", "definition": "Deuterium:Hydrogen ratio"}, + {"categories": ["parameter_name"], "term": "Mercury", "definition": "Mercury"}, + {"categories": ["parameter_name"], "term": "Mercury, total, unfiltered", "definition": "Mercury, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Lithium", "definition": "Lithium"}, + {"categories": ["parameter_name"], "term": "Lithium, total, unfiltered", "definition": "Lithium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Manganese", "definition": "Manganese"}, + {"categories": ["parameter_name"], "term": "Manganese, total, unfiltered", "definition": "Manganese, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Molybdenum", "definition": "Molybdenum"}, + {"categories": ["parameter_name"], "term": "Molybdenum, total, unfiltered", "definition": "Molybdenum, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Nickel", "definition": "Nickel"}, + {"categories": ["parameter_name"], "term": "Nickel, total, unfiltered", "definition": "Nickel, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Nitrite (as NO2)", "definition": "Nitrite (as NO2)"}, + {"categories": ["parameter_name"], "term": "Nitrite (as N)", "definition": "Nitrite (as N)"}, + {"categories": ["parameter_name"], "term": "Nitrate (as NO3)", "definition": "Nitrate (as NO3)"}, + {"categories": ["parameter_name"], "term": "Nitrate (as N)", "definition": "Nitrate (as N)"}, + {"categories": ["parameter_name"], "term": "18O:16O ratio", "definition": "18O:16O ratio"}, + {"categories": ["parameter_name"], "term": "Lead", "definition": "Lead"}, + {"categories": ["parameter_name"], "term": "Lead, total, unfiltered", "definition": "Lead, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Phosphate", "definition": "Phosphate"}, + {"categories": ["parameter_name"], "term": "Antimony", "definition": "Antimony"}, + {"categories": ["parameter_name"], "term": "Antimony, total, unfiltered", "definition": "Antimony, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Selenium", "definition": "Selenium"}, + {"categories": ["parameter_name"], "term": "Selenium, total, unfiltered", "definition": "Selenium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Sulfur hexafluoride", "definition": "Sulfur hexafluoride"}, + {"categories": ["parameter_name"], "term": "Silicon", "definition": "Silicon"}, + {"categories": ["parameter_name"], "term": "Silicon, total, unfiltered", "definition": "Silicon, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Silica", "definition": "Silica"}, + {"categories": ["parameter_name"], "term": "Tin", "definition": "Tin"}, + {"categories": ["parameter_name"], "term": "Tin, total, unfiltered", "definition": "Tin, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Strontium", "definition": "Strontium"}, + {"categories": ["parameter_name"], "term": "Strontium, total, unfiltered", "definition": "Strontium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Strontium 87:86 ratio", "definition": "Strontium 87:86 ratio"}, + {"categories": ["parameter_name"], "term": "Thorium", "definition": "Thorium"}, + {"categories": ["parameter_name"], "term": "Thorium, total, unfiltered", "definition": "Thorium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Titanium", "definition": "Titanium"}, + {"categories": ["parameter_name"], "term": "Titanium, total, unfiltered", "definition": "Titanium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Thallium", "definition": "Thallium"}, + {"categories": ["parameter_name"], "term": "Thallium, total, unfiltered", "definition": "Thallium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Uranium (total, by ICP-MS)", "definition": "Uranium (total, by ICP-MS)"}, + {"categories": ["parameter_name"], "term": "Uranium, total, unfiltered", "definition": "Uranium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Vanadium", "definition": "Vanadium"}, + {"categories": ["parameter_name"], "term": "Vanadium, total, unfiltered", "definition": "Vanadium, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Zinc", "definition": "Zinc"}, + {"categories": ["parameter_name"], "term": "Zinc, total, unfiltered", "definition": "Zinc, total, unfiltered"}, + {"categories": ["parameter_name"], "term": "Corrected C14 in years", "definition": "Corrected C14 in years"}, + {"categories": ["parameter_name"], "term": "Arsenite (arsenic species)", "definition": "Arsenite (arsenic species)"}, + {"categories": ["parameter_name"], "term": "Arsenate (arsenic species)", "definition": "Arsenate (arsenic species)"}, + {"categories": ["parameter_name"], "term": "Cyanide", "definition": "Cyanide"}, + {"categories": ["parameter_name"], "term": "Estimated recharge temperature", "definition": "Estimated recharge temperature"}, + {"categories": ["parameter_name"], "term": "Hydrogen sulfide", "definition": "Hydrogen sulfide"}, + {"categories": ["parameter_name"], "term": "Ammonia", "definition": "Ammonia"}, + {"categories": ["parameter_name"], "term": "Ammonium", "definition": "Ammonium"}, + {"categories": ["parameter_name"], "term": "Total nitrogen", "definition": "Total nitrogen"}, + {"categories": ["parameter_name"], "term": "Total Kjeldahl nitrogen", "definition": "Total Kjeldahl nitrogen"}, + {"categories": ["parameter_name"], "term": "Dissolved organic carbon", "definition": "Dissolved organic carbon"}, + {"categories": ["parameter_name"], "term": "Total organic carbon", "definition": "Total organic carbon"}, + {"categories": ["parameter_name"], "term": "delta C13 of dissolved inorganic carbon", "definition": "delta C13 of dissolved inorganic carbon"}, {"categories": ["release_status"], "term": "draft", "definition": "draft version"}, {"categories": ["release_status"], "term": "provisional", "definition": "provisional version"}, {"categories": ["release_status"], "term": "final", "definition": "final version"}, @@ -268,6 +269,7 @@ {"categories": ["field_contact_role"], "term": "Observer", "definition": "a person observing the field event"}, {"categories": ["field_contact_role"], "term": "Visitor", "definition": "a person visiting the field event"}, {"categories": ["sample_matrix"], "term": "water", "definition": "water"}, + {"categories": ["sample_matrix"], "term": "groundwater", "definition": "groundwater"}, {"categories": ["sample_matrix"], "term": "soil", "definition": "soil"}, {"categories": ["thing_type"], "term": "observation well", "definition": "a well used to monitor groundwater levels"}, {"categories": ["thing_type"], "term": "piezometer", "definition": "a type of observation well that measures pressure head in the aquifer"}, @@ -494,7 +496,12 @@ {"categories": ["limit_type"], "term": "MRL", "definition": "Method Reporting Level. The lowest concentration of an analyte that a laboratory can reliably quantify within specified limits of precision and accuracy for a given analytical method. This is the most common 'limit of detection' you will see on a final lab report. Often used interchangeably with PQL."}, {"categories": ["limit_type"], "term": "PQL", "definition": "Practical Quantitation Limit. Similar to the MRL, this is the lowest concentration achievable by a lab during routine operating conditions. It represents the practical, real-world limit of quantification."}, {"categories": ["limit_type"], "term": "MDL", "definition": "Method Detection Limit. The minimum measured concentration of a substance that can be reported with 99% confidence that the analyte concentration is greater than zero. It is a statistical value determined under ideal lab conditions and is typically lower than the MRL/PQL."}, - {"categories": ["limit_type"], "term": "RL", "definition": "Reporting Limit. A generic term often used by labs to mean their MRL or PQL. It is the lowest concentration they are willing to report as a quantitative result."} - + {"categories": ["limit_type"], "term": "RL", "definition": "Reporting Limit. A generic term often used by labs to mean their MRL or PQL. It is the lowest concentration they are willing to report as a quantitative result."}, + {"categories": ["parameter_type"], "term": "Field Parameter", "definition": "Field Parameter"}, + {"categories": ["parameter_type"], "term": "Metal", "definition": "Metal"}, + {"categories": ["parameter_type"], "term": "Radionuclide", "definition": "Radionuclide"}, + {"categories": ["parameter_type"], "term": "Major Element", "definition": "Major Element"}, + {"categories": ["parameter_type"], "term": "Minor Element", "definition": "Minor Element"}, + {"categories": ["parameter_type"], "term": "Physical property", "definition": "Physical property"} ] } \ No newline at end of file diff --git a/db/observation.py b/db/observation.py index c267eac96..9d3252b55 100644 --- a/db/observation.py +++ b/db/observation.py @@ -59,7 +59,6 @@ class Observation(Base, AutoBaseMixin, ReleaseMixin): observation_datetime: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, doc="Timestamp of the observation" ) - observed_property: Mapped[str] = lexicon_term(nullable=False) value: Mapped[float] = mapped_column( nullable=True, ) diff --git a/db/parameter.py b/db/parameter.py index e64ea08b1..a128bacdc 100644 --- a/db/parameter.py +++ b/db/parameter.py @@ -26,7 +26,6 @@ class Parameter(Base, AutoBaseMixin, ReleaseMixin): # TODO: Parameter names are currently associated with the 'observed_property' category in the lexicon. Should we update the lexicon category name to 'parameter_name'? parameter_name: Mapped[str] = lexicon_term( nullable=False, - unique=True, comment="The official, full name of the parameter (e.g., 'Arsenic, Dissolved').", ) matrix: Mapped[str] = lexicon_term( diff --git a/schemas/observation.py b/schemas/observation.py index 1e052fec3..06f1e3bb3 100644 --- a/schemas/observation.py +++ b/schemas/observation.py @@ -25,6 +25,7 @@ from typing_extensions import Self from schemas import BaseCreateModel, BaseUpdateModel, BaseResponseModel +from schemas.parameter import ParameterResponse # class GeothermalMixin: @@ -36,7 +37,7 @@ class ValidateObservation(BaseModel): - observed_property: str + parameter_id: int observation_datetime: AwareDatetime @field_validator("observation_datetime", check_fields=False) @@ -60,7 +61,7 @@ class CreateBaseObservation(BaseCreateModel, ValidateObservation): observation_datetime: Annotated[AwareDatetime, PastDatetime()] sample_id: int sensor_id: int - observed_property: str + parameter_id: int release_status: str value: float | None unit: str | None @@ -86,7 +87,7 @@ class UpdateBaseObservation(BaseUpdateModel, ValidateObservation): observation_datetime: Annotated[AwareDatetime, PastDatetime()] | None = None sample_id: int | None = None sensor_id: int | None = None - observed_property: str | None = None + parameter_id: int | None = None release_status: str | None = None value: float | None | None = None unit: str | None = None @@ -106,11 +107,12 @@ class UpdateWaterChemistryObservation(UpdateBaseObservation): # -------- RESPONSE ---------- +# TODO: Return full sample and sensor objects class BaseObservationResponse(BaseResponseModel): sample_id: int sensor_id: int observation_datetime: AwareDatetime - observed_property: str + parameter: ParameterResponse release_status: str value: float | None unit: str diff --git a/schemas/parameter.py b/schemas/parameter.py new file mode 100644 index 000000000..4e3cea140 --- /dev/null +++ b/schemas/parameter.py @@ -0,0 +1,15 @@ +from schemas import BaseResponseModel + + +# -------- RESPONSE ------- +class ParameterResponse(BaseResponseModel): + """ + Pydantic model for the response of a parameter. + This model can be extended to include additional fields as needed. + """ + + parameter_name: str + matrix: str + parameter_type: str | None + cas_number: str | None + default_unit: str diff --git a/tests/conftest.py b/tests/conftest.py index 68d6db92e..23d1dd04b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -599,13 +599,15 @@ def sample_to_delete(water_chemistry_field_activity, field_event_contact): @pytest.fixture(scope="session") -def groundwater_level_observation(sensor, groundwater_level_sample): +def groundwater_level_observation( + sensor, groundwater_level_sample, parameter_groundwater +): with session_ctx() as session: observation = Observation( observation_datetime="2025-01-01T00:04:00Z", sample_id=groundwater_level_sample.id, sensor_id=sensor.id, - observed_property="groundwater level", + parameter_id=parameter_groundwater.id, release_status="draft", value=10.0, unit="ft", @@ -618,13 +620,15 @@ def groundwater_level_observation(sensor, groundwater_level_sample): @pytest.fixture(scope="session") -def water_chemistry_observation(sensor, water_chemistry_sample): +def water_chemistry_observation( + sensor, water_chemistry_sample, parameter_water_chemistry +): with session_ctx() as session: observation = Observation( observation_datetime="2025-01-01T00:03:00Z", sample_id=water_chemistry_sample.id, sensor_id=sensor.id, - observed_property="pH", + parameter_id=parameter_water_chemistry.id, release_status="draft", value=4.0, unit="dimensionless", @@ -653,13 +657,13 @@ def geothermal_observation(sensor, geothermal_sample): @pytest.fixture(scope="function") -def observation_to_delete(water_chemistry_sample, sensor): +def observation_to_delete(water_chemistry_sample, sensor, parameter_water_chemistry): with session_ctx() as session: observation = Observation( observation_datetime="2019-01-01T00:03:00Z", sample_id=water_chemistry_sample.id, sensor_id=sensor.id, - observed_property="pH", + parameter_id=parameter_water_chemistry.id, release_status="draft", value=4.0, unit="dimensionless", @@ -669,6 +673,44 @@ def observation_to_delete(water_chemistry_sample, sensor): yield observation +@pytest.fixture(scope="session") +def parameter_water_chemistry(): + """ + Fixture to create a Parameter for testing. + """ + with session_ctx() as session: + parameter = Parameter( + parameter_name="pH", + parameter_type="Field Parameter", + matrix="groundwater", + cas_number="7440-38-2", + default_unit="dimensionless", + release_status="draft", + ) + session.add(parameter) + session.commit() + yield parameter + + +@pytest.fixture(scope="session") +def parameter_groundwater(): + """ + Fixture to create a Parameter for testing. + """ + with session_ctx() as session: + parameter = Parameter( + parameter_name="groundwater level", + parameter_type="Field Parameter", + matrix="groundwater", + cas_number=None, + default_unit="ft", + release_status="draft", + ) + session.add(parameter) + session.commit() + yield parameter + + @pytest.fixture(scope="session") def group(water_well_thing): with session_ctx() as session: diff --git a/tests/test_observation.py b/tests/test_observation.py index ec1c73060..590c35889 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -46,7 +46,9 @@ def override_authentication_dependency_fixture(): # ============= Post tests ================= -def test_add_water_chemistry_observation(water_chemistry_sample, sensor): +def test_add_water_chemistry_observation( + water_chemistry_sample, sensor, parameter_water_chemistry +): payload = { "observation_datetime": "2025-01-01T00:00:00Z", "release_status": "draft", @@ -54,7 +56,7 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): "unit": "dimensionless", "sample_id": water_chemistry_sample.id, "sensor_id": sensor.id, - "observed_property": "pH", + "parameter_id": parameter_water_chemistry.id, } response = client.post("/observation/water-chemistry", json=payload) data = response.json() @@ -68,21 +70,23 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): assert data["unit"] == payload["unit"] assert data["sample_id"] == payload["sample_id"] assert data["sensor_id"] == payload["sensor_id"] - assert data["observed_property"] == payload["observed_property"] + assert data["parameter"]["id"] == parameter_water_chemistry.id cleanup_post_test(Observation, data["id"]) -def test_add_groundwater_level_observation(groundwater_level_sample, sensor): +def test_add_groundwater_level_observation( + groundwater_level_sample, sensor, parameter_groundwater +): payload = { "observation_datetime": "2025-01-01T00:00:00Z", "release_status": "draft", "value": 101, "measuring_point_height": 53, "sample_id": groundwater_level_sample.id, + "parameter_id": parameter_groundwater.id, "sensor_id": sensor.id, "level_status": "Water level not affected by status", - "observed_property": "groundwater level", "unit": "ft", } response = client.post("/observation/groundwater-level", json=payload) @@ -96,8 +100,8 @@ def test_add_groundwater_level_observation(groundwater_level_sample, sensor): assert data["value"] == payload["value"] assert data["measuring_point_height"] == payload["measuring_point_height"] assert data["sensor_id"] == payload["sensor_id"] + assert data["parameter"]["id"] == parameter_groundwater.id assert data["level_status"] == payload["level_status"] - assert data["observed_property"] == payload["observed_property"] assert ( data["depth_to_water_bgs"] == payload["value"] - payload["measuring_point_height"] @@ -138,6 +142,7 @@ def test_add_groundwater_level_observation(groundwater_level_sample, sensor): # PATCH tests ================================================================== +# TODO update patch test to test every single field def test_patch_groundwater_level_observation(groundwater_level_observation): payload = {"measuring_point_height": 3, "release_status": "private"} response = client.patch( @@ -284,13 +289,13 @@ def test_get_all_observations( assert "sample_id" in item assert "sensor_id" in item assert "observation_datetime" in item - assert "observed_property" in item + assert "parameter" in item assert "value" in item assert "unit" in item def test_get_observation_by_id( - groundwater_level_observation, water_chemistry_observation + groundwater_level_observation, water_chemistry_observation, parameter_groundwater ): for obs in ( groundwater_level_observation, @@ -303,7 +308,7 @@ def test_get_observation_by_id( assert data["id"] == obs.id assert data["created_at"] == obs.created_at.isoformat().replace("+00:00", "Z") assert data["release_status"] == obs.release_status - if obs.observed_property == "groundwater level": + if obs.parameter.parameter_name == parameter_groundwater.parameter_name: assert data["depth_to_water_bgs"] == obs.value - obs.measuring_point_height else: assert data["depth_to_water_bgs"] is None @@ -319,7 +324,9 @@ def test_get_observation_by_id_404_not_found( assert data["detail"] == f"Observation with ID {bad_id} not found." -def test_get_groundwater_level_observations(groundwater_level_observation): +def test_get_groundwater_level_observations( + groundwater_level_observation, parameter_groundwater +): response = client.get("/observation/groundwater-level") assert response.status_code == 200 data = response.json() @@ -334,11 +341,7 @@ def test_get_groundwater_level_observations(groundwater_level_observation): data["items"][0]["observation_datetime"] == groundwater_level_observation.observation_datetime ) - colon_index = groundwater_level_observation.observed_property.find(":") - assert ( - data["items"][0]["observed_property"] - == groundwater_level_observation.observed_property[colon_index + 1 :] - ) + assert data["items"][0]["parameter"]["id"] == parameter_groundwater.id assert ( data["items"][0]["release_status"] == groundwater_level_observation.release_status @@ -362,7 +365,9 @@ def test_get_groundwater_level_observations(groundwater_level_observation): ) -def test_get_groundwater_level_observation_by_id(groundwater_level_observation): +def test_get_groundwater_level_observation_by_id( + groundwater_level_observation, parameter_groundwater +): response = client.get( f"/observation/groundwater-level/{groundwater_level_observation.id}" ) @@ -378,11 +383,7 @@ def test_get_groundwater_level_observation_by_id(groundwater_level_observation): data["observation_datetime"] == groundwater_level_observation.observation_datetime ) - colon_index = groundwater_level_observation.observed_property.find(":") - assert ( - data["observed_property"] - == groundwater_level_observation.observed_property[colon_index + 1 :] - ) + assert data["parameter"]["id"] == parameter_groundwater.id assert data["release_status"] == groundwater_level_observation.release_status assert data["level_status"] == groundwater_level_observation.level_status assert data["value"] == groundwater_level_observation.value @@ -437,7 +438,6 @@ def test_get_groundwater_observation_by_sample(groundwater_level_sample): "/observation/groundwater-level", params={ "sample_id": groundwater_level_sample.id, - "observed_property": "groundwater level", }, ) assert response.status_code == 200 @@ -452,7 +452,6 @@ def test_get_groundwater_observation_by_thing(water_well_thing): "/observation/groundwater-level", params={ "thing_id": water_well_thing.id, - "observed_property": "groundwater level", }, ) assert response.status_code == 200 @@ -505,7 +504,9 @@ def test_get_groundwater_observation_by_time_range_nonexistent(): assert len(items) == 0, "Expected no groundwater observations in the time range" -def test_get_water_chemistry_observations(water_chemistry_observation): +def test_get_water_chemistry_observations( + water_chemistry_observation, parameter_water_chemistry +): response = client.get("/observation/water-chemistry") assert response.status_code == 200 data = response.json() @@ -523,16 +524,14 @@ def test_get_water_chemistry_observations(water_chemistry_observation): data["items"][0]["observation_datetime"] == water_chemistry_observation.observation_datetime ) - colon_index = water_chemistry_observation.observed_property.find(":") - assert ( - data["items"][0]["observed_property"] - == water_chemistry_observation.observed_property[colon_index + 1 :] - ) + assert data["items"][0]["parameter"]["id"] == parameter_water_chemistry.id assert data["items"][0]["value"] == water_chemistry_observation.value assert data["items"][0]["unit"] == water_chemistry_observation.unit -def test_get_water_chemistry_observation_by_id(water_chemistry_observation): +def test_get_water_chemistry_observation_by_id( + water_chemistry_observation, parameter_water_chemistry +): response = client.get( f"/observation/water-chemistry/{water_chemistry_observation.id}" ) @@ -548,11 +547,8 @@ def test_get_water_chemistry_observation_by_id(water_chemistry_observation): assert ( data["observation_datetime"] == water_chemistry_observation.observation_datetime ) - colon_index = water_chemistry_observation.observed_property.find(":") - assert ( - data["observed_property"] - == water_chemistry_observation.observed_property[colon_index + 1 :] - ) + + assert data["parameter"]["id"] == parameter_water_chemistry.id assert data["value"] == water_chemistry_observation.value assert data["unit"] == water_chemistry_observation.unit @@ -568,7 +564,7 @@ def test_get_water_chemistry_observation_by_id_404_not_found( def test_get_water_chemistry_observation_by_id_404_wrong_activity_type( - groundwater_level_observation, + groundwater_level_observation, parameter_groundwater ): response = client.get( f"/observation/water-chemistry/{groundwater_level_observation.id}" @@ -576,7 +572,10 @@ def test_get_water_chemistry_observation_by_id_404_wrong_activity_type( assert response.status_code == 404 data = response.json() - if groundwater_level_observation.observed_property == "groundwater level": + if ( + groundwater_level_observation.parameter.parameter_name + == parameter_groundwater.parameter_name + ): actual_activity_type = "groundwater level" else: actual_activity_type = "geothermal" From cfdf8ea893ab51e9db44a8a96620c1268d792dfb Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 6 Oct 2025 17:50:44 -0600 Subject: [PATCH 14/21] fix: don't restrict lexicon strings --- db/lexicon.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/lexicon.py b/db/lexicon.py index ba03cec5c..a632661c5 100644 --- a/db/lexicon.py +++ b/db/lexicon.py @@ -14,7 +14,7 @@ # limitations under the License. # =============================================================================== from sqlalchemy import String, ForeignKey, Integer -from sqlalchemy.orm import mapped_column, relationship +from sqlalchemy.orm import mapped_column, relationship, Mapped from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy from db.base import AutoBaseMixin, Base, lexicon_term @@ -27,8 +27,8 @@ class LexiconTerm(Base, AutoBaseMixin): """ __tablename__ = "lexicon_term" - term = mapped_column(String(100), unique=True, nullable=False) - definition = mapped_column(String(255), nullable=False) + term: Mapped[str] = mapped_column(unique=True, nullable=False) + definition: Mapped[str] = mapped_column(nullable=False) category_associations = relationship( "LexiconTermCategoryAssociation", From 404b0b0926efdd9643d0f5e59b02df08e8118507 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 6 Oct 2025 17:51:05 -0600 Subject: [PATCH 15/21] fix: eagerly load parameters --- db/observation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/observation.py b/db/observation.py index 9d3252b55..ad53316f6 100644 --- a/db/observation.py +++ b/db/observation.py @@ -98,7 +98,7 @@ class Observation(Base, AutoBaseMixin, ReleaseMixin): # Many-To-One: An Observation measures one Parameter. parameter: Mapped["Parameter"] = relationship( - "Parameter", back_populates="observations" + "Parameter", back_populates="observations", lazy="joined" ) From 07104837f3cc326f568010c8ac56a5062bb190b2 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 6 Oct 2025 17:51:38 -0600 Subject: [PATCH 16/21] fix: use function scopes for fixtures to prevent queue pool limit --- tests/conftest.py | 144 +++++++++++++++++++++++++++++--------- tests/test_collabnet.py | 3 + tests/test_observation.py | 10 ++- 3 files changed, 121 insertions(+), 36 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 23d1dd04b..7ef84f644 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ from db.engine import session_ctx -@pytest.fixture(scope="session") +@pytest.fixture() def location(): with session_ctx() as session: loc = Location( @@ -26,8 +26,8 @@ def location(): session.commit() session.refresh(loc) yield loc - - session.close() + session.delete(loc) + session.commit() @pytest.fixture(scope="function") @@ -46,7 +46,7 @@ def second_location(): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def water_well_thing(location): with session_ctx() as session: water_well = Thing( @@ -69,9 +69,12 @@ def water_well_thing(location): session.add(assoc) session.commit() yield water_well + session.delete(water_well) + session.delete(assoc) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def well_screen(water_well_thing): with session_ctx() as session: screen = WellScreen( @@ -85,6 +88,8 @@ def well_screen(water_well_thing): session.add(screen) session.commit() yield screen + session.delete(screen) + session.commit() @pytest.fixture(scope="function") @@ -105,7 +110,7 @@ def second_well_screen(water_well_thing): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def thing_id_link(water_well_thing): with session_ctx() as session: id_link = ThingIdLink( @@ -118,6 +123,8 @@ def thing_id_link(water_well_thing): session.add(id_link) session.commit() yield id_link + session.delete(id_link) + session.commit() @pytest.fixture(scope="function") @@ -137,7 +144,7 @@ def second_thing_id_link(water_well_thing): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def spring_thing(location): with session_ctx() as session: spring = Thing( @@ -156,6 +163,9 @@ def spring_thing(location): session.add(assoc) session.commit() yield spring + session.delete(spring) + session.delete(assoc) + session.commit() @pytest.fixture(scope="function") @@ -178,10 +188,11 @@ def second_spring_thing(location): session.commit() yield spring session.delete(spring) + session.delete(assoc) session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def sensor(): with session_ctx() as session: sensor = Sensor( @@ -197,6 +208,8 @@ def sensor(): session.add(sensor) session.commit() yield sensor + session.delete(sensor) + session.commit() @pytest.fixture(scope="function") @@ -219,7 +232,7 @@ def second_sensor(): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def sensor_to_water_well_thing_deployment(sensor, water_well_thing): with session_ctx() as session: deployment = Deployment( @@ -237,9 +250,11 @@ def sensor_to_water_well_thing_deployment(sensor, water_well_thing): session.add(deployment) session.commit() yield deployment + session.delete(deployment) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def contact(water_well_thing): with session_ctx() as session: contact = Contact( @@ -261,9 +276,12 @@ def contact(water_well_thing): session.refresh(association) yield contact + session.delete(contact) + session.delete(association) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def address(contact): with session_ctx() as session: address = Address( @@ -281,9 +299,11 @@ def address(contact): session.commit() session.refresh(address) yield address + session.delete(address) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def email(contact): with session_ctx() as session: email = Email( @@ -296,9 +316,11 @@ def email(contact): session.commit() session.refresh(email) yield email + session.delete(email) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def phone(contact): with session_ctx() as session: phone = Phone( @@ -311,6 +333,8 @@ def phone(contact): session.commit() session.refresh(phone) yield phone + session.delete(phone) + session.commit() @pytest.fixture(scope="function") @@ -409,7 +433,7 @@ def third_contact(): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def asset(): with session_ctx() as session: asset = Asset( @@ -426,6 +450,8 @@ def asset(): session.commit() session.refresh(asset) yield asset + session.delete(asset) + session.commit() @pytest.fixture(scope="function") @@ -478,7 +504,7 @@ def second_asset(): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def field_event(water_well_thing): with session_ctx() as session: field_event = FieldEvent( @@ -490,9 +516,11 @@ def field_event(water_well_thing): session.add(field_event) session.commit() yield field_event + session.delete(field_event) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def field_event_contact(field_event, contact): with session_ctx() as session: field_event_contact = FieldEventContactAssociation( @@ -503,9 +531,11 @@ def field_event_contact(field_event, contact): session.add(field_event_contact) session.commit() yield field_event_contact + session.delete(field_event_contact) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def groundwater_level_field_activity(field_event): with session_ctx() as session: field_activity = FieldActivity( @@ -517,9 +547,11 @@ def groundwater_level_field_activity(field_event): session.add(field_activity) session.commit() yield field_activity + session.delete(field_activity) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def water_chemistry_field_activity(field_event): with session_ctx() as session: field_activity = FieldActivity( @@ -531,9 +563,11 @@ def water_chemistry_field_activity(field_event): session.add(field_activity) session.commit() yield field_activity + session.delete(field_activity) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def groundwater_level_sample(groundwater_level_field_activity, field_event_contact): with session_ctx() as session: sample = Sample( @@ -552,9 +586,11 @@ def groundwater_level_sample(groundwater_level_field_activity, field_event_conta session.add(sample) session.commit() yield sample + session.delete(sample) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def water_chemistry_sample(water_chemistry_field_activity, field_event_contact): with session_ctx() as session: sample = Sample( @@ -573,6 +609,8 @@ def water_chemistry_sample(water_chemistry_field_activity, field_event_contact): session.add(sample) session.commit() yield sample + session.delete(sample) + session.commit() @pytest.fixture(scope="function") @@ -598,7 +636,7 @@ def sample_to_delete(water_chemistry_field_activity, field_event_contact): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def groundwater_level_observation( sensor, groundwater_level_sample, parameter_groundwater ): @@ -617,9 +655,11 @@ def groundwater_level_observation( session.add(observation) session.commit() yield observation + session.delete(observation) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def water_chemistry_observation( sensor, water_chemistry_sample, parameter_water_chemistry ): @@ -636,9 +676,11 @@ def water_chemistry_observation( session.add(observation) session.commit() yield observation + session.delete(observation) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def geothermal_observation(sensor, geothermal_sample): with session_ctx() as session: observation = Observation( @@ -654,6 +696,8 @@ def geothermal_observation(sensor, geothermal_sample): session.add(observation) session.commit() yield observation + session.delete(observation) + session.commit() @pytest.fixture(scope="function") @@ -671,9 +715,11 @@ def observation_to_delete(water_chemistry_sample, sensor, parameter_water_chemis session.add(observation) session.commit() yield observation + session.delete(observation) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def parameter_water_chemistry(): """ Fixture to create a Parameter for testing. @@ -690,9 +736,11 @@ def parameter_water_chemistry(): session.add(parameter) session.commit() yield parameter + session.delete(parameter) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def parameter_groundwater(): """ Fixture to create a Parameter for testing. @@ -709,9 +757,11 @@ def parameter_groundwater(): session.add(parameter) session.commit() yield parameter + session.delete(parameter) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def group(water_well_thing): with session_ctx() as session: group = Group( @@ -733,6 +783,9 @@ def group(water_well_thing): session.refresh(group_thing_association) yield group + session.delete(group) + session.delete(group_thing_association) + session.commit() @pytest.fixture(scope="function") @@ -758,8 +811,12 @@ def second_group(water_well_thing): yield group + session.delete(group) + session.delete(group_thing_association) + session.commit() -@pytest.fixture(scope="session") + +@pytest.fixture() def lexicon_category(): with session_ctx() as session: category = LexiconCategory( @@ -769,6 +826,8 @@ def lexicon_category(): session.commit() session.refresh(category) yield category + session.delete(category) + session.commit() @pytest.fixture(scope="function") @@ -786,7 +845,7 @@ def second_lexicon_category(): session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def lexicon_term(lexicon_category): with session_ctx() as session: term = LexiconTerm( @@ -805,9 +864,12 @@ def lexicon_term(lexicon_category): session.refresh(term_category_association) yield term + session.delete(term) + session.delete(term_category_association) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def second_lexicon_term(lexicon_category): with session_ctx() as session: term = LexiconTerm( @@ -827,8 +889,12 @@ def second_lexicon_term(lexicon_category): yield term + session.delete(term) + session.delete(term_category_association) + session.commit() + -@pytest.fixture(scope="session") +@pytest.fixture() def third_lexicon_term(lexicon_category): with session_ctx() as session: term = LexiconTerm( @@ -848,8 +914,12 @@ def third_lexicon_term(lexicon_category): yield term + session.delete(term) + session.delete(term_category_association) + session.commit() + -@pytest.fixture(scope="session") +@pytest.fixture() def fourth_lexicon_term(lexicon_category): with session_ctx() as session: term = LexiconTerm( @@ -869,8 +939,12 @@ def fourth_lexicon_term(lexicon_category): yield term + session.delete(term) + session.delete(term_category_association) + session.commit() + -@pytest.fixture(scope="session") +@pytest.fixture() def lexicon_triple(lexicon_term, second_lexicon_term): with session_ctx() as session: triple = LexiconTriple( @@ -882,9 +956,11 @@ def lexicon_triple(lexicon_term, second_lexicon_term): session.commit() session.refresh(triple) yield triple + session.delete(triple) + session.commit() -@pytest.fixture(scope="session") +@pytest.fixture() def second_lexicon_triple(third_lexicon_term, fourth_lexicon_term): with session_ctx() as session: triple = LexiconTriple( @@ -896,3 +972,5 @@ def second_lexicon_triple(third_lexicon_term, fourth_lexicon_term): session.commit() session.refresh(triple) yield triple + session.delete(triple) + session.commit() diff --git a/tests/test_collabnet.py b/tests/test_collabnet.py index 96712e081..ce57f07c1 100644 --- a/tests/test_collabnet.py +++ b/tests/test_collabnet.py @@ -41,6 +41,9 @@ def well(): yield wt + session.delete(wt) + session.commit() + @pytest.mark.skip def test_add_collabnet_well(well): diff --git a/tests/test_observation.py b/tests/test_observation.py index 590c35889..ca7c41728 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -433,7 +433,9 @@ def test_get_groundwater_level_observation_by_id_404_wrong_activity_type( assert data["detail"][0]["loc"] == ["path", "observation_id"] -def test_get_groundwater_observation_by_sample(groundwater_level_sample): +def test_get_groundwater_observation_by_sample( + groundwater_level_observation, groundwater_level_sample +): response = client.get( "/observation/groundwater-level", params={ @@ -447,7 +449,9 @@ def test_get_groundwater_observation_by_sample(groundwater_level_sample): assert len(items) > 0, "Expected at least one groundwater observation for the thing" -def test_get_groundwater_observation_by_thing(water_well_thing): +def test_get_groundwater_observation_by_thing( + groundwater_level_observation, water_well_thing +): response = client.get( "/observation/groundwater-level", params={ @@ -472,7 +476,7 @@ def test_get_groundwater_observation_by_thing_nonexistent(): ), "Expected no groundwater observations for a non-existent thing" -def test_get_groundwater_observation_by_time_range(): +def test_get_groundwater_observation_by_time_range(groundwater_level_observation): response = client.get( "/observation/groundwater-level", params={ From 8879457545b3c59cf820d2a6fea65ce11ee6aa8a Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 6 Oct 2025 17:52:27 -0600 Subject: [PATCH 17/21] fix: coalesce contatinated contact search to prevent null from breaking match --- api/search.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/api/search.py b/api/search.py index 852d09919..b9df2065c 100644 --- a/api/search.py +++ b/api/search.py @@ -14,7 +14,7 @@ # limitations under the License. # =============================================================================== from fastapi import APIRouter -from sqlalchemy import select +from sqlalchemy import select, func, text from sqlalchemy.orm import Session from api.pagination import CustomPage from fastapi_pagination import paginate @@ -39,14 +39,14 @@ def _get_contact_results(session: Session, q: str, limit: int) -> list[dict]: vector = ( - Contact.search_vector - | Email.search_vector - | Phone.search_vector - | Address.search_vector + func.coalesce(Contact.search_vector, text("''::tsvector")) + .op("||")(func.coalesce(Email.search_vector, text("''::tsvector"))) + .op("||")(func.coalesce(Phone.search_vector, text("''::tsvector"))) + .op("||")(func.coalesce(Address.search_vector, text("''::tsvector"))) ) query = search( - select(Contact).join(Email).join(Phone).join(Address), + select(Contact).outerjoin(Email).outerjoin(Phone).outerjoin(Address), q, vector=vector, limit=limit, @@ -66,7 +66,6 @@ def _get_contact_results(session: Session, q: str, limit: int) -> list[dict]: } for c in contacts ] - return results From 77a541fc6928e97177818e7e3f85a5e96f6a7d5e Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 6 Oct 2025 17:55:14 -0600 Subject: [PATCH 18/21] reversion: add pytest back to pre commit hooks --- .pre-commit-config.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 312e85016..7b2ef0036 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,15 +15,15 @@ repos: '--statistics' ] exclude: ^db/__init__.py$ # all models need to be imported for Alembic, but are not used directly -# - repo: local -# hooks: -# - id: pytest -# name: pytest -# entry: pytest # Or your specific test command, e.g., poetry run pytest -# language: system -# types: [python] # Specify relevant file types for your tests -# pass_filenames: false -# always_run: true + - repo: local + hooks: + - id: pytest + name: pytest + entry: pytest # Or your specific test command, e.g., poetry run pytest + language: system + types: [python] # Specify relevant file types for your tests + pass_filenames: false + always_run: true # - repo: https://github.com/pre-commit/mirrors-mypy # rev: v1.10.0 # Use the latest stable version or pin to your preference From da5170eea631b8f4c97591ebb6ef1146b96b894c Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Tue, 7 Oct 2025 14:50:15 -0600 Subject: [PATCH 19/21] refactor: initialize parameters --- core/app.py | 3 +- core/initializers.py | 31 +++++++++++++ core/parameter.json | 16 +++++++ tests/__init__.py | 18 +++++++- tests/conftest.py | 97 +++++++++++++++++++-------------------- tests/test_observation.py | 63 +++++++++++-------------- transfers/transfer.py | 13 +++++- 7 files changed, 149 insertions(+), 92 deletions(-) create mode 100644 core/parameter.json diff --git a/core/app.py b/core/app.py index 2b018614b..3498b20ab 100644 --- a/core/app.py +++ b/core/app.py @@ -24,7 +24,7 @@ ) from fastapi.openapi.utils import get_openapi -from .initializers import init_db, init_lexicon +from .initializers import init_db, init_lexicon, init_parameter from .settings import settings @@ -36,6 +36,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: if settings.get_enum("MODE") == "development": init_db() init_lexicon() + init_parameter() yield diff --git a/core/initializers.py b/core/initializers.py index 233365c93..3d43e5787 100644 --- a/core/initializers.py +++ b/core/initializers.py @@ -20,6 +20,7 @@ from db import Base from db.engine import engine, session_ctx +from db.parameter import Parameter from services.lexicon_helper import add_lexicon_term, add_lexicon_category @@ -50,6 +51,36 @@ def init_hypertables(): # session.close() +def init_parameter(path: str = None) -> None: + """ + Populate the parameter table to allow their use in creating and editing + observations + """ + if path is None: + path = Path(__file__).parent / "parameter.json" + + with open(path) as f: + import json + + default_parameter = json.load(f) + + with session_ctx() as session: + for param in default_parameter: + try: + parameter_obj = Parameter( + parameter_name=param["parameter_name"], + matrix=param["matrix"], + parameter_type=param["parameter_type"], + cas_number=param["cas_number"], + default_unit=param["default_unit"], + ) + session.add(parameter_obj) + session.commit() + except DatabaseError as e: + print(f"Failed to add parameter {param['parameter_name']}: error: {e}") + session.rollback() + + def init_lexicon(path: str = None) -> None: if path is None: path = Path(__file__).parent / "lexicon.json" diff --git a/core/parameter.json b/core/parameter.json new file mode 100644 index 000000000..5d9b7db7a --- /dev/null +++ b/core/parameter.json @@ -0,0 +1,16 @@ +[ + { + "parameter_name": "groundwater level", + "matrix": "groundwater", + "parameter_type": "Field Parameter", + "cas_number": null, + "default_unit": "ft" + }, + { + "parameter_name": "pH", + "matrix": "groundwater", + "parameter_type": "Field Parameter", + "cas_number": null, + "default_unit": "dimensionless" + } +] \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py index 985e4ae10..02566806e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -15,8 +15,8 @@ # =============================================================================== from fastapi.testclient import TestClient -from core.initializers import init_lexicon -from db import Base +from core.initializers import init_lexicon, init_parameter +from db import Base, Parameter from db.engine import engine, session_ctx from main import app @@ -25,9 +25,23 @@ Base.metadata.create_all(engine) init_lexicon() +init_parameter() client = TestClient(app) +# map (name, type) to id for easy lookup in tests +parameter_map = {} +with session_ctx() as session: + for param in session.query(Parameter).all(): + if ( + param.parameter_name in ["groundwater level", "pH"] + and param.parameter_type == "Field Parameter" + ): + parameter_map[(param.parameter_name, param.parameter_type)] = param.id + +groundwater_level_parameter_id = parameter_map[("groundwater level", "Field Parameter")] +pH_parameter_id = parameter_map[("pH", "Field Parameter")] + def override_authentication(default=True): """ diff --git a/tests/conftest.py b/tests/conftest.py index 7ef84f644..e9c1d5862 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ from db import * from db.engine import session_ctx +from tests import groundwater_level_parameter_id, pH_parameter_id @pytest.fixture() @@ -637,15 +638,13 @@ def sample_to_delete(water_chemistry_field_activity, field_event_contact): @pytest.fixture() -def groundwater_level_observation( - sensor, groundwater_level_sample, parameter_groundwater -): +def groundwater_level_observation(sensor, groundwater_level_sample): with session_ctx() as session: observation = Observation( observation_datetime="2025-01-01T00:04:00Z", sample_id=groundwater_level_sample.id, sensor_id=sensor.id, - parameter_id=parameter_groundwater.id, + parameter_id=groundwater_level_parameter_id, release_status="draft", value=10.0, unit="ft", @@ -660,15 +659,13 @@ def groundwater_level_observation( @pytest.fixture() -def water_chemistry_observation( - sensor, water_chemistry_sample, parameter_water_chemistry -): +def water_chemistry_observation(sensor, water_chemistry_sample): with session_ctx() as session: observation = Observation( observation_datetime="2025-01-01T00:03:00Z", sample_id=water_chemistry_sample.id, sensor_id=sensor.id, - parameter_id=parameter_water_chemistry.id, + parameter_id=pH_parameter_id, release_status="draft", value=4.0, unit="dimensionless", @@ -701,13 +698,13 @@ def geothermal_observation(sensor, geothermal_sample): @pytest.fixture(scope="function") -def observation_to_delete(water_chemistry_sample, sensor, parameter_water_chemistry): +def observation_to_delete(water_chemistry_sample, sensor): with session_ctx() as session: observation = Observation( observation_datetime="2019-01-01T00:03:00Z", sample_id=water_chemistry_sample.id, sensor_id=sensor.id, - parameter_id=parameter_water_chemistry.id, + parameter_id=pH_parameter_id, release_status="draft", value=4.0, unit="dimensionless", @@ -719,46 +716,46 @@ def observation_to_delete(water_chemistry_sample, sensor, parameter_water_chemis session.commit() -@pytest.fixture() -def parameter_water_chemistry(): - """ - Fixture to create a Parameter for testing. - """ - with session_ctx() as session: - parameter = Parameter( - parameter_name="pH", - parameter_type="Field Parameter", - matrix="groundwater", - cas_number="7440-38-2", - default_unit="dimensionless", - release_status="draft", - ) - session.add(parameter) - session.commit() - yield parameter - session.delete(parameter) - session.commit() - - -@pytest.fixture() -def parameter_groundwater(): - """ - Fixture to create a Parameter for testing. - """ - with session_ctx() as session: - parameter = Parameter( - parameter_name="groundwater level", - parameter_type="Field Parameter", - matrix="groundwater", - cas_number=None, - default_unit="ft", - release_status="draft", - ) - session.add(parameter) - session.commit() - yield parameter - session.delete(parameter) - session.commit() +# @pytest.fixture() +# def parameter_water_chemistry(): +# """ +# Fixture to create a Parameter for testing. +# """ +# with session_ctx() as session: +# parameter = Parameter( +# parameter_name="pH", +# parameter_type="Field Parameter", +# matrix="groundwater", +# cas_number="7440-38-2", +# default_unit="dimensionless", +# release_status="draft", +# ) +# session.add(parameter) +# session.commit() +# yield parameter +# session.delete(parameter) +# session.commit() + + +# @pytest.fixture() +# def parameter_groundwater(): +# """ +# Fixture to create a Parameter for testing. +# """ +# with session_ctx() as session: +# parameter = Parameter( +# parameter_name="groundwater level", +# parameter_type="Field Parameter", +# matrix="groundwater", +# cas_number=None, +# default_unit="ft", +# release_status="draft", +# ) +# session.add(parameter) +# session.commit() +# yield parameter +# session.delete(parameter) +# session.commit() @pytest.fixture() diff --git a/tests/test_observation.py b/tests/test_observation.py index ca7c41728..974fd7ec0 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -22,7 +22,14 @@ viewer_function, ) from main import app -from tests import client, cleanup_post_test, override_authentication, cleanup_patch_test +from tests import ( + client, + cleanup_post_test, + override_authentication, + cleanup_patch_test, + groundwater_level_parameter_id, + pH_parameter_id, +) import pytest @@ -46,9 +53,7 @@ def override_authentication_dependency_fixture(): # ============= Post tests ================= -def test_add_water_chemistry_observation( - water_chemistry_sample, sensor, parameter_water_chemistry -): +def test_add_water_chemistry_observation(water_chemistry_sample, sensor): payload = { "observation_datetime": "2025-01-01T00:00:00Z", "release_status": "draft", @@ -56,7 +61,7 @@ def test_add_water_chemistry_observation( "unit": "dimensionless", "sample_id": water_chemistry_sample.id, "sensor_id": sensor.id, - "parameter_id": parameter_water_chemistry.id, + "parameter_id": pH_parameter_id, } response = client.post("/observation/water-chemistry", json=payload) data = response.json() @@ -70,21 +75,19 @@ def test_add_water_chemistry_observation( assert data["unit"] == payload["unit"] assert data["sample_id"] == payload["sample_id"] assert data["sensor_id"] == payload["sensor_id"] - assert data["parameter"]["id"] == parameter_water_chemistry.id + assert data["parameter"]["id"] == pH_parameter_id cleanup_post_test(Observation, data["id"]) -def test_add_groundwater_level_observation( - groundwater_level_sample, sensor, parameter_groundwater -): +def test_add_groundwater_level_observation(groundwater_level_sample, sensor): payload = { "observation_datetime": "2025-01-01T00:00:00Z", "release_status": "draft", "value": 101, "measuring_point_height": 53, "sample_id": groundwater_level_sample.id, - "parameter_id": parameter_groundwater.id, + "parameter_id": groundwater_level_parameter_id, "sensor_id": sensor.id, "level_status": "Water level not affected by status", "unit": "ft", @@ -100,7 +103,7 @@ def test_add_groundwater_level_observation( assert data["value"] == payload["value"] assert data["measuring_point_height"] == payload["measuring_point_height"] assert data["sensor_id"] == payload["sensor_id"] - assert data["parameter"]["id"] == parameter_groundwater.id + assert data["parameter"]["id"] == groundwater_level_parameter_id assert data["level_status"] == payload["level_status"] assert ( data["depth_to_water_bgs"] @@ -295,7 +298,7 @@ def test_get_all_observations( def test_get_observation_by_id( - groundwater_level_observation, water_chemistry_observation, parameter_groundwater + groundwater_level_observation, water_chemistry_observation ): for obs in ( groundwater_level_observation, @@ -308,7 +311,7 @@ def test_get_observation_by_id( assert data["id"] == obs.id assert data["created_at"] == obs.created_at.isoformat().replace("+00:00", "Z") assert data["release_status"] == obs.release_status - if obs.parameter.parameter_name == parameter_groundwater.parameter_name: + if obs.parameter.id == groundwater_level_parameter_id: assert data["depth_to_water_bgs"] == obs.value - obs.measuring_point_height else: assert data["depth_to_water_bgs"] is None @@ -324,9 +327,7 @@ def test_get_observation_by_id_404_not_found( assert data["detail"] == f"Observation with ID {bad_id} not found." -def test_get_groundwater_level_observations( - groundwater_level_observation, parameter_groundwater -): +def test_get_groundwater_level_observations(groundwater_level_observation): response = client.get("/observation/groundwater-level") assert response.status_code == 200 data = response.json() @@ -341,7 +342,7 @@ def test_get_groundwater_level_observations( data["items"][0]["observation_datetime"] == groundwater_level_observation.observation_datetime ) - assert data["items"][0]["parameter"]["id"] == parameter_groundwater.id + assert data["items"][0]["parameter"]["id"] == groundwater_level_parameter_id assert ( data["items"][0]["release_status"] == groundwater_level_observation.release_status @@ -365,9 +366,7 @@ def test_get_groundwater_level_observations( ) -def test_get_groundwater_level_observation_by_id( - groundwater_level_observation, parameter_groundwater -): +def test_get_groundwater_level_observation_by_id(groundwater_level_observation): response = client.get( f"/observation/groundwater-level/{groundwater_level_observation.id}" ) @@ -383,7 +382,7 @@ def test_get_groundwater_level_observation_by_id( data["observation_datetime"] == groundwater_level_observation.observation_datetime ) - assert data["parameter"]["id"] == parameter_groundwater.id + assert data["parameter"]["id"] == groundwater_level_parameter_id assert data["release_status"] == groundwater_level_observation.release_status assert data["level_status"] == groundwater_level_observation.level_status assert data["value"] == groundwater_level_observation.value @@ -508,9 +507,7 @@ def test_get_groundwater_observation_by_time_range_nonexistent(): assert len(items) == 0, "Expected no groundwater observations in the time range" -def test_get_water_chemistry_observations( - water_chemistry_observation, parameter_water_chemistry -): +def test_get_water_chemistry_observations(water_chemistry_observation): response = client.get("/observation/water-chemistry") assert response.status_code == 200 data = response.json() @@ -528,14 +525,12 @@ def test_get_water_chemistry_observations( data["items"][0]["observation_datetime"] == water_chemistry_observation.observation_datetime ) - assert data["items"][0]["parameter"]["id"] == parameter_water_chemistry.id + assert data["items"][0]["parameter"]["id"] == pH_parameter_id assert data["items"][0]["value"] == water_chemistry_observation.value assert data["items"][0]["unit"] == water_chemistry_observation.unit -def test_get_water_chemistry_observation_by_id( - water_chemistry_observation, parameter_water_chemistry -): +def test_get_water_chemistry_observation_by_id(water_chemistry_observation): response = client.get( f"/observation/water-chemistry/{water_chemistry_observation.id}" ) @@ -552,7 +547,7 @@ def test_get_water_chemistry_observation_by_id( data["observation_datetime"] == water_chemistry_observation.observation_datetime ) - assert data["parameter"]["id"] == parameter_water_chemistry.id + assert data["parameter"]["id"] == pH_parameter_id assert data["value"] == water_chemistry_observation.value assert data["unit"] == water_chemistry_observation.unit @@ -568,7 +563,7 @@ def test_get_water_chemistry_observation_by_id_404_not_found( def test_get_water_chemistry_observation_by_id_404_wrong_activity_type( - groundwater_level_observation, parameter_groundwater + groundwater_level_observation, ): response = client.get( f"/observation/water-chemistry/{groundwater_level_observation.id}" @@ -576,13 +571,7 @@ def test_get_water_chemistry_observation_by_id_404_wrong_activity_type( assert response.status_code == 404 data = response.json() - if ( - groundwater_level_observation.parameter.parameter_name - == parameter_groundwater.parameter_name - ): - actual_activity_type = "groundwater level" - else: - actual_activity_type = "geothermal" + actual_activity_type = "groundwater level" assert ( data["detail"][0]["msg"] diff --git a/transfers/transfer.py b/transfers/transfer.py index 56977e9bd..61b88ef9d 100644 --- a/transfers/transfer.py +++ b/transfers/transfer.py @@ -20,7 +20,7 @@ load_dotenv() from sqlalchemy.orm import Session -from core.initializers import init_lexicon +from core.initializers import init_lexicon, init_parameter from db import Base from db.engine import session_ctx @@ -36,9 +36,12 @@ def erase_and_initalize(session: Session) -> None: - logger.info("Erasing existing data and initializing lexicon and sensors") + logger.info( + "Erasing existing data and initializing lexicon, parameter, and sensors" + ) erase(session) lexicon() + parameter() sensor(session) @@ -54,6 +57,12 @@ def lexicon(): init_lexicon() +@timeit +def parameter(): + logger.info("Initializing parameter") + init_parameter() + + @timeit def erase(session: Session): logger.info("Erasing existing data") From ed5971db066e528ffad54ba9a6c3c8128d92696b Mon Sep 17 00:00:00 2001 From: Jake Ross Date: Wed, 8 Oct 2025 09:29:00 -0600 Subject: [PATCH 20/21] Update test_observation.py --- tests/test_observation.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_observation.py b/tests/test_observation.py index bc9936487..663fdda7f 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -62,7 +62,6 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): "sample_id": water_chemistry_sample.id, "sensor_id": sensor.id, "parameter_id": pH_parameter_id, - "value_reason": "Observed value not affected", "observed_property": "pH", } response = client.post("/observation/water-chemistry", json=payload) @@ -78,7 +77,6 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): assert data["sample_id"] == payload["sample_id"] assert data["sensor_id"] == payload["sensor_id"] assert data["parameter"]["id"] == pH_parameter_id - assert data["value_reason"] == payload["value_reason"] assert data["observed_property"] == payload["observed_property"] cleanup_post_test(Observation, data["id"]) @@ -109,7 +107,6 @@ def test_add_groundwater_level_observation(groundwater_level_sample, sensor): assert data["measuring_point_height"] == payload["measuring_point_height"] assert data["sensor_id"] == payload["sensor_id"] assert data["parameter"]["id"] == groundwater_level_parameter_id - assert data["value_reason"] == payload["value_reason"] assert data["groundwater_level_reason"] == payload["groundwater_level_reason"] assert data["observed_property"] == payload["observed_property"] assert ( From 1dad9c0a87f7d28b250a90970215757a31d4ae5e Mon Sep 17 00:00:00 2001 From: jakeross Date: Wed, 8 Oct 2025 09:37:05 -0600 Subject: [PATCH 21/21] refactor: update test_observation.py to remove redundant assertions and add value_reason field --- tests/test_observation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_observation.py b/tests/test_observation.py index 663fdda7f..22717744b 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -62,6 +62,7 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): "sample_id": water_chemistry_sample.id, "sensor_id": sensor.id, "parameter_id": pH_parameter_id, + "value_reason": "Observed value not affected", "observed_property": "pH", } response = client.post("/observation/water-chemistry", json=payload) @@ -77,7 +78,6 @@ def test_add_water_chemistry_observation(water_chemistry_sample, sensor): assert data["sample_id"] == payload["sample_id"] assert data["sensor_id"] == payload["sensor_id"] assert data["parameter"]["id"] == pH_parameter_id - assert data["observed_property"] == payload["observed_property"] cleanup_post_test(Observation, data["id"]) @@ -92,7 +92,6 @@ def test_add_groundwater_level_observation(groundwater_level_sample, sensor): "parameter_id": groundwater_level_parameter_id, "sensor_id": sensor.id, "groundwater_level_reason": "Water level not affected", - "observed_property": "groundwater level", "unit": "ft", } response = client.post("/observation/groundwater-level", json=payload) @@ -108,7 +107,6 @@ def test_add_groundwater_level_observation(groundwater_level_sample, sensor): assert data["sensor_id"] == payload["sensor_id"] assert data["parameter"]["id"] == groundwater_level_parameter_id assert data["groundwater_level_reason"] == payload["groundwater_level_reason"] - assert data["observed_property"] == payload["observed_property"] assert ( data["depth_to_water_bgs"] == payload["value"] - payload["measuring_point_height"]