From 1bb629fe7729f2c2d36add6a2a406c15f398e3d9 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 25 Aug 2026 16:00:26 -0400 Subject: [PATCH 01/66] feat(engine): add streams entity type and distance-bounded flow tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recreates UC1-CQ2c ("what streams are downstream at most N km from facilities of industry X?") from David's notebook, which needed two things the query builder could not express. Streams as an answerable entity. Flowlines previously reached the map only as a decorative layer traced from the anchors; hyf:HY_FlowPath was not selectable in either block. Adds 'streams' to EntityType with an FTYPE filter, IRI hydration, and map wiring. When the target is a flowline the ?s2target hop is replaced with a direct bind — that hop would otherwise match any flowline sharing a cell with the answer — and the supporting stream layer is skipped so flowlines aren't drawn twice. Cumulative distance cutoff. downstream/upstream traces were the full transitive closure. Adds an optional maxDistanceKm that sums nhdplusv2:hasFlowPathLength over the segments between seed and candidate and filters on the total. Unset, the emitted SPARQL is byte-identical to before, so existing questions are unaffected. The bound is not just a filter: "samples within 30 km downstream of NH airports" returns 27 sample points in ~15s, where the unbounded form times out against the federation gateway. Two things worth knowing for review: The notebook and this implementation do not agree, and the notebook is wrong. Its outer block re-joins facilities on schema1:address as a required triple, a predicate only 13 of 144 NH airport facilities carry, so it silently discards 91% of its own anchor set. Drop that triple and it returns 1,547 flowlines where we return 1,605 on the same seeding — we are a superset. Address stays OPTIONAL here. Neighbour-cell expansion is kept, per discussion: we seed from the facility's S2 cell and its 8 neighbours where the notebook uses the facility's own cell only. That is the app-wide convention and accounts for the rest of the difference (2,757 vs 1,605 for NH airports at 30km). scripts/flow-distance-check.mjs runs the real planner against the live endpoints and asserts the step plan, the superset relation, that the bound actually excludes flowlines, and that every hydrated stream has drawable geometry. --- README.md | 7 +- scripts/flow-distance-check.mjs | 106 ++++++++++++ src/components/Map/MapPopup.tsx | 6 + src/components/QueryEditor/EntityBlock.tsx | 8 + .../QueryEditor/EntityTypeSelector.tsx | 1 + .../QueryEditor/RelationshipSelector.tsx | 24 +++ src/components/QueryEditor/StreamFilters.tsx | 32 ++++ src/engine/planner.ts | 12 +- src/engine/resultTransformer.ts | 1 + src/engine/templates/fusedQueries.ts | 158 ++++++++++++++++-- src/engine/templates/hydrate.ts | 24 +++ src/hooks/useMapLayers.ts | 5 +- src/types/map.ts | 2 +- src/types/query.ts | 10 +- src/utils/questionGenerator.ts | 13 +- 15 files changed, 385 insertions(+), 24 deletions(-) create mode 100644 scripts/flow-distance-check.mjs create mode 100644 src/components/QueryEditor/StreamFilters.tsx diff --git a/README.md b/README.md index f219bdf..bc32b9d 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,14 @@ When you click Apply, the query engine: 2. **Executes** steps sequentially (`engine/executor.ts`), threading S2 cell sets between steps 3. **Renders** results as map layers (`resultTransformer.ts` → `MapFeature[]`) -Supported entity types: **samples**, **facilities**, **water bodies** +Supported entity types: **samples**, **facilities**, **water bodies**, **wells**, **streams** Supported relationships: **near** (~1–2 km), **downstream**, **upstream** +Downstream/upstream traces accept an optional cumulative flowpath cutoff +(`Within N km of flow`). Unset, the trace is the full transitive closure. +`node scripts/flow-distance-check.mjs` verifies the bounded trace against the +live endpoints. + ## SPARQL endpoints All hosted at `frink.apps.renci.org`: diff --git a/scripts/flow-distance-check.mjs b/scripts/flow-distance-check.mjs new file mode 100644 index 0000000..8e00036 --- /dev/null +++ b/scripts/flow-distance-check.mjs @@ -0,0 +1,106 @@ +// Checks the distance-bounded downstream trace against the live SPARQL +// endpoints, using the same planner the app runs. +// +// Reference values come from UC1_CQ2c (New Hampshire, NAICS 488119 airports, +// 30 km): the notebook returns 162 flowlines, but only because it requires +// schema1:address on facilities — a predicate 13 of 144 NH airport facilities +// have. Without that accidental filter its answer is 1,547 flowlines, and ours +// is a superset of exactly that set (we also expand to neighbouring S2 cells). +// +// Run: node scripts/flow-distance-check.mjs +import assert from 'node:assert/strict'; +import { build } from 'esbuild'; + +const bundle = await build({ + entryPoints: ['src/engine/planner.ts'], + bundle: true, + format: 'esm', + platform: 'neutral', + write: false, +}); +const { planPipeline } = await import( + 'data:text/javascript;base64,' + Buffer.from(bundle.outputFiles[0].text).toString('base64') +); + +const ENDPOINTS = { + sawgraph: 'https://frink.apps.renci.org/sawgraph/sparql', + spatialkg: 'https://frink.apps.renci.org/spatialkg/sparql', + hydrologykg: 'https://frink.apps.renci.org/hydrologykg/sparql', + federation: 'https://frink.apps.renci.org/federation/sparql', +}; + +async function run(endpoint, query) { + const res = await fetch(ENDPOINTS[endpoint], { + method: 'POST', + headers: { + Accept: 'application/sparql-results+json', + 'Content-Type': 'application/sparql-query', + }, + body: query, + }); + if (!res.ok) throw new Error(`${endpoint} ${res.status}: ${await res.text()}`); + const json = await res.json(); + return json.results.bindings.map((row) => + Object.fromEntries(Object.entries(row).map(([k, v]) => [k, v.value])), + ); +} + +// "What streams are within 30 km downstream of 488119 (Airports) facilities +// in New Hampshire?" — the notebook's question, expressed in the app's model. +const question = { + blockA: { type: 'streams' }, + relationship: { type: 'downstream', maxDistanceKm: 30 }, + blockC: { + type: 'facilities', + region: { stateCode: '33' }, + facilityFilters: { industryCodes: ['488119'] }, + }, +}; + +const steps = planPipeline(question); +const stepTypes = steps.map((s) => s.type); + +// The answer set *is* the flowlines, so the supporting stream layer is skipped. +assert.ok( + !stepTypes.includes('GET_FLOWLINE_GEOMETRIES'), + `expected no supporting flowline step, got ${stepTypes.join(', ')}`, +); + +const ctx = { question, targetIris: [], anchorIris: [], results: {} }; +for (const step of steps) { + const rows = await run(step.endpoint, step.buildQuery(ctx)); + ctx.results[step.type] = rows; + if (step.type === 'FIND_TARGET_IRIS') ctx.targetIris = [...new Set(rows.map((r) => r.iri))]; + if (step.type === 'FIND_ANCHOR_IRIS') ctx.anchorIris = [...new Set(rows.map((r) => r.iri))]; + console.log(`${step.type}: ${rows.length} rows`); +} + +const streams = ctx.targetIris.length; +const facilities = ctx.anchorIris.length; +console.log(`\n${streams} streams within 30 km downstream of ${facilities} NH airport facilities`); + +// The bound has to actually bind: unbounded, this trace runs to the coast. +const unbounded = planPipeline({ ...question, relationship: { type: 'downstream' } }); +const unboundedRows = await run(unbounded[0].endpoint, unbounded[0].buildQuery(ctx)); +const unboundedStreams = new Set(unboundedRows.map((r) => r.iri)).size; +console.log(`${unboundedStreams} streams with no distance bound`); + +assert.ok(streams > 1547, `expected a superset of the notebook's 1547, got ${streams}`); +// The bound must actually exclude flowlines the unbounded trace reaches. +// Observed 2026-08: 2757 bounded vs 3490 unbounded — downstreamFlowPathTC in +// this KG does not reach as far as the coast, so the gap is smaller than the +// notebook's parameters suggest. +assert.ok( + unboundedStreams > streams, + `bound had no effect: ${streams} bounded vs ${unboundedStreams} unbounded`, +); + +// Every hydrated stream carries geometry the map can draw. +const hydrated = ctx.results['HYDRATE_TARGET_BY_IRI'] ?? []; +assert.ok(hydrated.length > 0, 'no hydrated streams'); +assert.ok( + hydrated.every((r) => r.flowlineWKT?.startsWith('LINESTRING')), + 'hydrated streams missing LINESTRING geometry', +); + +console.log('\nOK'); diff --git a/src/components/Map/MapPopup.tsx b/src/components/Map/MapPopup.tsx index d13fa74..e95102b 100644 --- a/src/components/Map/MapPopup.tsx +++ b/src/components/Map/MapPopup.tsx @@ -321,6 +321,12 @@ export function MapPopupContent({ feature }: MapPopupProps) { {props.flowType} )} + {props.pathLength && ( + + Flow distance + {Number(props.pathLength).toFixed(1)} km + + )} {feature.id && ( Flowline diff --git a/src/components/QueryEditor/EntityBlock.tsx b/src/components/QueryEditor/EntityBlock.tsx index f7f09c4..743e96c 100644 --- a/src/components/QueryEditor/EntityBlock.tsx +++ b/src/components/QueryEditor/EntityBlock.tsx @@ -4,6 +4,7 @@ import { SampleFilters } from './SampleFilters'; import { FacilityFilters } from './FacilityFilters'; import { WaterBodyFilters } from './WaterBodyFilters'; import { WellFilters } from './WellFilters'; +import { StreamFilters } from './StreamFilters'; import { RegionSelector } from './RegionSelector'; import { useState } from 'react'; @@ -21,6 +22,7 @@ export function EntityBlock({ label, value, onChange }: EntityBlockProps) { value.sampleFilters?.materialTypes?.length || value.facilityFilters?.industryCodes?.length || value.waterBodyFilters?.ftypes?.length || + value.streamFilters?.ftypes?.length || value.wellFilters?.wellTypes?.length ) ); @@ -62,6 +64,12 @@ export function EntityBlock({ label, value, onChange }: EntityBlockProps) { onChange={(f) => onChange({ ...value, waterBodyFilters: f })} /> )} + {value.type === 'streams' && ( + onChange({ ...value, streamFilters: f })} + /> + )} {value.type === 'wells' && ( r.value === value.type) || RELATIONSHIP_TYPES[0]; const currentHops = value.hops ?? 1; @@ -40,6 +50,20 @@ export function RelationshipSelector({ value, onChange }: RelationshipSelectorPr isClearable={false} placeholder="Select relationship..." /> + {(value.type === 'downstream' || value.type === 'upstream') && ( + { + const km = vals[0] ? parseInt(vals[0]) : undefined; + onChange({ ...value, maxDistanceKm: km }); + }} + isMulti={false} + isClearable={false} + searchable={false} + placeholder="Flow distance..." + /> + )} {value.type === 'near' && ( void; +} + +// NHDPlusV2 FTYPE values present on hyf:HY_FlowPath in hydrologykg. +const FTYPE_OPTIONS = [ + { value: 'StreamRiver', label: 'Stream / River' }, + { value: 'ArtificialPath', label: 'Artificial Path' }, + { value: 'CanalDitch', label: 'Canal / Ditch' }, + { value: 'Connector', label: 'Connector' }, + { value: 'Pipeline', label: 'Pipeline' }, +]; + +export function StreamFilters({ value, onChange }: StreamFiltersProps) { + return ( +
+
+ + onChange({ ...value, ftypes: vals })} + placeholder="Any stream type..." + /> +
+
+ ); +} diff --git a/src/engine/planner.ts b/src/engine/planner.ts index 574e23b..4431c75 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -10,6 +10,7 @@ import { } from './templates/fusedQueries'; import { buildFacilitiesByIri, + buildStreamsByIri, buildWaterBodiesByIri, buildWellsByIri, } from './templates/hydrate'; @@ -54,6 +55,7 @@ function entityEndpoint(block: EntityBlock): EndpointKey { return 'sawgraph'; case 'waterBodies': case 'wells': + case 'streams': return 'hydrologykg'; } } @@ -102,6 +104,8 @@ function hydrateStep( return buildWaterBodiesByIri(iris, block.waterBodyFilters); case 'wells': return buildWellsByIri(iris, block.wellFilters); + case 'streams': + return buildStreamsByIri(iris, block.streamFilters); } }, }; @@ -149,6 +153,7 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { project, anchorRegion: anchorRegionOpt, targetRegion: targetRegionOpt, + maxDistanceKm: relationship.maxDistanceKm, }); }; @@ -166,7 +171,11 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { buildQuery: () => buildIriQuery('anchor'), }); - if (relationship.type !== 'near') { + // Supporting stream layer. Skipped when a side is already streams — those + // flowlines come back as the answer set and would be drawn twice. + const streamsAreAnswer = + targetBlock.type === 'streams' || anchorBlock.type === 'streams'; + if (relationship.type !== 'near' && !streamsAreAnswer) { steps.push({ type: 'GET_FLOWLINE_GEOMETRIES', endpoint: 'federation', @@ -177,6 +186,7 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { anchor: anchorBlock, direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', anchorIris: ctx.anchorIris, + maxDistanceKm: relationship.maxDistanceKm, }), }); } diff --git a/src/engine/resultTransformer.ts b/src/engine/resultTransformer.ts index 6f1f86b..6dd8494 100644 --- a/src/engine/resultTransformer.ts +++ b/src/engine/resultTransformer.ts @@ -173,6 +173,7 @@ export function transformFlowlinesToFeatures(rows: SparqlRow[]): MapFeature[] { type: 'stream', name: r.streamName || '', flowType: r.fl_type || '', + ...(r.path_length ? { pathLength: r.path_length } : {}), }, }); } diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index a3914bf..03752c4 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -2,6 +2,7 @@ import { PREFIXES } from '../../constants/prefixes'; import type { EntityBlock, FacilityFilters, + StreamFilters, WellFilters, SpatialRelationship, } from '../../types/query'; @@ -20,6 +21,8 @@ export function entityIriVar(block: EntityBlock, suffix: string): string { return `?waterBody${suffix}`; case 'wells': return `?well${suffix}`; + case 'streams': + return `?stream${suffix}`; } } @@ -86,9 +89,22 @@ export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: stri return `${s2Var} spatial:connectedTo ?well${suffix} . ${typeFilter}`; } + case 'streams': { + return `${s2Var} spatial:connectedTo ?stream${suffix} . + ?stream${suffix} rdf:type hyf:HY_FlowPath . + ${streamFtypeFilter(block.streamFilters, suffix)}`; + } } } +// FTYPE restriction for flowlines, shared by the s2-hop and direct-bind forms. +function streamFtypeFilter(filters: StreamFilters | undefined, suffix: string): string { + if (!filters?.ftypes?.length) return ''; + const values = filters.ftypes.map((f) => `"${f}"`).join(' '); + return `?stream${suffix} nhdplusv2:hasFTYPE ?flFtype${suffix} . + VALUES ?flFtype${suffix} { ${values} }`; +} + function regionClause(regionCodes: string[] | undefined, s2Var: string, internalVar: string): string { if (!regionCodes?.length) return ''; if (regionCodes.length === 1) { @@ -122,6 +138,45 @@ function neighborPath(hops: number, fromVar: string, toVar: string): string { interface FusedBodyOpts extends FusedBaseOpts { mode: 'near' | 'downstream' | 'upstream'; hops?: number; + maxDistanceKm?: number; +} + +// Wraps the hydrology trace in a cumulative-length cutoff. The seed block is +// duplicated inside so the closure stays anchored — without it the aggregate +// runs over the whole national flowline graph. +// +// Membership semantics: a flowline qualifies if *some* seed reaches it within +// the cutoff, matching GROUP BY (seed, end) with no MIN. The per-flowline +// number shown in popups is computed separately in buildFusedFlowlineQuery / +// buildStreamsByIri, where MIN() picks the shortest qualifying path. +function boundedTrace( + seed: string, + direction: 'downstream' | 'upstream', + maxDistanceKm: number, +): string { + const trace = + direction === 'downstream' + ? `?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?ds_flowline .` + : `?ds_flowline hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?upstream_flowline .`; + + return `{ + SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { + { + SELECT ?upstream_flowline ?ds_flowline (SUM(?_flLen) AS ?_plen) WHERE { + { + SELECT ?upstream_flowline ?_flMid ?ds_flowline WHERE { + { SELECT DISTINCT ?upstream_flowline WHERE { ${seed} } } + ${trace} + } + } + ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . + } GROUP BY ?upstream_flowline ?ds_flowline + } + FILTER (xsd:float(?_plen) < xsd:float(${maxDistanceKm})) + } + }`; } // Returns just the inner WHERE-body patterns shared across all fused queries: @@ -144,22 +199,41 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ${targetBind}`; } - const traceTriple = - opts.mode === 'downstream' - ? `?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline .` - : `?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline .`; - - return `?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + const seed = `?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ${aRegion} ${anchorBind} ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . - ?upstream_flowline rdf:type hyf:HY_FlowPath . - ${traceTriple} - ?s2target spatial:connectedTo ?ds_flowline ; + ?upstream_flowline rdf:type hyf:HY_FlowPath .`; + + const trace = opts.maxDistanceKm + ? boundedTrace(seed, opts.mode, opts.maxDistanceKm) + : opts.mode === 'downstream' + ? `?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline .` + : `?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline .`; + + // When the target *is* a flowline, the traced ?ds_flowline already is the + // answer — the s2target hop would find any flowline sharing a cell with it. + // The cell is still needed if the target carries a region filter. + const targetPart = + opts.target.type === 'streams' + ? `${ + tRegion + ? `?s2target spatial:connectedTo ?ds_flowline ; + rdf:type kwg-ont:S2Cell_Level13 . + ${tRegion}` + : '' + } + BIND(?ds_flowline AS ?streamC) + ${streamFtypeFilter(opts.target.streamFilters, 'C')}` + : `?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ${tRegion} ${targetBind}`; + + return `${seed} + ${trace} + ${targetPart}`; } function relationshipMode( @@ -209,6 +283,7 @@ export function buildFusedNearQuery(opts: FusedNearOpts): string { export interface FusedHydrologyOpts extends FusedBaseOpts { direction: 'downstream' | 'upstream'; project: 'anchor' | 'target'; + maxDistanceKm?: number; } // Server-side downstream/upstream query. @@ -219,6 +294,7 @@ export function buildFusedHydrologyQuery(opts: FusedHydrologyOpts): string { anchorRegion: opts.anchorRegion, targetRegion: opts.targetRegion, mode: opts.direction, + maxDistanceKm: opts.maxDistanceKm, }); const projectVar = opts.project === 'anchor' @@ -252,6 +328,7 @@ export function buildFusedSampleAggregateQuery(opts: FusedSampleSideOpts): strin targetRegion: opts.targetRegion, mode: relationshipMode(opts.relationship), hops: opts.relationship.hops, + maxDistanceKm: opts.relationship.maxDistanceKm, }); const suffix = opts.sampleSide === 'anchor' ? 'A' : 'C'; const s2Var = opts.sampleSide === 'anchor' ? '?s2anchor' : '?s2target'; @@ -291,6 +368,7 @@ export function buildFusedSampleDetailsQuery(opts: FusedSampleSideOpts): string targetRegion: opts.targetRegion, mode: relationshipMode(opts.relationship), hops: opts.relationship.hops, + maxDistanceKm: opts.relationship.maxDistanceKm, }); const suffix = opts.sampleSide === 'anchor' ? 'A' : 'C'; const spVar = `?sp${suffix}`; @@ -353,6 +431,7 @@ export interface FusedFlowlineOpts { anchor: EntityBlock; direction: 'downstream' | 'upstream'; anchorIris: string[]; + maxDistanceKm?: number; } // Returns flowline geometries traced from the anchor entities the pipeline @@ -375,6 +454,15 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { .map(wrapUri) .join(' ')} }`; + const seedCells = `{ + SELECT DISTINCT ?s2cellus WHERE { + ${anchorValues} + ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + ${anchorBind} + ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . + } + }`; + const flowlinePattern = opts.direction === 'downstream' ? `?upstream_flowline rdf:type hyf:HY_FlowPath ; @@ -384,18 +472,54 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { spatial:connectedTo ?s2cellus . ?flowline hyf:downstreamFlowPathTC ?downstream_flowline .`; - return ` + // Unbounded: the flowline set is the plain transitive closure. + if (!opts.maxDistanceKm) { + return ` ${PREFIXES} SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { + ${seedCells} + ${flowlinePattern} + ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; + nhdplusv2:hasFTYPE ?fl_type . + OPTIONAL { ?flowline rdfs:label ?streamName } + } + `; + } + + // Bounded: sum the lengths of the segments between seed and candidate, then + // MIN across seeds so each flowline carries one distance for its popup. + const boundedTraceInner = + opts.direction === 'downstream' + ? `?_flSeed hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?flowline .` + : `?flowline hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?_flSeed .`; + + return ` + ${PREFIXES} + SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { - SELECT DISTINCT ?s2cellus WHERE { - ${anchorValues} - ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . - ${anchorBind} - ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . - } + SELECT ?flowline (MIN(?_plen) AS ?path_length) WHERE { + { + SELECT ?_flSeed ?flowline (SUM(?_flLen) AS ?_plen) WHERE { + { + SELECT ?_flSeed ?_flMid ?flowline WHERE { + { + SELECT DISTINCT ?_flSeed WHERE { + ${seedCells} + ?_flSeed rdf:type hyf:HY_FlowPath ; + spatial:connectedTo ?s2cellus . + } + } + ${boundedTraceInner} + } + } + ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . + } GROUP BY ?_flSeed ?flowline + } + FILTER (xsd:float(?_plen) < xsd:float(${opts.maxDistanceKm})) + } GROUP BY ?flowline } - ${flowlinePattern} ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } diff --git a/src/engine/templates/hydrate.ts b/src/engine/templates/hydrate.ts index 8d87f4b..b8ff3c7 100644 --- a/src/engine/templates/hydrate.ts +++ b/src/engine/templates/hydrate.ts @@ -1,6 +1,7 @@ import { PREFIXES } from '../../constants/prefixes'; import type { FacilityFilters, + StreamFilters, WaterBodyFilters, WellFilters, } from '../../types/query'; @@ -65,6 +66,29 @@ export function buildWaterBodiesByIri( `; } +// Column names match buildFusedFlowlineQuery so transformFlowlinesToFeatures +// consumes either one unchanged. +export function buildStreamsByIri(streamIris: string[], filters?: StreamFilters): string { + let filterClauses = ''; + if (filters?.ftypes?.length) { + const ftypeValues = filters.ftypes.map((f) => `"${f}"`).join(' '); + filterClauses = `VALUES ?fl_type { ${ftypeValues} }`; + } + const vals = streamIris.map(wrapUri).join(' '); + + return ` + ${PREFIXES} + SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { + VALUES ?flowline { ${vals} } + ?flowline rdf:type hyf:HY_FlowPath ; + geo:hasGeometry/geo:asWKT ?flowlineWKT ; + nhdplusv2:hasFTYPE ?fl_type . + OPTIONAL { ?flowline rdfs:label ?streamName } + ${filterClauses} + } + `; +} + export function buildWellsByIri(wellIris: string[], filters?: WellFilters): string { const wellTypes = filters?.wellTypes; let typeFilter: string; diff --git a/src/hooks/useMapLayers.ts b/src/hooks/useMapLayers.ts index 4eb8dec..614ae16 100644 --- a/src/hooks/useMapLayers.ts +++ b/src/hooks/useMapLayers.ts @@ -48,6 +48,9 @@ export function useMapLayers(result: PipelineResult | null): MapLayerData { const facilityRows = allRows.filter((r) => r.facWKT); const waterBodyRows = allRows.filter((r) => r.wbWKT); const wellRows = allRows.filter((r) => r.wellWKT); + // Streams can arrive either as the answer set (hydrated, when a block is + // streams) or as the supporting layer traced from the anchors. + const streamRows = allRows.filter((r) => r.flowlineWKT); const sampleFeatures = transformSamplesToFeatures(sampleRows); if (sampleDetailRows.length > 0) { @@ -59,7 +62,7 @@ export function useMapLayers(result: PipelineResult | null): MapLayerData { facilities: transformFacilitiesToFeatures(facilityRows), waterBodies: transformWaterBodiesToFeatures(waterBodyRows), wells: transformWellsToFeatures(wellRows), - streams: transformFlowlinesToFeatures(flowlineRows), + streams: transformFlowlinesToFeatures([...streamRows, ...flowlineRows]), regionBoundaries: transformRegionBoundaries(boundaryRows), }; }, [result]); diff --git a/src/types/map.ts b/src/types/map.ts index 0552167..7d16624 100644 --- a/src/types/map.ts +++ b/src/types/map.ts @@ -3,7 +3,7 @@ import type { LatLngExpression } from 'leaflet'; export interface MapLayer { id: string; label: string; - type: 'samples' | 'facilities' | 'waterBodies' | 'wells' | 'regionBoundary'; + type: 'samples' | 'facilities' | 'waterBodies' | 'wells' | 'streams' | 'regionBoundary'; visible: boolean; data: MapFeature[]; } diff --git a/src/types/query.ts b/src/types/query.ts index 822ba0f..436a794 100644 --- a/src/types/query.ts +++ b/src/types/query.ts @@ -5,7 +5,7 @@ export interface AnalysisQuestion { blockC: EntityBlock; } -export type EntityType = 'samples' | 'facilities' | 'waterBodies' | 'wells'; +export type EntityType = 'samples' | 'facilities' | 'waterBodies' | 'wells' | 'streams'; export interface EntityBlock { type: EntityType; @@ -14,6 +14,7 @@ export interface EntityBlock { facilityFilters?: FacilityFilters; waterBodyFilters?: WaterBodyFilters; wellFilters?: WellFilters; + streamFilters?: StreamFilters; } export interface RegionFilter { @@ -43,6 +44,10 @@ export interface WaterBodyFilters { ftypes?: string[]; } +export interface StreamFilters { + ftypes?: string[]; +} + export interface WellFilters { wellTypes?: string[]; } @@ -50,4 +55,7 @@ export interface WellFilters { export interface SpatialRelationship { type: 'near' | 'downstream' | 'upstream' | 'within'; hops?: number; + // Cumulative flowpath length cutoff (km) for downstream/upstream traces. + // Undefined = unbounded transitive closure, the original behavior. + maxDistanceKm?: number; } diff --git a/src/utils/questionGenerator.ts b/src/utils/questionGenerator.ts index eae9012..7e9fc22 100644 --- a/src/utils/questionGenerator.ts +++ b/src/utils/questionGenerator.ts @@ -149,6 +149,11 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { } case 'waterBodies': return 'surface water bodies'; + case 'streams': { + const ftypes = block.streamFilters?.ftypes ?? []; + if (!ftypes.length) return 'streams'; + return `${summarize(ftypes, undefined, 'stream types', 'stream type', '/', 'any')} streams`; + } case 'wells': return 'wells'; } @@ -162,9 +167,13 @@ function describeRelationship(rel: SpatialRelationship): string { return `near (~${miles} mile${miles > 1 ? 's' : ''})`; } case 'downstream': - return 'downstream of'; + return rel.maxDistanceKm + ? `within ${rel.maxDistanceKm} km downstream of` + : 'downstream of'; case 'upstream': - return 'upstream from'; + return rel.maxDistanceKm + ? `within ${rel.maxDistanceKm} km upstream from` + : 'upstream from'; case 'within': return 'within'; } From 0ff2f393df88fac991a5f8a74b98e7984248982d Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 25 Aug 2026 17:12:05 -0400 Subject: [PATCH 02/66] feat(engine): extend bounded traces one flowline past the cutoff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "+1" from David's second UC1-CQ2c notebook. A distance budget runs out at whatever segment happens to fit, which is an artifact of how NHDPlus split the river rather than a real feature — the drawn path stops mid-channel. Extending one segment past the boundary means the flowpath visibly crosses the threshold instead of ending at it, which is the notebook's stated intent: the total may deliberately exceed the limit. Always on when a cutoff is set. A checkbox for a 1%-at-30km difference is a control nobody would understand, and "within 30 km" already reads as approximate. Implemented as a zero-or-one property path, which yields the endpoint and its immediate neighbour in one triple. A UNION says the same thing, but QLever — which the notebooks run against — returns unbound results for MIN() over a variable bound inside a UNION, verified on a two-row test case with no data involved. The path form works on both hosts. Same reason `?a = ?b` rather than sameTerm(): QLever has not implemented sameTerm. Fringe segments cannot inherit their parent's distance, since that would report a sub-threshold number for a flowline outside the threshold. They carry the parent's path plus the parent's own length — the distance to where the fringe segment begins, which never understates. A flowline reachable as both a valid endpoint and a fringe keeps the smaller value, since MIN runs over both. Effect scales inversely with the cutoff, as the fringe is a larger share of a smaller answer (NH airports): 5 km 1,533 -> 1,669 (+8.9%) 10 km 2,019 -> 2,096 (+3.8%) 30 km 2,757 -> 2,784 (+1.0%) Verified against apps.okn.us: 2,784 at 30 km, 1,669 at 5 km, 3,490 unbounded (unchanged), and flowline distances spanning 0.01–32.23 km with the fringe correctly reporting past the threshold. FRINK is returning 503 across all five endpoints right now, so the committed check script has not been re-run against it — the two hosts were verified to return identical result sets earlier in this work. --- scripts/flow-distance-check.mjs | 16 ++++++--- src/engine/templates/fusedQueries.ts | 52 ++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/scripts/flow-distance-check.mjs b/scripts/flow-distance-check.mjs index 8e00036..735a961 100644 --- a/scripts/flow-distance-check.mjs +++ b/scripts/flow-distance-check.mjs @@ -5,7 +5,8 @@ // 30 km): the notebook returns 162 flowlines, but only because it requires // schema1:address on facilities — a predicate 13 of 144 NH airport facilities // have. Without that accidental filter its answer is 1,547 flowlines, and ours -// is a superset of exactly that set (we also expand to neighbouring S2 cells). +// is a superset of exactly that set (we also expand to neighbouring S2 cells +// and add the "+1" segment past the cutoff). // // Run: node scripts/flow-distance-check.mjs import assert from 'node:assert/strict'; @@ -79,6 +80,13 @@ const streams = ctx.targetIris.length; const facilities = ctx.anchorIris.length; console.log(`\n${streams} streams within 30 km downstream of ${facilities} NH airport facilities`); +// The "+1" fringe must land past the cutoff, so some flowlines carry a +// distance above the threshold — that is the point of it. +const overThreshold = (ctx.results['GET_FLOWLINE_GEOMETRIES'] ?? []) + .concat(ctx.results['HYDRATE_TARGET_BY_IRI'] ?? []) + .filter((r) => r.path_length !== undefined && Number(r.path_length) >= 30); +console.log(`${overThreshold.length} flowlines past the 30 km cutoff (the "+1" fringe)`); + // The bound has to actually bind: unbounded, this trace runs to the coast. const unbounded = planPipeline({ ...question, relationship: { type: 'downstream' } }); const unboundedRows = await run(unbounded[0].endpoint, unbounded[0].buildQuery(ctx)); @@ -87,9 +95,9 @@ console.log(`${unboundedStreams} streams with no distance bound`); assert.ok(streams > 1547, `expected a superset of the notebook's 1547, got ${streams}`); // The bound must actually exclude flowlines the unbounded trace reaches. -// Observed 2026-08: 2757 bounded vs 3490 unbounded — downstreamFlowPathTC in -// this KG does not reach as far as the coast, so the gap is smaller than the -// notebook's parameters suggest. +// Observed 2026-08: 2784 bounded (2757 within the cutoff + 27 fringe) vs 3490 +// unbounded — downstreamFlowPathTC in this KG does not reach as far as the +// coast, so the gap is smaller than the notebook's parameters suggest. assert.ok( unboundedStreams > streams, `bound had no effect: ${streams} bounded vs ${unboundedStreams} unbounded`, diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 03752c4..da4bed3 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -141,6 +141,25 @@ interface FusedBodyOpts extends FusedBaseOpts { maxDistanceKm?: number; } +// Extends the trace one flowline past the cutoff ("+1"). The budget runs out at +// whatever segment happens to fit, which is an artifact of how NHDPlus split +// the river rather than a real feature — without this the drawn path stops +// mid-channel. Matches David's second UC1-CQ2c notebook, where the total +// flowpath may deliberately exceed the threshold. +// +// The zero-or-one path yields the endpoint itself *and* its immediate +// neighbour in one triple. A UNION would express the same thing, but QLever — +// which the notebooks run against — returns unbound results for MIN() over a +// variable bound inside a UNION, so the path form keeps this portable across +// both hosts. Note the direction flip: downstream extends past the downstream +// end, upstream past the upstream end. hyf:downstreamFlowPath has no TC, so +// it is one segment. +function fringePath(direction: 'downstream' | 'upstream', endVar: string, outVar: string): string { + return direction === 'downstream' + ? `${endVar} hyf:downstreamFlowPath? ${outVar} .` + : `${outVar} hyf:downstreamFlowPath? ${endVar} .`; +} + // Wraps the hydrology trace in a cumulative-length cutoff. The seed block is // duplicated inside so the closure stays anchored — without it the aggregate // runs over the whole national flowline graph. @@ -157,24 +176,25 @@ function boundedTrace( const trace = direction === 'downstream' ? `?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . - ?_flMid hyf:downstreamFlowPathTC ?ds_flowline .` - : `?ds_flowline hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?_flEnd .` + : `?_flEnd hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?upstream_flowline .`; return `{ SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { - SELECT ?upstream_flowline ?ds_flowline (SUM(?_flLen) AS ?_plen) WHERE { + SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { - SELECT ?upstream_flowline ?_flMid ?ds_flowline WHERE { + SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ${seed} } } ${trace} } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . - } GROUP BY ?upstream_flowline ?ds_flowline + } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(${maxDistanceKm})) + ${fringePath(direction, '?_flEnd', '?ds_flowline')} } }`; } @@ -491,19 +511,25 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { const boundedTraceInner = opts.direction === 'downstream' ? `?_flSeed hyf:downstreamFlowPathTC ?_flMid . - ?_flMid hyf:downstreamFlowPathTC ?flowline .` - : `?flowline hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ?_flEnd .` + : `?_flEnd hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flSeed .`; + // The "+1" segment lies past the cutoff, so it can't reuse its parent's + // distance — that would report a number under the threshold for a flowline + // outside it. Adding the parent's own length gives the distance to where the + // fringe segment starts, which never understates. A flowline that is both a + // valid endpoint (via one seed) and a fringe (via another) keeps the smaller + // value, since MIN runs over the union. return ` ${PREFIXES} SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { - SELECT ?flowline (MIN(?_plen) AS ?path_length) WHERE { + SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { - SELECT ?_flSeed ?flowline (SUM(?_flLen) AS ?_plen) WHERE { + SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { - SELECT ?_flSeed ?_flMid ?flowline WHERE { + SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { ${seedCells} @@ -515,9 +541,13 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . - } GROUP BY ?_flSeed ?flowline + } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(${opts.maxDistanceKm})) + ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . + ${fringePath(opts.direction, '?_flEnd', '?flowline')} + BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) + BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; From 3818e81a94a662abbea489c72e458df643aef13d Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 8 Sep 2026 23:16:03 +0530 Subject: [PATCH 03/66] fix(substance): read labels from rdfs:label and stop dropping unlabelled substances The Substance dropdown returned nothing. buildDiscoverSubstancesQuery required `?substance dcterms:alternative ?_label`, and that predicate has zero triples on substances, on sawgraph and federation alike. Because it was required rather than OPTIONAL the query returned 0 rows instead of returning substances without labels. Substance names live on rdfs:label. Switching the predicate alone still hid 32 of the 101 substances, since only 69 carry rdfs:label. Those 32 account for 47,642 observations, 5.0% of everything with a substance link. So both label patterns are now OPTIONAL, with a fallback to the DTXSID from the URI in useSubstances, mirroring how useMaterialTypes already handles a missing label. Verified live: unfiltered 0 -> 69 -> 101 substances, Maine 0 -> 69 -> 79. The likely origin of the wrong predicate is the facility table in docs/SCHEMA.md, where dcterms:alternative is a legitimate facility predicate: 3,824,195 triples in fiokg, 0 of them on comptox:ChemicalEntity. --- src/engine/templates/regions.ts | 4 ++-- src/hooks/useDiscoveryQueries.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/templates/regions.ts b/src/engine/templates/regions.ts index 70a2bbc..21f4733 100644 --- a/src/engine/templates/regions.ts +++ b/src/engine/templates/regions.ts @@ -83,8 +83,8 @@ export function buildDiscoverSubstancesQuery(region?: { stateCode?: string; coun ?observation rdf:type coso:ContaminantObservation ; ${regionPattern ? 'coso:observedAtSamplePoint ?sp ;' : ''} coso:ofDSSToxSubstance ?substance . - ?substance a comptox:ChemicalEntity ; - dcterms:alternative ?_label . + ?substance a comptox:ChemicalEntity . + OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } } GROUP BY ?substance ORDER BY DESC(?num) ?label diff --git a/src/hooks/useDiscoveryQueries.ts b/src/hooks/useDiscoveryQueries.ts index 1e042fd..b1d55b4 100644 --- a/src/hooks/useDiscoveryQueries.ts +++ b/src/hooks/useDiscoveryQueries.ts @@ -117,7 +117,7 @@ export function useSubstances(region?: RegionParam) { if (rows.length === 0) return key ? [] : FALLBACK_SUBSTANCES; return rows.map((r) => ({ uri: r.substance, - label: r.label, + label: r.label || r.substance.split('/').pop() || r.substance, shortLabel: r.short_label, count: r.num ? Number(r.num) : undefined, })); From 8d1bb43d2e56d755f86b0561e195a39c27bbe7f2 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 8 Sep 2026 23:16:13 +0530 Subject: [PATCH 04/66] feat(dropdowns): always show the Select all count, and comma format counts Both select components already computed the option count but only rendered it while a search term was typed, so opening a dropdown showed a bare "Select all". It now always shows the number of options the checkbox would tick, for example "Select all (79)". The number still excludes disabled options and narrows with an active search, so it keeps matching what the checkbox actually does. Counts are comma formatted everywhere, on the Select all row and on individual options: "PFOA (20,120)" rather than "PFOA (20120)". Note that dropdown search matches on the label text, which contains the count, so typing 20120 no longer matches "PFOA (20,120)". --- src/components/QueryEditor/FlatSelect/FlatSelect.tsx | 2 +- .../QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx | 2 +- src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx | 2 +- src/components/QueryEditor/SampleFilters.tsx | 2 +- src/components/QueryEditor/WellFilters.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/QueryEditor/FlatSelect/FlatSelect.tsx b/src/components/QueryEditor/FlatSelect/FlatSelect.tsx index a875a66..8835a6d 100644 --- a/src/components/QueryEditor/FlatSelect/FlatSelect.tsx +++ b/src/components/QueryEditor/FlatSelect/FlatSelect.tsx @@ -297,7 +297,7 @@ export function FlatSelect({ onChange={handleSelectAll} onClick={(e) => e.stopPropagation()} /> - {allSelected ? 'Deselect all' : 'Select all'}{q ? ` (${selectable.length})` : ''} + {allSelected ? 'Deselect all' : 'Select all'} ({selectable.length.toLocaleString()}) )} {groupedForRender(filtered).map((entry) => diff --git a/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx b/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx index c669755..81d737c 100644 --- a/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx +++ b/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx @@ -321,7 +321,7 @@ export function HierarchicalSelect({ onChange={() => handleSelectAllVisible(visibleRoots)} onClick={(e) => e.stopPropagation()} /> - {allChecked ? 'Deselect all' : 'Select all'}{query.trim() ? ` (${visibleRoots.length})` : ''} + {allChecked ? 'Deselect all' : 'Select all'} ({visibleRoots.length.toLocaleString()}) ); })()} diff --git a/src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx b/src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx index 308f0f8..abdb86f 100644 --- a/src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx +++ b/src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx @@ -75,7 +75,7 @@ export function TreeNode({ /> {node.code} - {node.label} - {count !== undefined && count > 0 ? ` (${count})` : ''} + {count !== undefined && count > 0 ? ` (${count.toLocaleString()})` : ''} diff --git a/src/components/QueryEditor/SampleFilters.tsx b/src/components/QueryEditor/SampleFilters.tsx index bb08218..bbd69b6 100644 --- a/src/components/QueryEditor/SampleFilters.tsx +++ b/src/components/QueryEditor/SampleFilters.tsx @@ -12,7 +12,7 @@ interface SampleFiltersProps { } function withCount(label: string, count?: number): string { - return count && count > 0 ? `${label} (${count})` : label; + return count && count > 0 ? `${label} (${count.toLocaleString()})` : label; } export function SampleFilters({ value, onChange, region }: SampleFiltersProps) { diff --git a/src/components/QueryEditor/WellFilters.tsx b/src/components/QueryEditor/WellFilters.tsx index f8ffb43..82f35b2 100644 --- a/src/components/QueryEditor/WellFilters.tsx +++ b/src/components/QueryEditor/WellFilters.tsx @@ -10,7 +10,7 @@ interface WellFiltersProps { } function withCount(label: string, count?: number): string { - return count && count > 0 ? `${label} (${count})` : label; + return count && count > 0 ? `${label} (${count.toLocaleString()})` : label; } export function WellFilters({ value, onChange, stateCode }: WellFiltersProps) { From 5b7aa745ff99bcdabc261e60f0c9bf6096e34625 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 8 Sep 2026 23:16:25 +0530 Subject: [PATCH 05/66] docs: correct the substance label model in the wiki, schema and debugging log The wiki page and SCHEMA.md both described the substance query wrongly, and the wiki's stated remedy would not have worked. Dropdowns Substance: query blocks updated to the OPTIONAL rdfs:label form, numbers refreshed (Maine returns 79, not 71; PFOA 20120, not 15217), the fixed "Known issue" callout removed, and the "dcterms:alternative only exists on federation" diagnosis replaced. That claim was wrong: the predicate returns zero rows on federation too, so both variants were broken, not just the unfiltered one. Added a troubleshooting entry for bare DTXSIDs, and supplied the screenshot the page has referenced since it was written. Dropdowns: documented the Select all count once, as shared FlatSelect behaviour. SCHEMA.md had no substance or chemical inventory at all. Added a Substance Labels section with the coverage that matters (rdfs:label 69 of 101, skos:altLabel 25, dcterms:alternative none), a comptox:ChemicalEntity class count, and an explicit warning that the identically named facility predicate is a different thing. DEBUGGING.md records the root cause and the reusable lesson: a required label pattern does not degrade, it deletes. --- docs/DEBUGGING.md | 11 +++++ docs/SCHEMA.md | 23 ++++++++++ docs/wiki/Dropdowns Substance.md | 57 +++++++++++++++--------- docs/wiki/Dropdowns.md | 5 +++ docs/wiki/images/dropdown_substance.png | Bin 0 -> 69621 bytes 5 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 docs/wiki/images/dropdown_substance.png diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 0835126..5cadfd3 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -192,3 +192,14 @@ For downstream/upstream, reverse directional trace is expensive — all anchors **Fix**: Simplified the logic — when a node's code is in `allCodes`, always add it to `userSelections` regardless of whether all descendants are also selected. **Files touched**: `src/components/QueryEditor/HierarchicalSelect/useNaicsTree.ts` **Prevention**: When writing selection collapse/expand logic, handle the case where stored data may not match the fully expanded representation. + +--- + +## 2026-09-08 — Substance dropdown empty: required label predicate with zero triples + +**Component**: `src/engine/templates/regions.ts` — `buildDiscoverSubstancesQuery()`, and `useSubstances()` in `src/hooks/useDiscoveryQueries.ts` +**Symptom**: The Substance dropdown rendered "No options available" with a state selected, and silently showed the seven-entry `FALLBACK_SUBSTANCES` list with no state selected. +**Root cause**: The query required `?substance dcterms:alternative ?_label`. That predicate has **zero** triples on substances, on `sawgraph` and `federation` alike. Because it was a required pattern rather than `OPTIONAL`, the whole query returned 0 rows instead of returning substances without labels. Substance names live on `rdfs:label` (896,899 triples). The likely origin of the mistake is `docs/SCHEMA.md`'s facility table, where `dcterms:alternative` is a legitimate *facility* predicate: 3,824,195 triples in fiokg, 3,742,487 of them on `fio:Facility`, 0 on `comptox:ChemicalEntity`. +**Fix**: Switched to `rdfs:label`, then made both label patterns `OPTIONAL` and added a DTXSID fallback in the hook. Fixing only the predicate still hid 32 of 101 substances (47,642 observations, 5.0% of everything with a substance link) because the label was still required. Live counts: 0 rows → 69 → 101 unfiltered, and 0 → 69 → 79 for Maine. +**Files touched**: `src/engine/templates/regions.ts`, `src/hooks/useDiscoveryQueries.ts`, `docs/wiki/Dropdowns Substance.md`, `docs/SCHEMA.md` +**Prevention**: A label pattern in a discovery query must be `OPTIONAL` with a URI-tail fallback. A required label does not degrade, it deletes: the row disappears along with its data, and the dropdown looks merely short rather than broken. This one mistake caused both the total outage and the 32 hidden substances. Cross-repo confirmation: `SAWGraph/streamlit-app/filters/substance.py:67` carries the identical bug and returns 0 rows live today, while `core/sparql.py:586` and `analyses/pfas_upstream/queries.py:147` in the same repo use `rdfs:label`; `analyses/aquifer_wells/queries.py:96-97` asks for both predicates but marks each `OPTIONAL`, and therefore survives. diff --git a/docs/SCHEMA.md b/docs/SCHEMA.md index eba0890..2432945 100644 --- a/docs/SCHEMA.md +++ b/docs/SCHEMA.md @@ -332,6 +332,28 @@ Same predicates as HY_WaterBody (73K instances each, same entities with dual typ ### Facility Labels - `rdfs:label` — 1.2M in fiokg, 3.6M in federation +### Substance Labels + +Substances are `comptox:ChemicalEntity` (`http://w3id.org/DSSTox/v1/`), reached from an +observation via `coso:ofDSSToxSubstance`. 101 of them are typed in sawgraph, and every +observed substance is typed, so the type pattern drops nothing. + +| Predicate | Coverage | Notes | +|-----------|----------|-------| +| `rdfs:label` | 69 of 101 | Full chemical name, e.g. "Perfluorooctanoic acid" | +| `skos:altLabel` | 25 of 101 | Acronym, e.g. "PFOA" | +| `dcterms:alternative` | **0** | Does not exist on substances, on any endpoint | + +**Both label predicates must be queried as `OPTIONAL`.** The 32 substances with no +`rdfs:label` carry 47,642 observations, 5.0% of the 944,541 with a substance link. A required +label pattern does not return them unlabelled, it drops them entirely. Fall back to the +DTXSID from the URI instead. + +**Trap:** `dcterms:alternative` in the facility table above is a *facility* predicate. +Measured on fiokg: 3,824,195 triples, of which 3,742,487 are on `fio:Facility` and **0 on +`comptox:ChemicalEntity`**. Using it for substance names returns zero rows. See +`docs/DEBUGGING.md`, 2026-09-08. + --- ## Class Counts @@ -348,6 +370,7 @@ Same predicates as HY_WaterBody (73K instances each, same entities with dual typ | `coso:MaterialSample` | sawgraph | ~28K | | `coso:WaterSample` | sawgraph | ~21K | | `coso:ContaminantObservation` | sawgraph | ~705K | +| `comptox:ChemicalEntity` | sawgraph | 101 (69 with `rdfs:label`) | | `kwg-ont:S2Cell_Level13` | spatialkg/hydrologykg | ~7.4M | | `kwg-ont:AdministrativeRegion_3` | spatialkg | ~35K (counties) | | `kwg-ont:AdministrativeRegion_2` | spatialkg | ~6K (states) | diff --git a/docs/wiki/Dropdowns Substance.md b/docs/wiki/Dropdowns Substance.md index fe0fb61..556bf58 100644 --- a/docs/wiki/Dropdowns Substance.md +++ b/docs/wiki/Dropdowns Substance.md @@ -12,12 +12,16 @@ It appears in the query editor whenever the entity type is **Samples**, inside The list is built from the data rather than hardcoded. It shows every substance that has at least one contaminant observation behind it, sorted by how many observations mention it, -with that number in brackets after the name, like `PFOA (15217)`. Labels prefer the short -acronym and fall back to the full chemical name when a substance has no acronym recorded. +with that number in brackets after the name, like `PFOA (20,120)`. Labels prefer the short +acronym, fall back to the full chemical name when a substance has no acronym recorded, and +fall back again to the bare DTXSID when it has no name either. Counts are comma formatted. + +Being multi select, the list is headed by a Select all row carrying the number of options it +would tick, like `Select all (79)`. Type a search term and that number narrows to the matches. The list is region aware. Pick a state or some counties in the Region selector and it narrows to substances actually observed there, with the counts moving to match. Maine, for -example, returns 71 substances. Changing the region triggers a refetch, and each region gets +example, returns 79 substances. Changing the region triggers a refetch, and each region gets its own cache entry. When the query returns nothing, two things can happen: @@ -27,10 +31,6 @@ When the query returns nothing, two things can happen: * **A region is selected.** You get an empty list, on purpose. "No PFAS data for this county" is real information, and quietly showing national defaults there would be misleading. -> **Known issue.** As of the last check the no region query returns zero rows, so the -> unfiltered dropdown always shows the seven item fallback. See -> [If it looks wrong](#if-it-looks-wrong) below for why. - ## The SPARQL query Two endpoints, picked by whether a region is set. Without a region it goes to `sawgraph`. @@ -45,8 +45,8 @@ SELECT ?substance WHERE { ?observation rdf:type coso:ContaminantObservation ; coso:ofDSSToxSubstance ?substance . - ?substance a comptox:ChemicalEntity ; - dcterms:alternative ?_label . + ?substance a comptox:ChemicalEntity . + OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } } GROUP BY ?substance ORDER BY DESC(?num) ?label @@ -57,11 +57,17 @@ Reading it a line at a time: * `?observation rdf:type coso:ContaminantObservation` is every recorded measurement in the graph. * `coso:ofDSSToxSubstance ?substance` is the chemical that measurement was for. * `?substance a comptox:ChemicalEntity` keeps only real chemical entities. -* `dcterms:alternative ?_label` is the full name, like "Perfluorooctanoic acid". -* `OPTIONAL { skos:altLabel ?_short }` is the acronym, like "PFOA". Not every substance has - one, which is why it is optional rather than required. +* `OPTIONAL { rdfs:label ?_label }` is the full name, like "Perfluorooctanoic acid". Only 69 + of the 101 substances have one. +* `OPTIONAL { skos:altLabel ?_short }` is the acronym, like "PFOA". Only 25 have one. * `COUNT(DISTINCT ?observation)` is the number shown in brackets. +Both labels are `OPTIONAL` on purpose. A required label pattern does not return an unlabelled +substance, it returns nothing at all for that substance, so the row vanishes from the dropdown +and takes its observations with it. That single mistake broke this dropdown twice, first to +zero rows and then to 32 missing substances. The hook fills the gap by falling back to the +DTXSID from the URI. + `SAMPLE()` is used on both labels because a substance can carry more than one of each and the dropdown only has room for one. Any of them will do. @@ -84,8 +90,8 @@ WHERE { ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance . - ?substance a comptox:ChemicalEntity ; - dcterms:alternative ?_label . + ?substance a comptox:ChemicalEntity . + OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } } GROUP BY ?substance ORDER BY DESC(?num) ?label @@ -103,8 +109,8 @@ Sub county selections, meaning codes longer than five digits, take a different r entirely. They join with `kwg-ont:sfWithin|kwg-ont:sfTouches` against a Data Commons `geoId` URI rather than walking the administrative hierarchy. -Verified against the live endpoints. The Maine query returns 71 substances, topped by -PFOA at 15217 observations, PFOS at 15098, PFBS at 14922. +Verified against the live endpoints on 2026-09-08. The Maine query returns 79 substances, +topped by PFOA at 20120 observations, PFOS at 19988, PFBS at 19895. Unfiltered returns 101. ## How it is wired up @@ -142,12 +148,10 @@ the Analysis Question sentence can say "PFOA" instead of a DSSTox URI. **Exactly seven PFAS substances and no counts.** You are looking at `FALLBACK_SUBSTANCES`. Either the endpoint failed, or the query genuinely returned zero rows. -**The unfiltered list is always the fallback.** This is the current state of things. The -`sawgraph` endpoint has 944541 `coso:ofDSSToxSubstance` triples and 101 `comptox:ChemicalEntity` -subjects, but zero `dcterms:alternative` triples. Substances there carry `rdfs:label` instead. -`dcterms:alternative` only exists on `federation`, which is why the region scoped version -works and the unfiltered one does not. Whoever fixes this should either point the no region -query at `federation` too, or relax the label pattern to accept `rdfs:label`. +**A bare DTXSID instead of a chemical name.** That substance has no `rdfs:label` in the graph. +32 of the 101 substances are in that state, carrying 47642 observations between them, which is +5.0 percent of everything with a substance link. They are listed rather than hidden, because +dropping them silently loses that data. Nothing to fix in the app. **Empty after picking a county.** There genuinely are no observations there. Expected, not a bug. @@ -161,6 +165,15 @@ graph. Nothing to fix in the app. **Stale after changing region.** The region is not reaching the hook. Check the `region` prop chain into `SampleFilters`, since the cache key is derived from it. +**A note on `dcterms:alternative`.** Earlier versions of this query, and of this page, read the +full name from `dcterms:alternative`. That predicate has zero triples on substances, on +`sawgraph` and on `federation` alike, so the query returned nothing at all and the dropdown sat +on its fallback. An earlier revision of this page blamed the outage on the predicate existing +only on `federation`. That was wrong, both variants were broken. The 3.8M `dcterms:alternative` +triples in `fiokg` are facility alternative names, which is the likely source of the mix up. +Substance names live on `rdfs:label`, which is what the maintainers' own competency question +[`CQ2.rq`](https://github.com/SAWGraph/contaminoso/blob/main/competencyQuestions/CQ2.rq) uses. + ## See also * [Dropdowns](Dropdowns), the index of all filter controls diff --git a/docs/wiki/Dropdowns.md b/docs/wiki/Dropdowns.md index dccc761..1cebe55 100644 --- a/docs/wiki/Dropdowns.md +++ b/docs/wiki/Dropdowns.md @@ -76,6 +76,11 @@ Everything on this page is one of two controls. is the shared one: a searchable list rendered through a portal, single or multi select, with support for disabled options and a loading state. Every dropdown uses it except one. +Multi select lists are headed by a Select all row, which carries the number of options it +would tick, like `Select all (79)`. That number counts what the checkbox actually toggles, so +it excludes disabled options and narrows to the matches while a search term is typed. Counts +are comma formatted throughout, both on the Select all row and on individual options. + [`HierarchicalSelect`](https://github.com/SAWGraph/explorer-app/blob/main/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx) is the exception, used only by Industry, because NAICS codes are a hierarchy and a flat list of 5596 of them is unusable. diff --git a/docs/wiki/images/dropdown_substance.png b/docs/wiki/images/dropdown_substance.png new file mode 100644 index 0000000000000000000000000000000000000000..d78013641f735b4c03c34d47fbbb0de870febf89 GIT binary patch literal 69621 zcmdS>XH=72)CLIS<6}WY9zjK^DosF|H0d^4kYZ@kMSAaq5{L~EkQPelAiXyUEhH!? zy+{o$2_n5|7=|Thx*N**(CxE&3`oNFP`f8rLAEudF$yT+BTmDaQ*vCJ><``%R=7& zs9k@0{U+;!M24!YEH&Mf2Y1<@^56d_{KEAcdc`-2zHx7JJk!4H5QAmy3=+T8=D~|} zzjI6(EhYPEWqt&e9j<{ggL*u@ylyJfMgn5o_Kfv!#AnuQmu{h3@@CBX$J@G|of7~$ z2G~x+FFQySExvWJDW~p?W*;=5xz2k<;OoBveCqw4B8M%`TN6}-JgS-22SK)guUW)&@etXSA!xucsPrIY`3*%QL$ zt()a2lbzI8wy|QgjCI4mF6jMR)ES3AM?>?Da=GQ``0n-Ys&GPCeeSRLny)?17ak}j z-m=}T9hEFGu=Q4;uCal8n$)b#Z9n2so`1R~jgIZhcb85-yoW;!XpD`n^r8jk0JU zhiJpz-yO>P2^2pPQTJQzJ07g86txg_0#6!f3Qmq26zdfk^se;FZ+3io^>L)v_mJJ- z>|IaP_4I5Md8HJEgv?lan-pAJb_x)2&bR_Y7(TuxEv>l(2W)F*VH1c1UED!W24g<6 z4^(Yl+fA?lmxE9Rbo3EZ2k4WSKkiISOwkkN+VT_10rXd;H2{FkEu~;WfW5oDAG}y! z-Vsr=>o7Y~S>9+Mdp9w-*?@(gzlg-noVmXPY6i6aE^5<7BAghY>FLNoO03gQ>F2JW zI+s`c>(Ldf*zvlA$1|yaKfV~%)zbylIVNOlZ$;(=*alY}y`#`N zIFo(Cu*G|dX~7Ek{0Oh!dAj^U4cDo!I++fT1{{P%Er^Zo-Z(O7c%F`zUBui71lG4(kDapw`%K&#`27|-l^^-~&Y*7^UY*gJKwNj<-e$Hqeh|qrQqp+`;qC0=>dMP}cke|w1tV7{ zj+9op`$!;Qu;(|4bsm?k(JnQ(`t3}xU*lXoD}K;!T$HEm#~WFwdziN@&RE%{NV)#0 z_McOsUj--|w-f-i`YxF{yl(DGRclss#514Te=@vE0n5;E$I&B>_@V*BZ$*t>fMZGIKLeuqj}I$Qm%cdK*ER;{3tpN006|^ zC#O;ZwX*9Q-8Y<$KSyN<$Q<>MBS=<4J-t4l*mc@*60*)5NMU=NRS}P?FlV5rjlA3l z#von=`H*4V5R@n3vqVM^DOTD%NXu-0J@ve8KgGA1vPs8Walx!{Vctml)@N00#&`FS zVKT-vT`^NiCFs-4IA7rUn3w%eXhQXPxIV-_Q@66V7WyVLJzXeBP-=93RQD{9>{ImL zTVe~6(R@~+JxO&h0rQNC{TIy>qaVT?{o8jH&E((-&K2>=H;(wevXp9)p0!kRgFD-p zKa>OB8OmMDMU|DqE1U}uL|A4}?hO+=oB>J9^kk_uJ@L5GpwDO1(_Neh`AUFs%56t7 z!y(4T#_}Twgs~w*bbTKE7N3?y4DrARV-dJ~htM|Iu(6wU0?dTTHgiKHdomSS<6~p_ zBgKf#<#KnPR;;t&*OsA`TbeWeKsD=Jc-H0b5-vBNcR zg?OlURO`rfV`>^SEWov(&{`o<`iJrxc-3T+DP&}4O7fPsWT}N}@ob}pX_`|pz522v z*NX4Ux4`P`1~bpiM%HfSKC*YsI$S$2Z;@*-wIzC@dkc^Y1`V4Cag;LWi)$lY;=~Ow`|KOTOvwEhoe6h6CQ085}^Ih z_7HRx7jSy5r=ca#n^5Uw@x=S(6jezQqa$=97c^OYR;S7x<}Usw>U8w>(m(d)6rly9sHtup72lkM%RuG z^4wV%eFurV!mwowokUWdK|fvpu6eT!n#4KU*%EXqI#H~L>H;NA?d|Mxq^KTX`17xw z*yj}VM0?<(IVH~S1NSCXFBAJ~(=V-zdK`MU1dbHnQiy{%8Xq)?G&4L7Fh=|u9DL?G zJUXVqC$r{|z5M zyn0WXum8YtW^EJj%HU`lk%ABOA&%wgrt+H858Lf9>}MvCe|zTDu-Nks8bUOv3UCEi zA8fW~#n&%~F5c|T*8Ur;AkZ+NnD3g*Ha2uet?ci=8(q6!r()VLW?=A&J@A+PHk2@7dyY=lH;TdL%yoeP@CKZYIMw;8py+!|%`p4p7^+XdJ6#XFXq%t!|(GW*RV^dW_AK@d`v>jZgn6-T#)D?jQTY{c7<*@k8x!|pP*LIy+uV1gh`1CXFJf*a05S8Q^k?aULrG0bsOcn0S~O1 z`R6pyPx@U^2?XanyqsrM4<_zb_Vh0tKd~e62%7Blh za5#J&+mPO9Vq6W{$#)fRtG&thXg*c&DHCl;6>o_m?HthsplD;qFvDyXv4zLNmzX%9@3 z0jb~Li!PDwXz%HHIatk2fF10R{Ry}7uI4Vj?b$#V^qbtujH$OD7r^L4dsLhEQlvsP zGF$dvxkXaEQBz|$sS_T~Qv-58FKt*5`}~sQ9@0Y`7-V~oUq;zA>mWbiOv|fE3N3e^ z{j-&(t*Ug0=bETmcZ9;!hzmfcwJ*}#&sL)hVY^?xQC4@{`3SpIRqR(B-|BrIVzj1g5vX7aCug#B1)-+Fwa2W zy&yXs2=ijfO5r)CI0W-}vGUxV%&&ze?V9XyBI@SP_ItEdMm+=%5i3&emIWzAa+FpnNTTsg0ss-`MrAQQe+?i8%O5~?1ZU&=go*@ z8Pz{MAPwaTNMrunEB~S92DHGzj&mLpE9`E$k86!225+d$!<8_*H&cfgWOt)HQ`1wlDr%{qxtviP8Ee0d?s$OLCy6&{=XULyXrrh z>o*_waGdQ^@8AE+X{TKp|K@xvdYTQQ{$y`n zkVz(UW?;7E$3}p1aeQj3Acct~;Vy0+Ui@HwB|@b6c)h^qZ?;F_`DpGRj1P2sFb|M! zFnnWk@{v~DcMU5Ni8l8~f%;vk7})Uay!(5N?wc#4&AY*rAz6Os&=A$$bg`#Jw{Pkv z8#TY6pnfL24GXTPuV*VI zxLGuw7zjKG`9zj%b}^91Syd;UNu6>xtd%i5A@E$ol)hS$5_mfvyth8CN#ze{Xr`6a z>3=&u5eD6SbS~rImTcGm{FjH4Hw^zcO$g>bIwJvS1g=^By(q5dNoTwI(edBH*$SeM zKKY*=>Fd@1eMI+OMgAEWoDP<~b^AWfrD^p6g{Lf4^6r+3hkfZWmGg zfvdY~aLT>=i;0KPIEZb{g+M4J;_)xqd6j>2Cnf0>1IOF)RP=R+nh*K2v**MgeRnAp zDlsf`_DiF3IZ5^04)tH1uozl5Qqs^k8!H~4u|Ro zAPVwrUbORc?s}Gkqch{;Sa01FETEpcs_uIcVa?vw);L_Sv!^Sni9HkaW2(t+VU7{# z`e`u|B-&K`wWoA!-&!Vq4G0fs%k{J|DQOXrlaW*qkiB0|AkCb7~u68}>8se+=|{6VitWa#tjram8o$a2Kr{aMUufjH#kn}34|A6hhvU#| zX`0L{S7M_sRs;wWOqTkwAVFRa+`tpsl8Wu1j*We23`0i!gBepQOl&FDbrJ#bwL{Ir z*sS|!wkGrqU0-ymvIH3NC>@P8IE~BJY1I!Gk0R6ST=_n1L-*N{caOO$X3Dc8elaIUQg50bsYAgD4Jgg^lF$uJhABS!_i%wFlGU-AnAlkvkF< zj)-FQZx_^G0x0=o@alhx$Z5~jxTJeh-dX6 z#pTNN)R-ole%j7{V3aGi&^PoJy$!RIV8moqSgJ2)9Iy!}MXO$fINzr}fXKH>;HAgl zO$27{B#%S0^Hg(k4d2>W&KRMM6dl_V(<)B*Lq|9k_Zytf6$ooUVF*lClrA-~U#-`J z#eG)&?K%lr=}QOabHw9Cf&?W?#-&}B)|Y3Toviq!MK`*7pM0d<&20;w-d9#90nK16 z2=8_^hKTGt+Eq5h&D?lzOr*BiWt6+*OK6kxP+@t*zkV8YUgLW|s_wQz9-XSv1G&z{ ziQ0dCFiP}w!@T}Tb_%D$>jW~wYK@3=MV1HlGQCGz&BpQc0umH)X2PK_8f9b@r@n>x ze)6|}vAzCo%i&Hkl!0fpi*X!1@KY;_sgyRm5uy6~S9fByTP)EJ<`jp0U##!UNgM>0 z8A}6Ab3eYBTc5j=Yy|tznkrqK6aRBL>pwZxk^)W#!75WTXi7$d4UtwR{3YaY7%D{~IDvzE~VobB|ZifjIMoc5$$7uq=p4HxAKlH5XU6 zuEe8$vi3VBs*I(Gt|9~r#R=0J4OT|QHR|jpKz^mhiXo2Y>*}C#Ij2HCQZs%#DA)(9^f?sav~19G!Z+(Yw`veIsorKojJehj)e!w?z$RZDcL zBmrcGp}5cgV;q1^`0Opbq{#06Nc463?~QL#k#Kc$J+Dfqq1+6Ka!gYmdobkwMhaNk zVX0h`1i&sG1I#9+5}zTxWz{Cmf@)UNa%4H|Px&nt_|>?kwQTv@99g0j*9u_VMRKYs zENhajM6WH3h5(__3sW>KgY}-vV^bx4!>S!Nw~ry@_?2Hpw0^rT7QnT_;|{nmDb`%H z1NhaTqOW@C_@kP|XIW82Da9gi#jmbGQ>nx_mOipwNdsk5ou6!qS9013=glmM{1pf? z0S5dcG=(w9ugW^9GTBQOFFu+M(>e}3OmPahkLSzHwS7QVSh%Zjp&U+<v`-YmEpA^$f@E0@Gl^A7W;Ettxm-M!hQd^*8@~ zxxJ&jI^dyBYH$}SHC((UWnfc0XlG-$*eoyT27Zra5IIcXF32a6l=v?AcP>h@m*`c+ z4Wb%CLXxc)a_q{not>`$-D~FkU${4(VFe&=bBN|{_Y7L)t(1Trd$RBSGsE?dtuL1@ zH%}mz`Z0XCbiYSqX2(|VYqmd2QwAcqCNVy6#xd!a27m5qU#tO;mp4J))CpksUiS3z zpBV?(Qp2~gtecY{G#4Pvrz+hWfn$mr!nX)t2<79>yO`FvO*O_wlj7&S^bn1ws!dz|hgyR&C#<2n*xs z5%kwiMMFg^qG}A=$5?mSZ)76VeGYHYdnTCDwgEX{z-D751G>4Q<>b!@wH4td`wN;| z`HDgoLd`|z!kZY&*gh_wZ*`mReZ@B)gya@+g%L*9cWZ&sb!y!mU!yeQ=T^&lQC@uV z0$Rc&RKun75^opq^(<;=Xz-xzlsqAiJ~@ zi%uONJ#Vn5V^zkwu-Z=XF4SyGWul#1jrb0@CbsKo-kigX&yl;H4oEk_4z`%4W{#*Y z^DwUV{V1@<;tV?EcC+W8AIg`N-u~w|pKn}M5$qOqz-Sic>BbiL)T_hDIAv8Rte)MX zM|FwrzTKXC_u(EilWWh&jSwqtxW}dl*9fWr;Z{$5&`uf9K}!l?4}2X*(xbgCb`qvos_(Upp_iMYF%g2m5CvTwJ-vYoz;p zes*%a7D9)eF*7!K9zue0zx4Swj0dsHrW$RC1{T?JDg@30-9H_)$dFOq3eWDBXD4TC z2gm|Ec>E_P7kG}om~2XOS^1o=JQ$TO!iTE-D&&`?B1ib2LbDS)AKX<7*|L;jpHgF^ z6+&S2zt}Hd4CEwpS!dVsSYaQzatUTQ&BNQ^0t0i#<@tj>cG`HYOFmcMdxO)iUQJ~6 z6n~`RR(fL49A~ndF;%~sv~GXC!OW@df-~0Z=uf8xl`yR^uRGo#%3bT$);+!LtlMeD za!aU+^`F}mr5^L%MQU-hT(ab5O(d15Wrwkx;=VSUHTEJy#AqiSdW7xuQ4#S)YW_|x zhj5tpv4tuXk+Ta-sv!-75|G|kB+7}!7~rvPaTofT+l5d}xwBPzYyywN&_vg>Yo7bt z3E*g4qXRMm-O5AhE~qX`s7*43hr29}Mgl-QD{f8fsSgzB{P{7%zlK^H%(gC8H+>8J zzJ0mlsqdvUadF95t;qdcy)fL)l#_awuvI}=a*+cAE+4Y4z~7FeqP>7i_&O(5{b8?) zaVk>swOT%08tpR?*!UJJMye9+PyM8gs5)Z9*a_mLinY(Fsj9s7bW8}W=!yuB>hI}V zeGt1*5y)ftN^E8FKYWLcf9_ez#PNXApWxqVWGKm_+quHa8`Ar_e3ZabjTM+=!qko? zIx1^yJ28pdw4%6j`ppUYBgSdNvk|g(6r`j`(%O1ou+UQ}w_pZYMq7{Mn zQb0>WIJ7RBnzNsEyCCgJgc!xI{?IB z=|1_4(8&pSZ)1qzr#Es*3}Jghgs! z8)~}Pk9hA?q|H6z2B$H{U(e-r&P%o~-(Q42G5fu~9(Sa?u74yL+iGl_G>`b!iev;S zPx-44?EXHHxwVjgOW!$SYHTgi5;W#$RY-%j1okLDL4w%z{}f2L&8QWQhTl)c8K5!P4jede8idSY#D zEV20xL1*dVyFq~mi`dKk>rw`J2>%S;NO|{62o$(a!KE%7_ie!pH zIHB_Ce_!~a#?{n>KN|mfpue&EW@0yg*S#K?Mh|bv8C7wDyLm^eo8xykPd|*m2gdV0 z4tw?*6;+X*MBzkOP)87dD|k8k@wva8i(7W8mj+8;H{-Gf+k(dRjys`e;6n6@O;Mtg zms8j^V56GF2T_Z`$7TbQXK&C!UD3|}{dFp@`~$PnAhUE2EO3yw@$9Fs5tdLP+&D2p zN!q-s1-$vOt}zc$;${DOKP1ACRl2w$epkl^M|XP6cTj=fcgf&AsLsPxjF}lg&qu^I zLz=(uef-;w5uHiG-ksek@byHm`08u_17i@v?4@90v}^@8U@*RNZ)>b!?WR&@7XJ=9@u`?H&ka!)OiR&Z8&ox;lCg252Pk*Wyl+y z@QLv}N0p2jCD<>1sP!n;=aS_W7F{9@%-I>&Zj`UTE_>1b5Yu+L4o!RxV`Lo~^LS}+ zq>8g&OYJ4ge%Drz#K?L}ok*Wp0)%%D;P~d+|8&{ZuqMcMI>8v&$(!F=`EtcJ<`+2v zb4y@$NFdu8yY}vq>dZa)r9rrh+}?5JinPOCK>b#l!yMgsUar5nbi*R&f<`)i=ayFL z)_miRNdhC+*qLxS*myFkPvEdj*3I=*%HtQo1IQQtD7KcSnTr>MWP)~E7F-a~Y;rzx zwlAJuItv*zqP*nL4JtuOnAqQj)M~dLZ~%ghkdHO4Ok{l#weW+AXgx(GX~aM4|NSHI z^q@Z|70;l)VuFOmr#)z+*AxaJwiGQo3Ixm0UnJtIO`hW(^ z^2{=vHUMNWEZ*J`2~NHl{7t!BNWKszvB=!OcDm|2&sROuM%M2PuQCS4p2LdvGiPkj zqZ6|pS@_)$8JL(YIG8OxQ|+v#+ih!Lv?Gi;eun-$_?}Y&qrqD5m4;s}hBw7a>})aW z-A!CLkmqIm*|HFE-8cZ%)}<0{7i@U}uXqj^=lzjWW~E)=&A29PA}xQi!=3T}VKmPH z+Y)a)@OqL#W|6S+% zuukbk{49DPqBA!sw0m!9UQ+E;w$!@WhZZmI&4{hv#XZcxJ?W+!AO6yV#sQWMF|W&R z$myou^vrL8ElyfyAw|?$NcryA=Q^0nOa-#)M^Ag zJzMNa$=Y=j;^n-G9>EJ&Z{F=c6JJ&y4AyOv7C2yu+PC9rJNquCVzzk+`FN)BWr9C) z=?fTOc z1Mu!@?v+4eA9?wSS|?noKi%H|Kv80>64WowJ#?ubbr<=5pP~51+^^rb`ZZtY$$*U? z!FkTPTu&6Q&&(h>R?Gg1;%7}&Qx-Ub*mi;ceh;(1_xuSorHR|0tR8f@OZfBcd2F+i zh3ELWbLUv4oMWELAnJ88&qOxl6O>LW^=GmlICqmWVzmHhNXJowEZ((E?;^R|o5UH-Nv9k`KRyb&AenU+-ii|)w zpuvI{C6go7Ff$I8(gd{ijM-U5!{&bmnn71xKYhMn)>k7WCb|G(!KzW|ESodd4o#1y$M-@}<{d4wNm5QTnUkQvVGoPrRv5|d z*)yQCscCHB_@tq4se!(m| z5lJ4T(>^O6>lioWmG#3Ml7dj{&-+BWbv}_4zN})T?%e8U9o|b)aQT2pjd<(K zU9@nlod=K_W$@nnStS0RS}+p}*ngv|tLxxARc$o@C5BIJ{tniT41iSb_V@Jks1GUP z;EV6Dw#WeQJBL3J)KaMrGeG1A>v@a#?+;C?iqTwV#c~FJq5qo(8`f8u6>pI#TGE-! z@gtOG#~n&D-Vm}kCz8{yNp0fu@)9Q~4JMTQJda~*piE!?JtjZ8m*5(`8#tT%zU%x$ zK0dp?MGN&Dn}~eEWUU@RP(i_JcuX6vj%}H0^0bkIBduV#?g}Jm-nbGgEV8@0s`J~t zQT|pi{Mo5Ryqo3M$`ZD%7k08aX-=Mj*E&zat;qm~q@<*#T}MiLfNu$59U7bLe;lwB z&WYYcSda4TrzdDVK7_-ox+=E*;y02rcCdKJH#V!uHJSYta6@Z$br& zczo2p`(T*vVlH9U)M@Gx5rBTz&_MpJVVDT1JNWU9EB000V$Y%D_^eE0d#rG(Do3zA zhSQ{$Fm~9or7h{OR&=UhPpT4-1{N8uYm|>aPtZQ8!)>1!aDgjf=8lsSU0n!|)&_B< z3|X&}d?k>rwKd@LaJjPoc$HUXcISvfqtBplDPdh86I@4ak34xh;OQ_nKA||Yw=PI~ zK8npSu1U9yMdMbVw{LNgu-n>*`)&REwFCzr(TY;hn;;jHKsOvzq{uS(}y+9nznNKQR*+<6Ks2Ruh*K6;&+m?12)K^mD( z8hhOCsIR~}x=P-7ZeWlIQ16I6-o5lmRizWcB&-E*^x1S7%W{3n+I~OKf(zQ}}vzvjT!rt~AFR!wEya%-l&8ofM zl>SVk))_`hpd{h$kiNB<;Z zL251?3{>Vi!JFwS`;iju*5HZbcyxdz%73VBq*$hdeM`>I?^mVtSu4ncZ`Hp7zqdr2 zbY#YSrFPZD-N}qePfw3eduwG?R`(u}+FeY%HIE<;%oVh2rrir%7B;QipCo(nO1jME z-T278NE>HMY=9~2cQ+rBtIRRH5Qzy^lZz9uePE%cwLPWBiTU82hG zar5BrJwZsq=U@Bhjt?DSp`ofpk+o$(SNBNHuPtg}ko*`{>3I_nuRK{vX8DSY`%*`5 z<(Ji;(xmjgGXNc~Ei%c>u@fPA&OCNe_oO66+No5^Hh6a)b7wkYrVBnT#;Iu-2OcTD zh9a1B*VQmF#i>LdOKjWvd0e}1rx(}suV*JklO?b?Var8sw~yl4fNguvEZlu(gxk&1 zb$w{cq&H7SMrP~Q!y#VZu&JGu(ZuKji?7?43n2?a{56dnw>Zen(xD~l*uK$P&5~Q| zt{_g+JvsON^u6|kLkRb!qv#^~q9bOzL)<9EUryGbQ?Oe}$gt3?eE0H~v?;K;u1MX} z$r;95x4zYlQY|Eq*-P(#EFK2dJE_P&)b=m6lcp^piQEgBwY$_bl4G*yY6edAlNP{7 zx-#;sf<=uy;nu`EnNb96UJkdNOiPqma3)w*TJfI8{-wC!eOnZE_0Kl=@Hi#XZ+P&}z`_<14|LaS~gJnRyr(}K1CM7Q`ax@Yder=01NzEC`B=9Q8F(Rk7{9`$^ zyuWOP$1L8c^*&`@5Dj-}h%}F6St=jd<@yw&EO6>%+&L4T+nA#vWdK}G;G$U0=fZJG zDJgT{CW1>bV87~w66p0QSGBY1GvcV)b*^l3VDR?IIx7Q+kh?C3i&h-;*;o}3O!?z? z^eg$9R!SPQdbV9M+;-Q;1!^dv?z8?iENY}!AZ4-jA4wG|koh|!;L}&H&WMmW*k0dU z(dbu)!fL6FJCmbAH4K4nV>QqDKWd>|?6lY^M;hlvjy{658hqBP}44Y`0FLUuGmHH~1|xOendraPJz! zi%TNM>iy0j#}$Kh%kk11i_^G)+W~96 zlFQ&YT3C(=?nixeoC|B`9FQC4VgQ*R5VQv`Uv1>RdGevpZ+aTTr2gMX>S39qe(0!B zs(LJCVuuxIY?!HsTLtYk97tb86@m)eIfLrWF|s5PM;rZVoe#51_(@*eyo<4sz(l>fo7 z3vvE|keRhw4j`dR+4X2kWOY7Mg{7it|7%%UB-U75{Cmh&ev`Ck_S9BK;UuRv`Q^aN z=Xa%bSg0NZHP&3w_y=oFF)(bXFoiiA@gZ9~@cWyNBb2fPce-dCf)2prvITo}1hOYO2Wh^ml~ z*j}u~;L476RP4usZr6WHcdG0-cY$#Za^i!`CZh+mCMw$dMtujGisA|&!P9?U?acCY zrY7kHoFpqgzr>&iV!ozdyhO0KwEWg~692Y8=nNLlXM) zvdu?Yqz2ZN`pa})UIeL%Ykqz1?eW8UCakP<8e7kX7xsSYALZp{)_bnc2DuR8olan*)+(qoN>2#UgJVaa|;~}WY{y$wK%_Uy@ z%}2B1pNZFoi%rK}v8CGg@4J~bdF#8zQ(@hd0(^~=jjh;qZhfV+4z|r-cmW(LuzQwK z-gp8^0~=w5Dk8eT%j$raqyH)g2Fk4-0e-Phz&(A7`LDlPX{CaeJR$O*si}v8f+mA= zmES(b13kQ(xSMr4Jiu8s4;eEZ8u!GnMd?i}l$Pg;SPawVNSU zw#R>jU*58{wIv~-P$<(C!nZFG5fmQ`ud+A`C1f!}FZ@2`32DIWzR~efh{j-LRjuR1 z3rP9lzr9OA%3G~xk+?p(%U|k{5^u%VCr_SoA|*>h98j#e`FT!@G9dSQlO~rHLY}=j z7juC4Gya4H&8A_MH-GZpy5M?DT+(E{%-!@o0bSV@s8q_lG^_NYcxsS=uYs1Mx^dHp@8MgkNob|8KC&M$;-f{!a5(+{4ZU>1J0S=C2XOa+TVuX#Bst?l&a z^5f(68+&CYk}!^ck?=5eP-_#{SH^a4;6jX5!${(Vx>G(?;Sp^SH*-&=H99x7F#S9Mq$TLw-4xsK7N z@`+Sc6jqIyn?kXB5x<%Zw|(tL>EZt5?~p&t3mQ^(sWzsmsp$hNF%)Fx^xg~y-k_tS zqc+rFzj!C4In5`z9nn11~1s@h(DIH#>Fei234x{x@(T8}tJ&GcK0x}-gt zi}>`38>3%UwW-l;lvisJnAbdmx+mQ-d@zal(0FLA&2&=z-L}n#^4L;~> zpMdXd77~Qvvx0^n>(<9|ZUvsDc3O|e*Osbu5xX4n{s&WE7;F{qjd33E$1l5IGAUF<&Qg9=nVGwcR z75&jH6&Xcw$Wg(5=C4CgC}jIZrs@QIH+DKmbb2Xs(pNC0e)40K%Gdr| zo$KYoTBp#(e+!x6>jK701In?;y&rWr^zu|uStPu7e2W=%9PIO&+LSAn3whz11(lYc z@l2m^{mcq(CZT(Jnlj=IFUmVvnN7?4d%_OnN3D+Y35*zvpt<9{&sQBse|7f^Z#%#F zGg|>s)9MW5ZC2gu>rDx`vmSVFse1SAS+5gSg>Nh*udZY2EaH|>wuH8{v?-jlb3!!s zA|qD;_~8w~B3XNnypJx;6#z0U zPB8reUK7&0j{BYa*C&*C9JCMY<3DZXv};>5+>(b3NH?+?mMq*gJ3q0~xYA(9q2#sx zK||9Fe6PXf>LT)fHDrUB0!P(X7HZ-SYnNUY;`V zS`O!ZwYNTE=H_BOOxQ`SRnIAYp0Jo1l)dr1Q|avsywLK?SR}7jMowLAg7%O$@7E5H z>JI$}lJ@9$UE~>w!}F>wdE={RQc#2U{rK*uJ-xjuNTt^;l{Z3nuAr&;fuc}K>Fa|A zSE!*;QfhxXd6TYRiO0hbp>u`Ar~^5&{b_}4ygAq7|M6)4Zf~m8sM!Obh1gcCG0LwN z`vT;dPK9ERvmm&x1WK?`<1fF4TF&NV+${F_jxl32Ulgl(vpM_ts{#B-3x$yfD3KTQ0wSQ}u3fj}kM82utog|{IZEOUU6Xx})qiE)$dqZ{R z5OrchKtpH+1K8ulPM4I9(djx_5x=b2#42{yH~AyTKs{aQp@abOcyS$0%Ai5#n<78& z%Hck{%89uRish+D%H=hc?b{luxo-?dn?;xREKMY8yeAaRG>!HI8C zX{KW^g?Yu#?}5!-ME6s?&Xup@U-qz-wbfUUcQz*vloAf@HwTI0->auErsn>eMrWXM zT`mVKnI1n>RQOy?{|E!R=z8L{h&n!}t+bOA($E0hJPpMSw`S*!C{(K#T+lnS2OZQ` z=YRfkjbD|2YreCK|KA?X=CA*c4|ww%)6aTos~Qt)jI{1G#eH- zSrW4JuKw?j|1Zv^is^p+Q>0sPbbS2rsg={CXH!SMqvB8ZmEUSGV_50@Rk$0zNrU=g+&d=R0E~O?Cd#*#(<0a=as%k19 z^a(c})lz1uhw#pM9|4O zid7?BP>R2H^5bWuTA;IC--XCj36lW*T;$3mxi>{(aB_MuVU-9GHPSpZ7Vd+i4&FK{ zL?3ByAGWzzfE%7wH~NOb;Ugv$$o+*M%-+%^Z!P?nOe%WP>a58ir_T)Rxu=)?Bj{(z za#v_VLf$SHtpRlF+q*eB7+C43mH$q1GI{+iP!uUd^`OY3w#%KJP&^M1!1+@*h{M0W zq#{1ThS2asqqQA;uv4du-)i~@ZgSe>!_hvVMec{ExH8K>>+OY zHyvwvAh^YlLLIWBR0S06YO52!eVcI#o@{bG9(^9FeU(*#yn111`+g%N5k%f)DH>Ajd)7`DF->mErX& z)yAcD()b4(Sj9z?q*Rds!jWp3LL0GtYlBx(iJH zUQ=nWgR`1V+EZjZNj&0TmKI&A1{!-Y2j}qm^Iwk!@A+W3MJC{`Rrc%Lk~zT*+wD~2 z1vA{&Uz#iEQ>O=$KFyF8Ynyj%s2GK(&VSXFoXFT{j{AiB$wg9FN?4>eYYxbFYz%}F zi_b4GoOnG9dhM6X4R&bS>wAI;K1WU5GrtB}uuzK+iv9=Sdxnf`o?B$Y&j2Va;4r%( zPL&~$3)gFXUY#^(la-2Brj}giROw^ec4BmpGka9k3Zk;FDUxh?R?jp^Ej>NXEtj4n zGO+6d)QX2LF>u1# zxG=KI!rEF|GJz-A60$W;MRgH)a&1|vU>A~mQ<5*XjZNDL=eav55v0PH9mtopZV*TB_dc$ao8l4W7UGdlgDO%kqQ@!iC} z_pBOi+yxh2hg!qvrl)I&<7@MH{B76D&HkoGe#8t6buvA#yxfQc13m-JCr$~In>v+3 zmkb|?k$pGU+?rD`)&5Ma$l-?h9oqn+f&1j_w%}&w`Z%W{gF1xm z2*cy?#R*_Ty8^H_eg&w3;=1ov)X$7Bp(YE`mrz-9v=%6q;XV7IYNPat@(X53Sa`Z3 zlOK_V)F4I9TQRw)mEMq5*EK0fyzu_gHTDFHf>Wpb;L~oN$L;!Qp?7qhFp{;8 zSepveX=KbDI~k-F2iF$Tw+vwM{v@~)=bAn3ywK5-zk5qnx z54W2@*p_{`T`nZ6LTPDYT?`@r%Ej-0`uDF;Z+{;*%+hZzjc&XtM9*)!S_V*idEifI z1MjU2R;8z|VyfN0@|sAIN(*i%BO=ZFdV0DhP(#`*NXfVw{uGZjWT5ZyZo7rF3q~>v zrwge1{i{vTpSH+hg!G5I(N-FhFw z6t-KpIYsE^G&MNk5rMrdQI1K}Qj&q-*hJRr%SDaUyd*C#kJ?4BB8;n}RK`b?l|Dp( zmb1+E_j52jJ(+Y(-a?OSGC~nR`6>^8OH?@0%tJ~G0PqLl+o|vfxOd{d{|2L9RJ07L z82_n=3o4P-Ye3i-rvT55mf;%z5ANPOs>!um`&~_0R+bf&rUD|OpwgtqPE!yNkiGx` z>74+fs0gS?Z_Y}*8p;Op-kFDWwf=|c+T;BJU(Tj zKXa#_j*0IJ6UR)HyCO_Xz;8BLo>iI^>++xA2Ve&Y%frI-1@SWjv$ zrT2OAO|`Fb_fu0-PwcT3&OeFa5_9hPdcbPzln<@$E{7nKZM3{kLGI!iBHt4NYObaU zA$zKc^eNYs*GK$X(L%05cr~l-a_ycj+mNU4w7=}@656p;C3vv4c2|#19Qf-Sg>tv_ z!n@}``bb9{$N05s&ZoUTb;_ZrO*31&spVDJKxooPeDQCpxh8Fz4RJHKP|qzZyyia^ z$}ZIDx<3K6OUiFV&8@qv}} zkL{-pi3is#sg&7$z0b;c)uA3q-ab=CchTMDor6C(W_a!9t(aNz+<+x%X~#C)**DrD zSgk`rL%WN=6O!2>CqM7+0}b&dD@cx6TBoPiH+rho z7-#lq&z0lHQoj_EY)rV<$o%}}&SiHWWI^js%;6z-J1icl0W*gyvV@c~va+bj)PO|$ z=iPO8xG=BGx3eexaez~haM+|};}VgL_bzlMT|fVB!0PYqI^NQJRlqUgszB{}F7Dhd zi_JD^SYcS6$}Ya6%8^lABYxH4NoX1)!NXYIC^$Sd5i`Yk;{acGsP;@368e&g<;I$; z8&iBnw{G2nTo9Q1<{S)ob?UWBYCCcs5HSuBy78GI*Vm!59l1s$!7~Hd*>1c_f`McH zIPDrnh2GBL{Vz>?Hk3glY2jgPD30vYfbu{jS*#HPQ6fUegR0XL4w1ue%bq;RT0HoW zpAm~-6^+qex?Q+6*RQqkZasjzpur({n4gV(0K@_tpzeV&o2sf*P9(3uww zv1hasFHIQDn-9Ic-@Gi};W-ysw5`=qu%tA=@*(qcp=_+#9TN-xjgJ&EJUGRjV0mKJf+5iclCSop^hm+X%b16>NoJl ze(YWDtIz83jN+Il$x8%{w473=?IB~yRe-~1!Z4zr=lm4Y2V>pw zZe)gh*oNii^oC{DQ-4j-m+OcdeVT(!%5g^E=Z!gfIuw!97ZTPMbD-PcxM+WZV z&gKh~{{5(hg#z*G1WS~y5-}${aL(wGFJtNik2}ROFC4~$l-1BL=angkCnkK?mkg30Q7D@=$yqf%6lVOo9Sjwv&O=X zXD-?|b=y9uq1sPX9FQ2z?S2(oET9_q8yg#fxzvfr<5l`r*Vl_pYKCfS%^M<4Jdcb( zp~m%IVooh2&L&z^;1ofh*LIZ(O_ zAUN@~+ul3-J?4d385?ih9GVZ`j#&%` zM-!a!AJ0AknKg5zX-LQk(MYzxN4%!c#EPC=TQ**=kHfA13THxLVPOnq_+Fun6;U$K z&S}*09lw{XLDIx+T+DjIrz}k^M|Jwa%JCj<)cE?epm*eE>e^3(yf@?IeSCaAe*DN_ zFyM1obfQ%`q|+apQK7tQr20D$#|8VeD@D65EYJ6sot_$BVAVuvX(CDTQ^S8E#tL-?iOG&cCm%y(aW)pV8iv!J2oj)(-JJFzItxd>dO;+Nql}dm=+6m*-^- zBF=B!Ra3KRom}mKNJDNukqf+5F|Qu`iXUY7N9t~%mc~d9h-#Ea12RM;pXD=$8_}bd7hyBvh)kSFS`}8R*-3T)7Vy;3Q zNF132l@;5sVS#~)H*ONZJMQd}H$C6|MtL+yMFS3sBBL7Tk?-9h@x|Kt6JI{%XUyHJ zd|RmLA}w7hic?^KwpCNC|6QZL)#+EdFJ$I`{|v%-V3G_I!{G1~8Pvx2`Kf!l@%o|i zoZ_|}4gLKpLeE~jXp#5Z&@Cn^si+j06sti}))+^l@-CvV#JO`yt_Og85Ls!>)d@YR z?go8+v+lKD0z?v$5>QeOrx8sHXLmePR+nQ11qRl=E^oFkDBPOP=KOh6`e)-@Tgtd! z#3A9{B12~Ih>HQ|?BQ12K$+e0%tNcQ=gvMa4H2oCueo%$q}M3wWej7ygICI-PssVM z|D*c;}9+_5X13o%_PHYuuP^~58?ygcs}(VzOPo~I2NzqIrsx0GZ4TRDPHObdJG z?HW~mg-2p;4`C<{8jxT-?Kxv%oLG2N!7bv4q|@Tok)=#QJQF%fF{&%N-~ILR{rke> zp5jKbNKy=ruMdegJyfk6FGQ=WvG5Ymmbemrt|1v+|Y4=*+-CBdxjkTbX-y zEE=uuNy5SJGhTz-jI`KT=5#?IX9a^cIzzO@ zVwe1vdC3y1!>JUhExkI}cZ*gsAouitAg`Zvw8 zvEkHvv7K>;5AT^l-QuDS1=kWa#VtnOr#Guuw;HX6CXNZ%hk!q& zf1{vxSxyb@gxi(qBi)?w9Jgf4$fS4c4sp$u#fI9^#DTZu_y3eJK`!}EGUiAm z#&1){ghnKclct6r=qeml_*W$}pOiQIA%jA|g*f766`0qHQ`wQE+hzfhB|Og?y9!w3&&*bGDfI>z$*OdCdgh6;4&^yCE7boi|p>4%hVgF zNH@x|y;h`%tcldRKWk5c3r|tml?x z`78CYhVv>tL8kdo<}pYRR|l7f}?6VSrFhguCfV>C5F z-W%_k<*2lHwH;YsGtF`NBdu2yE5eCIJj)&mtnfE_whBz zf?zgr^4%vwBXgUJnmV%0Q>twj^_gH1@elO;@ z<|edX)Y>SAKU{mh{@8fTI14J_HNS30LA4ZFuTyWv5hhmz<1yX@0yZ)x+3?H0WSi~> z&??e*#rHb)FTz|*21FC=@(hjBk1cFaUa14Iw*#$(rRB%pPQ!XKC%7qJMdH^PG=_C+ zlK0WnX3(e9i9U;??KSNzo4Ur%$?|59Ewg>)))hK z!N2miFe*6~T2Jb)#KmX(Nyy5aa_FfRpp!&m?@P2;Sy))zw*>EF$sc>Q=b(SdT1ZV! z&cjyUDE-Xo&$OiW7;O$CoL8Wq;@AXCk;1(_#Rlu$Kewx#(RqI26v?3w+a;cL*y88+8^)^iuDw+I@{WoM~djTgmZAxCC)#Bq3#~v6#60tD^yM9(_n(oe_lvpq}@tQ z{6cOPCM2}H+@ncK9)ien_kd@k@7B!72S8bGJgYiXxHkitlgV3Qd$(8;MtqbVRc`ZR z)2`WV#+ME{$(^{MEP|rEpo7#jCx)8)KcVNJp?@?wydr&^vX7S88olbx23-X6xk60j&ONqq z(w7DaKntdT@n@H1lOo^x@^r2|U<;)1m6?h;Y`072gy=@kK>ihM56g4kWwc6cLE%{~ z%}!{i|MAywIlj+$LOx&6tcVt=)+#vE)T8e zW;Qnc)R8vLbka%<5+29Bys}33U-nwgWsSw;?bVLyh>~MapVM`V1C^|eY$o7VgN`L^ ztw>hyB=JVuK=A{L&x#1QTH3CvqlZtdH?il=lTJz*+H5E*3wg0Q*P#9oiei<^l4*YJ zG~ZiEW94=Qg$S+-_dfa<`g|N2&F1N@9#Xes+NMRVJb8=({H(F&<3MpunFCX2`uevL z+ZyAS@tx?y=M}b2g{FN!^kiM$ArT}yl17vDbNY5m0pS(Bk@K9YzN%J{L7gU~}>}zLkx3C0xdhKYNDc?d?rU-fF3vIEr7R(%s45^TVLgvaa|eSLYmT3bmTy4H#!Q;?Gt_Ou0y zs8YZ7(t7#K0}g@W@L_-g&dj%(p4sy19(sPBby>_TeD-fGAo_PE)ZeOnV>iF8Hl~fs zcCL@S%APp4cJu3RO77;`@oM%K&#n)W{q^I?AJo$zAH(L2c;e9)2q}Jgk8w2p+SS?^ z&B%0Fc%fejw!GunpNCN~qt3V|WqoB;DpW}JY~#M-eV{FQS5&}@giFF=!m5t*#Wju^ zf_pug-G2Rn?l#z5^^e6whOUZD;>ZPmracv~n5?hWdgk*V4<{}IaUw-oFA;42Ef2Q? zMv6TK=#;#OEo3YG>b?nHH%FZ0d#Hh|=VYBcVc1bM{vF!Mv|a}W99L1_1g6xus70i+ zr2RE%-qpe4_mfO{Z^ivyIKM06-a6FdL?6fGGJ#A4t7WvVaz9Ob8F+kQ^hu7DQg}-sTh`YChgq7$^#BOy+4Ga>NvQYSJIm@ zKXqiD!i`-PWvsDTm)VgBxMregX!Ljb7bz1BalQo;Ki_v_3k3ys?%LPK3Zd=IMM=<> zecq`m&Kr}f7vG`-Z|LirV>h?PvCLOO;qoi3+JbvN3ERs zkVrAu(y?;R%Zahlqc2sNH6}xA!6WZ%IXM(SiFCn1lzY}#7dTiX5+NwMC7Ch8N06PJ zmxcM&MX^%;7FETEJ_QA50Y^TSofV{bJ@*4XHF$k<-a@r^CCDH*#Z;&O;QMV0-0b5w zo&pr1JH#dQ3{!!%1+F9FOA-{Cnh_?HI&s3|W!mr;BNV&xXkRu@r%22$9x=*%<*vAO zUg@v-s$V3rxuX;UduWHi#FLd#O*-C-^npkpf2c*+TYOMiyg zVotebrFbFU&@Nx!KcheI@i$aZCwX}S`}!b)^ea*-ey-pwU5jwJN_V1t<5RBA9-M3L zq4j@A)hCZyycBh@Sux|eeqq1nZ^l(lYyF4~L!3kOZ@uqUf1~H*!!-p$?Q(x}`*f>d zcGR$p!%{??!tKMN23~yPx6aV}F@wqv$z2&VMf0K3(sGUG*#pTTL}wLd1m_lw`;z!!VL30$(OMz{_>?yTN^E-uDWr~3NZ+8K*cGP%Z& z>CMg_e&Slt>6=$c^Rc!kG&{5EAiu-1FPg^9+YJ0UW zZ7o#&GmgdR#Km4zQoaqUcN16^VTgNb@t(?3(0~sRH8AOO0Ii;$nLy{^mpMfOQiyb5| zEKko+_df&nuqz-2r#0*sMI3m85B78<@?K(v}`E{y=+v{K!|YzBboF z-_=o?ZZvhTa0UiWKHp1%sRVS^B;n0?u{1UQ%(nHJklYmCft>kXlX*dm1rT~`ay_`e z5g-zW@oilNeokA2ChfNJZP|lPJ|j`&VEF8OVq!$2TRY>(%N@fXSHCX^$O_4qwDy-*R_XyTX5u$8{dy>LOoUt3Yq=6g#Na^9-7t8> zulBEJw{6$SyAK3Cxv?Hq<~XZW`PTlH-QbhPv{s`xazG-@O~$?wO7uV0CqN8;rp6mF zIPf80d&44!4=rV@ZeNMi(3#*Br_J_knA3>khW`z&dZQm>e_K2FOh4kl{^+dIKR0xV z%31NJ2l8$l0Clmy9Gdw`=z}^u-{q6X7WufiHh3axmctPUgEw>Fd+$s0XM*lkCx`u8 z|An#ivfBEA_W8oe;M11m`;B~CdwWe55TU_sMjlV%16di zq>2Ch_+*TkXPIJr0u`@cLofcBnM$D)6#saFuUOz2%G<%- zAzke`VKDgI?s%7*o6DH?AIl>3oA?t?5~EO)?HkuY90e9qVFo9a<$QkloqnK5R2Lm% z*Dk!#eAGQ2DnsO#hzn6;oDu~q&FmrG@{BupEWARo{5H>ssvIp}pt>CjcEl%-->KUG z&!uSME|E{mDSkHN{vVRn%ao0ka(!m%UsdCdok?W-xyjF%mYQ?z$n#e&76Z@=H=J8@ zUFX@lfk+%6QXczK>{yuCjdq^QFy zW^KM~RKJO694cn9ni779GhR2LxG1-USK7~edD8KMCzYhQ&^r{mIv{0 zlb(0#4Fe6LKld8vj#`!6!QWe(aiG(v;PW$6;>h0`OTle>Vet5z@eU(yqHzQO4u~X4 zzowRLCTESE<;N_GdDy)qb5OG$OVgzshecUJ5)yxlqD`Jd;CZY}b9uG@K(sM0#S}J* z^lQUh>sJ$R67xjyQJy9cVs&4wfgNvG##RFRu-}Q6zwpjjsUDnr^K0*XuuJ$!p1zo0 z?#w#LDfg0$Nn4Xb0x1&S-CNgH%~R&V^&u*NddVCcgNT( zBaxMvS$b!p6b&9!GCsaY6D>8wEhxVY@CWcfdx)L=K9=wv>>-YRt2b0uYJ>M)td``+ z)~}CsEph&#_YQJ^tR?vKDyTLRvy#jT(|kr>xhqOko%z-ScG47hsZt0=d0&D|6(AnR zH`ze<&oATfroBd6xdCnKs2yS%Dz&lJI#Gy~+^E!gn}0A_)Uf(w8d;~P5SlHpiNrq5 zKX~odAmO9?q4g$}+`n|qoqLvhc}4%$0zy2g1n0EmF)!Q9n<6**OJspzCBp1uwj zce}0BZw%KVzZ+s?0$j?~7v9tiC5@;!8`JixvMbfDxySol=zbNJR3!%ubhNbzfaU80 zy#BHNDR4G+V7H@MTc3pr+c|9w@?-cmWzVvI%AQY8)5iW)_LN~u$~YEAzlGjl_NHlr zA)#V3K>qsB&K-LOmV5E`vdju{KfI2BmD1m3(aZ( zU!}8khyV|mwA}ch&l%XoO&`T>s`ig%gCx<9KJhqoT69Tmf4TJq zi=JOLHBD<*d<;MNUSZy#c%_}YY3NK?hhOGOtvMnU2k8X+%oPZ4EE56(d~@5^@6=aN z8drV+wh+$#_$T!D>B8V8fDu)dt-T$^A#B-r^9#OwgRdn%0DzA|lhV8E*%0`YlwbM@ zfqvX5H00;|ex{t09}Re9Uix{~N?<}F2qC3iW$R3`k#ZK`6e1T}bSvZCqocIkPzO|0 zT-^U5J(>bV)(fBiMiI-y%}!JEc~pFf(awG;LBYvl0^7mXPk#OU#R39L?25bN&hv7l zIjyedDx%zkim5Xif(i|7Z3?a;O5{SnnT)&`kAZFE=fGht4In-%I|D_(*TYz+DD&fZAnmW5>8GWp4h*>r#&jw8MzQR zGE3^pSpR$d);m$p_G;(oJooFL&RL7+kTXR3u!wZ+NkId|5;)oBA1_yN9}p(~EgmlI zI=w=%QHJZMNDpJ(Ejru1VCT8Gi4(#`lu%I7VUktZM-UOD$@>TGkB;IyN%bpOeiqb` zf`kH8R)N9*GZRI=8N51OLHQvYOHXE6zpB}67BW8_3O(;Q80U+*>1#;D5D0nhpb83T zs~9skvfb$rR|nlrD0k%HR5klEkm1Kh7=N&e^XCYaQwFI_zl!F z#O}NbqV49j`n@s|>H62}!}+n=IpQK#CNRk-3&ykkFslvnJ@3^hg=p*tf^Bm)KPkGn zo?DMn8l5cXvYgSQbN3}ckY2WyaUi-=EBOBi!jhkCqqR!Wl-<#6!>FM=2 zBX6rI?+JgZ8Gz$w1*Y9TGchnxvX#-`)O1;y5;ZyAwXOBZR!cqJcDlBjUz2u)bP?n@ zeRyP{0vpJ=f;-%LY_kk@EWA%}eidA{Wc}8&uZc6m6i$-f^KkH6>uZL^G!iO(m-1?j(mzlY3 z0^~)MXi(p#F7nRt4A_erSWj*WD7|wpj^%JH6VfftV76g02Gnk~52(uP)AirpS9bb0 z-?_Y;T+r^LnG6(oI#fxq;azB`;wSIs2Wh&r@Ah1W0V^2ASoCa^u*DzXdO76x?7Kse zTF225IFv^ue% z(1MGi|H_kgbWftOCpL}cN`121c$_q`ac3~#C!boeO9R^q%k z?D>a(s%9ojp_-9JY{5;ikx-%Ts2qz$@^G7jcnq-egXh(CYXU#02!LH`c+lhZ9N*0q zNd6bkPq{cX-2S1Pf$iV92)*+89a|4{R(oc8kIFrGhz<<=tN)F>{cuYsdsve5ZpXq4 z$Cp1699ho)wk_y?u>I%%;D7Q`=;l;cuGYrJ#)l6dRII%`Jy+M()>c=4B=;WS9Nk4V zsIXh4Qni{+-QzoZwm>~iVe8xZ>1JKS$Lg*zfks_e2<%A2bIZ6zz)J)i=HGdgl~q-7 zXa(N?TPXB3DK#*M4|5wZkOS>CrlzJP*7Gi$wzfZ%;#Bb2`}_O<2-(b!i5ru0Ux9GU=AWDQPw4&+ zT;rR@R6ka&P{)zww)YrgR7v{$%IY?srD;RDQ8trx_CZoiSDBTux1hZIweM4;a|mIy z`?*VQwEo-B6T-~e`rR^I_0G|js%*h!y1ud|npKdn@`A`Ip?tNRbQKW!PC?&qRTf(4 zZ(vz4oqnDM@4GvPByBlac9c&#aby`>h5oF7MjO#u;-q^Kt(!w@*UZm!-_Z(Dyx|Ew zBkXl=t}&C5)<>dK4mx#s$`_1rg0y2Jh1|27S4L^8&wXxn|G;o=d!y=YV<9oxaSN{n zBPCni?lb$jcnat+Z!8=HkgTz9R1Tz(S3|?hbe0jn``ZeA4;zfpm*;sxn`R?r25%! zlyCtkJ~g4#x@MiW4Th~UrQAk`OvoRA@lClc0X)06{B&8mL`bAd9$E&4ZSOHkMsnSU z4|qjP7?^qdVKwHs$r-tmHp9bT-}WpVtZ^Jv@cR4A%{9fS(zJM%81gc z?#)@VFnB<%+=lUPZG}_nM_^Nq=Oz+7eY02h)0MkF#5Zt_MGalMR@=*{@FJ`g!o79` zhLq3@Pv3CE89k3lNs%|DSk*8VEbzbfhL{71;Ew@(=7t@5Y?=EKm($Yy^34cB{b`Z# z7gd`i<)|Q4(=B_i{od_dVuQL-)btE<{zs~r#`p)8@ML$5A3d4?4jTDkf4h-h1R$H6 zlfuZ};}Txha=j}h&aZ+VI4VKE&wJ~oh_iRkqzP+nG`@d+JZ&^(Mey}&G+ms!VY6`; zQX1Upc|K=s5KG(ct zmhjsvH-ikKvAPY6xGMIB$4EtOqlhDU1LY&*dXAsR*vF;7Vpzrcq5+lQ55G*6vN0%Y z7yP>ZxFJR{aa?6m$hyQz*KEr@^$F34E`=7+Sk?~S-La)gTb6H;xkY0_Om$cgA8;2x zcrh>v{zs|Kj%WVs4ZLpg06*FfJtpZmkdl-%(3GuARFFp(@uWrMa3VvLKQ4c$tw(Q) zYE{jS1o0;pGSl>TD{kGBP; z8>7y(5FT{$5o0trZC0&O=N5>>0z`1|ior;-s_L}iEaGg%)BVp`>~{7Aj*9g;;jSD+P{ts)SXo=|hs7Ju+{+WY z=A*p#)hf5lNg_oLnf_x*-wH5+>!O$pqH!_k~ zgnuyHm9Wb@AB5nhl}FbUskq&n-QH=%C-j~C86+?}bVQubjY+uQ?EH$Fx;Ru~%Yv}@ zkeboY2^FRD;#C82`?>Fis#j?M6URoq+m|S%jm7BxiXP*ik(C|C4dVZmrIZd^ zb3!qz${h(|M-?VIIZROgpco<;jDe5E{zoo;9~E53?c;LM5(178IwUtOmBXFe+Vpt1pI5w*mW?s3v)+EC?r$|st*mhkFVZGGT^5yjdo8f=A zf=|@hS>28~7x*8cNefp;f;On7`Mm@jr*dOsAlG%@PnU~K7v3xa;+e1Q{$L=lG9Z9i z5^Ys%ylcmv5YJJ9Gx1!4(OAr?8T8x%B1U3TQd-#`I%NY@KOj2maxMS-Vo@8+ZJ10V z?dRka<#@gMbzBaFMGZCJA%SBa@SmlDpu*=9G)sUByX}NnZHWN66Ks2&&Yo@wQU6@y zzcv^+@U`RsA_c=}*1NISA$~!$+ziTXl99{<4uy>e$Q{(lUqqF8iY7;j4yxN38ow+y zbIguuY8I7aPKMz$HF#yrz7HNf;4@IJnf-|!Y#Zy1c9lnTIRvfq*-wqB%AD%x6wA8c z*TF^SS?kFMW+lp_aB1J}qY8^2ZZF2@M4fYy9o{E6N*$Oz;7d_4pKCxa-5kz-jc!Jk z=V|Zk$K+XR+t?%yQU0U3Jmhb4`6d7vC0+ik3`Ewn_T&dgD#7wnu7#h@1#7v`%WH?$ z)dj=2;9+?s*tU85ZDN8#F*2X=&>xPy=nvd8ivqR8dE90J@|yQTbs)qe(UNaYQ_X-h z3}Jkt{DX!g)6XJiF{P#U69lE_(=Z8oy9{ITveI(;M6gL&bO>zF+(jH?&^9YO+q`t07)oz`5LJTbF=UyO^hc2vhO)zakeC z<3BgzqV@*<6I>i_`=wG1Y(g*)wMMLTy$a$iv+p)MN9Nsq$@tDo1mxwi@wP^!QSYWH z4*6T9k8HPbyn6jp;bW0&^Sn^TZ>#ivRM4kj3a zM}tk0&liu$-y|J3RZz(I(PhiJ!VTys@%MN*Je_ zIJ&qPYY#Sce01st%l@WW{Q&rF#E@%G9uIMR%c~>w?Y!m~q`T;lg^`pLQMf@Zt6n-b zRj6|7mJaXFPQZ`;sBW*nl+uA>I~Y%=z+t%x?Dl@=JyMWN4Esg2t$o(J=PC**UJAsL z#9HuaffIT4>r142T8`*bJAXd$7N^52X8qs*y5DsU=Bk>9qzpIF!d$y8v~Wqn53EzG z=AB{C(zt>zT%6itkQ5z_n!7&~G6jeZO@|N`c2v&p>MgtEB}1PJ>!UttzIVI;ny)_& zG^dGHzmkv& z?$f91j~CkrY_VoeUH9)cQellyPYScH17_TY>^r&*+^3sp-LsO)uUM|WJH4^knUNyA zO%ThbPaObhZ(IL+#-^pBXA$1onamI|(^Lbd|8Bj!DqkS!3ddo+A}~Gu2jC zMixF`9O|D8{@%Gh6}bFJRNl(UmhY?Y*gNZy6`i_zLBI3PuNl^smdnetqDMF0gY5o% z;@lGD+7A{`X?LlV14M6v5ro=UCb|^I#wEQK-;F~1V6J-jSL?1oUKE$C^Qnt76*7wk zC#pP1Z{R`byC^AwKUing_#PUy<2&TU&wh`UQdF5LglKzfIsPR}HMJr)<+F6NM3QMS zTQI2~rF5)af%cN*oG4)}{+-av;mfSW{~A25RpVffT5qyyH;HlhrS(QdniQ3f(8o5O zSnkXA>vmikxm?0}(20ihZ|4IuFblja!C`BcV1rJl=w64RE>#h*pdS}nho;^dM$}_j zL2QwsRFUC~y?<4?XQ(&H;6$cP^=LSbY;T37iRDHBsT_Vwt|iFm>)%s~8>)7X*E|Tg zx6LrZed4j^8HoBdz`AUXfBE;TJ~POh?Y(w&d`?r9KH1`B{oS+~wG`Mc&ql*!kA!+e82yPrS`*{A~pE#S~uJZG`B;Q0cM6u59ZC#neMEn6f$Z8Z@4!4 zmaLFo)gznPhx_)Jcd@p9DA5k$! z;EjljbFjBZ$HYA`&h5YmxqbI8zep@G%D-CS>|7+ki~a~3o^594h0;!92CK}AGmi>f ziP{v!oOqA)okxLjn7;S--|sZtl7H%b`Cv4J0W?yh#xP`x)|q>MQE_q$|85(HCin1! zuP@bD18-Wp-QS<38Q)`}2sm`6{PE|G-v)k#I`N!wh2}||rYR6|*BqW`BMZO>Q$%@h zur}Wg{Svu`s$UsS-TWvIeUA1;{K?Ck_U6rb1fqs^Or_6ly5q*)oOJ%I4Y@TY29hJ( z$r}%cSUxEz>F0mLa(gZOQ!_LFNy~YclKx4{-OW}@iR$on+T6jy!^5K){nz%LGkXsV zGXuhZtU!M6zn`42r4asio5cSQ7XJQiefo<8vnOgPGUH@2WM>z|#03Wj7Z(?Yhlg(| zst-#p;Lq1sG#^GF5NNx{5|BNxwluv3iv9HG-4|zDK=q08ftqb?d43?{8k_ZLf%v2( z&OiQm0}qLGOn$yFZ7WXsq4R~eRufDnbKD@Ry13YJI;uK?+X5;5bon7X4nO^LWFKFC zOa5OXl61owZMK;*i~~v%d-O0YqL`YPDKL6qX){Bburo8${35crLs=yQsunGz`fb&a zr`3g6eiL}aFq!6A(V3f>Olt5976(6R>h_kh`4igRm^iLUbZ@Xpl?!u4TNUCTk2?Ip zvoAI-)zsX69Ig~1-~IddNsH7PD1bCIU4VfB|J(3<_m@vupNym@MGX~vNms$WP@kt= z&54q<9(?oM*8=@UxV;a{S{Tpo9sRz4kYLnbVM7Az*GTs12@xn;QH-v>G~KfiyqTN7 zNAW#cbI{=6AfQHP6A;}_D-hQ5Qrz6n#pOBaYGn!B zKX>k|N*z3Q_`+yuG004v@CUb)1hGZ5X2A`QO_t%j1aub+srm(6Q0sF2zTdyCfXk%$ zUGvLG$C~pCxCCk(XQulz}FNXTvPSV=U>7z)}E&I6vXqJe1SO-yI@-kzoUc0DQ$-xLy!*LI4|!( znR6}P9hc{UVtDm9LgQ$1Q3EI4+aTdKk?3mUmlAXabEPvG|YIi z03(nifGbF2?JB$mNC59cydY;P`Z`wJ<{tU0VpXaF>PpX<&F}1v%T2um|1VwOWDDm7T+Qv&1x|923_7aL`; zOqhAM`UE=Ix5akZSf6=b|F(o0aXvn+tL3riKnDo}Ti`c=nS9F4MD1GZ0n+vYSwUN8;K}yJ92?W1g4zxiofpsfy&9?I1jC_K6MwqvXqs$nRP=G2 z1fG6(DLIy$jx5x!afl$p_(7g}U$nMd3&B(F zHnL<&W~lF^^#}Uf4T=!$4IuGnJ{QAG*IiF|c~|9@$`Ax8k|>&UCviKBWHIrdp`6?D zm~H(!Q3rd$)c}wko%P2AB!5yHoVDVMR;2|b<^#eltIs=qgRTPtYGutyy6Wsl&XzAe z=Fy2i?z`kUG&-fJ;dqbu$`2=lBn{F5E<`_BCbfs;rtX=U*~8~Jr^kvXbBreyl|w2) z*G)+Cq&pmM)WdHAq0yP?0a@8r$y-r&&gVatpM-*J?4v+Tkaf$M=Saw zY7#I;6%7SR-~mUR8Aq(!h0}@WO&SU|d#9fw0JN#obWH^6i^AfEomL;m+CAp_$ur-V zKDw&Q^}h=7wZK9$e7Qe^4wlC;Y%|DQ7QccH={`G#n<@&oj9`35AcX|RkPA;?1ABo< z0go)CXc9HzMG1+OMPHIeY(^nn=JB$;yW|}L&h%II8`K3BSiPF@22AkH*KFX&d*+YS zf*bsD%6$86tFmel_k+x7F^;CUAu7J2DTbfHa`xld*>UQ9{^kA8M2#wo9vGuvGZ4~l zt51B|6C^hvWc4(%_{=0kw}J=We(^0Y+OBBta!9D($+o$n=7R0unEd1v@CJomfB9|o@!tJB&Z=K;nI6A@0^uL}zHoJ= zuA&r}tGtg-<%V^URoLtGpK?PV51}UWD&GuTD6#0fG2Zv4C?O%iP3j3qm%TqSR_kuQ zEWVuYr^gHO$gx5L$!>$#h?h%{??oqdqs?WdbeYE-SuC8D{(|r&BZmv zpOO|vzCchc+z|dXHYvt05geY2-bxSPCih;M%M*$G=mN$Jh#9sYtg?k5gVS}?AW8`e5*Axw@8i%xAtm zFI7ysCvkDc!|nrf-`@`uJ(>$OYPkww$xtI|Z^V?%jpv%A#JP~RP(7UG9>v=8#U49j z+Ti_~J{NgJI-M8|XCLGH_$)L6RqfIFwbOuvYGjkNlw%>f2^8_0ySeY1X%;AonSCd1 z?*e%&R`V!mJmk<+xD6L4u%ilT5*pmp|Ha;0M@8L*eZRLN7NH1|0s;ckAt8+j(%mg0 zCEXp0fHX+wAP7izcXth)LpKZzJ=EEX_wzjKyw6%E-oM`W9PWSa1^{Lw5BV(;0y_5Al@N>wR zvh6R#6x~2hkD}u6iY9qQQl4~uM`SSEA}(5`t=4A4Vd#581m5bB1aH-I@DjbQU;j4d z30Y4wx|ewx8XA~j8^*}&@I$zUT7^B2*+J*g{vqdE5J)BflTF-(-e5P-IhXX2UYhhF z-BiWL1?#P=-|#&;laY}DlV706#9|vxz=8gA->G1?nn+-3=?9lCeH}3|w$<`SFyk}o z!=OsSA4eYazl4ol&+D1hxbZf}^BBrp*i(Bj)NiuJI8gNz25(IbHMfe7Axh_EIl#eU z zRV!uMC=228XH*A!d$mSKD=<}_EIk^BAqC5jIlA>fAWrP-na%Sor~i@z4&-`Pmzs|A z7-twdJi34af|1hk<2`iF1!dFU;W|8yq+$d-y<_bfG!jv+1Uxic>0uV%$i=p^8g_;4ZM1f}t@3VEm@H3(4*#_Uxk+U>rJ14p7yuf0D~ldhiPj zyhRf8W*ZyUZXFmq*6l<@D1szC3t;jc`IkNojh&!bYUDAVN$)dn$WT%%t z`^_{~i7(98Oflc%acwAi_v&^(;YVi|m($lC71V)HEif{INl)M56Q`O(MZhyWak$pM z_|-Y9J*VXqdsq5chrD=+slmM7c1;G%aYOH!1)TR^v)#iu2|2jR1SRNvY*hnzmYicIimmUXC(l@9%o@ zW!$|FFJIG+{M^tLlNi^2LWo>@Y?iZh7q8QNSLz&g z*Zp6CsaP9%)x^Z-J=J{yhGt(Zj5;JQlfPSXU4etlrH1}&m0IMWn6FB*x(B?GsT)S} zFnQUV%L)~~o_SV*{Yn;6lj4jv%P#V20|~^?yO5;##Kc8_d7AbrM*4obxLpb9;|k6 zjv!a9?E%b&H()KD7Q|n;&&$K>gRt~7cV}z`r?Y-je=w&3ZIsvVy6N0<2BJNksl<7*F&Xu7AXU8+BJ(r=0>!Xe-I0HF6D&Q)`tbP;S28*3D zTmGThtL2RYaC6Uh82i!EP<4+0a&LA)pT7=7u72$ggB}QItXAW?EsgEe&fNkR$pCvW z7^^J=9|7YloR0G3!MGzGQtk|Kec39@C$$u57CqT(kljl#yMsW-oW?;OE(Ip;PI>-$ zfiJ1ja(hi-i&xhkkJI*$IhTeq1WSub2M%_*V6>26KjhMSTE$V<4iXVj<2-F)!V9fa ztY?A_Z_efRjLBLE-tsj$QRC4&A*4+ zued}k_xR)V{d9CGuywSzMxNE60;7LFfWICdjYAQizQ^=`DX5Q~`e82Faxj*=P`Q{h z39|lC*JAysIx}D%Q;`-X4;a1xs>z-c1<9fwAe$m<8AESUu90$-N0$qLu00W&Fn|4B9j_K>p^9%zx3o& zO%2;V;`g}kT8A@%gy6#UH1X{99BvKTFV~ZE5=fo3gCY3O;pB2I!5JHiKsntZaD6@YsK*G8 zNki;07Wf)!z$)e-8CLH>qDJhp8XgCKP%{wR|Hbc>t|!<%Mdc9B$I9DW8xw=)J3BKo z0%>o78RZagDuy@$2O z#BEE1SF^o+!C7JCzrRwiUk}$9)?3V0Gia9ESy?^y_nItvOfMm4Q(RbxKLv+ZR-R6x zseD^L6!u_ptYFQj3J?B0#bCetXo@{M(vE@r+n+CVqwjT-HQf)OG@0%pA4C!lxR;*@ zC{?lMGsKS^G@L)5Hwi=R%tVYO3_3b+71P18c8wgCPYK3T8Btv9asRw7;dd-Wn0q&W z-8U%_guR#1_lgXPKffk9l1V?7`sROGK?30B2ZX77^^$LXptF^^7yI`IhJ_V}@9TW? zo#fap%(6G%`tbw)s{hTmN};##-h5}czuy1ee`$nJ>~jG80H5{p`bUrc-o1N{j*ehR zmPJza$iUcd|EfI_Ay_@yLy!HdmX5?@E*uI)HMQmLxR#k2t!a9=z}E*!h}ABd zJ`#ebM;C3TD=dUQJ|eX)*Z~p&ZkScVi(hM>3ny>DW8YZs`9HEEM{q>aL zPeichlv2~m)gzrr=iB_XAh@x4j{Bp`|5#945Uf3X}o&>++^+O}o0K7Z$JrSa5N1l|8K!m|gyvqiE}# zb;TS|FQsitH&A#daRUGl`m0dV^wIqPOEJnD?Z6p2m<>PU5q@ceB()mzXmo7VQvN-km5(_;lDuReg$MV_E*}OQ* zRcF0csF&*d6!i?T926MH_Nw7F2#*-cj33|I?D51#=D)3YBZg2bDozii z$iF@|6;Y~mL*npRwJzuJoY2SynN-^u`?JSYIF&vB^HL?)BFy5hCtt7j)wv!hv%pA8*Wh{0^48a`2Tw{qSIW)~J-%rGsg>ODF;8hI#g*8>iDYle6Njr-H#DT1xtY_=-ci#9WzEvqX8H60Ptg~6Y_~1go4V}k*OmzTtm&fUL zsPUX?ezRbSXT;cS_;NTDulE^GiYj&RfyK?sLeLDT<%$!@tW{FIM&)Ljp&bOK6STQO0RKc)otG zSL{spFsO3!L$ts~#Zy;CxTj2Kfh8WobjiHLNLd$$mTIcPLLpD$ET-VC4@sEEfOgo* z#HKRs%TUiF?n8Ywr%7m=qlH?KaGv>b#9Z+?S|qJ}>m&`NTT$#(nrIXY5qR5fJhaw> z!ZmM(YlrYEe<9%VNgEp4nKL4QFQsL-PE;tlK`MqrdJ7lhDaF3;hgW&@45Li*1M!rK zbG*fO-INx8@lx)DfxO;-JclO7U7a&C=;l34x^-{p7!if1A&=Sbp+oTT@B~sEjiRtS zjrw(cy*|ZIoc9NlK=HHMZ{1Rxh9Xb4UmW_DpX}}3FFn9>uvQ>}ko$#|PTpGVke%r#t{2vr;~y7jV@_XEPkG96uDL%yLKQ zVaEgQCJLDfK^@c8Q~K|^BcnHom(b3{?>I@Nk2EF!G{#aF@Vq7Kos4>y+9~dzKgUlv zrdgb<4%B}J>`#m5LQA$aD#e@LB0XbtCx^bDP+vH=Zum>gR>jyvu`@Mz95^gM?a7B~ z2XtH0-tH!5UB?+pR^x8WGBC zv4JH18o=|2KrwW<=;5G9Wm6N zmux)#6hYUhoQ&LKF&jSSBV5Z?syCBy9Zjg_G@Tw6I%n7-Cr=v@)zHX@Wwo#hJg)24 zt*kzo-*+j?$x|z#1d2_6ZlGFo z*j8yDO{rP&sgG*ge#TXdmZnsopx4))qXhut>8hGgQWbt^O_ zC4C+uGtKdTSGe%|SXme2A$MGyVuOykB%OOcwdZz5)T4%*oIl_h{fNQWuI0ILqb;>c zH1B`i4#BLeE>8f{w}PsA9#g31Pe+rB1a#@&%hKHlj$W3gTLb%G|5oFWq^d=0M~6Q4 zUWF?>yf=<@EJrc#1h&IAXQ4ei?O4nV;nybAi&W_&B6)4IIl48t>n_@#$U9SKCZ0u0 z_IkMu?By0`u!@S3wnBd5AxVCbj`x;ySN@-HN(b;dA*$&af~fKPs`;~2%YBHf(R`2b z_5M0P?{_l(fq@0ebqbfwr&LH;_DFg5r6|yc)va(VZlFIU4-<%;RiYMkWKtxeAD8atxTF1%h>p)wMP`%{29el7#bgKeLrB6e}_UV#1Q5K4s`$DoewQ#;uUDgTDh39PeH>QTPVnd$(Q>gOoy|poQ6bY zlSM?+2+28BG`X4P!)psp!AbJ92%JmB<|nsG)8TwhTKciD!nT8!jzV+-XqlM?Q&YO0 z{`KxFR_0SK6_c)7ac-FuuR`WY3vtVB6SNy0`^5L`Mc4otUUTLt4OwJJ5-%P~zYLgJ z;mPYZBlY#;isnjNM~CMbLZovSrQqzn;MaW3wC)Q^Q}~SQR~qcvKAnspf-p;%=Y4E{ z-+u}ejvg}#DC=}u2qCXQm7Ai95`Q0MhLnkce0+15yoUXeZ~lE7Eu~MGIIX9e$1Uenz|OOhx)Jxv zpwYMJ(sI#&OSnwk zr}p*p-0YN5Pdot%xE5TiDUWR`!Y?#|0GlW$wphL{-s!O6JjEn|1PmKf6-G`>3;>gb zIkeh!ecG|Jop_pUbj==(d!=P*hv(5(`OWdH=oSv5u^&d)ESwgz%0Z&HNm*S8<5%SA zen5j^rIV6Kj3j25e((qM@`_Yf0`x;t4r_3jEWo%E14I0|?0ReTE1HDn%smd;?Ui-h zk9>)-!sYKzgSE0Gaze`Q{~62M<)O2L>a`*l(?912O=;9Z9$nslCHoznSJwsXhR|oF zHh2tLh3ZSNrxc=?yF-NrewcY|qse7F7)?rBx(kT3lWiy=j(u)8!SH?pjzMle5Q;ny$O9ZgPoo&H1rx1u2s_wD6LfLeOhE1x{Q zlcg}p``~^g_x+cPi)@xi{HXp-Iin)ya}snrsDE?}drWcy4W!m>IFYyq=Qycc{xdR5R2$mM)OW4ZXTz|Rd+8DlC zjkO<4+OzG{w_$vu(k9G{U7@%;nwB8UG=M!2czeABi|s;@~LB z48k9*u?3Ynz2eXN&R0(~aY#v38;5?_2m0pl8UAuqsj!(X2b=OMqwWcRs0?Z^rmSROAEH499i3i?=amu-yhJ0?V+7t{)3gz zMkILMF6dcVp;akq{3pS(R6Et^l@2WpjupqWF%SMC#HTk1F&_DIjK9PZr-c?pC`((; z;2+5rugEg#Z8q1BPG6mwn3&LOs;aU|-8LVLVt{*dph8b{Y4(`B+b=*>b&Bo3C+a;l z?FbjJZ^tuVt*!|lX0WFvDuu?3O>ZC@_PH3jB=v|x0-MkvYp8@D5OWXy zmNo$Az&AGupFP{&+1a6?ev+w>E}@o^^3!*je&FC9Ch3XAsVhc!;_c*a;J&C(SX^5z zyT<<%K1c=O)5N_YMv<>G9Q)h=BLbPyjrsZKPi~dylc`0fEDzOLJAVX?d}`cB%j0~TFCHHVSbq`?o)-Y=CY!XMr=1oc z#xcagBBJ$hwJ$>Qq7{?$pdTKaDd`tYlb8D+Kdg4o=`Z}tAV1@7eAT5nd?S>wE@N2! ze+2mFz4)Idpj1B0Z@>*S{QUeN3*4-RiHQlI9zf1t{?fdWSe;l{gJ(lUMTJ=6KUMSd z^VRlSHzhPVdBlegdL-ruF@&L^AqF9vm91@y7qga|8?Xx&08ox=U}-sU{Fl(OGEh16 z)rN*XA_-rfot+JqM0gRf@ZhGZJ-_)-!ym8|MLTbBJC}9^3bzRH^6_EYF7Scdmho^d z7BBrmxpr({zRM^q?2LNl2V4Q=>T^J8aIf@5C;~7~yLlEkPCJlMTHGDaj!oh-2kH$7 zFGj0m4NfnFO8S!?J^k81i2JU9Td`@H-`nKGP3*6{o&-lU+)=^ynA2v2F^`FfZK2a^ zLlH)LdJBNv;Lygx+N!*&s+x{i!Lf7YNXqMk^FDzgC(zbodRu)ovx!RI$DT=aI{Tf7 z`$OmbhbUY-W{MdX*ZI36?wx?kC#dwbd_ucm$NUYeK1cm2%-U7xwNb#_;#}^`O56 z_9VR&^`&aSUU1r{>Q0!+**GNlx;k3h`?X6yEvXa$ECK)$->QrpEViWnoad?2`uawGov7W;t7qny)vA^QP5RJ(4Bu?x zzIy<03+@k#RMQRtiHe&s9F~1>434UF~{@ zgV3>Ad2_Nus~zMH=sTXz9?FI{-_Aoej3b}g-!g&z#B@K;hllOcjhibbPjq)bDM;Uu z)yKH6fru#pRAWn!rYna|?YVB>W>f*Jwgf)-;AZPP^p5@5b1~4)V!1n;5JP+Ae@KFl zUu>{ePn>*jK(}(rv~hy+fGS(qE=v809ikD)UMOAkHDZ*gVe3lMapyO2_L21Hn?4dk zu^FR}W9uh+dbBaoWeeTwDBK%1V!QyvQLoY zsKZvI%KhWb1E5n0xD8#jw6w7BGQqz{6a5%*VbHPrcJH;v)a`*jNrj(-_JSXdLD8Z| z{1A_p*%WcVHj#~=mG;x%HyVI^;wzl&lL(b@f-lxWb_dIUG3nM{%$3?&b)tc0Oh7mg zGb9`i$SBhaW+3$rxnMnnYa$rUO%$1{j2g;-*51|L7W}gVM=DLQLJlAAA$Yiho&mcg zq+w4MCOLiq=YK4IuV)}>INxJ-b1P;b`~#Q5`ntbusdVUzP~K2=?lN;<&s{DnDSS-n z-SbC1Q>muozfyTUpg|(o84QBo3)J(VAxD9TmA*7<2QaA(tL=bmS%cfM*hc%G+h+kj zihvKC&@(%2j|8Qlk|Z?PU40Y*_uX&JnH$OwGAiGB4n^a0+7SqN5z1~dTl<-f zYTiWd4_tipQLN(q>cp)&Zj*%ZI3WTI*P}q2!CYh1#Aa$*V!WD3y@-Y5xMXm*yDZ_? zcVo2z-|nniUiMZF-F}~mD&PTM=ar-Lr-D9nFc8sTd*-;m}OZ?M*NJxnDCAZQ_Rvlu7G3h;1z4m^{-95k1+h56& zQM(c4VAt1s-FCDy)h~DdYRrxld0fXV_kQnyoyY;5kP8%HZc|@>C?xq{PCF7iT~e{R zSC@Knm_83$QF>lr=YKWa`2O$SGF!xX{;||LXRSxol36ZW7%M81-wl1b)IGGliZ+TV zVR%jjpImdSz{t1ZfxD6A$+ffP84T#{!QS57W6P*?7N>GGtTnJR?{YcSdJf3AFp`em z37410AH25M>ozMfV$k~42sr&1~T3&WYl8^`uLS7wReWMqzxN;d$#0Nq-*%dx$wdw^m>Ic3Em2Xef3~xQZQm^{J1#n!L{|KLbv|syVcrOOVL6%u=`sc#E`z!mOn_c3Od44A9{31&)^{rBdn5@HVD|}GQ-cOIBjZES*_=${~$TBngsRJ7^ z=*vBG*yrYTx=@oNS8in)p-}iz^A>!_1v6?Xirzoj--7Wbzwo=WPa$8Q4crZ2BwNpC9s_r&b`w?+PA^^%JQ@_!gc!Afs!1nVDk#HD;(<8SE2Y%kX)XG^Vef=0`Yt9Z?5EULQ(Hm*-nO%Ky%DC7MC*m zv3-?rUm_C$?PO3+6$6SSp=|36w7PnKR!OeOLSOf^=jp&6D22cWrW;?{(J3D#Sejp27mSDNjZ zXrZ04WOdBA2)9u%V8L=08t2^`VfbYFPUnLX zFm0?28hPUVf|vKhPJ0r*F)Ul0HldZHC(u%r4c|Tc_DyZ_0qjSg!Qy$cEzEaT>q6`@ zeO(_Wvhpy1@DAG>S4ho^WsGrqQx)Yn)Gh~r)LDv(K;1s%9_R$xX1XXBevkBoVCRD- zzU=h!y{Mku6zSdfd6m1%zLf)W&|*uo!R%7HbcBY!h`()9fn%)a#d4fWtZs$#I9SFb z!lh>4@AM&r=6rsH?ZlzqNbU6+{a8-(`@gi$gT8%>v}cE&?yHDs$KkfXYIyBQjR4_@kdg{-*_zk(vvb;pN|T;^`%j$~DvoV%mCg#+ z+O04E+d+AFU*9q(B)|(S?ce-ruQLn0fwTh_(`DDYm!kOV6B$_{K5FV3W4SsHP!cNO zZ}@z=ON=XEbnt4@t&LdDitZ9q&Rz7-Z^C;PR~>M2nv`SVO-abVztw$T=ixni=H-o& z_Zx6P)ie7~f%?r>Njvu7yxcb{BJcM`I><|1yneoSOg!nowMjieccJjZEPfK@ju@i+ZF)u-(koF(Q8!BH>)rC1tq)mTzd?2@P+jf+pM`=Ax6(n zie=7O_6u*##8T=5b5M^KMW`1<=8ikcg)hTN4ZHqaS*ao&Q5 zcndzjsp-jRI|gW)WP*1Mm@hP;&DGV>)&}RXyNv?O1A|VgygtA@bpI@URpFrCLfON* zMIQi+4F|_}#-q7Sw4ocIwd8(=SosaS8PCYN^f9m+Sai}O+-k$ZAl6}2_OvVePiG}9 zb@;BwyLSN;ekUx7#`T>yn}N16N(WRaF5f{z-=e3#4u5?x!(SrM{exD6wP+{p>+ZiW zgtSSjdc|qJ=h6L&s^Xs8QU8S=UA#z;)X;z;Km+vtedCG3AHYZ^_KcL2R905@-aS9y zlzIStn-;B2%ID1CVhpFkFbxzIY<$;q3}_eEj(HMdO(dZT$+lCCDZJ!1kZ)dNXPjlu z1==foZij55A!fgxKZeN*e^iQ^Vn|KXA7g@O*BX=E=zyQ7H=wBc2?|*~AXzzpXpP=0 zWJ4EIpKjGyO-F~XtoXdNup8z!Y~5D-_Tlr-&@pBz}2gR9-d$k4CoXJy~w1#_1VdeZV8E$m~R;^8) zLoh9nX8$VL))%fNj#1c$vr%+QQ>o&7z~pl~`7YOT7tQyM|8$V8S^u9MWC9`n_Fkel zeCQ+X#4VD)Xvn?o|Jy#W|5rA+|Mejdc8Pv<1)Tr><-}U2g?W;~y7bbgpW;chlB+>r z3ly?c>j!#UPC((;dynw@)OFw{Z4%uAhca>fyV(Lnq@>r&CXYz~i~en&43>1lM((z5 z9K0c8VlFF*&_!C3SPz8tMVdrt2vx~R{DRPtc;9tRdj`&o*U zI83Vw)xtxd08B3}h8p1-%=uN27h6mgjqA6)`vGB>H2m$rJj?(Qg1$arf77V@3oHwnglZ_8HAa{|4MgL+i}k^cJQxc31YLh+a1 z_v3wrMc|{v0n?X;yje=s|G?J&AwP-jb6gzqmEqJXd$onoiak(ILqCHOuSIh#Uac{x z`ghQN`JyW(PI64jO%qh+up~pDZ4lwIIeH76`By{L36aa}LIKIFJ^Dw;9ko$569v^A z1rh>&M;RX8GV}2(!yT7;4{X}QLi@G)eD`(y$WqS%{W zX7loMa~rN+taMJ`Gis-RdEnnU+;!^z{H>jkEK@@CAZ+Sl1 z8+qa5nW{W_y^Esv5c*TbhaEnXe-_P-7RJDGHwr6<(`@`TOMDvW^oHCLHZFZH;Bs*Y zG+eXQZ#PWpgQtzp?rqBOmL5Y&>>5#!^sieO9<*g2{GxEAJWI5C+ z^o4GTMmq5p-bzn`DE{q0ZmVUSyVdp}@QX@~oI%I%>E!(8mM zm9yn=^^c#uW<+<~3}Pb5QO!!>W#!jNacG?Dci4f(B~4chI(%wWhx8N`6-PidIkGZ6 ze!Pj&ohiIyb_F`rJ~9=T@U?!E@x@TsD8zmIHtZ&yLo>~U^%g?{-jBH-zt%~mHaRz#oR`rf;vH{(P&W_$9T8V5ja^*@a zygIcu+9v^dYHaqfkf@_AmGQkNWK8Lji)gr3U@XD%a;1IWmv={>?zix{;aHuh+%Qc1v^~J{yw_@zh&}1cy1JHK@Gs&?K2h;m%Ssy0ZvJ@96pKLd1xB2vV zDBSz(gZ5O8Bvd+=0NkyX}(8`L*NO?yl{R>;dgkg zsd;_;K%>?TCFEfRE2RVuQ|?u6V97S7Cop(EzFA7Ye_@Ijz2}c0_noiJ$`$HLxUbPoyGbhs&IpIfAB@8jbiY8hN~ z4f6vxFM!5b^C}vhH4je9B%Js2s&qVMQM~tK8B7gJ#n4*xhQHS4)M`5JZY8rG?(pc{ z9|@YNyLKA+Ithxcu1J;^sB=VV(xzot%?T;7fIA7w?A50{>)TlhOL1-$H*O1)mbn{q z8E9!Yd3C1`?Jej}P&t!sZ~lv^UIG&oV1Ufb=FM{8s0i4<-xX*WYB`nhyUF}w?uo=~ z<`#vi%A~=8r4TGT2xcpYJC&oFXKZqI^f>!KGm7s#)EQE@$3p*%Om}^4hiCHawnO=( zkGuzsZhJSBm5Re*r=7U%VW=Dz%3|1snS;2R+E;!wbmyyL`!$c^jTQ!v@L%ig9(gZpPN1IC6{tm#( zXm{o2$k2xf<4-bEP03&DiD81RZKD5qs98mTck1`TG@xadyTBG#s8%9*ocG5v<_j!i z39N|vNx-%e#qoE`FLr^XcT=(mQE@`BiFMY9qMgmol2Zue&6Z+E-S-Q1=2`8D;Mb1VtbmJlv;wj9 zse9s$XX!339v+j=@}0>^L!QMlnNHJ>Umy*K{H}U_YfV5dJR;`d^K6e5&e-xn$Qt5eb*bG#fZfaNjYgq5hm7+Dg)^c7SmlR}nxN*J*kIz7 zzi9AD*f`8E(oc5kc=8RjyXX<^J$I6JVK$q)%itE}KH&u(T7z$u%f5R$2F@W8R`PHj~ znPQ*~&}Op`Jp7fT2PVm^#Are)?X8UyI zJEnJmR#@cARfKDvZrw5I5w{gRi=M}jf_j@Mu%=d9mSac79iuSSM_ayxSRP7CpKwG2X#-di2^^zkJ8b+lhB4W>F#Kz;J!7820g1KYgp3~ zUv;Uxr;2t)P_g99AH!F4cl%w84O)tHI<$vRdm$WoV>L5+L?Do%XI^$Ry#{W{*5hYh zcQ)HL3SLuxvA!6!b&Abh5FO)o`f~ay5a=#CcsHGnA>FTo2BY1^~nQzWnna zP!jrvB>UcKod>{4oT9<)%w~R%hRpPV<*4-V#$s8v>Zh4(O@Luy3TEjQi`Bjqkk5w8 zNEE&Umu>HaFBS9O{&cCLe!1!Z8eVhdt_@)jn*x2Z6H?x@5`EIrIns%;_I{28t{q*0KkG4p|dG3Ed)n0BoD9BC)K@AN0tEL{x*U~$O&*%d-|W>0wX}X+S+}=v=DRda_ zKa(80dsiT){hnVfKC>GXbHKZEAzwrpE{R8UPOu@5L~|mvTN;~f>8KM8f}DwN?J5Wy zd}{(5oU#;?y}K%?n||t=n<@Y!GB5DY9)mtX_~W(PXM3kC^t>-meV7wLWGAz{@9PEa zB^WA0S4|e=AAF=%v=3U)_!h&()?@V7@J7qb@gE*3$`R5CazsK_1_n`WO95>B275v zakV&#VAoXXye>BA3#vr|%PAQc2tBgzJ&Ju=k`m_9$8D+=9~^uX=AoS)N%w~62rTtQ zNJWgQAF}{VA4B6P6vD5onnf;1G5&!OwBKE?7nXKvPHd-$hDEgj?n{|!CMJA(#(pULw-4OR(vpdwfecYfk2QnaYD zcTH7yW#MO5Yn`A9EVu9(AqHU(2D!AD$x_ez&ist^Y`MrA zh!$SQeOe{XnOb*QLI~O0>X5vI->!u8d!M~B-#F3h0$Z1unGztSiD;|3bspzQ=b>^a zr2HO)V9RB&xnA46p)*;`fq{W7 z*SB>&1ot|lw8zRS{~ysfe^0zxRG=m5-Hxb0`3;PWod=85AY2&tnSu(q7SFzoyV%+; zZ5bDiettt%0p}GAew(ay{HwOGNWRY9-E4b}HHv6HR=373qug}9C^01rkBp27ZQ1d( ze>|T_t=Qo#o&jJqEmq6#H+9~yUv6-R-B>ZMaF+DcHc?w)x7VV)`(HCxt^o-FiQZg~ z};?>nxnqNvk%)m}9cVu;h%mZ$Zhx&Rswrj;5kPwq( zRG;Tvnc_(j9er~K5RCI@r`WLBA8DEU6Q%One>q`iGQpdrM18S+4NcQMAg< zw^1+UKz#Jx;U=%s$O!OWQ&aVBz2)wx2hAFRg~^A&b^Z|DLnlATw2XG;rs)|jlQEv) z{y+M;AcA?o$!*6_d_Cw7#GwE3;j&4JT+RC{qsOGA0;WwiN-XF**OoQw-hZCE@804L zUTd_}>$-Qy92O5z?_oklGSm3ee0)SFRyuW>b~4cpKpFtNAJ?-RvK_TmH~+f4kW?-T z?~PZ4Tru2@cs_2<$;qMQ54>M#{zpVrDz%wcbLnqj zH7Kl8urK=mcBWN4p1Htnf#0?5Z**2cETpsdzx{EAU!g*2p1_$E;`}7>dDR*C0`aLk zckb(Ry?$K@xOa8+UsG2qDRmPzoLwfYmEi!k@a63C{KRsumWxH4JuwI0-03suyo^`Gfj zO#SNrMOG*LomMdm#~aNnEAlF$X|j^%A*g?1km9~Xru0)X$VchLQ}wBp+OP3@jm*Po5{W4M;?A@R9I8G#;zm1!wY6oWXc< z3m7xh2UI<==hD9j&Yf;O4V>Om6eXjH9v5^V%=1xO@-w4;IOr1ik5roToDquDwYqfR>4X z7S|NzjxDN^Ao})YOqspJ57M`RcYvjQgU`wg=*Vu09h;B3yhcL&3=kLMY3P3wfJLfP zia%)8y2d*tkl=+*9vMgA`BO2x2+!PVi6(aS3r_kB+0i=YdR!%s7ZTw1!W?w!cpQkn zas&FTXylxtG_(aT-^5_LFVMlhT=p*uXzAz!El-@TyG)<*lMs<0st}#4R-n+gx+q`? zZ^C{lk$T_f-H3OMiY$?Ua2Scx{jBrQXOaynjJi24=^*Y~`e{tijS29b9Q8T`Fc}Uu zGkJV4o^4yZ?TIhvoDCA9AkcBOJF>YZi|~rt9;;$kskA%^A)nN$@gRCrZM^VB*+ZV; zMT%jqaz{OA3V$+nZFExF&DCijZm0r&IuH%zWp&$4ba47KoqyRkbp#$jrS+yk^3O2o zYs}fZWL-v`VVF!)S>~?*3X!w+QaN$ZzB{je6f;=IK%=N(zcI)Py7F_2qoCz2750W; z=JZ`5=>&$(cO|+PT|#npvAl|7f|o|a$hXMrJhfGjy8}5L>yxV`N;=L>XNe!xpoMg* zQ|+6|`{|Hf#*6eks{{67;CqUv9`c{^{EQXy?zX5cV;E?E^{nH%E9bfXMFf6#I75Hbj;b77kXj0+dy?;t6YR*5dAXqQ2g2&|vhLY-2c+0rZ8k zo@kuo{gXQZ3VSu7_QMUZf7#P%DqKSEmgd~?tL+3$*ZouMMo-poS7GYu6o=>+Rk!nFcNy2|FQ|wt-lI+Xb+B}Brc-Y}xZ~3dW;eFC zwXGHQ`Ko5ks%Ar11d3Juh&pp7tDY(S$@nG%AbluWXi#xln2F%O!j*mU${Hx zdbqc*Sc?iqjNsA6lICRFe6H)J@UEMGjm4^Pc)ts}?b@*LePjv`C&Z z5N{0Y2jE$7&l9o_-Ub0UU_Jta(jbd%Mo>4l8!$GZyfr?<0nZ^W7FLviE{T~>`^uIl zJ%Kg;dV}oVtUbI*f7|L#f{;u|KPvHPL4)#@@ceMFENKV}k?9u5I@6KrpDyb(*x&Qx z=0~&zyw-PF@o8;qOFBGm6BHkBCV2HzRTtxoqrUq)rDC{{j1$?9h^vlQn8~29aNZGc zL2jegDmG6frG(A@$VbQ8J&Z#GT<^n&4`9ZFsvT3BO*wCJ^DP1#gcg#zz8kRr4=HNl zU(`!FGXQP)=gp%dEJB#@GY+6q7ts1RTvc-Y6+gR)1qoT6s(0|WN*4_LDnGi%N{_ul)uuFpO$+>y{E(G=qP%l<+K%=q>D zx|6HhGnp_hLCl#Yg;&$U+#>d;mXOal#q+5u2#apZb(3W!XQhD}+%`663$nPKmI1ud#v&j9H|kgp#4vA8bq%N7Yx!Q9h3 zZ}Y#D;D5KMF&gJEFRJ35zB>ryBy!8U_WEU=c^eyvH{WP2ELIi8E~ny70uo(e-;))+ zJj!Q(SS@kA6X~rBc{*$Cu9DbXoqdOq`Q`M?WiuAIJeX2Ax$Lw2+Ugcu55+BCKL4#E z?%8lKhLnpz87q&urLv}F!+&tW7a;s{=jh9V@y!c~R$PTWbYLlQ(XCwh_vD7I0GUyR zG+JqHa!#(AA)(bmtX+Ibr&AGs&Y)Qog_9Bn_~o26E*)pdZ**p069d;Rh3k` zDEE5M)l{9ID97{YELNh+_fX2yc0S`Z)<~D| zf3Q(iR10BvIPRt35fDZHQ^?29zUwxs*DR5!G0cQmwWssd&u`Q?&vg zjzM zhDa2Hl*r9I{LQ!w7dxkQVC+mjf4L*t4^gx_h9+^!O-Q)} zw8=-~e?>r0sJf;hjFF53?*9g7Lz-v!&&o4uy|L5d=|be&au$pNiy$sGTR_$w&mumtdH@2bmxOp zO!*i2BsvWNtr23dicVTc!izDf&U5f(qA^Y|)f=9_tokjVEVb^4=SHtTNezOaG!y@Y zK9^sZvs(}1EAnF}JTG+OaQQ%l4tJGg;Q7uYIGHVR`sk}ATb`G0k zH{*f1ckdJsh*ud}HqHQ#RJ-;5t`kq~nM^HPo|sRxQ} z#P#GWB7RDztq4PV zkRHTh5fxs%o}A2_?Of(A8TBupjlA(|^k(@G?dzv2^*aUC`YsM1@5R%Gfk&VC1#l=N zl!_@Q#;fSF72IXzSm*#aasutIwetYE?Rf}&j0FpZ>W#~WXL+I!CU+$ zpo|awK|HQb;^`02fnpboo#h;wogu%W;5KDZjQ=`LGAzWafC27~sEcQk`*7;~{>cPuZRbIew zUM#`6Mzbt=SUrRC>x|V@iGlJ-xX|~$s!sw65Z16->hA3*^zg)RXIgH#g{U3>X9j?V zAm>GGNgiLN)2TPG;Fs`<$#UQIkT(HD#lf_;WHc}o>F=XlGwwP_viV(+g!=Qp!P{fR zMjxR4)pX2fNcdetYWug1^a{*%srh8t6V?lp`5A3zGkxWiHZ1U+Kq% zzV}lO<_8(|gz<*S;h!|yO_dynHN05V7oxpxc2<9PonI2`?1Sn$37Atj+0P?S_TM&2 zmW=%WS%8GT;af12m`wt{E7Y52c6yqSU6h8HV(Y$bWD8s=vx zjz41Dj>{btYo(BN+FKiR8$Z8ae!a=uKVC}bLi>*mb=h31>8K?XO0pscWXxEM&ekhZ z`o8raEnaYkTW3qW--JanXJW3WuCc2KUdT6kh1l72D{{X0eOeGG6Dg)~wI>L-hiLHq z=DET5!QW|CIykH~c8c*z6lbizt7EfjIB}IZ%%(R}A}RTiLm2-s)zLenQL3ibJo5?+ z1gi=0e;ih=8bfS)rk7?Hu2C~tt-hX}2H8w#O%PxPk&eD0PK9Yfb#JaJ9QeC(#C@i2 zZGqjRxSW{3yy|S!G?+`_b=)ado8-r^5hX&TmKX=M|P|*Ru-7ToSZ%})H+ou}d>j)0eW!$Fx!75m9 zz#tWjyn3F!Kc^-|=O*nqsTqf%5`<=2$$Zorza3?~qD9@b?m ze;kzkH-iM^x09)W?+SY_MtNKtYtOzLjbgqYAANgTLI8O_T*l*aVSOVM7-;kMuUv-c zkdd=iFgBmnnvHsJexx0AwyR~7byBp2l;5X?14S_uwwF-z{UmDnth3X3iaOSL4Dp*8 zRiqznGJZY4`*=+9N5v7Q9W6fi#fUiILZo)(y?SMCc>mUt-tAA7Fkei7ap$G~=R3{X zb1fB2ziS>5LdwhHU@qFrqpE+F4hG@hT?S0U`PCmq?wVrr+r}rb~nwA|*;r zL1#^`r11#JxV?ZeGl4){yXLbB6V)|7-?RP5H<-c&a$ktJiy^*CNU${ZuR^}EmbXK- zyXhR|70Vw)>-tL_-U+4@}sx`zi z6Z_y^d}34Odom`GAaQNts?M#9;9HL7)oaB#BL{>qSMqWTi#V4GXrn zARkjZ`Rd2oW7Z_m3>OmP+azv(td6PHU)<`qQ0wh1*C=3JZUVp^KFc|DPDHVpNf*1}vHLgQYEs8Gi}5T>DzD45E=HGjqG$fL|tT zf?^H5Eo>}=q6co|N@x_ae;F{ir=gtC)<(`;BQwYJ5;x^7DTJw#0;~0==aNPK-a@va-IJ7(%$l&?;!^F zKJ#7L)`?b~TcyV!*L7#XDeCYsK2h_3{ zsg`6WUMrcZkO7%pJ_$kVSt=A<6!lM+t(>5A^d6e3(rs@lOsB?2T=4HlZZJ*{3Gr1_ zEs?)bdC(U5jCXdz{BW+DqC`h@jeUM|p3Eaz=Hp*gM7*20u-)qy2g)|s(szJCEI1^s z7Hn;NIAN1tSA(_}0{NQqU5+~;Y3}i+hsBFjK3|#hM#1rrfGsy{lF1^`iM0fW@0=r9 z6C)|L#*W3G#?cQ^!h{Z0eB*BYN~;Wn|BCri&{|1xNM#NT&3#0;3t^inxhHlQ1e}*C_wTGGnQ;cPx#bEYEDixO@;8b-S>l~N0b=%hIR?26 zkzfH{YmKS`p>NJlWJt2)zL+p)v9I2QYk`1x3wRK&MDkz9$TmfZFHKzSzUM=Eg%AnQ zK18hEZ|3{P3AL9iusaA~5V>?_g*~w7Eh1Au$r~?BZNI^`5b9tJzIH}=eYBjov5OUy z7bJUO#dGy4B)b{NI56^L{^U&7um*3_i`_7>;D7M6^N*34bgiQ8x=$Buv`-!6(y7sX zBY-PXJ?p*cnm$IS_U!D*$!P5S@}>-eYVid|P#}@FXe(;{Xp{9NlFTidhS zesc*IL|1thaE2hCZ<(2u*p_!w=J!zKu@}l+i)n7oOylput-4P444jOK>Yn-;B{T zKE-f#h5@r!gYxicRt}uf6;>8%F3lFT79k%*iheVhY|@H^R~-#PB{4dX6MY#PE3+F{ zq79^12pq0JlaY34+F)EcYIi79E7*QwvCFm>8r1#Cqchr&2=Ecz-Bcjo6K11NFx@hw?=@iGD)>+m^1Dj-7xTE zfE8Fmm5;D7aamSQ_FRf(e4{+hWip4?c_!V5j*#F2{mWzP+NtWTrEe-O|Ljf$UJ!G6Wb)0y)({WH6nKz(1m(V1Nd7=|rD}SK<;2p|djv#4UFzk8} zP_A@GNn^4-J5#3jJI7eB1y`pRB&s23otc>()Ro<5{BHn$ot8OtdQo|5^rs)t4G4?0F6cgj39Y3( zz=){^BZIR|EnA3wZ{k#KJ33QS71rO6XLI!#g8M z7tTKDCX2L3w_@wi|55o1oai9`>sIb~mGR;b@jHggq%zMSO9l5@%-ucj>WXPe|BsxQ zZIJU;_rqlg^JH7fCY-b#w4eLD3|Y^nzv@)ZRv8yvid=A;!VA1YW(l5G&CRT9)7My7 zRz9whK-$#<0;!5~qdlfKJ-6NEuk5uJ6jS$=ro*JA=Re!a^)*<7a8XVq$00Lc+MEGU z-l;J1eap%x9J0wMTTlv;7bus*awA{U)KL~tmWJEc=$*k0tcS31cU6Z*(!9uUA*YGX z+5J@lFqjzE$>53XQ?&qp84xuZn}s!+uKzOFD2&m5M7SUR$^UDONd%#A@-`twKNg)T zb0R8kKfdT2#dr(~$=QbY&0gdRy5BDG-HP?TS5&)67p#HSmoB=C=-nlKfU=eS)n$+$ zFo1r;3GC!W(<)(nx>*grq$^_9KBtw}u{NlKUNTa2+M7pDEXWqT{``Rc`seaiGM+GF zQQ>{~*x`Z}&{k0{Pp8*(tXce^Yq|?@^CVIAK%JrmM>u`q>$9O=NM(sozW0+S7<(Ti zMAaK-?B^<$Lw`ni42?&G8dq&K#ZLhvO##+S)4`$}2!18*f)VGu{SM+V#QR%Wqqxki z>W5^mNZD+CP^M-Id8xdMN^tjKxd9TJiU;b@F}u3}#uLfjF#tG3icV`0@zv!qwIEHd zoKeP31J;LRKCY`~cLmcmCjP(FwMp!juMlv;j!z=2NM=gNXa-Tch@ycvVW}M+y{<6L zeH}2jH$epYi_b{1B!aX^q~BfrbAvq{JRm(mOj%$(fd;iyOy6lxzT(Y-h(mLX(8@M2 z&PZTLwBClCvTI<}0TG>~1^r0aIj_;|OXym#9)yNhefAJwV@!=e%Un|q6>U$0y$OT*+>=CdPPEBFZi&e)&+y5scflD#xH zAJz@xets+o?6g>)5^^Pug(q!QmTT^yC{iJ z%$sJQ%v>L;!`UmbO8n1sFD+~gry5(e{Gl3_h!R63vV`#o#co+C-#kH&5&?9> zBcv+SRa0YhIIZVp5?ZWr{sLMQXT={t-!fP!FX}+HUXvftmeqS)2q=6H-B><82UUqn zo7`7X;(en75>BHjl`+OEBz42HZ5WyXqMpTmmz;n+#`U4%|lr9+d%NhKcWpcu;=nf)k zl3%~LZPf$duYrJv;K3;Fl4czH{sMyVk&MoQETxx%SyX_1lhCMgGi?!c1RjK!M}7?s z!|6n2GZmvU#6&Px!)5UBH+EI$E9lZKQy&ZrBj3G4)#mHUMo?dqClth-FviP0Qr*+X zC{dkO7O+Cqe0f)qH8LU%O>*r$rK^H|!o z9>+erg(}*bHWl^|u>m#!u{+HDKoA(fz{uX@%EzYMyPsh4;LlJs5VdM*;GJoGV-!!9 z6G$JV<*sIkCyR#4W(a+qvWYI^!x}tKWL#adZf)T}ZuaVCp%i0#ff;jYPpK8`9u*T+ z9QCtO;E}9XmXSe?FJ0@HfT@L1@b7Y_-$K28oxWtLoZ_W^4$1D~ zQcCeqGFr}Q`^V%lL`dpmJ0BW?M&(YU#hfR0obmyCz1c&P0Yl!e!sU8vS`M{8O6zJC zF?0XtAA@`fp9Mp$`CO5$=3`n^jbOJbjZTKd$1&{AFLQh)SDzp3Sy*c7>obIn<%>wg z!2&9J2K5 zvRm8>9RL~gRNyNF+Wrv#;z+=WfN4@N^ny0&cPdw@SLb*L_q8}1q3M{twKbRN;@kSe zorg7}#gmTQ++$F6@d4DRw~W&o30T}TzYSasqbWS{yiElFAqs}fA!D?2ZpYlHb2x*d zu`Rls);W%Pw61r6$e`nP6rG<3C}s2$lw#cQb+^sk1`;ud9F7xkY7R|nM6Zod z6ojp)=!ICvs?4Qr`-`$n68S0bIz7&DEs-KqVT#B;clxCtySD9s&L4)a*)Dr?W(OI$ z)9*rZ+AaMpiOSm>?w$Z}KNPXq!RQB--qIIYi;{))es0+3&i*KdjMXLfV*2 zwx5Vl@*k@UK+r7FYY2hvubkQostL!tr~_xuNmX)ohG=e!f9+wBLb~T^2Ff+DAR1~{ z&9|Tn;<-9QqmuQP>LeIslj0t$JoTUf-5g`HpPa8h7$eFK2fPxEDpgSn6%a1Gp86U5 z+;-`@?sparQjogo*Yz*Azj9lMd`|;I<-_;ry(w2&+?ek|LI%c~j!y*neAZZPGNBh9 z=NsM0Ok5k#2HitAX#k?NnH}{5wUPa+ohfYy9tsZ6r=lpLe?j1ZpYAh#sp+ecKaq$b zA@8Ze4RxvIb>CimKkUYPPXFg5Yj0v9qXp!yMVLsV$^gCCcA=e2Bffa%C(@_A)hf+P zS;5x(eDg@GqS1WVzwE}D_UXTx#?;?Uld$iu%)wI~$5vm^03Z1SX{YII&+SDX*jh7) z*l7{cgD=9-$jbe;rOf?~4fT|GWiMpAG`XovK1}nDkwDc@b@*gY??=@BwoA6Xy|JlX zVmBk-meW{SG#FvPD-%{oJ$gj36Or5>$ZH&5uV{>xYEN!m4@(B@%O8Jr#4%@E3r)Z=)#NtEL)1-Tlp&cPo z7N$$JW*x6tY>T^mT61iIiNj$6vh^}&v~kP^Je>JSgv7uyQC$W(dZGeNpdgm@s-uoB z*Kf#UMGPygD~hsNsAYq_UFIxMct@77HU2d;S-F$si4|WGONzf3lbOW#L~N}S#mn7g zL*LHlC5VPTE8ySln*n1R(EO9M z(%PnRP>fgG0nwoQOhuRc5b>Rd1fF`WjX|eO^A)EJXDNHotAnTjEW9gl+`xe=5>pSF z=&d`G>D*`*)6ky|y=0aQe;iHi>jCn19gY$jy&vTKRPS=h)YQu&31Mi` zB{2pEk$Sh0hY)) zhZm@l#5B_qkqmzs1{irnyP#y~RlV-!p=eIncnwQbs)n~9CRTP9Op@H)pwT}WONjO> zYOIk>=Y#Y%p=m-;F1#ZmLc^mrNp}D9yzg{UK_J?t_8;`&(&YQNd_s&Ad=&IA@&TE9 zjGBeYW9spQGst7`u3E|Pb#{TDt}aBz($tWuHM=VHAk73a#*A(eev!St7P~F%7aDC` z{NL)RJU`C*??u%yF7J}NKUrI7bp{AAGn3BoQvY>w9!^$btCc%Bk(i&HCV)M{`EC%q z+pf*C`fIx>j4ASr9#12naQJCwRW#uv)*6`--3vJH$)y31iY*}l)a7sg%Z5;_r&to1 z7ry_N3bUw#!{to>STAy^-6?U7z~Nm7`>Kh3C^ruq6NR<4s(Trd4*~b!p8#$d8JzC+ zyeMThWtJto^VgtPxklDS_Nu;g<4neOpmOMiSS$>lx~h@y)%H2#e_OD6O14}Y{8Asz zMQI^!ki`n#L2LQrQc?ZguEj-xz`$m(lN#)$c9G@SE7Mo8|B`|S7f9A$|9YD*v*YM_ z>9>bJEg1J-Xo~j3&Q7`FLUq)_$S&`p_8DHaZA*?DLTvVD@uUVZD{M&m_d8ibR%Y_wS~on{)_lf z1s&ae-LoK_nNF&7z$H;4U|LP`h*idF$wfayVOF+ywfFMmzuZRxaXn-ok!aWj$;(H| zN;j&{&zGcxZ5Zvrs8NV!biV_p@003pKL39d=-1=X`FF%#x&4XfVx8=Jm%LT_);QmV z4E1+x;_-rz+#{LJDF}=Nte^h(IUm#Cc#*a)gST(}$0Zt%Z=$u!Q2*VUiI+H1Kn+`# zcIJOCi^x}+=PsrZ@OkmZ&%gaw3dV^#U(>{OLf_Ne$zHv<3$NsXFx>xzR$>bTS3?8l zmt9ysDb*HKa!tdGNwt+0e|-1vBULo<35j4L2uJ zgFSMu2LFm3dsmuUw>@4W|L-*`-yZd*cPC_7E)>rwax0?9q}@kuYSh%Lds z>i<5k>R*z|Y&w*Bmlz$jLhIOb6_1Y-fE>i^wd*`h{@jd(#OF8T3othC@768n)` zG_mhzB>dlHFn(1u`r(+cAOAwh@H3Ua_8QS3y28N+{6DET|NjF?Wq4JYS95c0qxC2u rU6X+&o^ZI6T5&%3;l;nM7vYI~)nmfI9QrKy%aae1iV~G#pZ)(Iy62E- literal 0 HcmV?d00001 From fb85193643c25ae6231efd031830c62aa093a5e9 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 8 Sep 2026 23:16:34 +0530 Subject: [PATCH 06/66] docs(changelog): add week 37 and correct the week 36 substance entry Week 36 entry 2 said dcterms:alternative "exists only on federation, which is why the region-scoped variant works and returns 71 substances for Maine", and proposed pointing the no-region query at federation. Measured again, that predicate returns zero rows on federation as well, so the region-scoped variant was also broken and the proposed fix would not have worked. Corrected in place with a dated note rather than a silent edit. Week 37 covers the query fix, the 32 recovered substances, the Select all counts, and this documentation pass. --- docs/changelog/2026-W36.md | 4 +++- docs/changelog/2026-W37.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/2026-W37.md diff --git a/docs/changelog/2026-W36.md b/docs/changelog/2026-W36.md index 0e262ea..f709456 100644 --- a/docs/changelog/2026-W36.md +++ b/docs/changelog/2026-W36.md @@ -12,7 +12,9 @@ *Files:* `docs/wiki/` (new, 9 pages), `.github/workflows/wiki-sync.yml`, `docs/CONVENTIONS.md`, `CLAUDE.md` 2. **Found: Unfiltered Substance Dropdown Always Falls Back** (2026-09-02) - With no region selected, `buildDiscoverSubstancesQuery()` returns zero rows, so the dropdown silently shows the seven hardcoded PFAS entries in `FALLBACK_SUBSTANCES`. The query requires `dcterms:alternative` for the label, and the `sawgraph` endpoint has zero triples using that predicate; substances there carry `rdfs:label`. `dcterms:alternative` exists only on `federation`, which is why the region-scoped variant works and returns 71 substances for Maine. This corrects last week's claim that all discovery queries return live data after the host migration. Not yet fixed. The fix is either to point the no-region query at `federation` as well, or to accept `rdfs:label` in the label pattern. + With no region selected, `buildDiscoverSubstancesQuery()` returns zero rows, so the dropdown silently shows the seven hardcoded PFAS entries in `FALLBACK_SUBSTANCES`. The query requires `dcterms:alternative` for the label, and the `sawgraph` endpoint has zero triples using that predicate; substances there carry `rdfs:label`. This corrects last week's claim that all discovery queries return live data after the host migration. Not yet fixed. The fix is to accept `rdfs:label` in the label pattern. + + **Correction (2026-09-08):** this entry originally said `dcterms:alternative` "exists only on `federation`, which is why the region-scoped variant works and returns 71 substances for Maine", and proposed pointing the no-region query at `federation` as one possible fix. That was wrong. `dcterms:alternative` has zero triples on substances on `federation` too, so the region-scoped variant was returning zero rows as well and the whole dropdown was broken, not just the unfiltered one. The proposed `federation` fix would not have worked. See week 37. *Files:* documented in `docs/wiki/Dropdowns Substance.md` diff --git a/docs/changelog/2026-W37.md b/docs/changelog/2026-W37.md new file mode 100644 index 0000000..bd6be30 --- /dev/null +++ b/docs/changelog/2026-W37.md @@ -0,0 +1,31 @@ +# Changelog — Week 37, 2026 (Sep 7 – Sep 13) + +--- + +1. **Fixed: Substance Dropdown Returned Nothing At All** (2026-09-08) + The Substance dropdown showed "No options available" with a state selected, and the seven-entry `FALLBACK_SUBSTANCES` list with no state selected. `buildDiscoverSubstancesQuery()` required `?substance dcterms:alternative ?_label`, and that predicate has zero triples on substances on every endpoint. Because it was required rather than `OPTIONAL`, the query returned zero rows rather than returning substances without labels. Substance names live on `rdfs:label`. Switched the predicate; the query went from 0 rows to 69. + + This also corrects week 36 entry 2, which blamed the outage on `dcterms:alternative` existing only on `federation` and reported the region-scoped variant as working. Both variants were returning zero rows. + + The likely origin of the wrong predicate is `docs/SCHEMA.md`'s facility table, where `dcterms:alternative` is a legitimate *facility* predicate: 3,824,195 triples in fiokg, 3,742,487 of them on `fio:Facility`, and 0 on `comptox:ChemicalEntity`. `SAWGraph/streamlit-app/filters/substance.py:67`, which this query was ported from, carries the identical bug and still returns zero rows. + + *Files:* `src/engine/templates/regions.ts` + +2. **Fixed: 32 Substances Were Being Silently Hidden** (2026-09-08) + Switching to `rdfs:label` fixed the outage but kept the underlying mistake, since the label was still a required pattern. Only 69 of the 101 substances in the graph carry `rdfs:label`, so the other 32 were dropped from the dropdown entirely, taking 47,642 observations with them, 5.0% of everything with a substance link. Made both label patterns `OPTIONAL` and added a DTXSID fallback in `useSubstances()`, mirroring how `useMaterialTypes()` already handles missing labels. Unlabelled substances now appear as their bare DTXSID, for example `DTXSID301035178 (6,493)`. + + Verified live: unfiltered went 0 → 69 → 101 substances, Maine went 0 → 69 → 79. + + *Files:* `src/engine/templates/regions.ts`, `src/hooks/useDiscoveryQueries.ts` + +3. **Select All Rows Now Show an Option Count** (2026-09-08) + Both select components already computed this count but only rendered it while a search term was typed, so opening a dropdown showed a bare "Select all". It now always shows the number of options the checkbox would tick, for example `Select all (79)`. The number excludes disabled options and narrows with an active search, so it always matches what the checkbox actually does. Counts are now comma formatted everywhere, on the Select all row and on individual options: `PFOA (20,120)` rather than `PFOA (20120)`. + + Note that dropdown search matches on the label text, which contains the count, so typing `20120` no longer matches `PFOA (20,120)`. + + *Files:* `src/components/QueryEditor/FlatSelect/FlatSelect.tsx`, `src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx`, `src/components/QueryEditor/HierarchicalSelect/TreeNode.tsx`, `src/components/QueryEditor/SampleFilters.tsx`, `src/components/QueryEditor/WellFilters.tsx` + +4. **Documented the Substance Label Model** (2026-09-08) + `SCHEMA.md` had no substance or chemical inventory at all, despite being the predicate reference. Added a Substance Labels section recording the coverage that matters: `rdfs:label` on 69 of 101, `skos:altLabel` on 25, `dcterms:alternative` on none, plus an explicit warning that the identically named facility predicate is a different thing. Rewrote `docs/wiki/Dropdowns Substance.md` around the corrected query and refreshed its numbers, which were stale. Logged the root cause in `DEBUGGING.md` with the reusable lesson: a required label pattern does not degrade, it deletes. + + *Files:* `docs/SCHEMA.md`, `docs/DEBUGGING.md`, `docs/wiki/Dropdowns Substance.md`, `docs/wiki/Dropdowns.md`, `docs/changelog/2026-W36.md` From 54172bdefdf7faf99e08cc7e83acac53646c3501 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 9 Sep 2026 22:51:49 +0530 Subject: [PATCH 07/66] fix(substance): name all 101 substances via the source parameter 32 substances have no rdfs:label of their own and were showing as bare DTXSIDs. Every one of them is the target of a comptox:sameAsDSSToxSubstance link from the source-data parameter it was matched to, and that parameter carries a name on rdfs:label. Added it as a fourth step in the chain: skos:altLabel -> rdfs:label -> parameter's rdfs:label -> DTXSID Verified live: 101 of 101 named unfiltered, 79 of 79 for Maine, no DTXSID rows and no duplicate labels. The DTXSID step is now unreachable and stays as a safety net. Surveyed all 39 predicates a substance carries first. Only two name it; the rest are identifiers (hasCASRN, hasInChIKey, all inside the already-labelled 69), provenance URIs, or physicochemical properties. owl:sameAs is self-referential. The parameter also carries acronyms covering 68 rather than 25, deliberately not adopted: the _A suffix marks the acid as distinct from the anion, so PFOS_A is Perfluorooctanesulfonic acid and PFOS is Perfluorooctanesulfonate, two different DTXSIDs. Borrowing them collapsed 10 pairs of distinct substances into identical rows. The full chemical names keep them apart. Three QLever behaviours shaped the query, all documented in DEBUGGING.md: COALESCE(SAMPLE(x), SAMPLE(y)) crashes on federation; SAMPLE over a nested OPTIONAL can return unbound even when rows bind it, which silently cost coverage; MIN is deterministic where SAMPLE is not. --- src/engine/templates/regions.ts | 2 ++ src/hooks/useDiscoveryQueries.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/engine/templates/regions.ts b/src/engine/templates/regions.ts index 21f4733..21dee9b 100644 --- a/src/engine/templates/regions.ts +++ b/src/engine/templates/regions.ts @@ -76,6 +76,7 @@ export function buildDiscoverSubstancesQuery(region?: { stateCode?: string; coun SELECT ?substance (SAMPLE(?_label) AS ?label) (SAMPLE(?_short) AS ?short_label) + (MIN(?_viaParam) AS ?param_label) (COUNT(DISTINCT ?observation) AS ?num) WHERE { ${spType} @@ -86,6 +87,7 @@ export function buildDiscoverSubstancesQuery(region?: { stateCode?: string; coun ?substance a comptox:ChemicalEntity . OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } + OPTIONAL { ?pL comptox:sameAsDSSToxSubstance ?substance ; rdfs:label ?_viaParam . } } GROUP BY ?substance ORDER BY DESC(?num) ?label `; diff --git a/src/hooks/useDiscoveryQueries.ts b/src/hooks/useDiscoveryQueries.ts index b1d55b4..db9afb7 100644 --- a/src/hooks/useDiscoveryQueries.ts +++ b/src/hooks/useDiscoveryQueries.ts @@ -105,6 +105,14 @@ function regionKey(region?: RegionParam): string { return codes.join(','); } +// Some source parameters carry a superseded name of the form +// "***retired***use ", which names its own replacement. +function resolveRetired(label?: string): string | undefined { + if (!label) return undefined; + if (label.includes('***retired***use ')) return label.split('***retired***use ')[1].trim(); + return label.split('***retired***')[0].replace(/[\s\-,]+$/, ''); +} + export function useSubstances(region?: RegionParam) { const key = regionKey(region); return useQuery({ @@ -117,7 +125,11 @@ export function useSubstances(region?: RegionParam) { if (rows.length === 0) return key ? [] : FALLBACK_SUBSTANCES; return rows.map((r) => ({ uri: r.substance, - label: r.label || r.substance.split('/').pop() || r.substance, + label: + r.label || + resolveRetired(r.param_label) || + r.substance.split('/').pop() || + r.substance, shortLabel: r.short_label, count: r.num ? Number(r.num) : undefined, })); From 826dccaa972fa521ba5deba9f2383b34d0d069f3 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 9 Sep 2026 22:51:49 +0530 Subject: [PATCH 08/66] docs: record the substance label chain and the QLever aggregate quirks SCHEMA.md: replaced the substance coverage table with a field-by-field verdict across all 39 predicates, the regeneration query, the four-step label chain, and why the parameter's skos:altLabel must not be used as an acronym (_A marks acid vs anion, _L and _BR mark isomers). Also records the parameter-name quality problems and the known upstream PFECHS misalignment. Dropdowns Substance: the new OPTIONAL in both query blocks with its gloss, a note on MIN over SAMPLE, and three rewritten troubleshooting entries covering bare DTXSIDs, full names where an acronym was expected, and the non-PFAS entry. DEBUGGING.md: the three QLever aggregate behaviours. The silent one, where SAMPLE returns unbound despite bound rows in the group, is the one worth remembering. --- docs/DEBUGGING.md | 16 ++++++++++ docs/SCHEMA.md | 53 +++++++++++++++++++++++++++----- docs/wiki/Dropdowns Substance.md | 47 ++++++++++++++++++++++------ 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 5cadfd3..58fe3e4 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -203,3 +203,19 @@ For downstream/upstream, reverse directional trace is expensive — all anchors **Fix**: Switched to `rdfs:label`, then made both label patterns `OPTIONAL` and added a DTXSID fallback in the hook. Fixing only the predicate still hid 32 of 101 substances (47,642 observations, 5.0% of everything with a substance link) because the label was still required. Live counts: 0 rows → 69 → 101 unfiltered, and 0 → 69 → 79 for Maine. **Files touched**: `src/engine/templates/regions.ts`, `src/hooks/useDiscoveryQueries.ts`, `docs/wiki/Dropdowns Substance.md`, `docs/SCHEMA.md` **Prevention**: A label pattern in a discovery query must be `OPTIONAL` with a URI-tail fallback. A required label does not degrade, it deletes: the row disappears along with its data, and the dropdown looks merely short rather than broken. This one mistake caused both the total outage and the 32 hidden substances. Cross-repo confirmation: `SAWGraph/streamlit-app/filters/substance.py:67` carries the identical bug and returns 0 rows live today, while `core/sparql.py:586` and `analyses/pfas_upstream/queries.py:147` in the same repo use `rdfs:label`; `analyses/aquifer_wells/queries.py:96-97` asks for both predicates but marks each `OPTIONAL`, and therefore survives. + +--- + +## 2026-09-09 — QLever aggregate quirks while building the substance label fallback + +**Component**: `src/engine/templates/regions.ts` — `buildDiscoverSubstancesQuery()` +**Symptom**: Three separate failures while adding a fallback that borrows a substance name from the source parameter it was matched to. +**Root cause**: All three are QLever aggregate behaviours, not SPARQL semantics. + +1. `COALESCE(SAMPLE(?a), SAMPLE(?b))` returns HTTP 500 on `federation` with `Assertion 'singleResult.size() == 1' failed. An expression returned a vector expression result that contained an unexpected amount of entries ... GroupByImpl.cpp:436`. The same query succeeds on `sawgraph`, so it passes a casual test. `SAMPLE(COALESCE(?a, ?b))` runs on both. +2. `SAMPLE(?x)` where `?x` is bound inside a nested `OPTIONAL` can return **unbound even when some rows in the group bind it**. This is the dangerous one: it fails silently, costing 8 of 69 acronyms with no error. Requiring the value in the OPTIONAL's own pattern (`OPTIONAL { ?p pred ?s ; rdfs:label ?_x . }`) rather than nesting a second OPTIONAL inside fixes it. +3. `SAMPLE()` picks arbitrarily across the 41 substances matched by more than one parameter, so labels changed between runs. `MIN()` is deterministic and, because `X` sorts before `X_A`, happens to prefer the unsuffixed base form. + +**Fix**: Project the borrowed name as its own column with `MIN(?_viaParam)`, require `rdfs:label` inside the OPTIONAL, and coalesce in the hook rather than in SPARQL. +**Files touched**: `src/engine/templates/regions.ts`, `src/hooks/useDiscoveryQueries.ts` +**Prevention**: Test aggregate expressions against **both** `sawgraph` and `federation`; they do not behave identically. And when an aggregate feeds a fallback chain, assert the expected coverage count rather than eyeballing the first few rows, since a silently unbound `SAMPLE` looks exactly like missing data. diff --git a/docs/SCHEMA.md b/docs/SCHEMA.md index 2432945..6ecf03a 100644 --- a/docs/SCHEMA.md +++ b/docs/SCHEMA.md @@ -338,16 +338,53 @@ Substances are `comptox:ChemicalEntity` (`http://w3id.org/DSSTox/v1/`), reached observation via `coso:ofDSSToxSubstance`. 101 of them are typed in sawgraph, and every observed substance is typed, so the type pattern drops nothing. -| Predicate | Coverage | Notes | -|-----------|----------|-------| -| `rdfs:label` | 69 of 101 | Full chemical name, e.g. "Perfluorooctanoic acid" | -| `skos:altLabel` | 25 of 101 | Acronym, e.g. "PFOA" | +A substance carries 39 distinct predicates. Only these can name it: + +| Field | Coverage | Verdict | +|-------|----------|---------| +| `skos:altLabel` on the substance | 25 of 101 | **Best acronym.** Canonical casing: `PFOS`, `PFHxS` | +| `rdfs:label` on the substance | 69 of 101 | **Best full name.** `Perfluorooctanoic acid` | +| `rdfs:label` on the source parameter | **101 of 101** | Polluted in general, good as a last resort | +| `skos:altLabel` on the source parameter | 68 of 101 | Rejected, see below | | `dcterms:alternative` | **0** | Does not exist on substances, on any endpoint | +| `owl:sameAs` | 101 of 101 | Self-referential, useless | +| `hasCASRN`, `hasInChIKey`, `hasSMILES`, `dcterms:identifier` | 40 of 101 | Identifiers, and all sit inside the labelled 69 | +| `rdfs:seeAlso`, `rdfs:isDefinedBy` | 68 of 101 | Provenance URIs | +| 30 physicochemical properties (`logP`, `meltingPoint`, …) | 40 of 101 | Not names | -**Both label predicates must be queried as `OPTIONAL`.** The 32 substances with no -`rdfs:label` carry 47,642 observations, 5.0% of the 944,541 with a substance link. A required -label pattern does not return them unlabelled, it drops them entirely. Fall back to the -DTXSID from the URI instead. +Regenerate with: + +```sparql +SELECT ?p (COUNT(DISTINCT ?s) AS ?substances) WHERE { + ?s a comptox:ChemicalEntity . ?s ?p ?v +} GROUP BY ?p ORDER BY DESC(?substances) +``` + +**The label chain is `skos:altLabel` → `rdfs:label` → source parameter's `rdfs:label` → +DTXSID.** The source parameter is reached by the inbound +`?param comptox:sameAsDSSToxSubstance ?substance`. This resolves all 101. + +**Every label predicate must be queried as `OPTIONAL`.** The 32 substances with no +`rdfs:label` of their own carry 47,642 observations, 5.0% of the 944,541 with a substance +link, and they hold only `rdf:type` and `owl:sameAs`. A required label pattern does not +return them unlabelled, it drops them entirely. + +**Do not use the parameter's `skos:altLabel` as an acronym.** Its `_A` suffix marks the +*acid* as distinct from the anion: `PFOS_A` is Perfluorooctanesulfonic acid +(`DTXSID3031864`), `PFOS` is Perfluorooctanesulfonate (`DTXSID80108992`). `_L` and `_BR` mark +linear and branched isomers. Borrowing these collapses 10 pairs of genuinely different +substances into identical labels; stripping the suffixes makes it worse, not better. + +**Parameter name quality**, for the 171 distinct values: 31 contain `***retired***use …` +(which names its own replacement, so split on it and take the right side), 78 are ALL CAPS, +21 are CAS-index style (`1-Octanesulfonic acid, 1,1,2,2,3,3,…`), and one is misspelled +(`PERFLOUROOCTANE`). 41 substances have several conflicting values, so aggregate with `MIN()` +for determinism. For the 32 that actually need it, 31 have exactly one value and 30 need no +cleanup. + +**Known upstream error:** `me-egad#parameter.PFECHS_A` is aligned to `DTXSID7022546`, which +is `Acetohydroxamic acid`, not a PFAS. 2 observations. Belongs in an issue against +`SAWGraph/pfas-kg`. **Trap:** `dcterms:alternative` in the facility table above is a *facility* predicate. Measured on fiokg: 3,824,195 triples, of which 3,742,487 are on `fio:Facility` and **0 on diff --git a/docs/wiki/Dropdowns Substance.md b/docs/wiki/Dropdowns Substance.md index 556bf58..870e44d 100644 --- a/docs/wiki/Dropdowns Substance.md +++ b/docs/wiki/Dropdowns Substance.md @@ -13,8 +13,10 @@ It appears in the query editor whenever the entity type is **Samples**, inside The list is built from the data rather than hardcoded. It shows every substance that has at least one contaminant observation behind it, sorted by how many observations mention it, with that number in brackets after the name, like `PFOA (20,120)`. Labels prefer the short -acronym, fall back to the full chemical name when a substance has no acronym recorded, and -fall back again to the bare DTXSID when it has no name either. Counts are comma formatted. +acronym, fall back to the full chemical name when a substance has no acronym recorded, then +to the name of the source data parameter it was matched to, and only then to the bare +DTXSID. In current data every one of the 101 substances resolves to a real name, so the +DTXSID step never fires. Counts are comma formatted. Being multi select, the list is headed by a Select all row carrying the number of options it would tick, like `Select all (79)`. Type a search term and that number narrows to the matches. @@ -41,6 +43,7 @@ graph joined in and only `federation` has both graphs. SELECT ?substance (SAMPLE(?_label) AS ?label) (SAMPLE(?_short) AS ?short_label) + (MIN(?_viaParam) AS ?param_label) (COUNT(DISTINCT ?observation) AS ?num) WHERE { ?observation rdf:type coso:ContaminantObservation ; @@ -48,6 +51,7 @@ WHERE { ?substance a comptox:ChemicalEntity . OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } + OPTIONAL { ?pL comptox:sameAsDSSToxSubstance ?substance ; rdfs:label ?_viaParam . } } GROUP BY ?substance ORDER BY DESC(?num) ?label ``` @@ -60,13 +64,20 @@ Reading it a line at a time: * `OPTIONAL { rdfs:label ?_label }` is the full name, like "Perfluorooctanoic acid". Only 69 of the 101 substances have one. * `OPTIONAL { skos:altLabel ?_short }` is the acronym, like "PFOA". Only 25 have one. +* `OPTIONAL { ?pL comptox:sameAsDSSToxSubstance ... }` reaches back to the source data + parameter the substance was matched to, and borrows its name. This is what covers the 32 + substances that have no name of their own, taking the list to 101 named out of 101. * `COUNT(DISTINCT ?observation)` is the number shown in brackets. +`MIN()` rather than `SAMPLE()` on the borrowed name, because 41 substances are matched by +more than one parameter and `SAMPLE()` would pick a different one from run to run. + Both labels are `OPTIONAL` on purpose. A required label pattern does not return an unlabelled substance, it returns nothing at all for that substance, so the row vanishes from the dropdown and takes its observations with it. That single mistake broke this dropdown twice, first to -zero rows and then to 32 missing substances. The hook fills the gap by falling back to the -DTXSID from the URI. +zero rows and then to 32 missing substances. The DTXSID fallback in the hook is the last +resort behind the borrowed name, and is unreachable in current data. It stays anyway, +precisely because a missing label must never delete a row. `SAMPLE()` is used on both labels because a substance can carry more than one of each and the dropdown only has room for one. Any of them will do. @@ -80,6 +91,7 @@ chosen state or counties: SELECT ?substance (SAMPLE(?_label) AS ?label) (SAMPLE(?_short) AS ?short_label) + (MIN(?_viaParam) AS ?param_label) (COUNT(DISTINCT ?observation) AS ?num) WHERE { ?sp rdf:type coso:SamplePoint . @@ -93,6 +105,7 @@ WHERE { ?substance a comptox:ChemicalEntity . OPTIONAL { ?substance rdfs:label ?_label . } OPTIONAL { ?substance skos:altLabel ?_short . } + OPTIONAL { ?pL comptox:sameAsDSSToxSubstance ?substance ; rdfs:label ?_viaParam . } } GROUP BY ?substance ORDER BY DESC(?num) ?label ``` @@ -109,8 +122,9 @@ Sub county selections, meaning codes longer than five digits, take a different r entirely. They join with `kwg-ont:sfWithin|kwg-ont:sfTouches` against a Data Commons `geoId` URI rather than walking the administrative hierarchy. -Verified against the live endpoints on 2026-09-08. The Maine query returns 79 substances, -topped by PFOA at 20120 observations, PFOS at 19988, PFBS at 19895. Unfiltered returns 101. +Verified against the live endpoints on 2026-09-09. The Maine query returns 79 substances, +topped by PFOA at 20120 observations, PFOS at 19988, PFBS at 19895. Unfiltered returns 101, +all of them named, none falling through to a DTXSID. ## How it is wired up @@ -148,10 +162,23 @@ the Analysis Question sentence can say "PFOA" instead of a DSSTox URI. **Exactly seven PFAS substances and no counts.** You are looking at `FALLBACK_SUBSTANCES`. Either the endpoint failed, or the query genuinely returned zero rows. -**A bare DTXSID instead of a chemical name.** That substance has no `rdfs:label` in the graph. -32 of the 101 substances are in that state, carrying 47642 observations between them, which is -5.0 percent of everything with a substance link. They are listed rather than hidden, because -dropping them silently loses that data. Nothing to fix in the app. +**A bare DTXSID instead of a chemical name.** This should no longer happen. 32 substances +have no `rdfs:label` of their own, but all 32 are named by the parameter they were matched +to, so the list resolves 101 out of 101. Seeing a raw DTXSID means a substance now has +neither, which is new data rather than a code bug. + +**A full chemical name where you expected an acronym.** Only 25 substances carry +`skos:altLabel`, so the other 76 show their full name. The source parameters do carry +acronyms for another 44, but they are deliberately not used: the `_A` suffix on them marks +the acid as distinct from the anion, so `PFOS_A` is Perfluorooctanesulfonic acid while +`PFOS` is Perfluorooctanesulfonate, two different DTXSIDs. Adopting them collapsed 10 pairs +of distinct substances into identical looking rows. The full names keep them apart. + +**A substance in the list that is not a PFAS.** `Acetohydroxamic acid` shows up with 2 +observations. That is an upstream alignment error, not a display bug: the Maine EGAD +parameter `me-egad#parameter.PFECHS_A` is mapped to `DTXSID7022546`, which really is +acetohydroxamic acid. Belongs in an issue against +[pfas-kg](https://github.com/SAWGraph/pfas-kg). **Empty after picking a county.** There genuinely are no observations there. Expected, not a bug. From ebe0e74050185ffa874b12ec074c18206f17655e Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 16:04:28 +0530 Subject: [PATCH 09/66] fix(prefixes): drop the dead me_egad_data v1 prefix Maine EGAD instance data has moved to http://w3id.org/sawgraph/v2/me-egad-data#. Verified live: 833,201 observations, 63,744 samples and 10,331 sample points on v2, zero on v1. Nothing broke, because no query constructs a me-egad-data IRI; they all reach that data by type and predicate. The prefix was declared but never referenced, and it now points at a namespace with no triples, which is the same trap that dcterms:alternative was. Removing it rather than repointing it: if a query ever needs it, it should add the correct namespace deliberately. Controlled vocabulary is unaffected, staying in the root v1/me-egad# namespace. --- src/constants/prefixes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/constants/prefixes.ts b/src/constants/prefixes.ts index c5c31e6..d03aa04 100644 --- a/src/constants/prefixes.ts +++ b/src/constants/prefixes.ts @@ -16,7 +16,6 @@ PREFIX naics: PREFIX qudt: PREFIX comptox: PREFIX me_egad: -PREFIX me_egad_data: PREFIX nhdplusv2: PREFIX il_isgs: PREFIX me_mgs: From 4bdf238601c198dd93857954e0deb27ca3e9f3c0 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 16:04:28 +0530 Subject: [PATCH 10/66] docs: correct the Material dropdown page after the namespace consolidation Controlled vocabulary now lives in the root namespaces on both endpoints, which retires three claims on this page. The "URIs change with the region" quirk is gone: sawgraph and federation once named groundwater me-egad# against me-egad-data#, so a selection made before picking a state stopped matching after. Verified 2026-09-09, all six fallback material types return identical counts on both endpoints. Its troubleshooting entry is rewritten as history rather than current behaviour. Species are under v1/us-wqp#biologicalTaxon.*, not us-wqp-data# as written. --- docs/wiki/Dropdowns Material.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/wiki/Dropdowns Material.md b/docs/wiki/Dropdowns Material.md index 53528a4..84a0a84 100644 --- a/docs/wiki/Dropdowns Material.md +++ b/docs/wiki/Dropdowns Material.md @@ -27,11 +27,12 @@ Two quirks worth knowing about before you trust what you see: Cumberland County surfaces `Mytilus edulis`, the blue mussel, sitting in the list next to `GROUNDWATER`. That is what the graph says, and the filter only excludes URIs outside the `http://w3id.org/` namespace. -* **The URIs change with the region.** Without a region the query hits `sawgraph`, which - names groundwater `me-egad#sampleMaterialType.GW`. With a region it hits `federation`, - which names the same thing `me-egad-data#sampleMaterialType.GW`. Same label, different URI. - A selection made before picking a state will therefore not match anything after picking - one. See [If it looks wrong](#if-it-looks-wrong). +* **The URIs used to change with the region, and no longer do.** `sawgraph` and + `federation` once named groundwater differently, `me-egad#sampleMaterialType.GW` against + `me-egad-data#sampleMaterialType.GW`, so a selection made before picking a state stopped + matching after. Fixed upstream: controlled vocabulary now lives in the root namespaces, + `me-egad#` and `us-wqp#`, and both endpoints agree. Verified 2026-09-09, all six fallback + material types return identical counts on both. ## The SPARQL query @@ -128,14 +129,16 @@ by splitting the URI on `#` or `/` and taking the tail. **Exactly six materials with tidy title case labels and no counts.** That is `FALLBACK_MATERIAL_TYPES`. Real results shout in uppercase and carry counts. -**A selection stops matching after picking a state.** This is the `me-egad` versus -`me-egad-data` URI split described above. The two endpoints name the same material -differently, and the stored selection is a URI. Reselect the material after setting the -region. +**A selection stops matching after picking a state.** Historic, fixed upstream in the +September 2026 rebuild. The two endpoints used to name the same material differently and the +stored selection is a URI, so it stopped matching. Both now use the root `me-egad#` +namespace. If you see this again, compare the material URIs the two endpoints return before +assuming it is an app bug. **Species names in a materials list.** Genuinely in the graph, under -`us-wqp-data#biologicalTaxon.*`. The namespace filter does not exclude them. If they should -not be offered, the filter needs to be narrower than `http://w3id.org/`. +`http://w3id.org/sawgraph/v1/us-wqp#biologicalTaxon.*`. The namespace filter does not exclude +them. If they should not be offered, the filter needs to be narrower than +`http://w3id.org/`. **Labels that are URI tails, like `sampleMaterialType.WW`.** That material has no `rdfs:label`, so the hook fell back to the URI tail. From f4da9f85c012349432f8fbc4a17d4f8660d313ea Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 16:05:10 +0530 Subject: [PATCH 11/66] fix(samples): derive a single-valued result_value from qudt:quantityValue coso:measurementValue became multi-valued. A non-detect result now carries two literals, "non-detect" and "non-quantified", so binding it duplicated every non-detect row: of 1,041,155 distinct results only 317,676 have a single value. It is also string-typed, which makes MAX(?result_value) return "non-quantified" rather than a number whenever a non-detect reaches the aggregate. Replaced the binding at all four sites with resultValueClauses(), which derives one value per result from qudt:quantityValue: the number if there is one, else "non-detect", else "non-quantified". Measured over the whole graph that is 1,041,433 rows for 1,041,420 results, down from roughly 723,000 duplicates; the 13 stragglers carry two numeric values and are absorbed by the GROUP BY. The two aggregates now use MAX(?numericResult). qudt:numericValue is xsd:double and orders numerically, verified returning 229.0 / 4.87 / 39.9 where the old form returned a string. No user-visible change yet: coso:measurementUnit is still required everywhere, and only detects have one, so non-detects never reach these queries. This is the correctness groundwork for the two commits that follow. --- src/engine/templates/downstreamSamples.ts | 12 ++++++------ src/engine/templates/fusedQueries.ts | 14 +++++++------- src/engine/templates/samples.ts | 16 +++++++++++++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/engine/templates/downstreamSamples.ts b/src/engine/templates/downstreamSamples.ts index 8b9e839..f32aab4 100644 --- a/src/engine/templates/downstreamSamples.ts +++ b/src/engine/templates/downstreamSamples.ts @@ -1,6 +1,6 @@ import { PREFIXES } from '../../constants/prefixes'; import type { SampleFilters } from '../../types/query'; -import { wrapUri, buildSampleFilterClauses } from './samples'; +import { wrapUri, buildSampleFilterClauses, resultValueClauses } from './samples'; function spValues(spIris: string[]): string { return spIris.map(wrapUri).join(' '); @@ -18,7 +18,7 @@ export function buildSampleRetrievalByIriQuery( SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) - (MAX(?result_value) as ?max) + (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) ?sp ?spWKT ?s2cell @@ -35,8 +35,8 @@ export function buildSampleRetrievalByIriQuery( ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . - ?result coso:measurementValue ?result_value ; - coso:measurementUnit ?unit . + ?result coso:measurementUnit ?unit . + ${resultValueClauses()} ${filterClauses} } GROUP BY ?sp ?spWKT ?s2cell `; @@ -86,8 +86,8 @@ export function buildSampleDetailByIriQuery( OPTIONAL { ?substanceUri skos:altLabel ?altLabel } OPTIONAL { ?substanceUri rdfs:label ?rdfLabel } BIND(COALESCE(?altLabel, ?rdfLabel, REPLACE(STR(?substanceUri), "^.*[#/]", "")) AS ?substance) - ?result coso:measurementValue ?result_value ; - coso:measurementUnit ?unit . + ?result coso:measurementUnit ?unit . + ${resultValueClauses()} OPTIONAL { ?unit qudt:symbol ?unit_sym0 } BIND(COALESCE(?unit_sym0, REPLACE(STR(?unit), "^.*[#/]", "")) AS ?unit_sym) OPTIONAL { ?observation sosa:resultTime ?date } diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 9a9f83d..3be7c07 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -5,7 +5,7 @@ import type { AquiferFilters, SpatialRelationship, } from '../../types/query'; -import { wrapUri, buildSampleFilterClauses } from './samples'; +import { wrapUri, buildSampleFilterClauses, resultValueClauses } from './samples'; import { buildIndustryValues } from './facilities'; import { AQUIFER_TYPE_VALUES } from './aquifers'; import { buildWellCategoryFilter } from './wells'; @@ -65,8 +65,8 @@ export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: stri coso:hasResult ?result${suffix} . ?sample${suffix} coso:sampleOfMaterialType ?matType${suffix} . ?matType${suffix} rdfs:label ?matTypeLabel${suffix} . - ?result${suffix} coso:measurementValue ?result_value${suffix} ; - coso:measurementUnit ?unit${suffix} . + ?result${suffix} coso:measurementUnit ?unit${suffix} . + ${resultValueClauses(suffix)} ${filters}`; } case 'waterBodies': { @@ -261,7 +261,7 @@ export function buildFusedSampleAggregateQuery(opts: FusedSampleSideOpts): strin const suffix = opts.sampleSide === 'anchor' ? 'A' : 'C'; const s2Var = opts.sampleSide === 'anchor' ? '?s2anchor' : '?s2target'; const spVar = `?sp${suffix}`; - const resultVar = `?result_value${suffix}`; + const numericVar = `?numericResult${suffix}`; const substanceVar = `?substance${suffix}`; const matLabelVar = `?matTypeLabel${suffix}`; const observationVar = `?observation${suffix}`; @@ -272,7 +272,7 @@ export function buildFusedSampleAggregateQuery(opts: FusedSampleSideOpts): strin SELECT (COUNT(DISTINCT ${observationVar}) as ?resultCount) (COUNT(DISTINCT ${sampleVar}) as ?sampleCount) - (MAX(${resultVar}) as ?max) + (MAX(${numericVar}) as ?max) (GROUP_CONCAT(DISTINCT ${substanceVar}; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ${matLabelVar}; separator="; ") as ?materials) (${spVar} AS ?sp) ?spWKT (${s2Var} AS ?s2cell) @@ -389,8 +389,8 @@ export function buildFusedSampleDetailsQuery(opts: FusedSampleSideOpts): string OPTIONAL { ?substanceUri skos:altLabel ?altLabel } OPTIONAL { ?substanceUri rdfs:label ?rdfLabel } BIND(COALESCE(?altLabel, ?rdfLabel, REPLACE(STR(?substanceUri), "^.*[#/]", "")) AS ?substance) - ?result coso:measurementValue ?result_value ; - coso:measurementUnit ?unit . + ?result coso:measurementUnit ?unit . + ${resultValueClauses()} OPTIONAL { ?unit qudt:symbol ?unit_sym0 } BIND(COALESCE(?unit_sym0, REPLACE(STR(?unit), "^.*[#/]", "")) AS ?unit_sym) ${outerFilter} diff --git a/src/engine/templates/samples.ts b/src/engine/templates/samples.ts index 28f2a32..07edcb6 100644 --- a/src/engine/templates/samples.ts +++ b/src/engine/templates/samples.ts @@ -7,8 +7,22 @@ export function wrapUri(uri: string): string { const NG_PER_L_UNIT_URI = 'http://qudt.org/vocab/unit/NanoGM-PER-L'; +// Binds ?numericResult, ?nonDetect and a single-valued ?result_value from +// qudt:quantityValue. coso:measurementValue is deliberately not used: it is +// multi-valued for non-detects, returning both "non-detect" and "non-quantified", +// which duplicates every non-detect row and makes MAX() return a string. +export function resultValueClauses(suffix = ''): string { + return `OPTIONAL { ?result${suffix} qudt:quantityValue/qudt:numericValue ?numericResult${suffix} } + OPTIONAL { ?result${suffix} qudt:quantityValue ?_qv${suffix} . + ?_qv${suffix} rdf:type coso:NonDetectQuantityValue . + BIND(true AS ?nonDetect${suffix}) } + BIND(COALESCE(STR(?numericResult${suffix}), + IF(BOUND(?nonDetect${suffix}), "non-detect", "non-quantified")) AS ?result_value${suffix})`; +} + // Emits the SPARQL fragment that filters by substance / material / concentration -// range. Requires the caller to bind ?result, ?result_value, and ?unit before +// range. Requires the caller to bind ?result and ?unit, and to emit +// resultValueClauses() beforehand, which provides ?result_value and friends. // this fragment appears. `suffix` (default '') is appended to every variable // so the same fragment can be used inside fused queries where anchor and // target sides need disambiguated vars (e.g. '?resultC'). From e346d39df8a4d2a7631bb3635dcf58f518a0c916 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 16:05:30 +0530 Subject: [PATCH 12/66] fix(samples): repair the dead non-detect filter The Include non-detects checkbox had been inert in both directions. It keyed off qudt:enumeratedValue, which has zero triples: contaminoso a533442 (2026-04-20) removed it in favour of typing the value node instead. ?enumDetected therefore never bound, so: range + include -> FILTER(numeric || BOUND(?enumDetected)) dropped non-detects even when asked to include them no range + exclude -> FILTER(!BOUND(?enumDetected)) was always true, so the exclusion did nothing Now keyed off ?nonDetect from resultValueClauses, which tests ?qv rdf:type coso:NonDetectQuantityValue (723,410 instances). Chose the narrow class over NonQuantifiedQuantityValue (814,291) because non-detect is a strict subset; the other 90,881 are unquantified for other reasons. Exclude now means "keep only rows with a real number", which also drops that non-quantified cohort. The redundant OPTIONALs and the xsd:decimal(?result_value) COALESCE leg go away, since resultValueClauses already binds those. Still no user-visible change: the required unit join keeps non-detects out of the query entirely. The next commit addresses that. --- src/engine/templates/samples.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/engine/templates/samples.ts b/src/engine/templates/samples.ts index 07edcb6..e321643 100644 --- a/src/engine/templates/samples.ts +++ b/src/engine/templates/samples.ts @@ -41,13 +41,8 @@ export function buildSampleFilterClauses(filters?: SampleFilters, suffix = ''): filters.minConcentration != null || filters.maxConcentration != null; const excludeNondetects = filters.includeNondetects === false; - if (hasRange || excludeNondetects) { - clauses += `OPTIONAL { ?result${suffix} qudt:quantityValue/qudt:numericValue ?numericResult${suffix} }\n `; - clauses += `OPTIONAL { ?result${suffix} qudt:enumeratedValue ?enumDetected${suffix} }\n `; - } - if (hasRange) { - clauses += `BIND(COALESCE(xsd:decimal(?numericResult${suffix}), xsd:decimal(?result_value${suffix})) as ?numericValue${suffix})\n `; + clauses += `BIND(xsd:decimal(?numericResult${suffix}) as ?numericValue${suffix})\n `; clauses += `VALUES ?unit${suffix} { <${NG_PER_L_UNIT_URI}> }\n `; const numericChecks: string[] = []; @@ -61,12 +56,11 @@ export function buildSampleFilterClauses(filters?: SampleFilters, suffix = ''): if (excludeNondetects) { clauses += `FILTER(${numericExpr})\n `; - clauses += `FILTER(!BOUND(?enumDetected${suffix}))\n `; } else { - clauses += `FILTER((${numericExpr}) || BOUND(?enumDetected${suffix}))\n `; + clauses += `FILTER((${numericExpr}) || BOUND(?nonDetect${suffix}))\n `; } } else if (excludeNondetects) { - clauses += `FILTER(!BOUND(?enumDetected${suffix}))\n `; + clauses += `FILTER(BOUND(?numericResult${suffix}))\n `; } return clauses; From 7cbe0e838942bcdfecf306f5b8edae2aa72551b7 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 16:05:49 +0530 Subject: [PATCH 13/66] fix(samples): stop the required unit join from hiding non-detects coso:measurementUnit exists on exactly 228,124 results, which is precisely the set that has a numeric value. Requiring it therefore excluded every non-detect from every sample query: about 70% of all results, 722,206 of 1,041,420. That join was only ever needed by the ng/L concentration-range filter, so it is now emitted only when a range is set (needsUnitJoin), and the unit test moved onto the numeric branch of the filter where it belongs. Verified live on one sample point: include non-detects 28 observations max=202.0 exclude non-detects 16 observations max=202.0 range 10-100 exclude 3 observations max=19.4 range 10-100 include 15 observations max=19.4 Warm-cache timings 2.5-3.5s; the 23s first run was cold cache. Two places deliberately keep the join, both documented in the code: The sample-detail queries, because making the unit optional there produces reproducible 502s and >120s hangs on a healthy endpoint. It buys nothing today since resultTransformer.ts discards non-numeric values anyway. The fused pipeline query, because admitting non-detects roughly triples the matched rows and the endpoint OOMs on statewide runs. Verified: the prebuilt Maine query fails outright with them included, and completes in 32s with 29 map features without. Consequence to be aware of: a sample point can now report more observations on the map than the popup lists, because the popup path is still detect-only. Surfacing non-detects in the popup is a separate, deferred decision. --- src/engine/templates/downstreamSamples.ts | 4 ++-- src/engine/templates/fusedQueries.ts | 3 +++ src/engine/templates/samples.ts | 17 +++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/engine/templates/downstreamSamples.ts b/src/engine/templates/downstreamSamples.ts index f32aab4..0fe5109 100644 --- a/src/engine/templates/downstreamSamples.ts +++ b/src/engine/templates/downstreamSamples.ts @@ -1,6 +1,6 @@ import { PREFIXES } from '../../constants/prefixes'; import type { SampleFilters } from '../../types/query'; -import { wrapUri, buildSampleFilterClauses, resultValueClauses } from './samples'; +import { wrapUri, buildSampleFilterClauses, resultValueClauses, needsUnitJoin } from './samples'; function spValues(spIris: string[]): string { return spIris.map(wrapUri).join(' '); @@ -35,7 +35,7 @@ export function buildSampleRetrievalByIriQuery( ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . - ?result coso:measurementUnit ?unit . + ${needsUnitJoin(filters) ? '?result coso:measurementUnit ?unit .' : ''} ${resultValueClauses()} ${filterClauses} } GROUP BY ?sp ?spWKT ?s2cell diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 3be7c07..1e9ebfa 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -56,6 +56,9 @@ export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: stri } case 'samples': { const filters = buildSampleFilterClauses(block.sampleFilters, suffix); + // ponytail: coso:measurementUnit exists only on detects, so the join below + // also excludes non-detects. Dropping it is correct but triples the matched + // rows and the endpoint OOMs on statewide pipelines. Revisit if capacity grows. return `?sp${suffix} rdf:type coso:SamplePoint ; spatial:connectedTo ${s2Var} . ?observation${suffix} rdf:type coso:ContaminantObservation ; diff --git a/src/engine/templates/samples.ts b/src/engine/templates/samples.ts index e321643..07af7ac 100644 --- a/src/engine/templates/samples.ts +++ b/src/engine/templates/samples.ts @@ -7,6 +7,13 @@ export function wrapUri(uri: string): string { const NG_PER_L_UNIT_URI = 'http://qudt.org/vocab/unit/NanoGM-PER-L'; +// The ng/L unit is only consulted by the concentration-range filter. A +// non-detect has no coso:measurementUnit at all, so binding it unconditionally +// silently drops ~70% of results. Callers emit the triple only when needed. +export function needsUnitJoin(filters?: SampleFilters): boolean { + return filters?.minConcentration != null || filters?.maxConcentration != null; +} + // Binds ?numericResult, ?nonDetect and a single-valued ?result_value from // qudt:quantityValue. coso:measurementValue is deliberately not used: it is // multi-valued for non-detects, returning both "non-detect" and "non-quantified", @@ -21,8 +28,7 @@ export function resultValueClauses(suffix = ''): string { } // Emits the SPARQL fragment that filters by substance / material / concentration -// range. Requires the caller to bind ?result and ?unit, and to emit -// resultValueClauses() beforehand, which provides ?result_value and friends. +// range. Requires the caller to bind ?result, ?result_value, and ?unit before // this fragment appears. `suffix` (default '') is appended to every variable // so the same fragment can be used inside fused queries where anchor and // target sides need disambiguated vars (e.g. '?resultC'). @@ -43,9 +49,12 @@ export function buildSampleFilterClauses(filters?: SampleFilters, suffix = ''): if (hasRange) { clauses += `BIND(xsd:decimal(?numericResult${suffix}) as ?numericValue${suffix})\n `; - clauses += `VALUES ?unit${suffix} { <${NG_PER_L_UNIT_URI}> }\n `; - const numericChecks: string[] = []; + const numericChecks: string[] = [ + // ponytail: the unit test belongs on the numeric branch. A non-detect has + // no coso:measurementUnit, so requiring it globally silently drops them. + `?unit${suffix} = <${NG_PER_L_UNIT_URI}>`, + ]; if (filters.minConcentration != null) { numericChecks.push(`?numericValue${suffix} >= ${filters.minConcentration}`); } From ef0c40b6ebd05a83fb3b5c6304c6d09da5d5b135 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 21:39:54 +0530 Subject: [PATCH 14/66] fix(material): point material type URIs at the live root namespace Every material type IRI we ship pointed at v1/me-egad-data#, which matches zero triples. Controlled vocabulary was moved out of the -data namespace into the root while instance data moved the other way, to v2/me-egad-data#. Source of truth is pfas-kg, datasets/maine/egad/controlledVocab/sample_type.ttl, where the prefix is v1/me-egad# and 47 terms are defined. Confirmed by Katrina's note on the reload: "all controlled vocabulary terms are in the root namespaces". Verified live, all four combinations for groundwater: v1/me-egad#sampleMaterialType.GW 46,110 triples v1/me-egad-data#sampleMaterialType.GW 0 v2/me-egad#sampleMaterialType.GW 0 v2/me-egad-data#sampleMaterialType.GW 0 The failure was silent. VALUES with a dead IRI is valid SPARQL, so the endpoint answers 200 with no rows and the app cannot tell that apart from "no data here". The PFHpA Cumberland County card ran every step, reported success and drew an empty map. Also corrects the sludge code. The fallback listed .SO, which appears nowhere in the vocabulary; the real code is .SU. All six shipped IRIs now resolve: GROUNDWATER 609,496, SOIL 80,386, SURFACE WATER 26,424, LEACHATE 6,126, DRINKING WATER 2,858, SLUDGE 850. Scoped to the sample side, the card's own filters now return 65 sample points and 171 observations in 2.3s, against 0 before. The full card still fails on the downstream hydrology join, which times out and OOMs on federation. That is pre-existing and unrelated: the same query fails identically with the old dead IRI, and the endpoint is currently reporting 88 MB available. --- src/constants/materialTypes.ts | 16 +++++++++------- src/constants/prebuiltQueries.ts | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/constants/materialTypes.ts b/src/constants/materialTypes.ts index 17f8714..06317ab 100644 --- a/src/constants/materialTypes.ts +++ b/src/constants/materialTypes.ts @@ -13,12 +13,14 @@ export const MATERIAL_GROUP_BY_PRIO: Record = { '4': 'Air', }; -// Fallback material types if discovery query fails +// Fallback material types if discovery query fails. Controlled vocabulary lives in +// the root me-egad namespace, not me-egad-data — see pfas-kg's +// datasets/maine/egad/controlledVocab/sample_type.ttl. Verified live 2026-09-11. export const FALLBACK_MATERIAL_TYPES: MaterialType[] = [ - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.GW', label: 'Groundwater (GW)' }, - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.DW', label: 'Drinking Water (DW)' }, - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.SW', label: 'Surface Water (SW)' }, - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.SL', label: 'Soil (SL)' }, - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.SO', label: 'Sludge (SO)' }, - { uri: 'http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.L', label: 'Leachate (L)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.GW', label: 'Groundwater (GW)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.DW', label: 'Drinking Water (DW)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.SW', label: 'Surface Water (SW)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.SL', label: 'Soil (SL)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.SU', label: 'Sludge (SU)' }, + { uri: 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.L', label: 'Leachate (L)' }, ]; diff --git a/src/constants/prebuiltQueries.ts b/src/constants/prebuiltQueries.ts index 56957de..c31ad40 100644 --- a/src/constants/prebuiltQueries.ts +++ b/src/constants/prebuiltQueries.ts @@ -180,7 +180,7 @@ export const PREBUILT_QUERIES: PrebuiltQuery[] = [ sampleFilters: { substances: ['http://w3id.org/DSSTox/v1/DTXSID1037303'], substanceLabels: { 'http://w3id.org/DSSTox/v1/DTXSID1037303': 'PFHpA' }, - materialTypes: ['http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.GW'], + materialTypes: ['http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.GW'], minConcentration: 10, maxConcentration: 1000, }, From 1574327b28747837bec7e5d1c7e92107a2406100 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 21:42:58 +0530 Subject: [PATCH 15/66] docs(changelog): record the material IRI fix and correct week 37 Entries 5 to 8 were written locally on 2026-09-09 and never committed. Restored them, then corrected the material entry, which described a fix that had not landed in the repo until ef0c40b. Changes to that entry: - Dated 2026-09-11, not 09-09, and moved last so the file stays chronological. Remaining entries renumbered, and the two cross references between them repointed. - Replaced "went from 0 to 49 sample points and 268 facilities" with what is measurable today: 65 sample points and 171 observations, scoped to the sample side. The old figure was a whole-pipeline result and cannot be reproduced, because the card now fails on the downstream hydrology join. - Records that the card is still broken for a second, unrelated reason. The same query times out with the old dead IRI too, so the namespace fix neither caused nor worsened it. - Labels the sludge count, which was a bare "334". It is a sample count, now 330 samples / 850 observations. - Adds the source of truth, pfas-kg's sample_type.ttl, and the four-namespace comparison behind the fix. - Notes that QLever returns HTTP 429 for a query timeout, which reads like rate limiting and is not. That cost some time to work out. The audit entry claimed 7 of 8 prebuilt queries passed. True on the day only because the material fix was applied in the working tree; anyone checking out that commit range would have seen the PFHpA card fail. Said so plainly. --- docs/changelog/2026-W37.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/changelog/2026-W37.md b/docs/changelog/2026-W37.md index bd6be30..1b12495 100644 --- a/docs/changelog/2026-W37.md +++ b/docs/changelog/2026-W37.md @@ -29,3 +29,37 @@ `SCHEMA.md` had no substance or chemical inventory at all, despite being the predicate reference. Added a Substance Labels section recording the coverage that matters: `rdfs:label` on 69 of 101, `skos:altLabel` on 25, `dcterms:alternative` on none, plus an explicit warning that the identically named facility predicate is a different thing. Rewrote `docs/wiki/Dropdowns Substance.md` around the corrected query and refreshed its numbers, which were stale. Logged the root cause in `DEBUGGING.md` with the reusable lesson: a required label pattern does not degrade, it deletes. *Files:* `docs/SCHEMA.md`, `docs/DEBUGGING.md`, `docs/wiki/Dropdowns Substance.md`, `docs/wiki/Dropdowns.md`, `docs/changelog/2026-W36.md` + +5. **Audit: All Prebuilt Queries and Dropdowns Run Against Live Endpoints** (2026-09-09) + Executed all 8 prebuilt pipelines and all 15 dropdown discovery queries end to end. Dropdowns: 15 of 15 return rows, no fallback triggered. The two slowest are Industry/NAICS at 26s (5,596 rows) and Illinois well purposes at 38s (33 rows). + + Prebuilt queries: 7 of 8 passed on the day, with the PFHpA card counted as passing because the material IRI fix in entry 8 was applied locally at the time — it did not land in the repo until 2026-09-11, so anyone checking out this commit range would have seen it fail. The remaining failure is "Samples Downstream of Waste Treatment Facilities in Indiana", which gets HTTP 500 from `federation` with `Tried to allocate 409.6 MB, but only 351 MB were available`. Reproducible on an idle endpoint, so it is not load. The `FIND_TARGET_IRIS` query selects only `?spC` but still binds `?observationC ?substanceC ?sampleC ?matTypeC ?matTypeLabelC ?resultC ?unitC`, none of which are projected or filtered on when the question carries no sample filters — statewide Indiana is large enough that the unused join blows the memory budget. Not yet fixed. + + Also worth recording: `apps.okn.us` is flaky under concurrent load. Two pipelines (`samples-near-agchem-maine`, `wells-near-landfill-dod-maine`) failed during the batch run and both pass cleanly in isolation — the latter completes all 5 steps in 14s on an idle endpoint after failing twice at 500s and 1165s under load. + +6. **All 101 Substances Now Show a Real Chemical Name** (2026-09-09) + Entry 2 made the 32 label-less substances visible as bare DTXSIDs. They now show real names. Every one of them is the target of a `comptox:sameAsDSSToxSubstance` link from the source-data parameter it was matched to, and that parameter carries a name on `rdfs:label`. Added it as a fourth step in the chain: `skos:altLabel` → `rdfs:label` → parameter's `rdfs:label` → DTXSID. Verified live: 101 of 101 named unfiltered, 79 of 79 for Maine, no DTXSID rows and no duplicate labels. + + Surveyed all 39 predicates a substance carries before picking. Only two name it; the rest are identifiers (`hasCASRN`, `hasInChIKey`, all sitting inside the already-labelled 69), provenance URIs, or physicochemical properties. `owl:sameAs` is self-referential and useless. + + The parameter also carries acronyms, covering 68 rather than 25, and those were deliberately **not** adopted. The `_A` suffix marks the acid as distinct from the anion, so `PFOS_A` is Perfluorooctanesulfonic acid and `PFOS` is Perfluorooctanesulfonate, two different DTXSIDs. Borrowing them collapsed 10 pairs of distinct substances into identical rows, and stripping the suffix made it 10 rather than 7. The full chemical names keep them apart. + + *Files:* `src/engine/templates/regions.ts`, `src/hooks/useDiscoveryQueries.ts`, `docs/SCHEMA.md`, `docs/DEBUGGING.md`, `docs/wiki/Dropdowns Substance.md` + +7. **Found: PFECHS Aligned to the Wrong Chemical Upstream** (2026-09-09) + `Acetohydroxamic acid` appears in the Substance dropdown with 2 observations. Not a PFAS, and not a display bug: the Maine EGAD parameter `me-egad#parameter.PFECHS_A` is aligned to `DTXSID7022546`, which genuinely is acetohydroxamic acid. The correct target is perfluoroethylcyclohexane sulfonate. Belongs in an issue against `SAWGraph/pfas-kg`; nothing to fix here. Worth noting that displaying the parameter acronym instead would have masked this behind a plausible-looking `PFECHS`. + + *Files:* documented in `docs/SCHEMA.md` and `docs/wiki/Dropdowns Substance.md` + +8. **Fixed: Material Type IRIs Pointed at a Dead Namespace** (2026-09-11) + The "PFHpA Groundwater Samples Downstream from Facilities in Cumberland County" prebuilt card ran to completion and rendered an empty map. Its material-type filter pinned `http://w3id.org/sawgraph/v1/me-egad-data#sampleMaterialType.GW`, which matches zero triples. All six entries of `FALLBACK_MATERIAL_TYPES` carried the same dead namespace, so the fallback list would have been equally inert had discovery ever failed over to it. + + The August reload moved the two halves in opposite directions: instance data went to `v2/me-egad-data#`, controlled vocabulary came out of `-data` into the root `v1/me-egad#`. Source of truth is `pfas-kg`, `datasets/maine/egad/controlledVocab/sample_type.ttl`, whose prefix is `v1/me-egad#` and which defines 47 terms. Confirmed by Katrina's note on the reload: "all controlled vocabulary terms are in the root namespaces". Checked all four combinations for groundwater — `v1/me-egad#` has 46,110 triples, the other three have none. + + The failure was silent by construction. `VALUES` with a dead IRI is valid SPARQL, so the endpoint answers 200 with no rows and the app cannot distinguish that from "no data here". + + Also corrected the sludge code: the fallback listed `sampleMaterialType.SO`, which appears nowhere in the vocabulary; the real code is `.SU` (SLUDGE, 330 samples / 850 observations). All six shipped IRIs now resolve — GROUNDWATER 609,496, SOIL 80,386, SURFACE WATER 26,424, LEACHATE 6,126, DRINKING WATER 2,858, SLUDGE 850 observations. + + Scoped to the sample side, the card's own filters now return 65 sample points and 171 observations in 2.3s, against 0 before. **The card as a whole still fails**, on the downstream hydrology join, which times out and then OOMs on `federation`. That is pre-existing and unrelated — the same query fails identically with the old dead IRI. Note that QLever reports a timeout as HTTP 429, which reads like rate limiting and is not. See entry 5 on endpoint flakiness; retry on an idle endpoint before investigating. + + *Files:* `src/constants/prebuiltQueries.ts`, `src/constants/materialTypes.ts` From 6bf13d8d58f81a52a9408f917a5b395eb4387b36 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Fri, 11 Sep 2026 22:08:22 +0530 Subject: [PATCH 16/66] feat(material): make the group headings selectable and collapsible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Material dropdown already grouped its 171 options into Water, Biota, Solid Material, Air and Other, but the headings were plain divs. No checkbox, no arrow, so no way to say "all water samples" and no way to fold a group away. That hurts because the distribution is lopsided: 131 of the 171 are individual fish species, all under Biota. Points the field at HierarchicalSelect, the tree the Industry dropdown already uses, rather than FlatSelect. No SPARQL changes. The groups are a display concept the graph knows nothing about, so a heading carries a synthetic __group: code that is expanded back to its children's real material-type URIs before anything is stored. The query the pipeline sends is identical to ticking every child by hand. Counts roll up correctly because MIN(?bucketPrio) already forces each material type into exactly one group — verified for Maine, where Water reads 556,269 and its thirteen children sum to 556,269. Generalising the tree component for a second caller: - buildTree takes an optional explicit parent, since material-type URIs have no prefix convention to derive one from. Prefix trimming stays as the fallback, so Industry is untouched. - When a caller supplies explicit parents, its ordering is kept rather than sorted by code length. Without this the discovery query's ORDER BY DESC(?num) was thrown away and Biota's 131 species came out in opaque URI order. Caught by the tree check, not by reading the code. - labelOnly keeps the code out of labels, chips and search, because "3253 - Agricultural Chemical Manufacturing" is right for NAICS and a URI is not. Search matching on the code would otherwise make "w3id" match all 171. - industries prop renamed to items; one call site. Also adds materialTypeLabels, so the generated question reads "GROUNDWATER samples" rather than "GW samples" and "Lepomis macrochirus" rather than "11868". Verified in the running app against Maine: four tickable groups with Air correctly absent, Water expanding to thirteen count-ordered children, ticking the heading yielding one chip instead of thirteen, and partial selection showing indeterminate. --- .../QueryEditor/FacilityFilters.tsx | 2 +- .../HierarchicalSelect/HierarchicalSelect.tsx | 27 +++++--- .../HierarchicalSelect/TreeNode.tsx | 5 +- .../HierarchicalSelect/useNaicsTree.ts | 50 ++++++++------ src/components/QueryEditor/SampleFilters.tsx | 68 ++++++++++++++++--- src/types/query.ts | 1 + src/utils/questionGenerator.ts | 3 +- 7 files changed, 114 insertions(+), 42 deletions(-) diff --git a/src/components/QueryEditor/FacilityFilters.tsx b/src/components/QueryEditor/FacilityFilters.tsx index f7eea9d..777bc94 100644 --- a/src/components/QueryEditor/FacilityFilters.tsx +++ b/src/components/QueryEditor/FacilityFilters.tsx @@ -17,7 +17,7 @@ export function FacilityFilters({ value, onChange, region }: FacilityFiltersProp
onChange({ ...value, industryCodes: codes, industryLabels: labels })} placeholder="Any industry..." diff --git a/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx b/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx index 81d737c..cf2b228 100644 --- a/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx +++ b/src/components/QueryEditor/HierarchicalSelect/HierarchicalSelect.tsx @@ -1,15 +1,18 @@ import { useState, useRef, useEffect, useCallback, useMemo } from 'react'; import { createPortal } from 'react-dom'; -import type { NaicsIndustry } from '../../../constants/naics'; +import type { TreeItem } from './useNaicsTree'; import { useNaicsTree, getAllDescendantCodes, rollupCounts, expandSelections, filterTree } from './useNaicsTree'; import { TreeNode } from './TreeNode'; interface HierarchicalSelectProps { - industries: NaicsIndustry[]; + items: TreeItem[]; selectedCodes: string[]; onChange: (codes: string[], labels: Record) => void; placeholder?: string; counts?: Record; + // Set when the code is a URI rather than something a reader recognises, so it + // is kept out of labels, chips and the search. + labelOnly?: boolean; } interface DropdownPosition { @@ -20,11 +23,12 @@ interface DropdownPosition { } export function HierarchicalSelect({ - industries, + items, selectedCodes, onChange, placeholder = 'Any industry...', counts, + labelOnly, }: HierarchicalSelectProps) { const [isOpen, setIsOpen] = useState(false); const [expandedNodes, setExpandedNodes] = useState>(new Set()); @@ -35,7 +39,7 @@ export function HierarchicalSelect({ const dropdownRef = useRef(null); const searchRef = useRef(null); - const { roots, nodeMap, userSelections } = useNaicsTree(industries, selectedCodes); + const { roots, nodeMap, userSelections } = useNaicsTree(items, selectedCodes); const allSelectedSet = useMemo( () => new Set(expandSelections(userSelections, nodeMap)), @@ -48,8 +52,8 @@ export function HierarchicalSelect({ ); const { roots: visibleRoots, expand: searchExpand } = useMemo( - () => filterTree(roots, query), - [roots, query], + () => filterTree(roots, query, !labelOnly), + [roots, query, labelOnly], ); const effectiveExpanded = query.trim() ? searchExpand : expandedNodes; @@ -217,8 +221,10 @@ export function HierarchicalSelect({ result.push({ code: node.code, label: node.label }); } } - return result.sort((a, b) => a.code.localeCompare(b.code)); - }, [userSelections, nodeMap]); + return result.sort((a, b) => + labelOnly ? a.label.localeCompare(b.label) : a.code.localeCompare(b.code), + ); + }, [userSelections, nodeMap, labelOnly]); const hasValue = chips.length > 0; @@ -245,7 +251,7 @@ export function HierarchicalSelect({ {chips.map((chip) => ( - {chip.code} - {chip.label} + {labelOnly ? chip.label : `${chip.code} - ${chip.label}`} +
+ ); +} diff --git a/src/components/Pipeline/PipelineProgressStrip.tsx b/src/components/Pipeline/PipelineProgressStrip.tsx index 7b8b6b6..bbfdef0 100644 --- a/src/components/Pipeline/PipelineProgressStrip.tsx +++ b/src/components/Pipeline/PipelineProgressStrip.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { useQueryStore } from '../../store/queryStore'; +import { userMessageFor } from '../../engine/sparqlErrors'; const MESSAGES = [ 'Please wait while we prepare the data for you…', @@ -12,6 +13,7 @@ export function PipelineProgressStrip() { const isRunning = useQueryStore((s) => s.isRunning); const isEditModalOpen = useQueryStore((s) => s.isEditModalOpen); const pipelineResult = useQueryStore((s) => s.pipelineResult); + const stepProgress = useQueryStore((s) => s.stepProgress); const [msgIndex, setMsgIndex] = useState(0); useEffect(() => { @@ -31,13 +33,24 @@ export function PipelineProgressStrip() { if (!isRunning && !isError) return null; + // When a step has been split into slices, show real progress instead of a + // rotating reassurance message. + const chunked = stepProgress.find( + (p) => p?.status === 'running' && (p.chunksTotal ?? 0) > 1, + ); + let message: string; - if (isRunning) { + if (isRunning && chunked) { + message = `${chunked.description} — ${chunked.chunksDone ?? 0} of ${chunked.chunksTotal} areas done…`; + } else if (isRunning) { message = MESSAGES[msgIndex]; } else if (pipelineResult?.status === 'empty') { message = 'No results found for this query. Try adjusting the filters.'; } else { - message = 'Something went wrong. You can edit the question and try again.'; + // Nine distinct failures used to share one message; tell the user which. + message = userMessageFor( + pipelineResult?.status === 'error' ? pipelineResult.error : undefined, + ); } // Running outside modal (initial load from dashboard) → full-screen blocking overlay diff --git a/src/engine/executor.ts b/src/engine/executor.ts index c3f9aaf..078c2bc 100644 --- a/src/engine/executor.ts +++ b/src/engine/executor.ts @@ -1,11 +1,20 @@ import type { AnalysisQuestion } from '../types/query'; import type { SparqlRow } from '../types/sparql'; import type { PipelineStep, PipelineContext } from './planner'; +import type { Scope } from './scope'; import { executeSparql } from './sparqlClient'; +import { SparqlError, isSplittable } from './sparqlErrors'; + +export interface PartialFailure { + step: string; + scopes: string[]; +} export interface PipelineSuccess { status: 'success'; data: Record; + // Set when some slices of the work failed but enough succeeded to show a map. + partial?: PartialFailure[]; } export interface PipelineEmpty { @@ -29,6 +38,110 @@ export interface StepProgress { description: string; status: 'running' | 'done' | 'failed' | 'skipped'; resultCount?: number; + // Present once a step has been split into slices, so the UI can show + // "3 of 8 areas" instead of an unmoving spinner. + chunksDone?: number; + chunksTotal?: number; +} + +// Splitting a very large question can produce dozens of slices, each taking +// seconds — "facilities downstream of facilities in Maine" divides into 16 +// counties and still cannot finish. Past this point a user is better served by +// a partial map (or a clear "too large" message) than by an open-ended spinner. +// +// Budgeted per step rather than per pipeline: a question whose every step makes +// steady progress should be allowed to finish — Illinois downstream questions +// legitimately take ~3.5 minutes across all steps — while a single step that +// cannot get anywhere is cut off quickly. +const STEP_BUDGET_MS = 120_000; + +// Queries that have already failed as a whole in this session. Re-running the +// same question would otherwise pay the engine's full 30s timeout again before +// reaching the same conclusion. +const knownTooLarge = new Set(); + +interface StepOutcome { + rows: SparqlRow[]; + failedScopes: string[]; + lastError?: SparqlError | Error; +} + +// Runs one step, slicing it up if the engine refuses the whole thing. +// +// The engine kills any query at 30s and reports it as a 429 (see sparqlErrors). +// Rather than guessing a safe size up front, we try the whole query and only +// split what actually fails — most questions never split at all, and the ones +// that do split only as far as they need. +async function runStep( + step: PipelineStep, + context: PipelineContext, + deadline: number, + report: (chunksDone: number, chunksTotal: number) => void, +): Promise { + const queue: (Scope | undefined)[] = step.initialScopes?.(context) ?? [undefined]; + const rows: SparqlRow[] = []; + const seen = new Set(); + const failedScopes: string[] = []; + let lastError: SparqlError | Error | undefined; + let done = 0; + + while (queue.length > 0) { + const scope = queue.shift()!; + + // Out of time. Keep whatever came back and record the rest as skipped; if + // nothing came back, the step reports failure below rather than running on. + if (Date.now() > deadline) { + failedScopes.push( + ...[scope, ...queue].map((s, i) => s?.label ?? `remaining slice ${i + 1}`), + ); + break; + } + + const total = done + queue.length + 1; + report(done, total); + + const query = step.buildQuery(context, scope); + + if (!scope && knownTooLarge.has(query) && step.divide) { + const smaller = await step.divide(context, undefined); + if (smaller?.length) { + queue.unshift(...smaller); + continue; + } + } + + try { + const result = await executeSparql(step.endpoint, query, { cache: step.cache }); + // Slices can overlap — the same river reach is reached from several + // anchors — so merge as a set. Whole-row identity is the right key: for + // aggregate rows the GROUP BY key never spans slices (chunking always + // follows that key), so identical rows are genuine duplicates. + for (const row of result) { + const key = JSON.stringify(row); + if (seen.has(key)) continue; + seen.add(key); + rows.push(row); + } + done++; + } catch (err) { + const error = err instanceof Error ? err : new Error(String(err)); + lastError = error; + const splittable = error instanceof SparqlError && isSplittable(error.kind); + if (splittable && !scope) knownTooLarge.add(query); + const smaller = splittable ? await step.divide?.(context, scope) : null; + + if (smaller?.length) { + queue.unshift(...smaller); + continue; + } + // Cannot divide further: keep whatever the other slices produced. + failedScopes.push(scope?.label ?? 'whole query'); + done++; + } + } + + report(done, done); + return { rows, failedScopes, lastError }; } export async function executePipeline( @@ -42,72 +155,23 @@ export async function executePipeline( anchorIris: [], results: {}, }; + const partial: PartialFailure[] = []; for (let i = 0; i < steps.length; i++) { const step = steps[i]; - onProgress({ - stepIndex: i, - totalSteps: steps.length, - description: step.description, - status: 'running', - }); + const base = { stepIndex: i, totalSteps: steps.length, description: step.description }; + onProgress({ ...base, status: 'running' }); + let outcome: StepOutcome; try { - const query = step.buildQuery(context); - const results = await executeSparql(step.endpoint, query); - context.results[step.type] = results; - - if (step.type === 'FIND_TARGET_IRIS') { - const iris = new Set(); - for (const r of results) if (r.iri) iris.add(r.iri); - context.targetIris = [...iris]; - - if (context.targetIris.length === 0) { - onProgress({ - stepIndex: i, - totalSteps: steps.length, - description: step.description, - status: 'done', - resultCount: 0, - }); - return { - status: 'empty', - failedAtStep: i, - message: `No results at step: ${step.description}`, - }; + const deadline = Date.now() + STEP_BUDGET_MS; + outcome = await runStep(step, context, deadline, (chunksDone, chunksTotal) => { + if (chunksTotal > 1) { + onProgress({ ...base, status: 'running', chunksDone, chunksTotal }); } - } - - if (step.type === 'FIND_ANCHOR_IRIS') { - const iris = new Set(); - for (const r of results) if (r.iri) iris.add(r.iri); - context.anchorIris = [...iris]; - } - - // Hydrate results are aliased into the legacy keys that useMapLayers - // (src/hooks/useMapLayers.ts:38-42) consumes unchanged. - if (step.type === 'HYDRATE_TARGET_BY_IRI') { - context.results['FIND_TARGET_ENTITIES'] = results; - } - if (step.type === 'HYDRATE_ANCHOR_BY_IRI') { - context.results['GET_ANCHOR_DETAILS'] = results; - } - - onProgress({ - stepIndex: i, - totalSteps: steps.length, - description: step.description, - status: 'done', - resultCount: results.length, }); } catch (err) { - onProgress({ - stepIndex: i, - totalSteps: steps.length, - description: step.description, - status: 'failed', - }); - + onProgress({ ...base, status: 'failed' }); return { status: 'error', failedAtStep: i, @@ -115,7 +179,60 @@ export async function executePipeline( error: err instanceof Error ? err : new Error(String(err)), }; } + + // Every slice failed and nothing came back: this step has no answer to give. + if (outcome.failedScopes.length > 0 && outcome.rows.length === 0 && !step.optional) { + onProgress({ ...base, status: 'failed' }); + return { + status: 'error', + failedAtStep: i, + message: `Error at step: ${step.description}`, + error: outcome.lastError ?? new Error('Query failed'), + }; + } + if (outcome.failedScopes.length > 0) { + partial.push({ step: step.description, scopes: outcome.failedScopes }); + } + + const results = outcome.rows; + context.results[step.type] = results; + + if (step.type === 'FIND_TARGET_IRIS') { + const iris = new Set(); + for (const r of results) if (r.iri) iris.add(r.iri); + context.targetIris = [...iris]; + + if (context.targetIris.length === 0) { + onProgress({ ...base, status: 'done', resultCount: 0 }); + return { + status: 'empty', + failedAtStep: i, + message: `No results at step: ${step.description}`, + }; + } + } + + if (step.type === 'FIND_ANCHOR_IRIS') { + const iris = new Set(); + for (const r of results) if (r.iri) iris.add(r.iri); + context.anchorIris = [...iris]; + } + + // Hydrate results are aliased into the legacy keys that useMapLayers + // (src/hooks/useMapLayers.ts:38-42) consumes unchanged. + if (step.type === 'HYDRATE_TARGET_BY_IRI') { + context.results['FIND_TARGET_ENTITIES'] = results; + } + if (step.type === 'HYDRATE_ANCHOR_BY_IRI') { + context.results['GET_ANCHOR_DETAILS'] = results; + } + + onProgress({ ...base, status: 'done', resultCount: results.length }); } - return { status: 'success', data: context.results }; + return { + status: 'success', + data: context.results, + ...(partial.length > 0 ? { partial } : {}), + }; } diff --git a/src/engine/planner.ts b/src/engine/planner.ts index eb1105e..7477a34 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -5,16 +5,23 @@ import { buildFusedNearQuery, buildFusedHydrologyQuery, buildFusedFlowlineQuery, - buildFusedSampleAggregateQuery, - buildFusedSampleDetailsQuery, buildFusedWellQuery, } from './templates/fusedQueries'; import { buildFacilitiesByIri, buildWaterBodiesByIri, + buildSamplesByIri, } from './templates/hydrate'; import { buildAquifersByIri } from './templates/aquifers'; import { buildRegionBoundaryQuery } from './templates/spatial'; +import { + chooseAxis, + refineRegionScope, + halve, + chunk, + IRI_CHUNK, + type Scope, +} from './scope'; export type PipelineStepType = | 'FIND_TARGET_IRIS' @@ -29,7 +36,18 @@ export interface PipelineStep { type: PipelineStepType; endpoint: EndpointKey; description: string; - buildQuery: (context: PipelineContext) => string; + buildQuery: (context: PipelineContext, scope?: Scope) => string; + // Pre-split before the first attempt. Only for steps that inline a list of + // IRIs, where the list length is already known and a single request would + // exceed the gateway's body limit. + initialScopes?: (context: PipelineContext) => Scope[] | undefined; + // Called when a scope fails with a splittable error. Returns smaller scopes, + // or null when this step cannot be divided any further. + divide?: (context: PipelineContext, scope: Scope | undefined) => Promise; + // Losing this step degrades the map but still leaves a usable answer. + optional?: boolean; + // Reuse the response for the rest of the session (immutable reference data). + cache?: boolean; } export interface PipelineContext { @@ -88,16 +106,13 @@ function hydrateStep( type, endpoint, description, - buildQuery: (ctx) => { + buildQuery: (ctx, scope) => { if (block.type === 'samples') { - return buildFusedSampleAggregateQuery({ - anchor: fused.anchorBlock, - target: fused.targetBlock, - relationship: fused.relationship, - anchorRegion: fused.anchorRegion, - targetRegion: fused.targetRegion, - sampleSide: side === 'target' ? 'target' : 'anchor', - }); + // Hydrate from the IRIs the previous step already resolved. Re-deriving + // the spatial/hydrology trace here is what used to time out; chunking + // (see initialScopes below) removes the size limit that made the old + // by-IRI path conditional. + return buildSamplesByIri(irisFor(ctx, scope, side), block.sampleFilters); } if (block.type === 'wells') { return buildFusedWellQuery({ @@ -109,7 +124,7 @@ function hydrateStep( wellSide: side === 'target' ? 'target' : 'anchor', }); } - const iris = side === 'target' ? ctx.targetIris : ctx.anchorIris; + const iris = irisFor(ctx, scope, side); switch (block.type) { case 'facilities': return buildFacilitiesByIri(iris, block.facilityFilters); @@ -119,9 +134,52 @@ function hydrateStep( return buildAquifersByIri(iris); } }, + // Wells re-derive their set server-side (they can run to 80k+ IRIs), so + // there is no IRI list to pre-split for them. + initialScopes: + block.type === 'wells' + ? undefined + : (ctx) => iriScopes(side === 'target' ? ctx.targetIris : ctx.anchorIris, side), + divide: async (ctx, scope) => + divideIriList(scope, side === 'target' ? ctx.targetIris : ctx.anchorIris, side), }; } +// Splitting a by-IRI step. With a scope in hand we halve it; without one the +// step ran the full list in a single request (under IRI_CHUNK), so halve that +// list instead of giving up. +function divideIriList( + scope: Scope | undefined, + allIris: string[], + side: 'target' | 'anchor', +): Scope[] | null { + if (scope) return halve(scope); + if (allIris.length < 2) return null; + return halve({ + label: 'all', + ...(side === 'target' ? { targetIris: allIris } : { anchorIris: allIris }), + }); +} + +// The IRIs a by-IRI step should hydrate: the chunk's slice when running a chunk, +// otherwise everything the discovery step found. +function irisFor( + ctx: PipelineContext, + scope: Scope | undefined, + side: 'target' | 'anchor', +): string[] { + const scoped = side === 'target' ? scope?.targetIris : scope?.anchorIris; + return scoped ?? (side === 'target' ? ctx.targetIris : ctx.anchorIris); +} + +function iriScopes(iris: string[], side: 'target' | 'anchor'): Scope[] | undefined { + if (iris.length <= IRI_CHUNK) return undefined; + return chunk(iris, IRI_CHUNK).map((slice, i) => ({ + label: `batch ${i + 1}`, + ...(side === 'target' ? { targetIris: slice } : { anchorIris: slice }), + })); +} + function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { const { blockA, relationship, blockC } = question; @@ -146,39 +204,64 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { const steps: PipelineStep[] = []; - const buildIriQuery = (project: 'target' | 'anchor'): string => { + // A scope narrows one side of the question: either to a slice of IRIs, or to + // a subset of the region that side was already filtered to. + const scopedRegions = (scope?: Scope) => ({ + anchorRegion: + scope?.regionSide === 'anchor' ? scope.regionCodes : anchorRegionOpt, + targetRegion: + scope?.regionSide === 'target' ? scope.regionCodes : targetRegionOpt, + }); + + const buildIriQuery = (project: 'target' | 'anchor', scope?: Scope): string => { + const shared = { + anchor: anchorBlock, + target: targetBlock, + project, + anchorIris: scope?.anchorIris, + targetIris: scope?.targetIris, + ...scopedRegions(scope), + }; if (relationship.type === 'near') { - return buildFusedNearQuery({ - anchor: anchorBlock, - target: targetBlock, - hops: relationship.hops ?? 1, - project, - anchorRegion: anchorRegionOpt, - targetRegion: targetRegionOpt, - }); + return buildFusedNearQuery({ ...shared, hops: relationship.hops ?? 1 }); } return buildFusedHydrologyQuery({ - anchor: anchorBlock, - target: targetBlock, + ...shared, direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', - project, - anchorRegion: anchorRegionOpt, - targetRegion: targetRegionOpt, }); }; + // Splitting a discovery query: halve a slice we already have, otherwise work + // out which side can be enumerated (see chooseAxis in scope.ts). + const axisContext = { + anchorBlock, + targetBlock, + anchorRegion: anchorRegionOpt, + targetRegion: targetRegionOpt, + endpoint: 'federation' as const, + }; + + const divideDiscovery = async (_ctx: PipelineContext, scope: Scope | undefined) => { + if (!scope) return chooseAxis(axisContext); + // Halve what we have; when a region slice is down to one county and still + // fails, switch axis and chunk the targets inside it. + return halve(scope) ?? refineRegionScope(axisContext, scope); + }; + const verb = relationship.type === 'near' ? 'nearby' : relationship.type; steps.push({ type: 'FIND_TARGET_IRIS', endpoint: 'federation', description: `Finding ${verb} ${targetBlock.type}`, - buildQuery: () => buildIriQuery('target'), + buildQuery: (_ctx, scope) => buildIriQuery('target', scope), + divide: divideDiscovery, }); steps.push({ type: 'FIND_ANCHOR_IRIS', endpoint: 'federation', description: `Finding ${anchorBlock.type} with ${verb} ${targetBlock.type}`, - buildQuery: () => buildIriQuery('anchor'), + buildQuery: (_ctx, scope) => buildIriQuery('anchor', scope), + divide: divideDiscovery, }); if (relationship.type !== 'near') { @@ -187,12 +270,17 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { endpoint: 'federation', description: `Loading ${relationship.type} stream geometries`, // Runs after FIND_ANCHOR_IRIS so it can trace from the resolved anchors. - buildQuery: (ctx) => + buildQuery: (ctx, scope) => buildFusedFlowlineQuery({ anchor: anchorBlock, direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', - anchorIris: ctx.anchorIris, + anchorIris: scope?.anchorIris ?? ctx.anchorIris, }), + initialScopes: (ctx) => iriScopes(ctx.anchorIris, 'anchor'), + divide: async (ctx, scope) => divideIriList(scope, ctx.anchorIris, 'anchor'), + // Stream geometry is map decoration — losing a slice of it should not + // discard the samples and facilities the run already found. + optional: true, }); } @@ -207,35 +295,9 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { steps.push(hydrateStep(targetBlock, 'target', fusedCtx)); steps.push(hydrateStep(anchorBlock, 'anchor', fusedCtx)); - // Per-observation sample details for popups, if either side is samples. - // Server-fused (re-derives sample IRIs in an inner subquery) for the same - // wire-size reason as sample hydration above. If both sides are samples, - // the target side is used — covering both would require a UNION and the - // anchor IRI set is typically a subset anyway when proximity is reciprocal. - const sampleSide: 'target' | 'anchor' | null = - targetBlock.type === 'samples' - ? 'target' - : anchorBlock.type === 'samples' - ? 'anchor' - : null; - - if (sampleSide) { - steps.push({ - type: 'GET_SAMPLE_DETAILS', - endpoint: 'federation', - description: 'Loading sample observation details', - buildQuery: () => - buildFusedSampleDetailsQuery({ - anchor: anchorBlock, - target: targetBlock, - relationship, - anchorRegion: anchorRegionOpt, - targetRegion: targetRegionOpt, - sampleSide, - }), - }); - } - + // Per-observation detail is no longer fetched up front. It filled map popups + // one click at a time but cost 18–37MB per run (one sample point is ~30KB); + // useSampleDetails fetches it per sample when a popup opens. // Region boundaries const stateCode = blockA.region?.stateCode || blockC.region?.stateCode; const hasRegion = anchorRegion.length > 0 || targetRegion.length > 0; @@ -245,6 +307,10 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { endpoint: 'spatialkg', description: 'Loading region boundaries', buildQuery: () => buildRegionBoundaryQuery(stateCode), + // County outlines never change within a session, and this step was + // measured at 25.5s on a cold cache (docs/QUERY-MATRIX.md 3.8). + cache: true, + optional: true, }); } diff --git a/src/engine/resultTransformer.ts b/src/engine/resultTransformer.ts index 6f1f86b..9ed1676 100644 --- a/src/engine/resultTransformer.ts +++ b/src/engine/resultTransformer.ts @@ -61,6 +61,7 @@ export function transformSamplesToFeatures(rows: SparqlRow[]): MapFeature[] { maxConcentration: row.max || '', substances: row.substances || '', materials: row.materials || '', + samplePointName: row.samplePointName || '', }, }; }) @@ -208,80 +209,63 @@ export function transformRegionBoundaries(rows: SparqlRow[]): MapFeature[] { * Enrich existing sample MapFeatures with per-observation detail data * from the detail query rows. */ -export function enrichSampleFeaturesWithDetails( - features: MapFeature[], - detailRows: SparqlRow[] -): void { - // Group detail rows by sample point URI - const bySp = new Map(); - for (const row of detailRows) { - const sp = row.sp; - if (!sp) continue; - let arr = bySp.get(sp); +// Builds the popup body for one sample point from its observation rows. +// Fetched per sample when a popup opens (useSampleDetails) rather than for every +// sample up front, which cost 18-37MB per pipeline run. +export function buildSamplePointDetail(rows: SparqlRow[]): SamplePointDetail | null { + if (rows.length === 0) return null; + + const samplePointName = rows[0].samplePointName || ''; + + // Group by sample URI + const bySample = new Map(); + for (const row of rows) { + const sampleUri = row.sample || ''; + let arr = bySample.get(sampleUri); if (!arr) { arr = []; - bySp.set(sp, arr); + bySample.set(sampleUri, arr); } arr.push(row); } - for (const feature of features) { - const rows = bySp.get(feature.id); - if (!rows || rows.length === 0) continue; - - const samplePointName = rows[0].samplePointName || ''; - - // Group by sample URI - const bySample = new Map(); - for (const row of rows) { - const sampleUri = row.sample || ''; - let arr = bySample.get(sampleUri); - if (!arr) { - arr = []; - bySample.set(sampleUri, arr); - } - arr.push(row); - } + const samples: SampleRecord[] = []; + let maxResult: SamplePointDetail['maxResult'] = null; - // Build sample records - const samples: SampleRecord[] = []; - let maxResult: SamplePointDetail['maxResult'] = null; + for (const [sampleUri, sampleRows] of bySample) { + const first = sampleRows[0]; + const observations: SampleObservation[] = []; - for (const [sampleUri, sampleRows] of bySample) { - const first = sampleRows[0]; - const observations: SampleObservation[] = []; + for (const r of sampleRows) { + const val = parseFloat(r.result_value); + if (isNaN(val)) continue; - for (const r of sampleRows) { - const val = parseFloat(r.result_value); - if (isNaN(val)) continue; + observations.push({ + substance: r.substance || '', + result: val, + unit: r.unit_sym || '', + }); - observations.push({ + // Track overall max + if (!maxResult || val > maxResult.value) { + maxResult = { substance: r.substance || '', - result: val, + value: val, unit: r.unit_sym || '', - }); - - // Track overall max - if (!maxResult || val > maxResult.value) { - maxResult = { - substance: r.substance || '', - value: val, - unit: r.unit_sym || '', - sampleId: first.sampleIdentifier || '', - date: (r.date || '').slice(0, 10), - }; - } + sampleId: first.sampleIdentifier || '', + date: (r.date || '').slice(0, 10), + }; } - - samples.push({ - sampleUri, - sampleId: first.sampleIdentifier || '', - date: (first.date || '').slice(0, 10), - sampleType: first.sampleType || '', - observations, - }); } - feature.sampleDetails = { samplePointName, maxResult, samples }; + samples.push({ + sampleUri, + sampleId: first.sampleIdentifier || '', + date: (first.date || '').slice(0, 10), + sampleType: first.sampleType || '', + observations, + }); } + + return { samplePointName, maxResult, samples }; } diff --git a/src/engine/scope.ts b/src/engine/scope.ts new file mode 100644 index 0000000..3cf33ff --- /dev/null +++ b/src/engine/scope.ts @@ -0,0 +1,185 @@ +import type { EntityBlock } from '../types/query'; +import type { EndpointKey } from '../constants/endpoints'; +import { executeSparql } from './sparqlClient'; +import { buildEntityProbeQuery } from './templates/fusedQueries'; +import { buildDiscoverCountiesQuery } from './templates/regions'; + +// A Scope is a slice of one pipeline step's work. `undefined` scope means "the +// whole thing" — the executor always tries that first and only slices when the +// engine refuses (docs/plans/drafts/2026-09-13-query-execution-architecture.md). +// +// Exactly one of the three slicing fields is set on any given scope; which one +// is decided per question by `chooseAxis`, because the right axis flips between +// states: Maine has 4,528 samples / 2,976 facilities, Illinois has 78 / 22,574. +export interface Scope { + label: string; + anchorIris?: string[]; + targetIris?: string[]; + regionCodes?: string[]; + // Which side's region `regionCodes` narrows. Region slicing is only valid on a + // side that already had a region filter — adding one to a side that had none + // would silently change the question. + regionSide?: 'anchor' | 'target'; +} + +// A side is "listable" if we can enumerate it in a bounded probe. 200 keeps the +// probe cheap; above it we fall through to the next axis. +const PROBE_LIMIT = 201; + +// Measured chunk sizes that comfortably clear the 30s budget: 25 anchor +// facilities ran 2.8–3.0s, 20 Illinois samples 12.7s, 4 Maine counties ~6s each. +// These are only starting points — any chunk that still fails gets halved. +const ENTITY_CHUNK = 25; +// One county at a time. Bigger groups look cheaper (fewer requests) but a group +// that fails costs a full 30s before we learn to halve it, and single counties +// measured 4.5-7.5s even on the worst shape — they almost always succeed first +// time. +const REGION_CHUNK = 1; +export const IRI_CHUNK = 1000; // by-IRI hydration: 1,000 IRIs ≈ 70KB, 1.0–3.3s + +function hasBlockFilters(block: EntityBlock): boolean { + const f = + block.sampleFilters ?? + block.facilityFilters ?? + block.waterBodyFilters ?? + block.wellFilters ?? + block.aquiferFilters; + return Boolean(f && Object.values(f).some((v) => (Array.isArray(v) ? v.length > 0 : v != null))); +} + +export function chunk(items: T[], size: number): T[][] { + const out: T[][] = []; + for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size)); + return out; +} + +// Splits a scope that already has a slicing list into two halves. Returns null +// when it cannot be divided further (a single entity that still fails). +export function halve(scope: Scope): Scope[] | null { + const split = (key: K): Scope[] | null => { + const list = scope[key]; + if (!list || list.length < 2) return null; + const mid = Math.ceil(list.length / 2); + return [ + { ...scope, [key]: list.slice(0, mid), label: `${scope.label} (1/2)` }, + { ...scope, [key]: list.slice(mid), label: `${scope.label} (2/2)` }, + ]; + }; + return split('anchorIris') ?? split('targetIris') ?? split('regionCodes'); +} + +export interface AxisContext { + anchorBlock: EntityBlock; + targetBlock: EntityBlock; + anchorRegion?: string[]; + targetRegion?: string[]; + endpoint: EndpointKey; +} + +// Picks how to slice a question that was too big to run whole, preferring +// whichever side we can actually enumerate. Probes are cached for the session. +export async function chooseAxis(ctx: AxisContext): Promise { + // Both probes are independent, and each can take seconds on an unfiltered + // side, so overlap them rather than paying for them one after the other. + const [anchor, target] = await Promise.all([ + probeSide(ctx.anchorBlock, ctx.anchorRegion, ctx.endpoint), + probeSide(ctx.targetBlock, ctx.targetRegion, ctx.endpoint), + ]); + + if (anchor) { + return chunk(anchor, ENTITY_CHUNK).map((iris, i) => ({ + label: `${ctx.anchorBlock.type} batch ${i + 1}`, + anchorIris: iris, + })); + } + + if (target) { + return chunk(target, ENTITY_CHUNK).map((iris, i) => ({ + label: `${ctx.targetBlock.type} batch ${i + 1}`, + targetIris: iris, + })); + } + + // Neither side is listable — fall back to geography, but only on a side that + // already has a region. Counties of an existing state filter narrow the same + // question; inventing a region where there was none would answer a different + // one. + const side: 'target' | 'anchor' | null = ctx.targetRegion?.length + ? 'target' + : ctx.anchorRegion?.length + ? 'anchor' + : null; + if (!side) return null; + + const codes = side === 'target' ? ctx.targetRegion! : ctx.anchorRegion!; + const counties = await expandToCounties(codes); + if (counties.length < 2) return null; + + return chunk(counties, REGION_CHUNK).map((group, i) => ({ + label: `area ${i + 1}`, + regionCodes: group, + regionSide: side, + })); +} + +// Last resort for a region slice that is down to a single county and still too +// big: chunk the target entities *inside* that county. +// +// Only the target side is safe to narrow this way. The target is already +// confined to the county by the region slice, so listing its entities changes +// nothing. Narrowing the anchor side would drop anchors outside the county that +// legitimately drain into it — the bug commit 3f50251 documents, where 16 of 39 +// contributing landfills sat outside the region. +export async function refineRegionScope( + ctx: AxisContext, + scope: Scope, +): Promise { + if (!scope.regionCodes?.length || scope.regionSide !== 'target') return null; + const targets = await probeSide(ctx.targetBlock, scope.regionCodes, ctx.endpoint); + if (!targets) return null; + return chunk(targets, ENTITY_CHUNK).map((iris, i) => ({ + ...scope, + label: `${scope.label} part ${i + 1}`, + targetIris: iris, + })); +} + +async function probeSide( + block: EntityBlock, + regionCodes: string[] | undefined, + endpoint: EndpointKey, +): Promise { + // No region and no filters means every entity of that type in the graph — + // certainly past the probe limit, and the probe itself would scan nationwide. + if (!regionCodes?.length && !hasBlockFilters(block)) return null; + + const rows = await executeSparql( + endpoint, + buildEntityProbeQuery(block, regionCodes, PROBE_LIMIT), + { cache: true }, + ); + const iris = [...new Set(rows.map((r) => r.iri).filter(Boolean))]; + // A full probe means "too many to enumerate" — we only know there are ≥200. + if (iris.length >= PROBE_LIMIT || iris.length < 2) return null; + return iris; +} + +// Turns state FIPS codes into their county FIPS codes. County codes are already +// county-level, so they pass through unchanged. +async function expandToCounties(regionCodes: string[]): Promise { + const out: string[] = []; + for (const code of regionCodes) { + if (code.length > 2) { + out.push(code); + continue; + } + const rows = await executeSparql('spatialkg', buildDiscoverCountiesQuery(code), { + cache: true, + }); + for (const row of rows) { + const fips = row.county?.match(/administrativeRegion\.USA\.(\d+)$/)?.[1]; + if (fips && fips.length > 2) out.push(fips); + } + } + return [...new Set(out)]; +} diff --git a/src/engine/sparqlClient.ts b/src/engine/sparqlClient.ts index 85caaac..2f748d9 100644 --- a/src/engine/sparqlClient.ts +++ b/src/engine/sparqlClient.ts @@ -1,27 +1,81 @@ import { ENDPOINTS, type EndpointKey } from '../constants/endpoints'; import type { SparqlResultSet, SparqlRow } from '../types/sparql'; +import { + SparqlError, + classifySparqlFailure, + extractSparqlDetail, + isRetryable, +} from './sparqlErrors'; + +export interface SparqlOptions { + // Cache the result for the lifetime of the page. Only for queries whose answer + // cannot change within a session — region boundaries, entity-set probes. + cache?: boolean; +} + +// ponytail: a plain Map, not an LRU. Entries are per-session and few (one per +// distinct cacheable query); nothing here justifies eviction logic yet. +const responseCache = new Map(); export async function executeSparql( endpoint: EndpointKey, - query: string + query: string, + options: SparqlOptions = {}, ): Promise { - const url = ENDPOINTS[endpoint]; - - const response = await fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/sparql-query', - 'Accept': 'application/sparql-results+json', - }, - body: query, - }); + const cacheKey = `${endpoint}::${query}`; + if (options.cache) { + const hit = responseCache.get(cacheKey); + if (hit) return hit; + } + + const rows = await requestWithRetry(endpoint, query, 0); + if (options.cache) responseCache.set(cacheKey, rows); + return rows; +} + +async function requestWithRetry( + endpoint: EndpointKey, + query: string, + attempt: number, +): Promise { + let response: Response; + try { + response = await fetch(ENDPOINTS[endpoint], { + method: 'POST', + headers: { + 'Content-Type': 'application/sparql-query', + 'Accept': 'application/sparql-results+json', + }, + body: query, + }); + } catch (err) { + throw new SparqlError('network', 0, err instanceof Error ? err.message : String(err)); + } if (!response.ok) { const text = await response.text().catch(() => ''); - throw new Error(`SPARQL error ${response.status}: ${text.slice(0, 200)}`); + const kind = classifySparqlFailure(response.status, text); + // The engine caches the sub-results a failed attempt computed, so one retry + // starts warm — measured 26.5s cold vs 1.5s warm on the same query. + if (isRetryable(kind) && attempt < 1) { + return requestWithRetry(endpoint, query, attempt + 1); + } + throw new SparqlError(kind, response.status, extractSparqlDetail(text)); } - const json: SparqlResultSet = await response.json(); + // A 200 can still carry a truncated body when the response is very large + // (observed at ~4MB and ~12MB under load), so parse defensively. + const text = await response.text(); + let json: SparqlResultSet; + try { + json = JSON.parse(text) as SparqlResultSet; + } catch { + throw new SparqlError( + 'network', + response.status, + `Truncated or invalid response (${text.length} bytes)`, + ); + } return transformSparqlResults(json); } diff --git a/src/engine/sparqlErrors.ts b/src/engine/sparqlErrors.ts new file mode 100644 index 0000000..50ddd00 --- /dev/null +++ b/src/engine/sparqlErrors.ts @@ -0,0 +1,84 @@ +// QLever reports several very different problems through a small set of HTTP +// statuses, and the most important one is actively misleading: a query that +// exceeds the engine's 30s limit comes back as 429 "Too Many Requests" with the +// real cause only in the JSON body. Classifying here keeps that knowledge in one +// place — the executor uses it to decide whether splitting the work would help, +// and the UI uses it to tell the user something more useful than "went wrong". +// +// See docs/QUERY-MATRIX.md Part 4 for the full catalogue with measurements. +export type SparqlErrorKind = + | 'timeout' // 429 + "Operation timed out" / "Sort operation was canceled" + | 'out-of-memory' // 500 + "Tried to allocate X, but only Y were available" + | 'payload-too-large' // 413/502 — our request body was too big + | 'sibling-failure' // 500 + "Waited for a result from another thread" + | 'network' // fetch rejected, response unparseable + | 'unknown'; + +export class SparqlError extends Error { + readonly kind: SparqlErrorKind; + readonly status: number; + readonly detail: string; + + constructor(kind: SparqlErrorKind, status: number, detail: string) { + super(`SPARQL ${kind} (${status}): ${detail.slice(0, 200)}`); + this.name = 'SparqlError'; + this.kind = kind; + this.status = status; + this.detail = detail; + } +} + +export function classifySparqlFailure(status: number, body: string): SparqlErrorKind { + let detail = body; + try { + detail = (JSON.parse(body) as { exception?: string }).exception ?? body; + } catch { + // Non-JSON error body (gateway HTML, truncated response) — match on raw text. + } + if (status === 413 || status === 502) return 'payload-too-large'; + if (/Tried to allocate/.test(detail)) return 'out-of-memory'; + if (/Operation timed out|Sort operation was canceled/.test(detail)) return 'timeout'; + if (/Waited for a result from another thread/.test(detail)) return 'sibling-failure'; + return 'unknown'; +} + +export function extractSparqlDetail(body: string): string { + try { + return (JSON.parse(body) as { exception?: string }).exception ?? body.slice(0, 200); + } catch { + return body.slice(0, 200); + } +} + +// True when the same query over a smaller slice of the data has a real chance of +// succeeding. Every one of these is a "too much work in one request" failure. +export function isSplittable(kind: SparqlErrorKind): boolean { + return kind === 'timeout' || kind === 'out-of-memory' || kind === 'payload-too-large'; +} + +// True when simply asking again may work — the engine caches partial results, so +// a retry after a timeout starts warm. +export function isRetryable(kind: SparqlErrorKind): boolean { + return kind === 'timeout' || kind === 'sibling-failure'; +} + +export function userMessageFor(error: unknown): string { + const kind = error instanceof SparqlError ? error.kind : 'unknown'; + switch (kind) { + case 'timeout': + case 'out-of-memory': + // Point at the second block specifically. Measured: narrowing the first + // block to a single county does not help at all (still 500 OOM at 2.6GB) + // because the work is driven by the unconstrained second block — with no + // filter it means every facility in the graph, 1.5 million of them. + return 'This question covers too much data for the knowledge graph to answer at once. The usual cause is that the second block has no filter or region set, which means "every one in the country". Adding an industry, type, or region there is the most effective change; a shorter distance also helps.'; + case 'payload-too-large': + return 'This question produced too much data to send in one request. Try narrowing the area or adding a filter.'; + case 'sibling-failure': + return 'The knowledge graph was busy and dropped this request. Running it again usually works.'; + case 'network': + return 'Could not reach the knowledge graph. Check your connection and try again.'; + default: + return 'Something went wrong. You can edit the question and try again.'; + } +} diff --git a/src/engine/templates/downstreamSamples.ts b/src/engine/templates/downstreamSamples.ts index 8b9e839..a1f0c11 100644 --- a/src/engine/templates/downstreamSamples.ts +++ b/src/engine/templates/downstreamSamples.ts @@ -21,11 +21,13 @@ export function buildSampleRetrievalByIriQuery( (MAX(?result_value) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) + (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { ${vals} } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . + OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 9a9f83d..b9e8136 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -42,7 +42,31 @@ function buildAquiferTypeFilterSuffixed(filters: AquiferFilters | undefined, suf // is supplied so the same helper can fill either ?s2anchor or ?s2target). // `suffix` disambiguates internal variables so same-type anchor+target queries // don't collide. -export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: string): string { +// True when the sample block actually constrains observations. When it does not, +// the IRI-finding queries can skip the observation join entirely. +export function hasSampleFilters(block: EntityBlock): boolean { + const f = block.type === 'samples' ? block.sampleFilters : undefined; + if (!f) return false; + return Boolean( + f.substances?.length || + f.materialTypes?.length || + f.minConcentration != null || + f.maxConcentration != null || + f.includeNondetects === false, + ); +} + +// `sampleObservations: false` drops the observation/material/result joins from a +// samples block. Only the IRI-finding queries may pass it: they project just the +// sample-point IRI, and re-deriving every observation there is what pushes the +// hydrology queries past QLever's 30s limit / memory ceiling (429/500). The +// hydrate queries still project those vars and must keep the full block. +export function bindEntityInCell( + block: EntityBlock, + s2Var: string, + suffix: string, + sampleObservations = true, +): string { switch (block.type) { case 'facilities': { const industry = buildIndustryValues( @@ -55,6 +79,10 @@ export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: stri ${industry}`; } case 'samples': { + if (!sampleObservations) { + return `?sp${suffix} rdf:type coso:SamplePoint ; + spatial:connectedTo ${s2Var} .`; + } const filters = buildSampleFilterClauses(block.sampleFilters, suffix); return `?sp${suffix} rdf:type coso:SamplePoint ; spatial:connectedTo ${s2Var} . @@ -94,6 +122,33 @@ export function bindEntityInCell(block: EntityBlock, s2Var: string, suffix: stri } } +function pinValues(entityVar: string, iris: string[] | undefined): string { + if (!iris?.length) return ''; + return `VALUES ${entityVar} { ${iris.map(wrapUri).join(' ')} }\n `; +} + +// Lists a block's entities inside its region, capped at `limit`. Used to decide +// whether a side is small enough to chunk over — a bounded LIMIT probe rather +// than COUNT, because counting Maine's unfiltered facilities took 11.0s while +// the same listing with a filter took 0.8s (docs/QUERY-MATRIX.md). +export function buildEntityProbeQuery( + block: EntityBlock, + regionCodes: string[] | undefined, + limit: number, +): string { + const entityVar = entityIriVar(block, 'P'); + const bind = bindEntityInCell(block, '?s2probe', 'P', hasSampleFilters(block)); + const region = regionClause(regionCodes, '?s2probe', '?_regionP'); + return ` + ${PREFIXES} + SELECT DISTINCT (${entityVar} AS ?iri) WHERE { + ?s2probe rdf:type kwg-ont:S2Cell_Level13 . + ${region} + ${bind} + } LIMIT ${limit} + `; +} + function regionClause(regionCodes: string[] | undefined, s2Var: string, internalVar: string): string { if (!regionCodes?.length) return ''; if (regionCodes.length === 1) { @@ -127,20 +182,33 @@ function neighborPath(hops: number, fromVar: string, toVar: string): string { interface FusedBodyOpts extends FusedBaseOpts { mode: 'near' | 'downstream' | 'upstream'; hops?: number; + // Chunk pins (src/engine/scope.ts). Restricting one side to a known slice of + // IRIs is what makes a too-large query fit inside the engine's 30s budget. + anchorIris?: string[]; + targetIris?: string[]; + // Set by the IRI-finding queries only — see bindEntityInCell. + anchorSampleObservations?: boolean; + targetSampleObservations?: boolean; } // Returns just the inner WHERE-body patterns shared across all fused queries: // anchor binding + spatial path (neighbor expansion for "near", hydrology trace // for downstream/upstream) + target binding + region clauses on each side. function buildFusedWhereBody(opts: FusedBodyOpts): string { - const anchorBind = bindEntityInCell(opts.anchor, '?s2anchor', 'A'); - const targetBind = bindEntityInCell(opts.target, '?s2target', 'C'); + // A sample block keeps its observation joins unless the caller drops them AND + // no sample filter depends on them. + const anchorObs = (opts.anchorSampleObservations ?? true) || hasSampleFilters(opts.anchor); + const targetObs = (opts.targetSampleObservations ?? true) || hasSampleFilters(opts.target); + const anchorBind = bindEntityInCell(opts.anchor, '?s2anchor', 'A', anchorObs); + const targetBind = bindEntityInCell(opts.target, '?s2target', 'C', targetObs); + const anchorPin = pinValues(entityIriVar(opts.anchor, 'A'), opts.anchorIris); + const targetPin = pinValues(entityIriVar(opts.target, 'C'), opts.targetIris); const aRegion = regionClause(opts.anchorRegion, '?s2anchor', '?_regionA'); const tRegion = regionClause(opts.targetRegion, '?s2target', '?_regionC'); if (opts.mode === 'near') { const hopPath = neighborPath(opts.hops ?? 1, '?s2anchor', '?s2target'); - return `?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + return `${anchorPin}${targetPin}?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ${aRegion} ${anchorBind} ${hopPath} @@ -154,7 +222,7 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ? `?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline .` : `?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline .`; - return `?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + return `${anchorPin}${targetPin}?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ${aRegion} ${anchorBind} ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . @@ -185,6 +253,8 @@ export interface FusedBaseOpts { export interface FusedNearOpts extends FusedBaseOpts { hops: number; project: 'anchor' | 'target'; + anchorIris?: string[]; + targetIris?: string[]; } // Server-side "near" query. Projects either anchor or target entity IRIs as @@ -197,6 +267,10 @@ export function buildFusedNearQuery(opts: FusedNearOpts): string { targetRegion: opts.targetRegion, mode: 'near', hops: opts.hops, + anchorIris: opts.anchorIris, + targetIris: opts.targetIris, + anchorSampleObservations: opts.project !== 'anchor', + targetSampleObservations: opts.project !== 'target', }); const projectVar = opts.project === 'anchor' @@ -214,6 +288,8 @@ export function buildFusedNearQuery(opts: FusedNearOpts): string { export interface FusedHydrologyOpts extends FusedBaseOpts { direction: 'downstream' | 'upstream'; project: 'anchor' | 'target'; + anchorIris?: string[]; + targetIris?: string[]; } // Server-side downstream/upstream query. @@ -224,6 +300,15 @@ export function buildFusedHydrologyQuery(opts: FusedHydrologyOpts): string { anchorRegion: opts.anchorRegion, targetRegion: opts.targetRegion, mode: opts.direction, + anchorIris: opts.anchorIris, + targetIris: opts.targetIris, + // Verified on the live endpoint: keeping the observation joins on either + // side of a downstream/upstream trace always fails (429 timeout / 500 OOM). + // Sample points with no observations are dropped again at hydration, so the + // sample layer is unchanged; the facility layer can include facilities whose + // only downstream sample points carry no observations. + anchorSampleObservations: false, + targetSampleObservations: false, }); const projectVar = opts.project === 'anchor' @@ -238,50 +323,11 @@ export function buildFusedHydrologyQuery(opts: FusedHydrologyOpts): string { `; } -export interface FusedSampleSideOpts extends FusedBaseOpts { - relationship: SpatialRelationship; - sampleSide: 'anchor' | 'target'; -} - -// Sample hydration without IRI inlining. The anchor/target derivation runs -// in the same query body, then per-sample aggregates project from the -// sample-side observation variables already bound by bindEntityInCell. -// Replaces buildSamplesByIri (templates/hydrate.ts) when the side is samples; -// statewide queries can have 1000+ sample IRIs and the gateway 502s on the -// inlined VALUES body — re-deriving server-side keeps the request small. -export function buildFusedSampleAggregateQuery(opts: FusedSampleSideOpts): string { - const body = buildFusedWhereBody({ - anchor: opts.anchor, - target: opts.target, - anchorRegion: opts.anchorRegion, - targetRegion: opts.targetRegion, - mode: relationshipMode(opts.relationship), - hops: opts.relationship.hops, - }); - const suffix = opts.sampleSide === 'anchor' ? 'A' : 'C'; - const s2Var = opts.sampleSide === 'anchor' ? '?s2anchor' : '?s2target'; - const spVar = `?sp${suffix}`; - const resultVar = `?result_value${suffix}`; - const substanceVar = `?substance${suffix}`; - const matLabelVar = `?matTypeLabel${suffix}`; - const observationVar = `?observation${suffix}`; - const sampleVar = `?sample${suffix}`; - - return ` - ${PREFIXES} - SELECT - (COUNT(DISTINCT ${observationVar}) as ?resultCount) - (COUNT(DISTINCT ${sampleVar}) as ?sampleCount) - (MAX(${resultVar}) as ?max) - (GROUP_CONCAT(DISTINCT ${substanceVar}; separator="; ") as ?substances) - (GROUP_CONCAT(DISTINCT ${matLabelVar}; separator="; ") as ?materials) - (${spVar} AS ?sp) ?spWKT (${s2Var} AS ?s2cell) - WHERE { - ${body} - ${spVar} geo:hasGeometry/geo:asWKT ?spWKT . - } GROUP BY ${spVar} ?spWKT ${s2Var} - `; -} +// buildFusedSampleAggregateQuery / buildFusedSampleDetailsQuery lived here. They +// re-derived the whole spatial trace inside the hydrate query to avoid inlining +// long IRI lists, and that re-derivation is what timed out (429) on every +// downstream question. Sample hydration now runs by IRI in chunks +// (planner.ts iriScopes), so neither is needed. export interface FusedWellSideOpts extends FusedBaseOpts { relationship: SpatialRelationship; @@ -331,77 +377,6 @@ export function buildFusedWellQuery(opts: FusedWellSideOpts): string { `; } -// Per-observation sample-detail query, server-derived. Inner subquery picks -// out sample IRIs via the same fused anchor→target logic; outer joins to -// observation/sample/result tuples and projects detail fields. Replaces -// buildSampleDetailsByIri for the same wire-size reason as the aggregate -// query above. -export function buildFusedSampleDetailsQuery(opts: FusedSampleSideOpts): string { - const body = buildFusedWhereBody({ - anchor: opts.anchor, - target: opts.target, - anchorRegion: opts.anchorRegion, - targetRegion: opts.targetRegion, - mode: relationshipMode(opts.relationship), - hops: opts.relationship.hops, - }); - const suffix = opts.sampleSide === 'anchor' ? 'A' : 'C'; - const spVar = `?sp${suffix}`; - const sampleBlock = opts.sampleSide === 'anchor' ? opts.anchor : opts.target; - const { substances, ...nonSubstanceFilters } = sampleBlock.sampleFilters ?? {}; - const substanceFilter = substances?.length - ? `VALUES ?substanceUri { ${substances.map(wrapUri).join(' ')} }` - : ''; - const outerFilter = buildSampleFilterClauses( - Object.keys(nonSubstanceFilters).length ? nonSubstanceFilters : undefined, - ); - - return ` - ${PREFIXES} - SELECT DISTINCT - ?sp ?spWKT - (SAMPLE(?spName) as ?samplePointName) - ?sample - (GROUP_CONCAT(DISTINCT ?sampleId; separator="; ") as ?sampleIdentifier) - ?observation - ?date - ?substance - ?result_value - ?unit_sym - (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator=", ") as ?sampleType) - WHERE { - { - SELECT DISTINCT (${spVar} AS ?sp) WHERE { - ${body} - } - } - ?sp geo:hasGeometry/geo:asWKT ?spWKT . - OPTIONAL { ?sp rdfs:label ?spName } - ?sample coso:fromSamplePoint ?sp ; - coso:sampleOfMaterialType ?matType . - ?matType rdfs:label ?matTypeLabel . - ?observation rdf:type coso:ContaminantObservation ; - coso:analyzedSample ?sample ; - coso:observedAtSamplePoint ?sp ; - coso:ofDSSToxSubstance ?substanceUri ; - coso:hasResult ?result . - ${substanceFilter} - OPTIONAL { ?substanceUri skos:altLabel ?altLabel } - OPTIONAL { ?substanceUri rdfs:label ?rdfLabel } - BIND(COALESCE(?altLabel, ?rdfLabel, REPLACE(STR(?substanceUri), "^.*[#/]", "")) AS ?substance) - ?result coso:measurementValue ?result_value ; - coso:measurementUnit ?unit . - OPTIONAL { ?unit qudt:symbol ?unit_sym0 } - BIND(COALESCE(?unit_sym0, REPLACE(STR(?unit), "^.*[#/]", "")) AS ?unit_sym) - ${outerFilter} - OPTIONAL { ?observation sosa:resultTime ?date } - OPTIONAL { ?sample dcterms:identifier ?sampleId } - } - GROUP BY ?sp ?spWKT ?sample ?observation ?date ?substance ?result_value ?unit_sym - ORDER BY ?sp ?sample ?substance DESC(?date) - `; -} - export interface FusedFlowlineOpts { anchor: EntityBlock; direction: 'downstream' | 'upstream'; diff --git a/src/hooks/useMapLayers.ts b/src/hooks/useMapLayers.ts index b081b52..fdfd237 100644 --- a/src/hooks/useMapLayers.ts +++ b/src/hooks/useMapLayers.ts @@ -8,7 +8,6 @@ import { transformWellsToFeatures, transformFlowlinesToFeatures, transformRegionBoundaries, - enrichSampleFeaturesWithDetails, } from '../engine/resultTransformer'; export interface MapLayerData { @@ -42,7 +41,6 @@ export function useMapLayers(result: PipelineResult | null): MapLayerData { const targetRows = data['FIND_TARGET_ENTITIES'] || []; const anchorRows = data['GET_ANCHOR_DETAILS'] || []; const boundaryRows = data['GET_REGION_BOUNDARIES'] || []; - const sampleDetailRows = data['GET_SAMPLE_DETAILS'] || []; const flowlineRows = data['GET_FLOWLINE_GEOMETRIES'] || []; // Determine what types came back by checking row shapes @@ -53,10 +51,8 @@ export function useMapLayers(result: PipelineResult | null): MapLayerData { const waterBodyRows = allRows.filter((r) => r.wbWKT); const wellRows = allRows.filter((r) => r.wellWKT); + // Popup detail is fetched per sample on open (useSampleDetails), not here. const sampleFeatures = transformSamplesToFeatures(sampleRows); - if (sampleDetailRows.length > 0) { - enrichSampleFeaturesWithDetails(sampleFeatures, sampleDetailRows); - } const matchedAquiferIris = [ ...new Set( diff --git a/src/hooks/useSampleDetails.ts b/src/hooks/useSampleDetails.ts new file mode 100644 index 0000000..1acd855 --- /dev/null +++ b/src/hooks/useSampleDetails.ts @@ -0,0 +1,32 @@ +import { useQuery } from '@tanstack/react-query'; +import { executeSparql } from '../engine/sparqlClient'; +import { buildSampleDetailsByIri } from '../engine/templates/hydrate'; +import { buildSamplePointDetail } from '../engine/resultTransformer'; +import type { SamplePointDetail } from '../types/map'; +import type { SampleFilters } from '../types/query'; + +// Loads the observation table for a single sample point, when its popup opens. +// +// The pipeline used to fetch this for every sample up front: 18-37MB per run +// (37,425 rows for one Maine question) to fill popups that open one at a time. +// One sample point is ~30KB. `enabled` is driven by the popup's open state so +// nothing is fetched until a user actually asks for it. +export function useSampleDetails( + samplePointIri: string | null, + enabled: boolean, + filters?: SampleFilters, +) { + return useQuery({ + queryKey: ['sampleDetails', samplePointIri, filters], + enabled: enabled && Boolean(samplePointIri), + staleTime: Infinity, + retry: false, + queryFn: async () => { + const rows = await executeSparql( + 'federation', + buildSampleDetailsByIri([samplePointIri as string], filters), + ); + return buildSamplePointDetail(rows); + }, + }); +} From 37d9a4f93a941bfb3026d6a533897dc91d8bf54f Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 07:42:35 -0400 Subject: [PATCH 21/66] fix(engine): bound request time, simplify the split budget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verification sweep of all 124 shapes through the real engine found three defects in what the previous commit shipped. No client-side timeout. executeSparql waited indefinitely, so a stalled endpoint blocked single requests for 959s and 1,918s in the sweep. The per-step budget could not intervene because it is checked between slices, and — worse — a hang never becomes a classified error, so the query never split. Three shapes recorded as "still failing" were only hanging; all three work once a stall is reported as a splittable timeout at 60s. facilities upstream facilities now returns 2,813 rows in 224s, complete. Two budget rules, both wrong in opposite directions. Budgeting elapsed time killed runs that were succeeding: wells near(4) had 13 of 16 county slices working and was cut off at 120s for being big. Budgeting only wasted time then broke the opposite case: Illinois downstream has slices that fail slowly before the ones that succeed, so it gave up before reaching the answer. Both are replaced by one rule — every slice is attempted, only the 300s step total is bounded. Illinois now completes in 248s, wells near(4) in 283s with 69,127 rows and nothing missing. Failed and skipped slices were reported as one number, so the UI blamed size for work that had simply run out of budget. They now carry separate counts and separate advice: narrow the question, versus just run it again against a warmer cache. Sweep result: of the 37 shapes failing at baseline, 34 now work and none regressed. The 3 that remain all leave the second block unconstrained — the largest being "every facility in the graph", all 1,506,326 of them. Small questions are unaffected: one county near-1-mile is 0.8s, and wells near 2 miles returns 45,280 rows in 18.8s. All 8 dashboard queries pass, three of them materially faster now that the 18-37MB detail step is gone. Documented in docs/QUERY-MATRIX.md Part 7, raw data in docs/query-matrix-after.csv. --- docs/QUERY-MATRIX.md | 113 +++++++++++++++- docs/query-matrix-after.csv | 125 ++++++++++++++++++ scripts/query-matrix.mts | 75 ++++++++++- .../Pipeline/PartialResultsNotice.tsx | 17 ++- src/engine/executor.ts | 58 +++++--- src/engine/sparqlClient.ts | 19 +++ 6 files changed, 378 insertions(+), 29 deletions(-) create mode 100644 docs/query-matrix-after.csv diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 074eb14..fedd9fd 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -70,8 +70,25 @@ but the editor never offers it, so no query in this sheet uses it. ## Part 3 — Results -**156 queries executed.** Every shape below was run once against the live -endpoints in a single sweep on 2026-09-13. +**156 queries executed, covering 95 of the 175 shapes the editor can express.** +Every shape below was run once against the live endpoints in a single sweep on +2026-09-13. + +**What is and is not covered** — so nobody reads this as exhaustive: + +| Dimension | Covered | Not covered | +| --- | --- | --- | +| Entity pairs × relationship | **all 75** (25 pairs × near-1 / downstream / upstream) | — | +| Near distances 0, 2, 3, 4 | 20 of 100 (5 representative pairs) | the other 80 combinations | +| States | 6 of 13 (IL, IN, MA, NH, AL, VT) | AZ, AR, KS, MN, OH, SC | +| Filters | 8 cases, all on one base shape | filter × shape interactions | +| Region scope | none / state / 1 county / 3 counties | arbitrary multi-county selections | +| Dashboard queries | all 8, every step | — | + +The gaps are deliberate: the 80 missing combinations are near-distance variants +of pairs whose hop-1 behaviour is already recorded, and distance cost is +characterised separately in 3.4. Fill them by adding pairs to phase M4 in +`scripts/query-matrix.mts` if a question there ever matters. | | Runs | Worked | of which slow (>15s) | Failed | | --- | --- | --- | --- | --- | @@ -450,3 +467,95 @@ reason. - **The okn.us asks** (access token to raise the 30s limit; a materialized downstream relation) would remove the ceiling that everything here works around. + +--- + +## Part 7 — Full verification sweep (2026-09-14) + +The whole matrix re-run through the real engine (`QUERY_MATRIX_MODE=engine`), so +splitting, merging, partial results and the step budget were all exercised — +not just the raw SPARQL. Raw data: `docs/query-matrix-after.csv`. + +**124 shapes compared. Of the 37 that failed at baseline, 34 now work. No +regressions.** + +| Outcome | Count | +| --- | --- | +| Fixed | **34** | +| Still failing | **3** | +| Regressions | **0** | +| Unchanged, working | 85 | + +### 7.1 The 3 that still fail + +Every one leaves the **second block** completely unconstrained, which is what +drives the cost — not the size of the answer. + +| Shape | What it asks | Failure | +| --- | --- | --- | +| `samples near(3) waterBodies [ME]` | within 3 miles of *any* water body in the graph | OOM, 1.4 GB | +| `facilities ↓ facilities [ME]` | downstream of *all 1,506,326* facilities | no response in 60s | +| `samples ↓ facilities [NO REGION]` | the above with no region on either side | OOM, 2.6 GB | + +Constraining the second block fixes them (measured in 6.3). Narrowing the +*first* block does not — the cost is not there. + +### 7.2 Small questions stay fast + +| Shape | Time | Rows | +| --- | --- | --- | +| 1 county, near 1 mile | 0.8s | 430 | +| 3 counties, near 1 mile | 1.4s | 1,048 | +| 1 county, downstream | 12.2s | 339 | +| 0-mile radius, any pair | 0.3–0.8s | — | +| 2-mile radius | 6–19s | up to 45,280 | + +Note `wells near(2) facilities`: **45,280 rows in 18.8s**. Large answers are +fine. Unbounded *search spaces* are not. + +### 7.3 Dashboard queries — all 8 pass, 3 materially faster + +| Query | Before | After | +| --- | --- | --- | +| Samples Near Agricultural Chemical Facilities | 62.7s | **33.4s** | +| Surface Water Bodies Near Landfills & DOD | 30.8s | **24.1s** | +| Samples Near Landfills & DOD (Penobscot/Knox) | 15.4s | **10.6s** | +| Samples Downstream of Waste Treatment (Indiana) | 67.2s | 70.8s | +| Maine Private Wells × 3 | 13–19s | 13–23s | +| PFHpA Groundwater Samples (Cumberland) | 2.1s, empty | 2.4s, **still empty** | + +The speed-ups are the deleted `GET_SAMPLE_DETAILS` step. PFHpA returning nothing +is unchanged and unrelated to performance — a data or query-correctness issue +that deserves its own investigation. + +### 7.4 Three defects the sweep exposed, and fixed + +**A missing client timeout.** `executeSparql` had no `AbortController`, so a +stalled endpoint blocked indefinitely — single requests recorded at **959s and +1,918s**. The per-step budget could not help, because it is checked *between* +slices. Worse, a hang never becomes a classified error, so the query never +split: three shapes recorded as "still failing" were only hanging, and all three +work now (`facilities upstream facilities` → 224s, 2,813 rows, complete). A 60s +cap now reports a stall as a timeout, which is splittable. + +**Two budget rules, both wrong, in opposite directions.** Budgeting *elapsed* +time killed runs that were succeeding: `wells near(4)` had 13 of 16 county +slices working and was cut off at 120s for being big. Budgeting only *wasted* +time then broke the opposite case: Illinois has slices that fail slowly before +the ones that succeed, so it gave up before reaching the answer. Both are gone. +One rule remains — every slice is attempted, only the 300s step total is +bounded. Both cases now complete: Illinois 248s, `wells near(4)` 283s with +69,127 rows and nothing missing. + +**"Failed" and "skipped" were the same number.** A slice the engine refused and +a slice never attempted were both reported as "too large". They need opposite +advice — narrow the question vs. just run it again — and are now tracked and +worded separately. + +### 7.5 Caveat on the recorded partial counts + +`query-matrix-after.csv` was captured *before* the budget fix, so its +`partialSlices` numbers are pessimistic: they count slices skipped by a rule +that has since been replaced. The one case re-measured afterwards +(`wells near(4)`) went from 11 missing to **0**. Several other partials in that +file are likely complete now; they have not been re-run. diff --git a/docs/query-matrix-after.csv b/docs/query-matrix-after.csv new file mode 100644 index 0000000..2e587d1 --- /dev/null +++ b/docs/query-matrix-after.csv @@ -0,0 +1,125 @@ +matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksMax,partialSlices +M1,"samples near(1) samples [ME]",samples,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,28821,4398,0,ok,"",0,0 +M1,"samples near(1) facilities [ME]",samples,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1418,2273,0,ok,"",0,0 +M1,"samples near(1) waterBodies [ME]",samples,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,1643,2199,0,ok,"",0,0 +M1,"samples near(1) wells [ME]",samples,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,5290,4279,0,ok,"",0,0 +M1,"samples near(1) aquifers [ME]",samples,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,1811,2759,0,ok,"",0,0 +M1,"facilities near(1) samples [ME]",facilities,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,12509,1358,0,ok,"",0,0 +M1,"facilities near(1) facilities [ME]",facilities,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1634,2976,0,ok,"",0,0 +M1,"facilities near(1) waterBodies [ME]",facilities,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,863,1591,0,ok,"",0,0 +M1,"facilities near(1) wells [ME]",facilities,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,2402,2900,0,ok,"",0,0 +M1,"facilities near(1) aquifers [ME]",facilities,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,1582,1728,0,ok,"",0,0 +M1,"waterBodies near(1) samples [ME]",waterBodies,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,18042,591,0,ok,"",0,0 +M1,"waterBodies near(1) facilities [ME]",waterBodies,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,902,1015,0,ok,"",0,0 +M1,"waterBodies near(1) waterBodies [ME]",waterBodies,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,1434,6612,0,ok,"",0,0 +M1,"waterBodies near(1) wells [ME]",waterBodies,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,3793,3553,0,ok,"",0,0 +M1,"waterBodies near(1) aquifers [ME]",waterBodies,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,2672,3165,0,ok,"",0,0 +M1,"wells near(1) samples [ME]",wells,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,17597,14897,0,ok,"",0,0 +M1,"wells near(1) facilities [ME]",wells,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1917,25668,0,ok,"",0,0 +M1,"wells near(1) waterBodies [ME]",wells,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,3053,52861,0,ok,"",0,0 +M1,"wells near(1) wells [ME]",wells,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,9761,83038,0,ok,"",0,0 +M1,"wells near(1) aquifers [ME]",wells,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,3069,40080,0,ok,"",0,0 +M1,"aquifers near(1) samples [ME]",aquifers,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,6268,899,0,ok,"",0,0 +M1,"aquifers near(1) facilities [ME]",aquifers,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1230,1504,0,ok,"",0,0 +M1,"aquifers near(1) waterBodies [ME]",aquifers,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,739,3712,0,ok,"",0,0 +M1,"aquifers near(1) wells [ME]",aquifers,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,1106,3659,0,ok,"",0,0 +M1,"aquifers near(1) aquifers [ME]",aquifers,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,724,4972,0,ok,"",0,0 +M9,"samples near(1) facilities [1 county (Cumberland)]",samples,near,1,facilities,1 county (Cumberland),"none",FIND_TARGET_IRIS,engine,success,848,430,0,ok,"",0,0 +M9,"samples near(1) facilities [3 counties]",samples,near,1,facilities,3 counties,"none",FIND_TARGET_IRIS,engine,success,1389,1048,0,ok,"",0,0 +M9,"samples downstream facilities [1 county (Cumberland)]",samples,downstream,,facilities,1 county (Cumberland),"none",FIND_TARGET_IRIS,engine,success,12166,339,0,ok,"",0,0 +M9,"samples downstream facilities [3 counties]",samples,downstream,,facilities,3 counties,"none",FIND_TARGET_IRIS,engine,success,16505,902,0,ok,"",0,0 +M4,"samples near(0) facilities [ME]",samples,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,755,985,0,ok,"",0,0 +M4,"samples near(0) wells [ME]",samples,near,0,wells,ME,"none",FIND_TARGET_IRIS,engine,success,501,3254,0,ok,"",0,0 +M4,"wells near(0) facilities [ME]",wells,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,527,5462,0,ok,"",0,0 +M4,"waterBodies near(0) facilities [ME]",waterBodies,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,364,352,0,ok,"",0,0 +M4,"samples near(0) waterBodies [ME]",samples,near,0,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,335,709,0,ok,"",0,0 +M4,"samples near(2) facilities [ME]",samples,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,7046,3061,0,ok,"",0,0 +M4,"samples near(2) wells [ME]",samples,near,2,wells,ME,"none",FIND_TARGET_IRIS,engine,success,12370,4438,0,ok,"",0,0 +M4,"wells near(2) facilities [ME]",wells,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,18817,45280,0,ok,"",0,0 +M4,"waterBodies near(2) facilities [ME]",waterBodies,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,6447,1628,0,ok,"",0,0 +M4,"samples near(2) waterBodies [ME]",samples,near,2,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,10823,3120,0,ok,"",0,0 +M4,"samples near(3) facilities [ME]",samples,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,20812,3734,0,ok,"",0,0 +M4,"samples near(3) wells [ME]",samples,near,3,wells,ME,"none",FIND_TARGET_IRIS,engine,success,21254,4500,0,ok,"",0,0 +M4,"wells near(3) facilities [ME]",wells,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,16681,59773,0,ok,"",0,0 +M4,"waterBodies near(3) facilities [ME]",waterBodies,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,9754,2245,0,ok,"",0,0 +M4,"samples near(3) waterBodies [ME]",samples,near,3,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,122626,0,0,failed,"SPARQL out-of-memory (500): Tried to allocate 1.4 GB, but only 227.8 MB were available",16,0 +M4,"samples near(4) facilities [ME]",samples,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,14519,4100,0,ok,"",0,0 +M4,"samples near(4) wells [ME]",samples,near,4,wells,ME,"none",FIND_TARGET_IRIS,engine,success,23713,4521,0,ok,"",0,0 +M4,"wells near(4) facilities [ME]",wells,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,130167,27668,0,ok-partial,"",16,11 +M4,"waterBodies near(4) facilities [ME]",waterBodies,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,105532,2727,0,ok,"",16,0 +M4,"samples near(4) waterBodies [ME]",samples,near,4,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,3913,4242,0,ok,"",0,0 +M8,"substance filter (PFOS)",samples,near,1,facilities,ME,"substance",FIND_TARGET_IRIS,engine,success,17282,1375,0,ok,"",0,0 +M8,"material filter (GW)",samples,near,1,facilities,ME,"material",FIND_TARGET_IRIS,engine,empty,995,0,0,empty,"No results at step: Finding nearby samples",0,0 +M8,"concentration range 10-1000",samples,near,1,facilities,ME,"range",FIND_TARGET_IRIS,engine,success,13511,944,0,ok,"",0,0 +M8,"exclude non-detects",samples,near,1,facilities,ME,"nondetect",FIND_TARGET_IRIS,engine,success,8113,1892,0,ok,"",0,0 +M8,"substance + downstream",samples,downstream,,facilities,ME,"substance+ds",FIND_TARGET_IRIS,engine,success,28260,1406,0,ok,"",0,0 +M8,"NAICS 2-digit (whole sector 31)",samples,near,1,facilities,ME,"naics-sector",FIND_TARGET_IRIS,engine,success,12370,334,0,ok,"",0,0 +M8,"aquifer type filter",samples,near,1,aquifers,ME,"aquifer-type",FIND_TARGET_IRIS,engine,success,121194,167,0,ok-partial,"",16,15 +M8,"waterbody ftype filter",samples,near,1,waterBodies,ME,"wb-ftype",FIND_TARGET_IRIS,engine,success,2291,1583,0,ok,"",0,0 +M2,"samples downstream samples [ME]",samples,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,12322,3214,0,ok,"",0,0 +M2,"samples downstream facilities [ME]",samples,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,13925,2412,0,ok,"",0,0 +M2,"samples downstream waterBodies [ME]",samples,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,21127,2610,0,ok,"",0,0 +M2,"samples downstream wells [ME]",samples,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,48404,3202,0,ok,"",0,0 +M2,"samples downstream aquifers [ME]",samples,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,26517,2741,0,ok,"",0,0 +M2,"facilities downstream samples [ME]",facilities,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,29074,1657,0,ok,"",0,0 +M2,"facilities downstream facilities [ME]",facilities,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,163342,0,0,failed,"SPARQL timeout (429): Operation timed out. Last operation: Join on ?s2neighbor",16,0 +M2,"facilities downstream waterBodies [ME]",facilities,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,133024,1068,0,ok-partial,"",16,7 +M2,"facilities downstream wells [ME]",facilities,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,123269,743,0,ok-partial,"",16,12 +M2,"facilities downstream aquifers [ME]",facilities,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,135441,1016,0,ok-partial,"",16,7 +M2,"waterBodies downstream samples [ME]",waterBodies,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,13564,1511,0,ok,"",0,0 +M2,"waterBodies downstream facilities [ME]",waterBodies,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,121757,1032,0,ok-partial,"",16,7 +M2,"waterBodies downstream waterBodies [ME]",waterBodies,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,33371,6095,0,ok,"",0,0 +M2,"waterBodies downstream wells [ME]",waterBodies,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,29810,3991,0,ok,"",0,0 +M2,"waterBodies downstream aquifers [ME]",waterBodies,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,101485,4041,0,ok,"",16,0 +M2,"wells downstream samples [ME]",wells,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,24669,28920,0,ok,"",0,0 +M2,"wells downstream facilities [ME]",wells,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,134449,3889,0,ok-partial,"",16,14 +M2,"wells downstream waterBodies [ME]",wells,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,132771,17375,0,ok-partial,"",16,11 +M2,"wells downstream wells [ME]",wells,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,127487,3105,0,ok-partial,"",16,15 +M2,"wells downstream aquifers [ME]",wells,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,124979,12064,0,ok-partial,"",16,13 +M2,"aquifers downstream samples [ME]",aquifers,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,12891,2599,0,ok,"",0,0 +M2,"aquifers downstream facilities [ME]",aquifers,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,29557,3242,0,ok,"",0,0 +M2,"aquifers downstream waterBodies [ME]",aquifers,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,122191,3031,0,ok-partial,"",16,6 +M2,"aquifers downstream wells [ME]",aquifers,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,123040,1776,0,ok-partial,"",16,9 +M2,"aquifers downstream aquifers [ME]",aquifers,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,128690,854,0,ok-partial,"",16,20 +M3,"samples upstream samples [ME]",samples,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,error,99678,0,0,failed,"SPARQL network (0): fetch failed",0,0 +M3,"samples upstream facilities [ME]",samples,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,13767,2739,0,ok,"",0,0 +M3,"samples upstream waterBodies [ME]",samples,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,12270,6072,0,ok,"",0,0 +M3,"samples upstream wells [ME]",samples,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,error,551866,0,0,failed,"SPARQL network (0): fetch failed",0,0 +M3,"samples upstream aquifers [ME]",samples,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,15097,4650,0,ok,"",0,0 +M3,"facilities upstream samples [ME]",facilities,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,28267,3195,0,ok,"",0,0 +M3,"facilities upstream facilities [ME]",facilities,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1918322,0,0,failed,"SPARQL network (0): fetch failed",0,0 +M3,"facilities upstream waterBodies [ME]",facilities,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,958890,0,0,failed,"SPARQL network (0): fetch failed",0,0 +M3,"facilities upstream wells [ME]",facilities,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,error,209172,0,0,failed,"SPARQL network (0): fetch failed",0,0 +M3,"facilities upstream aquifers [ME]",facilities,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,122995,2690,0,ok-partial,"",16,12 +M3,"waterBodies upstream samples [ME]",waterBodies,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,9531,3064,0,ok,"",0,0 +M3,"waterBodies upstream facilities [ME]",waterBodies,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,12450,2770,0,ok,"",0,0 +M3,"waterBodies upstream waterBodies [ME]",waterBodies,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,27386,6504,0,ok,"",0,0 +M3,"waterBodies upstream wells [ME]",waterBodies,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,25719,51437,0,ok,"",0,0 +M3,"waterBodies upstream aquifers [ME]",waterBodies,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,14828,4764,0,ok,"",0,0 +M3,"wells upstream samples [ME]",wells,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,48346,3221,0,ok,"",0,0 +M3,"wells upstream facilities [ME]",wells,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,131202,1729,0,ok-partial,"",16,10 +M3,"wells upstream waterBodies [ME]",wells,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,129915,5028,0,ok-partial,"",16,10 +M3,"wells upstream wells [ME]",wells,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,191792,8834,0,ok-partial,"",16,14 +M3,"wells upstream aquifers [ME]",wells,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,127053,4172,0,ok-partial,"",16,11 +M3,"aquifers upstream samples [ME]",aquifers,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,24083,2935,0,ok,"",0,0 +M3,"aquifers upstream facilities [ME]",aquifers,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,17251,1919,0,ok,"",0,0 +M3,"aquifers upstream waterBodies [ME]",aquifers,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,129101,5101,0,ok-partial,"",16,3 +M3,"aquifers upstream wells [ME]",aquifers,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,121522,26679,0,ok-partial,"",16,11 +M3,"aquifers upstream aquifers [ME]",aquifers,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,128409,4290,0,ok-partial,"",16,3 +M6,"samples downstream facilities [17]",samples,downstream,,facilities,17,"none",FIND_TARGET_IRIS,engine,error,124001,0,0,failed,"SPARQL timeout (429): Operation timed out. Last operation: Join on ?s2anchor",4,0 +M6,"samples downstream facilities [18]",samples,downstream,,facilities,18,"none",FIND_TARGET_IRIS,engine,success,19942,234,0,ok,"",0,0 +M6,"samples downstream facilities [25]",samples,downstream,,facilities,25,"none",FIND_TARGET_IRIS,engine,success,134271,115,0,ok-partial,"",14,8 +M6,"samples downstream facilities [33]",samples,downstream,,facilities,33,"none",FIND_TARGET_IRIS,engine,success,74450,43,0,ok,"",3,0 +M6,"samples downstream facilities [01]",samples,downstream,,facilities,01,"none",FIND_TARGET_IRIS,engine,empty,95736,0,0,empty,"No results at step: Finding downstream samples",3,0 +M6,"samples downstream facilities [50]",samples,downstream,,facilities,50,"none",FIND_TARGET_IRIS,engine,success,5012,17,0,ok,"",0,0 +M7,"samples near facilities [NO REGION]",samples,near,1,facilities,none,"none",FIND_TARGET_IRIS,engine,success,1166,4770,0,ok,"",0,0 +M7,"samples downstream facilities [NO REGION]",samples,downstream,,facilities,none,"none",FIND_TARGET_IRIS,engine,error,28640,0,0,failed,"SPARQL out-of-memory (500): Tried to allocate 2.6 GB, but only 1.3 GB were available",0,0 +M7,"wells near facilities [NO REGION]",wells,near,1,facilities,none,"none",FIND_TARGET_IRIS,engine,success,21728,219026,0,ok,"",0,0 +M5,"PREBUILT: Samples Near Agricultural Chemical Facilities in Maine",samples,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,33375,31,0,ok,"",0,0 +M5,"PREBUILT: Samples Near Landfills & DOD Sites in Penobscot and Knox County",samples,near,1,facilities,23019|23013,"prebuilt",PIPELINE,engine,success,10618,61,0,ok,"",0,0 +M5,"PREBUILT: Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County",waterBodies,near,1,facilities,23019|23013,"prebuilt",PIPELINE,engine,success,24072,103,0,ok,"",0,0 +M5,"PREBUILT: Samples Downstream of Waste Treatment Facilities in Indiana",samples,downstream,,facilities,18,"prebuilt",PIPELINE,engine,success,70778,15696,0,ok,"",0,0 +M5,"PREBUILT: Maine Private Wells Near Landfills & DoD Sites",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,22779,751,0,ok,"",0,0 +M5,"PREBUILT: Maine Private Wells Near Wastewater Treatment Facilities",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,13742,2431,0,ok,"",0,0 +M5,"PREBUILT: Maine Private Wells Near Airports & Air Transportation Sites (AFFF)",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,13122,4425,0,ok,"",0,0 +M5,"PREBUILT: PFHpA Groundwater Samples Downstream from Facilities in Cumberland County",samples,downstream,,facilities,23005,"prebuilt",PIPELINE,engine,empty,2435,0,0,empty,"No results at step: Finding downstream samples",0,0 diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 10aeacd..b86119d 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -22,12 +22,35 @@ import { appendFileSync, writeFileSync } from 'node:fs'; import { planPipeline } from '../src/engine/planner'; +import { executePipeline } from '../src/engine/executor'; import { ENDPOINTS } from '../src/constants/endpoints'; import { PREBUILT_QUERIES } from '../src/constants/prebuiltQueries'; import type { AnalysisQuestion, EntityType } from '../src/types/query'; +// 'raw' posts each step's SPARQL directly — measures the endpoint, not us, and +// is how the pre-Phase-2 baseline was recorded. 'engine' runs the real pipeline +// so splitting, merging, partial results and the step budget are all exercised; +// that is the mode to use for an after-the-change sweep. +const MODE = (process.env.QUERY_MATRIX_MODE ?? 'raw') as 'raw' | 'engine'; +// Default output is the *baseline* file, which is committed history — an `init` +// run truncates whatever it points at, so writing there needs to be deliberate. const OUT = process.env.QUERY_MATRIX_OUT ?? 'docs/query-matrix.csv'; -if (process.argv[3] === 'init') writeFileSync(OUT, 'matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg\n'); +if (process.argv[3] === 'init' && OUT === 'docs/query-matrix.csv' && !process.env.QUERY_MATRIX_OVERWRITE_BASELINE) { + console.error( + 'Refusing to truncate the committed baseline docs/query-matrix.csv.\n' + + 'Set QUERY_MATRIX_OUT=docs/query-matrix-after.csv (or another path) for a new sweep,\n' + + 'or QUERY_MATRIX_OVERWRITE_BASELINE=1 if you really mean to replace the baseline.', + ); + process.exit(1); +} +if (process.argv[3] === 'init') { + writeFileSync( + OUT, + MODE === 'engine' + ? 'matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksMax,partialSlices\n' + : 'matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg\n', + ); +} const classify = (status: number, ex: string): string => { if (status === 200) return 'ok'; @@ -42,7 +65,57 @@ const classify = (status: number, ex: string): string => { const csv = (s: unknown) => `"${String(s).replace(/"/g, "'").replace(/\s+/g, ' ').slice(0, 180)}"`; +// Runs through the real engine. For phases that measured only the discovery +// step in the baseline, the step list is truncated to that step so the two +// sweeps compare like with like — discovery is where almost every failure was. +async function runViaEngine( + matrix: string, + label: string, + q: AnalysisQuestion, + meta: Record, + stepIdx: number | 'all', +) { + const all = planPipeline(q); + const steps = stepIdx === 'all' ? all : all.slice(0, (stepIdx as number) + 1); + let chunksMax = 0; + const t0 = Date.now(); + const result = await executePipeline(steps, q, (p) => { + if ((p.chunksTotal ?? 0) > chunksMax) chunksMax = p.chunksTotal ?? 0; + }); + const ms = Date.now() - t0; + + const rows = + result.status === 'success' + ? Object.values(result.data).reduce((n, r) => Math.max(n, r.length), 0) + : 0; + const partialSlices = + result.status === 'success' + ? (result.partial ?? []).reduce((n, p) => n + p.failed.length + p.skipped.length, 0) + : 0; + const errorClass = + result.status === 'success' + ? partialSlices > 0 + ? 'ok-partial' + : 'ok' + : result.status === 'empty' + ? 'empty' + : 'failed'; + const detail = + result.status === 'error' ? result.error.message : result.status === 'empty' ? result.message : ''; + + appendFileSync( + OUT, + [matrix, csv(label), meta.blockA, meta.rel, meta.hops, meta.blockC, meta.region, csv(meta.filters), + stepIdx === 'all' ? 'PIPELINE' : steps[steps.length - 1].type, 'engine', + result.status, ms, rows, 0, errorClass, csv(detail), chunksMax, partialSlices].join(',') + '\n', + ); + console.log( + `${matrix} ${label.padEnd(44).slice(0, 44)} ${result.status.padEnd(8)} ${String(ms).padStart(7)}ms rows=${String(rows).padStart(5)} chunks=${chunksMax} partial=${partialSlices}`, + ); +} + async function run(matrix: string, label: string, q: AnalysisQuestion, meta: Record, stepIdx: number | 'all') { + if (MODE === 'engine') return runViaEngine(matrix, label, q, meta, stepIdx); const steps = planPipeline(q); const ctx: any = { question: q, targetIris: [], anchorIris: [], results: {} }; const idxs = stepIdx === 'all' ? steps.map((_, i) => i) : [stepIdx]; diff --git a/src/components/Pipeline/PartialResultsNotice.tsx b/src/components/Pipeline/PartialResultsNotice.tsx index a2740a5..d25785b 100644 --- a/src/components/Pipeline/PartialResultsNotice.tsx +++ b/src/components/Pipeline/PartialResultsNotice.tsx @@ -10,14 +10,23 @@ export function PartialResultsNotice() { if (pipelineResult?.status !== 'success' || !pipelineResult.partial?.length) return null; if (dismissed) return null; - const missing = pipelineResult.partial.reduce((n, p) => n + p.scopes.length, 0); + const failed = pipelineResult.partial.reduce((n, p) => n + p.failed.length, 0); + const skipped = pipelineResult.partial.reduce((n, p) => n + p.skipped.length, 0); + + // These two need different advice: a failed slice will fail again unless the + // question is narrowed, while a skipped one simply ran out of budget and + // usually completes on a second run against a warmer cache. + const reasons = [ + failed > 0 ? `${failed} too large to answer` : null, + skipped > 0 ? `${skipped} not attempted before the time limit` : null, + ].filter(Boolean); return (
- Showing incomplete results — {missing} {missing === 1 ? 'part' : 'parts'} of this - question were too large for the knowledge graph to answer. Narrowing the area or - adding a filter will give a complete answer. + Showing incomplete results — {reasons.join(', ')}.{' '} + {skipped > 0 && 'Running the question again picks up where this left off. '} + {failed > 0 && 'For the parts that were too large, add a filter or region to the second block.'} +
+ ); +} diff --git a/src/engine/cacheKey.ts b/src/engine/cacheKey.ts new file mode 100644 index 0000000..649ac6f --- /dev/null +++ b/src/engine/cacheKey.ts @@ -0,0 +1,82 @@ +import type { AnalysisQuestion } from '../types/query'; + +// Two questions that produce the same SPARQL must produce the same cache key, +// and a question that produces different SPARQL must not. Raw JSON.stringify +// fails both directions: object key order is incidental, and the question +// carries display-only fields that never reach a query. +// +// Bump WIRE_VERSION when the set of result keys we store changes (see wire.ts) — +// old entries would then be missing data the map expects. +const WIRE_VERSION = 'w1'; + +// Bump DATA_VERSION after a knowledge-graph reload to make every existing key +// unreachable in one move. +// +// Deliberately a constant, not an environment variable: this value has to agree +// between the browser bundle and the warm-cache script, and an env var that +// differs between the two would produce silent, permanent cache misses with +// nothing to see in either place. +const DATA_VERSION = '2026-09'; + +// Label maps exist to render chips in the editor. Verified not to reach any +// query template (`grep -rn "Labels" src/engine/` finds nothing), so a user +// re-picking the same county with different label text must not miss the cache. +const DISPLAY_ONLY = new Set(['countyLabels', 'substanceLabels', 'industryLabels']); + +// Filter arrays are sets — order is a UI artefact of the click sequence. +const UNORDERED_ARRAYS = new Set([ + 'countyCodes', + 'countySubdivisionURIs', + 'substances', + 'materialTypes', + 'industryCodes', + 'waterTypes', + 'ftypes', + 'wellCategories', + 'aquiferTypes', +]); + +function canonical(value: unknown, key?: string): unknown { + if (value === null || value === undefined) return undefined; + + if (Array.isArray(value)) { + const items = value.map((v) => canonical(v)).filter((v) => v !== undefined); + // An empty filter array means the same as no filter at all. + if (items.length === 0) return undefined; + return UNORDERED_ARRAYS.has(key ?? '') ? [...items].sort() : items; + } + + if (typeof value === 'object') { + const out: Record = {}; + for (const k of Object.keys(value as object).sort()) { + if (DISPLAY_ONLY.has(k)) continue; + const v = canonical((value as Record)[k], k); + if (v !== undefined) out[k] = v; + } + // An object left empty carries no meaning either — `{ sampleFilters: {} }` + // and a missing `sampleFilters` are the same question. Without this, a + // filter the user set and then cleared would miss the cache forever. + if (Object.keys(out).length === 0) return undefined; + return out; + } + + return value; +} + +export function canonicalQuestion(question: AnalysisQuestion): unknown { + const rel = question.relationship; + // `hops` is only read on the near path (fusedQueries.ts buildFusedWhereBody), + // so a leftover hops value from switching the dropdown must not split the key. + const relationship = + rel.type === 'near' || rel.type === 'within' + ? { type: rel.type, hops: rel.hops ?? 1 } + : { type: rel.type }; + return canonical({ ...question, relationship }); +} + +export async function cacheKey(question: AnalysisQuestion): Promise { + const body = `${WIRE_VERSION}|${DATA_VERSION}|${JSON.stringify(canonicalQuestion(question))}`; + const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(body)); + const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join(''); + return `q:${hex}`; +} diff --git a/src/engine/wire.ts b/src/engine/wire.ts new file mode 100644 index 0000000..b221e29 --- /dev/null +++ b/src/engine/wire.ts @@ -0,0 +1,51 @@ +import type { SparqlRow } from '../types/sparql'; +import type { PartialFailure, PipelineSuccess } from './executor'; + +// The shape a cached result takes over the wire and in Postgres. +// +// Only successes are cached. An error is nearly always transient endpoint load +// (see docs/QUERY-MATRIX.md Part 4), so freezing one would turn a bad minute +// into a bad month, and an empty result is cheap to recompute. +export interface WireResult { + status: 'success'; + data: Record; + partial?: PartialFailure[]; + computedAt: string; +} + +// The only keys useMapLayers reads (useMapLayers.ts:41-44). Everything else in +// `data` is pipeline bookkeeping — the intermediate IRI lists, which for a +// statewide well query ran to 22.6MB on their own and are never rendered. +const RENDERED_KEYS = [ + 'FIND_TARGET_ENTITIES', + 'GET_ANCHOR_DETAILS', + 'GET_REGION_BOUNDARIES', + 'GET_FLOWLINE_GEOMETRIES', +] as const; + +export function toWire(result: PipelineSuccess, computedAt = new Date().toISOString()): WireResult { + const data: Record = {}; + for (const key of RENDERED_KEYS) { + if (result.data[key]?.length) data[key] = result.data[key]; + } + return { + status: 'success', + data, + ...(result.partial?.length ? { partial: result.partial } : {}), + computedAt, + }; +} + +export function fromWire(wire: WireResult): PipelineSuccess { + return { + status: 'success', + data: wire.data, + ...(wire.partial?.length ? { partial: wire.partial } : {}), + }; +} + +export function isWireResult(value: unknown): value is WireResult { + if (!value || typeof value !== 'object') return false; + const candidate = value as Partial; + return candidate.status === 'success' && typeof candidate.data === 'object' && candidate.data !== null; +} diff --git a/src/hooks/useQueryPipeline.ts b/src/hooks/useQueryPipeline.ts index 6c3c068..0b33898 100644 --- a/src/hooks/useQueryPipeline.ts +++ b/src/hooks/useQueryPipeline.ts @@ -3,6 +3,7 @@ import { useQueryStore } from '../store/queryStore'; import type { PipelineResult } from '../engine/executor'; import { planPipeline } from '../engine/planner'; import { executePipeline } from '../engine/executor'; +import { fetchCachedResult } from '../api/resultCacheClient'; export function useQueryPipeline() { const { @@ -14,13 +15,26 @@ export function useQueryPipeline() { addStepProgress, clearProgress, setPipelineResult, + setResultProvenance, } = useQueryStore(); - const runPipeline = useCallback(async () => { + const runPipeline = useCallback(async (options: { skipCache?: boolean } = {}) => { clearProgress(); setIsRunning(true); try { + // A cached answer to this exact question skips the pipeline entirely. + // Only trusted writers populate the cache (the publisher and the + // warm-cache script), and a miss or any error falls through to running + // locally, so this can only make a run faster. + const cached = options.skipCache ? null : await fetchCachedResult(question); + if (cached) { + setPipelineResult(cached.result); + setResultProvenance({ computedAt: cached.computedAt, partial: cached.partial }); + return cached.result; + } + setResultProvenance(null); + const steps = planPipeline(question); const result = await executePipeline(steps, question, addStepProgress); setPipelineResult(result); @@ -37,7 +51,14 @@ export function useQueryPipeline() { } finally { setIsRunning(false); } - }, [question, clearProgress, setIsRunning, addStepProgress, setPipelineResult]); + }, [ + question, + clearProgress, + setIsRunning, + addStepProgress, + setPipelineResult, + setResultProvenance, + ]); return { runPipeline, isRunning, stepProgress, pipelineResult }; } diff --git a/src/store/queryStore.ts b/src/store/queryStore.ts index 47acb47..c7a505b 100644 --- a/src/store/queryStore.ts +++ b/src/store/queryStore.ts @@ -22,6 +22,9 @@ interface QueryStore { baselineQuestion: AnalysisQuestion; stepProgress: StepProgress[]; pipelineResult: PipelineResult | null; + // Set when the result came from the cache rather than a live run, so the UI + // can say so. Null means the displayed result was just computed. + resultProvenance: { computedAt: string | null; partial: boolean } | null; isRunning: boolean; isEditModalOpen: boolean; questionSnapshot: AnalysisQuestion | null; @@ -58,6 +61,9 @@ interface QueryStore { addStepProgress: (progress: StepProgress) => void; clearProgress: () => void; setPipelineResult: (result: PipelineResult | null) => void; + setResultProvenance: ( + provenance: { computedAt: string | null; partial: boolean } | null, + ) => void; openTour: () => void; closeTour: () => void; @@ -71,6 +77,7 @@ export const useQueryStore = create((set) => ({ baselineQuestion: defaultQuestion(), stepProgress: [], pipelineResult: null, + resultProvenance: null, isRunning: false, isEditModalOpen: false, questionSnapshot: null, @@ -87,6 +94,7 @@ export const useQueryStore = create((set) => ({ baselineQuestion: deepClone(question), stepProgress: [], pipelineResult: null, + resultProvenance: null, pendingAutoRun: options.autoRun ?? true, lastApplyError: null, }), @@ -131,6 +139,7 @@ export const useQueryStore = create((set) => ({ }), clearProgress: () => set({ stepProgress: [] }), setPipelineResult: (pipelineResult) => set({ pipelineResult }), + setResultProvenance: (resultProvenance) => set({ resultProvenance }), openTour: () => set({ isTourOpen: true }), closeTour: () => set({ isTourOpen: false }), From 767e1b5b1db17f935b9ceaad30a61c876c972f2b Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 08:57:46 -0400 Subject: [PATCH 24/66] ci: warm the result cache from a button in the Actions tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dashboard questions are cached by a maintainer-run script, which only helps if running it is easy. Actions -> Warm result cache -> Run workflow now does it: choose development or production, optionally filter to one question by title, and read what was cached in the job summary. Concurrency is capped at one run per environment — these queries are heavy on a shared graph engine and two runs would compete for it. The job fails with an explicit message when the environment's token is missing, rather than uploading nothing and reporting success. No schedule attached. A cached entry goes stale only when the graph reloads or its 30-day TTL lapses, both of which we control; the workflow header carries the three lines that would add a weekly cron if that changes. tsx moves from an on-demand npx download to a pinned devDependency so CI resolves it deterministically, and the repo scripts get npm aliases (warm-cache, check-cache-key, query-matrix). --- .github/workflows/warm-cache.yml | 83 +++ docs/changelog/2026-W38.md | 9 + .../active/2026-09-14-phase-3-result-cache.md | 18 + package-lock.json | 504 ++++++++++++++++++ package.json | 6 +- 5 files changed, 619 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/warm-cache.yml diff --git a/.github/workflows/warm-cache.yml b/.github/workflows/warm-cache.yml new file mode 100644 index 0000000..af529a8 --- /dev/null +++ b/.github/workflows/warm-cache.yml @@ -0,0 +1,83 @@ +name: Warm result cache + +# Runs the dashboard questions and stores their results, so visitors get them +# instantly instead of waiting 10-70s for a live pipeline run. +# +# Manual on purpose: a cached entry only goes stale when the knowledge graph +# reloads or its 30-day TTL expires, and both are things we control. To make it +# periodic anyway, add a schedule trigger: +# +# schedule: +# - cron: '0 6 * * 1' # Mondays, 06:00 UTC +# +# Setup (once): add the repository secrets CACHE_WRITE_TOKEN_DEV and +# CACHE_WRITE_TOKEN_PROD, matching CACHE_WRITE_TOKEN on each API service. + +on: + workflow_dispatch: + inputs: + environment: + description: Which API to warm + type: choice + required: true + default: development + options: [development, production] + only: + description: 'Optional: only questions whose title contains this text' + type: string + required: false + allow_partial: + description: Cache results even when some slices failed + type: boolean + default: false + +# One warm run at a time — these queries are heavy on a shared endpoint, and two +# concurrent runs would compete for the same graph engine. +concurrency: + group: warm-cache-${{ inputs.environment }} + cancel-in-progress: false + +jobs: + warm: + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + + # react-leaflet's peer range does not include React 19 (see CLAUDE.md) + - run: npm ci --legacy-peer-deps + + - name: Warm the cache + env: + API_BASE: >- + ${{ inputs.environment == 'production' + && 'https://sawgraph-explorer-api.up.railway.app' + || 'https://sawgraph-explorer-api-development.up.railway.app' }} + CACHE_WRITE_TOKEN: >- + ${{ inputs.environment == 'production' + && secrets.CACHE_WRITE_TOKEN_PROD + || secrets.CACHE_WRITE_TOKEN_DEV }} + ALLOW_PARTIAL: ${{ inputs.allow_partial && '1' || '0' }} + run: | + if [ -z "$CACHE_WRITE_TOKEN" ]; then + echo "::error::No cache write token for '${{ inputs.environment }}'." + echo "::error::Add CACHE_WRITE_TOKEN_DEV / CACHE_WRITE_TOKEN_PROD as repository secrets." + exit 1 + fi + npm run warm-cache -- "${{ inputs.only }}" | tee warm-cache.log + + - name: Summary + if: always() + run: | + { + echo "### Warm result cache — ${{ inputs.environment }}" + echo + echo '```' + tail -20 warm-cache.log 2>/dev/null || echo "no output" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 0caa19f..7859b7d 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -49,3 +49,12 @@ Note for whoever reads this next: `CLAUDE.md` lives one directory *above* the repo root and is not tracked by this repo, so edits to it stay on one machine. The deployment table was put in the README for that reason. *Files:* `.env.example`, `README.md`, `server/.gitignore` + +7. **One-Click Cache Warming from the Actions Tab** (2026-09-14) + The dashboard questions are cached by a maintainer-run script, which is only useful if running it is easy. `Actions → Warm result cache → Run workflow` now does it: pick development or production, optionally filter to one question by title, and the run reports what it cached in the job summary. Concurrency is limited to one run per environment, since these queries are heavy on a shared endpoint and two runs would compete for the same graph engine. + + Needs `CACHE_WRITE_TOKEN_DEV` / `CACHE_WRITE_TOKEN_PROD` as repository secrets; the workflow fails with a clear message rather than silently uploading nothing when one is absent. No schedule attached — a cached entry only goes stale when the graph reloads or its TTL expires, both of which we control, and the workflow header shows the three lines that would add a weekly cron if that changes. + + `tsx` moved from an on-demand `npx` download to a pinned devDependency so CI installs it deterministically, and the repo scripts now have npm aliases: `warm-cache`, `check-cache-key`, `query-matrix`. + + *Files:* `.github/workflows/warm-cache.yml` (new), `package.json` diff --git a/docs/plans/active/2026-09-14-phase-3-result-cache.md b/docs/plans/active/2026-09-14-phase-3-result-cache.md index 577d9c6..22562c8 100644 --- a/docs/plans/active/2026-09-14-phase-3-result-cache.md +++ b/docs/plans/active/2026-09-14-phase-3-result-cache.md @@ -229,6 +229,24 @@ proxy** URL — the `*.railway.internal` host only resolves inside Railway. Running `npm run dev` against it would migrate the wrong database. Replace it before any local server work. +### Warming the dashboard questions + +A GitHub Action does this on a button press: **Actions → Warm result cache → Run +workflow**, pick `development` or `production`, optionally filter by title, then +Run. It checks out the repo, runs the eight questions through the real engine on +the runner, and uploads each result. + +One-time setup: add repository secrets `CACHE_WRITE_TOKEN_DEV` and +`CACHE_WRITE_TOKEN_PROD` matching `CACHE_WRITE_TOKEN` on each API service. The +workflow fails with an explicit message if the one it needs is missing, rather +than silently uploading nothing. + +Locally the same thing is `npm run warm-cache` with `API_BASE` and +`CACHE_WRITE_TOKEN` set. Run it after a graph reload (bump `DATA_VERSION` +first), after editing `prebuiltQueries.ts`, or when the 30-day TTL lapses. +Deliberately no schedule — the header of the workflow file shows the three lines +that would add one. + ### Railway dashboard (manual, outside the repo) Add `CACHE_WRITE_TOKEN` to both API services, and optionally `DATA_VERSION`. No diff --git a/package-lock.json b/package-lock.json index 6dd64d2..e8a6a7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "tsx": "^4.23.13", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1" @@ -3614,6 +3615,509 @@ "typescript": ">=4.8.4" } }, + "node_modules/tsx": { + "version": "4.23.13", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.13.tgz", + "integrity": "sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 59f2837..7512cef 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,10 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "warm-cache": "tsx scripts/warm-cache.mts", + "check-cache-key": "tsx scripts/check-cache-key.mts", + "query-matrix": "tsx scripts/query-matrix.mts" }, "dependencies": { "@tanstack/react-query": "^5.90.21", @@ -34,6 +37,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "tsx": "^4.23.13", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1" From 81377baa03d39787329a73a4ec94f563280e52f7 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 14:14:29 -0400 Subject: [PATCH 25/66] fix(cache): include maxDistanceKm in the result-cache key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit canonicalQuestion rebuilt the relationship as `{ type }` for downstream and upstream, which silently dropped any other field on it. That was harmless until #41 merged: a 30km-bounded question and an unbounded one then hashed to the same key, so caching either would have served its answer for the other — for "facilities upstream from PFOS samples in York/Washington/Waldo" that is 12,077 river reaches and 14 sample points quietly missing, with the map giving no hint that it was showing a bounded answer to an unbounded question. Caught while warming that exact question for a demo; the upload was stopped before it wrote, and the dev cache was verified clean afterwards (404 on the colliding key), so nothing needs purging. The fix keeps every relationship field except hops, which is genuinely read only on the near path. The default direction now fails safe: an unrecognised field that should have been ignored costs a cache miss, where one that should have been included and was dropped serves the wrong answer. Rebuilding the object from a whitelist had the opposite default, which is why one merge was enough to break it. Unbounded traces keep the key they had before maxDistanceKm existed, so entries cached earlier remain reachable — verified: the unbounded key is byte-identical before and after. check-cache-key gains four cases: bounded vs unbounded differ, two different bounds differ, the same on downstream, and the unbounded key is unchanged. 19 checks pass. --- scripts/check-cache-key.mts | 27 +++++++++++++++++++++++++++ src/engine/cacheKey.ts | 16 ++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/scripts/check-cache-key.mts b/scripts/check-cache-key.mts index 47d186b..39d7df0 100644 --- a/scripts/check-cache-key.mts +++ b/scripts/check-cache-key.mts @@ -67,6 +67,33 @@ await differs( q({ a: { region: { stateCode: '23', countyCodes: ['23005', '23019'] } } }), ); +// A distance bound changes the answer, so it must change the key. This is the +// case that was wrong once: canonicalQuestion rebuilt the relationship as +// `{ type }` for traces, silently dropping maxDistanceKm, so a bounded and an +// unbounded question collided. +await differs( + 'maxDistanceKm vs unbounded', + q({ rel: { type: 'upstream' } }), + q({ rel: { type: 'upstream', maxDistanceKm: 30 } }), +); +await differs( + 'different maxDistanceKm', + q({ rel: { type: 'upstream', maxDistanceKm: 30 } }), + q({ rel: { type: 'upstream', maxDistanceKm: 10 } }), +); +await differs( + 'maxDistanceKm on downstream', + q({ rel: { type: 'downstream' } }), + q({ rel: { type: 'downstream', maxDistanceKm: 30 } }), +); +// ...while an unbounded trace keeps the key it had before maxDistanceKm existed, +// so entries cached earlier stay reachable. +await same( + 'unbounded trace key is unchanged', + q({ rel: { type: 'downstream' } }), + q({ rel: { type: 'downstream', hops: 3 } }), +); + // The dashboard questions are what the warm-cache script writes: they must be // distinct from each other and stable between runs. const keys = await Promise.all(PREBUILT_QUERIES.map((p) => cacheKey(p.question))); diff --git a/src/engine/cacheKey.ts b/src/engine/cacheKey.ts index 649ac6f..935b056 100644 --- a/src/engine/cacheKey.ts +++ b/src/engine/cacheKey.ts @@ -67,10 +67,22 @@ export function canonicalQuestion(question: AnalysisQuestion): unknown { const rel = question.relationship; // `hops` is only read on the near path (fusedQueries.ts buildFusedWhereBody), // so a leftover hops value from switching the dropdown must not split the key. + // + // Everything else on the relationship is carried through untouched, and that + // is deliberate. An earlier version rebuilt this object as `{ type }` for the + // trace relationships, which meant a field it did not know about vanished + // from the key: when maxDistanceKm arrived, a 30km question and an unbounded + // one hashed identically, and caching one would have served its answer for + // the other — 12,000 river reaches and 14 sample points quietly missing. + // + // Keep the default direction safe. An unrecognised field that should have + // been ignored only costs a cache miss; one that should have been included + // and was dropped serves the wrong answer. + const { hops, ...restOfRelationship } = rel; const relationship = rel.type === 'near' || rel.type === 'within' - ? { type: rel.type, hops: rel.hops ?? 1 } - : { type: rel.type }; + ? { ...restOfRelationship, hops: hops ?? 1 } + : restOfRelationship; return canonical({ ...question, relationship }); } From 0b21295b0f99587633b3fb920c8af0ea1c732080 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 14:45:27 -0400 Subject: [PATCH 26/66] docs: record the distance bound, the rejected trim, and the cache-key trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QUERY-MATRIX Part 2 understated the query space after #41 — six entity types now, not five, and traces carry an optional distance bound. Says so, and marks the Part 3 baseline as predating both so nobody reads it as current. New Part 8 carries the distance-bound measurements (30km: 77% fewer reaches, every facility kept, 22.3MB to 7.1MB) including the costs — 14 sample points lost at 30km, 62 facilities and 85 samples at 10km — and the reliability caveat that the same question ran 99s complete and 361s partial an hour apart. It also records the connectivity trim as tried and rejected with the numbers (429 timeout at 70s against 16s for the current query), because the plan reads like a good idea and someone will otherwise rebuild it. DEBUGGING gains the cache-key collision. The entry leads with "symptom: none visible", since that is the whole problem — a complete, plausible map belonging to a different question. The general lesson is the part worth keeping: a cache key must be built by removing known-irrelevant fields, never by listing known-relevant ones, because the two failure modes are not symmetric. Wrongly including a field costs a miss; wrongly dropping one serves the wrong answer, and only the second is silent. Three facts about the hydrology graph are recorded because each cost time to establish: downstreamFlowPathTC is reflexive, A TC B means B is downstream, and braided channels give genuine two-way connectivity so a single pair cannot settle a direction question. Plan moved to done/, marked partially done, with the rendering cap named as the piece still outstanding. --- docs/DEBUGGING.md | 67 ++++++++++++++ docs/QUERY-MATRIX.md | 89 +++++++++++++++++-- docs/changelog/2026-W38.md | 18 ++++ .../done/2026-09-14-trim-stream-layer.md | 65 ++++++++++++++ 4 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 docs/plans/done/2026-09-14-trim-stream-layer.md diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index d2a37c9..fae9c30 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -292,3 +292,70 @@ query the engine refuses is split into slices and merged **Prevention**: benchmark against more than Maine, and re-run `npm run query-matrix` after any engine change, diffing against `docs/query-matrix.csv`. + +--- + +## 2026-09-14 — Cached results served for the wrong question (FIXED) + +**Component**: `src/engine/cacheKey.ts` — `canonicalQuestion` + +**Symptom**: none visible. That is the point of this entry. A map would render a +complete, plausible answer that belonged to a *different* question, with no +error, no warning, and the usual "showing saved results" banner. + +**Root cause**: `canonicalQuestion` normalised the relationship by rebuilding it +from a whitelist: + +```ts +const relationship = + rel.type === 'near' || rel.type === 'within' + ? { type: rel.type, hops: rel.hops ?? 1 } + : { type: rel.type }; // ← everything else on the relationship is gone +``` + +Correct when written — `hops` is genuinely only read on the near path, so a +leftover value must not split the key. But the `else` branch discards *any* other +field. When PR #41 added `maxDistanceKm`, a 30 km-bounded question and an +unbounded one immediately hashed to the same key: + +``` +unbounded : q:6b1d1ee8b88e820f5b44f6833c15730d3a9c574894339c8dba671e8c7b04e615 +30 km : q:6b1d1ee8b88e820f5b44f6833c15730d3a9c574894339c8dba671e8c7b04e615 +``` + +Caching either would have served its answer for the other. For "facilities +upstream from PFOS samples in York/Washington/Waldo" that is **12,077 river +reaches and 14 sample points missing**, presented as the complete answer. + +**Caught**: while warming that question for a demo — the key was printed as part +of checking the upload, and the two matched. The upload was killed before it +wrote and the cache verified clean (404 on the colliding key), so nothing needed +purging. It would not have been caught by looking at a map. + +**Fix**: strip only the field known to be irrelevant, and carry the rest +through: + +```ts +const { hops, ...restOfRelationship } = rel; +const relationship = + rel.type === 'near' || rel.type === 'within' + ? { ...restOfRelationship, hops: hops ?? 1 } + : restOfRelationship; +``` + +Unbounded traces keep the key they had before `maxDistanceKm` existed, so +entries cached earlier stay reachable. + +**Prevention** — the general lesson, which matters more than this instance: + +- **A cache key must fail safe, and "safe" is asymmetric.** A field wrongly + *included* costs a cache miss. A field wrongly *dropped* serves the wrong + answer. So build the key by removing known-irrelevant fields, never by + listing known-relevant ones — a whitelist silently drops whatever is added + next, and adding a field to `AnalysisQuestion` is a normal thing to do. +- Any new field on `AnalysisQuestion` that changes results must be reflected in + `scripts/check-cache-key.mts`. It now covers bounded vs unbounded, two + different bounds, and that the unbounded key is unchanged — 19 checks. +- The same reasoning applies to `WIRE_VERSION` in that file: bump it when the + set of stored result keys changes, or cached entries will be missing data the + map expects. diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 0aecdfe..0de203b 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -43,19 +43,25 @@ A question is three choices (`src/types/query.ts`): [ Block A: what you want to see ] → [ relationship ] → [ Block C: what it relates to ] ``` -**Block A and Block C** — 5 entity types each -(`src/components/QueryEditor/EntityTypeSelector.tsx:10-14`): -samples, facilities, surface water bodies, wells, aquifers. +**Block A and Block C** — 6 entity types each +(`src/components/QueryEditor/EntityTypeSelector.tsx`): +samples, facilities, surface water bodies, wells, aquifers, **streams**. **Relationship** — 3 kinds -(`src/components/QueryEditor/RelationshipSelector.tsx:10-21`): +(`src/components/QueryEditor/RelationshipSelector.tsx`): - **Near**, with 5 distances: 0, ~1, ~2, ~3, ~4 miles (S2-cell hops) -- **Downstream of** (follows rivers) -- **Upstream from** (follows rivers) +- **Downstream of** (follows rivers), optionally bounded by **distance in km** +- **Upstream from** (follows rivers), same optional bound -That's **5 × 5 × 7 = 175 distinct shapes** before any filter or region is -applied. On top of that: +> **The measured baseline in Part 3 predates two of these.** `streams` as an +> entity type and the `maxDistanceKm` bound on traces both arrived with PR #41 +> on 2026-09-14. No row below exercises either, so the sheet covers 95 of the +> shapes the editor offered *then*, not the larger space it offers now. The +> distance bound is characterised separately in Part 8. + +That's **6 × 6 × 7 = 252 shapes** before distance bounds, filters or regions. +On top of that: - **Region**: none, one of 13 states (`src/constants/regions.ts:8-22`), or any set of counties within a state @@ -559,3 +565,70 @@ worded separately. that has since been replaced. The one case re-measured afterwards (`wells near(4)`) went from 11 missing to **0**. Several other partials in that file are likely complete now; they have not been re-run. + +--- + +## Part 8 — Distance-bounded traces (2026-09-14) + +PR #41 added an optional `maxDistanceKm` to downstream and upstream questions: +the trace sums `nhdplusv2:hasFlowPathLength` over the segments between seed and +candidate and drops anything past the budget, then extends one segment further +so the drawn path does not stop mid-channel. + +Measured on "facilities upstream from PFOS samples in York, Washington and Waldo +counties" — the question that prompted this, because its map covered most of +southern Maine in river lines: + +| Bound | Time | Reaches | Facilities | Samples | Payload | +| --- | --- | --- | --- | --- | --- | +| none | 109s | 15,782 | 616 | 372 | 22.3 MB | +| **30 km** | 99s | **3,705** | **616** | 358 | **7.1 MB** | +| 10 km | 52s | 1,684 | 554 | 287 | 4.6 MB | + +**30 km removes 77% of the river reaches while keeping every facility**, and +brings the payload under the 25 MB cache limit. It is not free: 14 sample points +disappear, and at 10 km, 62 facilities and 85 samples do. A bound answers a +different question — "within this distance" — rather than rendering the same +answer more legibly. + +Note the time barely moves at 30 km. The engine still computes the closure and +then filters on summed length; the saving is in what is transferred and drawn. +Only 10 km meaningfully cuts runtime. + +**Reliability caveat, worth knowing before relying on it.** The same 30 km +question ran 99s complete in one hour and 361s *partial* (2 slices missing) in +the next, with no code change between. Distance bounds reduce volume; they do +not make a heavy trace dependable. + +### What was tried and rejected: trimming by connectivity + +The original goal was to keep only the reaches that actually connect a matched +facility to a matched sample — bounding by *terminus* rather than by distance. +That was measured and **does not work**: + +| Query | Result | +| --- | --- | +| current (no terminus) | 16s, 4,661 reaches | +| terminus-bounded | **429 timeout at 70s** | + +Adding a second `hyf:downstreamFlowPathTC` join — a 408M-triple relation — +exceeds what the endpoint will do, even with all 1,172 target IRIs pinned in a +`VALUES` block. `maxDistanceKm` is the trimming mechanism that exists. + +If anyone revisits this: the remaining untested idea is applying the terminus +constraint only on the *distance-bounded* path, where `boundedTrace` has already +cut the candidate set before the second join runs. That would only help +questions that set a distance. + +### Useful facts established while measuring + +- **`hyf:downstreamFlowPathTC` is reflexive** — ` hyf:downstreamFlowPathTC ` + returns a row. A zero-or-one path (`?`) after it is redundant. +- **`A TC B` means B is downstream of A.** Three Penobscot headwater reaches at + ~46.1°N had successors averaging 0.73–0.79° south (seaward) and predecessors + immediately upslope. +- **The network contains genuine two-way connectivity.** Testing linked pairs + returned *both* directions true for every pair sampled, and not because the + reaches coincided (0 of 50 shared one). Braided channels mean "is A upstream + of B" has no clean yes/no answer — so do not use a single pair to reason about + trace direction. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 7859b7d..fa093f5 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -58,3 +58,21 @@ `tsx` moved from an on-demand `npx` download to a pinned devDependency so CI installs it deterministically, and the repo scripts now have npm aliases: `warm-cache`, `check-cache-key`, `query-matrix`. *Files:* `.github/workflows/warm-cache.yml` (new), `package.json` + +8. **Distance-Bounded River Tracing; Streams as an Answerable Type** (2026-09-14) + Downstream and upstream questions drew the entire river network they traced — a question about facilities upstream from PFOS samples in three counties covered most of southern Maine in blue, because the flowline query had no notion of a terminus and emitted the whole transitive closure. Rebased and merged the stream-distance work that had been open as #32 since 2026-08-28, which adds an optional distance bound (5–100 km) and makes streams selectable as an answer rather than only decoration. + + On that PFOS question, a 30 km bound removes 77% of the river reaches — 15,782 down to 3,705 — while keeping all 616 facilities, and brings the payload from 22.3 MB to 7.1 MB, under the cache limit. It is a different question rather than a tidier rendering of the same one: 14 sample points drop at 30 km, and at 10 km, 62 facilities and 85 samples. Runtime barely moves at 30 km; the engine still computes the closure and filters afterwards. + + #32 predated both the wells-classification and bounded-execution work, so three of its changes were stale rather than conflicting and were dropped: `wellFilters.wellTypes` (renamed to `wellCategories`), `buildWellsByIri` (deleted in `ebc6dda` after 20k inlined IRIs produced a 413), and `buildFusedSampleAggregateQuery` (deleted because re-deriving the trace inside hydration is what timed out). + + Trimming by *connectivity* instead — keeping only reaches that reach a matched sample — was measured and rejected: a second `hyf:downstreamFlowPathTC` join times out at 70s where the current query answers in 16s. Recorded in `docs/QUERY-MATRIX.md` Part 8 so it is not rebuilt. + + *Files:* `src/engine/templates/fusedQueries.ts`, `src/engine/templates/hydrate.ts`, `src/engine/planner.ts`, `src/engine/scope.ts`, `src/types/query.ts`, `src/components/QueryEditor/StreamFilters.tsx` (new), `RelationshipSelector.tsx`, `EntityBlock.tsx` + +9. **Fixed: Cached Results Could Be Served for the Wrong Question** (2026-09-14) + The result-cache key normalised a question by rebuilding its relationship from a whitelist of fields, which silently discarded anything not on that list. Correct until entry 8 added a distance bound — after which a 30 km question and an unbounded one hashed identically, so caching either would have served its answer for the other, with 12,077 river reaches and 14 sample points missing and nothing in the UI to indicate it. + + Caught while warming that question for a demo; the upload was stopped before it wrote and the cache verified clean, so nothing needed purging. The key is now built by removing the one field known to be irrelevant rather than listing the ones known to matter — a field wrongly included costs a cache miss, one wrongly dropped serves the wrong answer, and only the second is silent. Unbounded traces keep their previous key, so entries cached earlier stay reachable. + + *Files:* `src/engine/cacheKey.ts`, `scripts/check-cache-key.mts` (19 checks), `docs/DEBUGGING.md` diff --git a/docs/plans/done/2026-09-14-trim-stream-layer.md b/docs/plans/done/2026-09-14-trim-stream-layer.md new file mode 100644 index 0000000..369e4f5 --- /dev/null +++ b/docs/plans/done/2026-09-14-trim-stream-layer.md @@ -0,0 +1,65 @@ +# Trim the stream layer to reaches that actually connect + +**Status**: done — partially. The connectivity trim was measured and rejected; +distance bounding shipped instead. +**Created**: 2026-09-14 +**Completed**: 2026-09-14 + +## Problem + +Downstream and upstream questions drew the entire river network they traced. A +question about facilities upstream from PFOS samples in three Maine counties +covered most of southern Maine in blue: 15,782 reaches for 616 facilities and +372 samples. + +`buildFusedFlowlineQuery` took the resolved anchors, expanded to their S2 cells +plus neighbours, and emitted the whole `hyf:downstreamFlowPathTC` closure. The +target entities appeared nowhere in it, so a reach was drawn whether or not it +ever reached a matched sample. Three costs: unreadable maps, payloads past the +25 MB cache limit, and ~64,000 React elements at 21,000 reaches. + +## What shipped + +**PR #41** — rebased and merged the stream-distance work that had been open as +#32 since 2026-08-28. Optional `maxDistanceKm` (5–100 km) on traces, plus +streams as an answerable entity type. On the PFOS question a 30 km bound cut +reaches by 77% and payload from 22.3 MB to 7.1 MB while keeping every facility. + +**PR #42** — fixed the cache-key collision that #41 exposed: a bounded and an +unbounded question hashed identically. See `docs/DEBUGGING.md`. + +## What was rejected, with the measurement + +Bounding by **terminus** — keeping only reaches that reach a matched sample — +was the original intent and does not work: + +| Query | Result | +| --- | --- | +| current (no terminus) | 16s, 4,661 reaches | +| terminus-bounded | **429 timeout at 70s** | + +A second `hyf:downstreamFlowPathTC` join over 408M triples exceeds what the +endpoint will do, even with all 1,172 target IRIs pinned. **Do not rebuild this +as specified.** The untested remainder is applying the constraint only on the +distance-bounded path, where `boundedTrace` has already shrunk the candidate set +— that would only help questions that set a distance. + +## Not done + +**The rendering safety net.** `StreamLayer.tsx` still maps 1:1 to +`` + `` + `` with no cap, no simplification and no +zoom awareness, and `parseWKTLineString` keeps every vertex. Independent of the +query, no correctness risk, and still worth doing — a distance bound reduces the +count but does not bound it. + +## Notes + +Facts established while measuring, kept in `docs/QUERY-MATRIX.md` Part 8: +`hyf:downstreamFlowPathTC` is reflexive; `A TC B` means B is downstream of A; +and the network has genuine two-way connectivity in braided channels, so a +single pair cannot be used to reason about trace direction. + +A suspicion that the upstream branch was inverted was investigated and **not +substantiated** — two attempts failed to produce a clean answer. It is recorded +here only so the next person does not re-raise it without a better method than +comparing population means or sampling one pair. From a119e16689ac578bf1e7630b9deadaae0621c262 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 15:08:52 -0400 Subject: [PATCH 27/66] fix: name the slice that failed, and give advice that applies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The partial-results banner said "1 too large to answer" and told the user to "add a filter or region to the second block". Both halves were unhelpful for the question that produced it — facilities within 30 km upstream of PFOS samples in York, Washington and Waldo counties. The user had to infer from an empty patch of map that York was the missing county, and the second block already had a substance and three counties on it, so there was nothing to add. chooseAxis was already carrying the county codes and throwing the identity away as "area 1", "area 2"; expandToCounties was already fetching ?countyName and discarding it. Both are kept now, so a slice is labelled "York County, Maine" from the dropdown's labels, the discovery query's names, or the FIPS code, in that order. halve inherits it — "York County, Maine (1/2)". The advice now picks the lever that applies to the question rather than asserting one cause. Measured on York alone: 30 km timed out (429 after 64s), 10 km returned 145 samples in 25s — so a bounded trace is told to shorten the distance, an unbounded one to set one, and only a block that genuinely has no filter and no region gets named. A filter is not offered first: it makes a query cheap by asking for less, and on this question it turned the timeout into an empty result. --- .../Pipeline/PartialResultsNotice.tsx | 22 +++++--- .../Pipeline/PipelineProgressStrip.tsx | 2 + src/engine/scope.ts | 29 ++++++++-- src/engine/sparqlErrors.ts | 53 ++++++++++++++++--- 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/components/Pipeline/PartialResultsNotice.tsx b/src/components/Pipeline/PartialResultsNotice.tsx index d25785b..0d8e41c 100644 --- a/src/components/Pipeline/PartialResultsNotice.tsx +++ b/src/components/Pipeline/PartialResultsNotice.tsx @@ -1,32 +1,34 @@ import { useState } from 'react'; import { useQueryStore } from '../../store/queryStore'; +import { adviceForOversizedQuestion } from '../../engine/sparqlErrors'; // Shown when some slices of a split query failed but the rest returned data. // Silently showing an incomplete map would be worse than saying so. export function PartialResultsNotice() { const pipelineResult = useQueryStore((s) => s.pipelineResult); + const question = useQueryStore((s) => s.question); const [dismissed, setDismissed] = useState(false); if (pipelineResult?.status !== 'success' || !pipelineResult.partial?.length) return null; if (dismissed) return null; - const failed = pipelineResult.partial.reduce((n, p) => n + p.failed.length, 0); - const skipped = pipelineResult.partial.reduce((n, p) => n + p.skipped.length, 0); + const failed = pipelineResult.partial.flatMap((p) => p.failed); + const skipped = pipelineResult.partial.flatMap((p) => p.skipped); // These two need different advice: a failed slice will fail again unless the // question is narrowed, while a skipped one simply ran out of budget and // usually completes on a second run against a warmer cache. const reasons = [ - failed > 0 ? `${failed} too large to answer` : null, - skipped > 0 ? `${skipped} not attempted before the time limit` : null, + failed.length > 0 ? `${nameList(failed)} could not be answered` : null, + skipped.length > 0 ? `${nameList(skipped)} not attempted before the time limit` : null, ].filter(Boolean); return (
Showing incomplete results — {reasons.join(', ')}.{' '} - {skipped > 0 && 'Running the question again picks up where this left off. '} - {failed > 0 && 'For the parts that were too large, add a filter or region to the second block.'} + {skipped.length > 0 && 'Running the question again picks up where this left off. '} + {failed.length > 0 && adviceForOversizedQuestion(question)}
); } + +// Slice labels are county names ("York County, Maine") or entity batches +// ("facilities batch 3"). Three is enough to be actionable; a list of twelve +// counties is a wall of text nobody reads. +function nameList(labels: string[]): string { + if (labels.length > 3) return `${labels.slice(0, 3).join(', ')} and ${labels.length - 3} more`; + return labels.join(', '); +} diff --git a/src/components/Pipeline/PipelineProgressStrip.tsx b/src/components/Pipeline/PipelineProgressStrip.tsx index bbfdef0..5c8710a 100644 --- a/src/components/Pipeline/PipelineProgressStrip.tsx +++ b/src/components/Pipeline/PipelineProgressStrip.tsx @@ -14,6 +14,7 @@ export function PipelineProgressStrip() { const isEditModalOpen = useQueryStore((s) => s.isEditModalOpen); const pipelineResult = useQueryStore((s) => s.pipelineResult); const stepProgress = useQueryStore((s) => s.stepProgress); + const question = useQueryStore((s) => s.question); const [msgIndex, setMsgIndex] = useState(0); useEffect(() => { @@ -50,6 +51,7 @@ export function PipelineProgressStrip() { // Nine distinct failures used to share one message; tell the user which. message = userMessageFor( pipelineResult?.status === 'error' ? pipelineResult.error : undefined, + question, ); } diff --git a/src/engine/scope.ts b/src/engine/scope.ts index 0b49418..8a4021a 100644 --- a/src/engine/scope.ts +++ b/src/engine/scope.ts @@ -116,8 +116,13 @@ export async function chooseAxis(ctx: AxisContext): Promise { const counties = await expandToCounties(codes); if (counties.length < 2) return null; - return chunk(counties, REGION_CHUNK).map((group, i) => ({ - label: `area ${i + 1}`, + // Name each slice after its county. When one of these fails the user sees + // "York County, Maine could not be answered" rather than "1 too large", + // which is the difference between a fact and a puzzle — the county is the + // one thing they can act on. + const names = countyNames(side === 'target' ? ctx.targetBlock : ctx.anchorBlock); + return chunk(counties, REGION_CHUNK).map((group) => ({ + label: group.map((code) => names.get(code) ?? code).join(', '), regionCodes: group, regionSide: side, })); @@ -145,6 +150,21 @@ export async function refineRegionScope( })); } +// Display names for county codes. The editor populates `countyLabels` when the +// user picks counties, and cacheKey strips it as display-only, so it is free to +// use for labelling. Falls back to the names `expandToCounties` collects, then +// to the code itself — a question built from a URL or the warm-cache script has +// no labels. +function countyNames(block: EntityBlock): Map { + const named = new Map(discoveredCountyNames); + const labels = block.region?.countyLabels; + if (labels) for (const [code, label] of Object.entries(labels)) named.set(code, label); + return named; +} + +// Filled in by expandToCounties, which already fetches the names. +const discoveredCountyNames = new Map(); + async function probeSide( block: EntityBlock, regionCodes: string[] | undefined, @@ -179,7 +199,10 @@ async function expandToCounties(regionCodes: string[]): Promise { }); for (const row of rows) { const fips = row.county?.match(/administrativeRegion\.USA\.(\d+)$/)?.[1]; - if (fips && fips.length > 2) out.push(fips); + if (fips && fips.length > 2) { + out.push(fips); + if (row.countyName) discoveredCountyNames.set(fips, row.countyName); + } } } return [...new Set(out)]; diff --git a/src/engine/sparqlErrors.ts b/src/engine/sparqlErrors.ts index 50ddd00..96b7646 100644 --- a/src/engine/sparqlErrors.ts +++ b/src/engine/sparqlErrors.ts @@ -1,3 +1,5 @@ +import type { AnalysisQuestion, EntityBlock } from '../types/query'; + // QLever reports several very different problems through a small set of HTTP // statuses, and the most important one is actively misleading: a query that // exceeds the engine's 30s limit comes back as 429 "Too Many Requests" with the @@ -62,16 +64,55 @@ export function isRetryable(kind: SparqlErrorKind): boolean { return kind === 'timeout' || kind === 'sibling-failure'; } -export function userMessageFor(error: unknown): string { +// What to actually change when a question is too big. The levers are ordered by +// measured effect, and only ones that apply to *this* question are offered — +// telling someone to filter a block that already has three counties and a +// substance on it is worse than saying nothing. +// +// Measured on "facilities within 30 km upstream of PFOS samples in York, +// Washington and Waldo counties": York alone timed out at 30 km (429 after 64s) +// and returned 145 samples in 25s at 10 km. Note that adding a filter can turn a +// timeout into an *empty* result rather than a smaller one — it makes the query +// cheaper by asking for less — so distance comes first when there is one. +export function adviceForOversizedQuestion(question?: AnalysisQuestion): string { + if (!question) return 'Try a shorter distance, a smaller region, or one county at a time.'; + + const { blockA, blockC, relationship } = question; + const isTrace = relationship.type === 'downstream' || relationship.type === 'upstream'; + + if (isTrace && relationship.maxDistanceKm) { + return `Try a shorter distance than ${relationship.maxDistanceKm} km, or run those areas one at a time.`; + } + if (isTrace) { + return 'Setting a maximum distance on the relationship is the most effective change — an unbounded trace follows the river network to the sea.'; + } + + const wide = !isNarrowed(blockC) ? 'second' : !isNarrowed(blockA) ? 'first' : null; + if (wide) { + return `The ${wide} block has no filter or region set, which means "every one in the country". Adding a type, filter, or region there is the most effective change.`; + } + return 'Try a smaller region, or run one county at a time.'; +} + +function isNarrowed(block: EntityBlock): boolean { + if (block.region?.stateCode || block.region?.countyCodes?.length) return true; + const filters = [ + block.sampleFilters, + block.facilityFilters, + block.waterBodyFilters, + block.wellFilters, + block.aquiferFilters, + block.streamFilters, + ]; + return filters.some((f) => f && Object.values(f).some((v) => (Array.isArray(v) ? v.length > 0 : v != null))); +} + +export function userMessageFor(error: unknown, question?: AnalysisQuestion): string { const kind = error instanceof SparqlError ? error.kind : 'unknown'; switch (kind) { case 'timeout': case 'out-of-memory': - // Point at the second block specifically. Measured: narrowing the first - // block to a single county does not help at all (still 500 OOM at 2.6GB) - // because the work is driven by the unconstrained second block — with no - // filter it means every facility in the graph, 1.5 million of them. - return 'This question covers too much data for the knowledge graph to answer at once. The usual cause is that the second block has no filter or region set, which means "every one in the country". Adding an industry, type, or region there is the most effective change; a shorter distance also helps.'; + return `This question covers too much data for the knowledge graph to answer at once. ${adviceForOversizedQuestion(question)}`; case 'payload-too-large': return 'This question produced too much data to send in one request. Try narrowing the area or adding a filter.'; case 'sibling-failure': From 81cbef2dfa090c2bb6061e7ff859aa5cf310ec05 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 15:10:56 -0400 Subject: [PATCH 28/66] docs: record which slice fails and what rescues it (Part 8.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 4 section 9 still described the error copy that PR #44 replaced — it said a timeout tells the user the second block is unfiltered, which for the York question was simply false. Corrected, and the per-county measurements behind the new advice recorded in Part 8, next to the question that produced them. Includes the 'empty is not a failure' trap: the landfill variant returns empty in 3s, and the first pass of this test scored it as broken. --- docs/QUERY-MATRIX.md | 51 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 0de203b..7043e88 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -334,9 +334,13 @@ client bug — but it means a very large response can fail *after* a successful "this question is too big" from "the server had a bad moment, press retry". **Now:** classified in `src/engine/sparqlErrors.ts` and shown per kind. A -timeout or out-of-memory says the second block is probably unfiltered (which -measurement showed is the real cause — see Part 6.3); a `sibling-failure` says -to just run it again; a network error says to check the connection. +`sibling-failure` says to just run it again; a network error says to check the +connection; a timeout or out-of-memory offers the lever that applies to the +question being asked (see Part 8.1) rather than one fixed sentence. + +A partial result — some slices answered, some not — names the slices that +failed, because a count alone leaves the user guessing which part of the map is +missing. --- @@ -600,6 +604,47 @@ question ran 99s complete in one hour and 361s *partial* (2 slices missing) in the next, with no code change between. Distance bounds reduce volume; they do not make a heavy trace dependable. +### 8.1 Which slice failed, and what actually rescues it + +The 361s partial run above is worth following, because it is the case the +error copy was getting wrong. Running each county on its own: + +| County | Result | +| --- | --- | +| York | ❌ 429 timeout at 72s | +| Washington | ✅ 7s — 16 samples | +| Waldo | ✅ 23s — 177 samples | + +York is the dense corner of the state, so it carries the most facilities and the +busiest river network. Not missing data: York holds 361 PFOS sample points. + +What rescues it, measured on York alone: + +| Change | Result | +| --- | --- | +| 30 km, no Block A filter | ❌ 429 timeout at 64s | +| **10 km** | ✅ **145 samples in 25s** | +| 30 km, Block A = landfills | ⬜ *empty* in 3s | + +Two things follow, and both are now encoded in `adviceForOversizedQuestion` +(`src/engine/sparqlErrors.ts`): + +- **A shorter distance is the lever that works here** — and it was the one the + old message never mentioned. It said to add a filter or region to the second + block, which on this question already had a substance and three counties. +- **A filter is not automatically good advice.** It makes a query cheap by + asking for less, and here it turned a timeout into an empty result: a missing + answer traded for no answer. + +The slice labels themselves used to read `area 1`, `area 2` — `chooseAxis` held +the county codes and discarded the identity. They now carry the county name, so +a partial result says *York County, Maine* rather than *1 too large*. + +**A trap to avoid when measuring this.** The landfill run above returns +`status: 'empty'`, which is a valid answer. The first pass of this test counted +it as a failure and reported all three variants as broken. Any script that +treats `status !== 'success'` as an error will draw the same wrong conclusion. + ### What was tried and rejected: trimming by connectivity The original goal was to keep only the reaches that actually connect a matched From dc39b23d34623c4a87d5a1a1b11797e8ad825593 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 15:23:40 -0400 Subject: [PATCH 29/66] docs: rewrite ARCHITECTURE.md against the code it describes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roughly half the document described an architecture that no longer exists. It is not an internal note — docs/wiki/_Sidebar.md links to it, so it is what someone arriving from the public wiki reads first. What was wrong: - The whole pipeline step vocabulary. GET_S2_FOR_ANCHOR, FILTER_S2_TO_REGION, EXPAND_S2_NEAR and FILTER_S2_POST_SPATIAL are not step types; the seven that exist are in planner.ts. The worked example built on them was fiction, as was the buildFacilityS2Query walk-through — facilities.ts is 14 lines now and exports one fragment helper. - The executor was shown as a for-loop threading context.s2Cells, a field that does not exist. It splits failed steps into scopes, halves what still fails, dedupes, and stops a step at 300s with a list of what it missed. - S2 cells no longer thread between steps. The federation endpoint does the join, so the chain is one fused query and entity IRIs are what carry between steps. - The endpoint roles were inverted: fiokg serves one dropdown, not facility details, and federation runs nearly every step rather than "step 1". - docs/DISCOVERY.md was cited three times, once as a whole heading. It has been SCHEMA.md for months. - Three entity types (wells, aquifers, streams), the within relationship, hops and maxDistanceKm were all missing. Added two sections for subsystems that had no coverage at all: bounded execution (why a QLever timeout arrives as a 429, and what the code does about it) and the result cache (what is cached, how the key is built, who may write). Kept verbatim: Knowledge Graphs 101, SPARQL Basics, Common SPARQL Patterns, Why S2 Cells, the endpoint inventories, and three of the five design decisions — those were still accurate. Verified: every path in the folder tree resolves, every step name the doc uses is in PipelineStepType, the worked example's SPARQL was executed as printed (14 rows, matching the figure quoted), Pattern 1 likewise, and every number traces to a code comment or QUERY-MATRIX.md. Also removes docs/query-matrix-current.csv, a one-row artefact of a killed query-matrix run that no script reads, and adds the four missing docs to the README table. --- README.md | 19 +- docs/ARCHITECTURE.md | 708 ++++++++++++++++++++++------------ docs/query-matrix-current.csv | 2 - 3 files changed, 473 insertions(+), 256 deletions(-) delete mode 100644 docs/query-matrix-current.csv diff --git a/README.md b/README.md index 3a196c9..a236343 100644 --- a/README.md +++ b/README.md @@ -101,11 +101,14 @@ All hosted at `apps.okn.us`: Inside `docs/`: -| File | Contents | -| ----------------- | --------------------------------------------------- | -| `ARCHITECTURE.md` | System design, module boundaries, data flow | -| `SCHEMA.md` | Predicate inventories, class counts, endpoint roles | -| `DEBUGGING.md` | Documented bugs with root causes and fixes | -| `CONVENTIONS.md` | Coding standards, endpoint selection rules | -| `changelog/` | Weekly changelogs (`YYYY-Www.md`) | -| `plans/` | Feature planning: `drafts/` → `active/` → `done/` | +| File | Contents | +| ------------------- | --------------------------------------------------------------- | +| `ARCHITECTURE.md` | System design, module boundaries, data flow | +| `SCHEMA.md` | Predicate inventories, class counts, endpoint roles | +| `QUERY-MATRIX.md` | Every query shape, measured — plus the error catalogue (Part 4) | +| `DEBUGGING.md` | Documented bugs with root causes and fixes | +| `CONVENTIONS.md` | Coding standards, endpoint selection rules | +| `wiki/` | One page per filter dropdown; source of truth for the GitHub Wiki | +| `queries/` | Write-ups of individual real questions | +| `changelog/` | Weekly changelogs (`YYYY-Www.md`) | +| `plans/` | Feature planning: `drafts/` → `active/` → `done/` | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 5ea4002..78d4bdf 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -11,9 +11,13 @@ A comprehensive guide to understanding how this application works, from knowledg 3. [Folder Structure](#folder-structure) 4. [Data Flow](#data-flow) 5. [The Query Pipeline](#the-query-pipeline) -6. [SPARQL Queries](#sparql-queries) -7. [Key Design Decisions](#key-design-decisions) -8. [The Endpoints](#the-endpoints) +6. [Bounded Execution](#bounded-execution) +7. [The Result Cache](#the-result-cache) +8. [SPARQL Queries](#sparql-queries) +9. [Key Design Decisions](#key-design-decisions) +10. [The Endpoints](#the-endpoints) +11. [Common Patterns](#common-patterns) +12. [Debugging Tips](#debugging-tips) --- @@ -62,6 +66,12 @@ This finds all facilities with industry code 3253 and returns their names. │ ▼ ┌─────────────────────────────────────────────────────────────┐ +│ Result Cache │ +│ A hit here skips everything below (server/ + Postgres) │ +└────────────────┬────────────────────────────────────────────┘ + │ miss + ▼ +┌─────────────────────────────────────────────────────────────┐ │ Query Pipeline │ │ (Planner → Executor → Result Transformer) │ └────────────────┬────────────────────────────────────────────┘ @@ -69,7 +79,7 @@ This finds all facilities with industry code 3253 and returns their names. ▼ ┌─────────────────────────────────────────────────────────────┐ │ SPARQL Query Templates │ -│ (Facilities, Samples, Water Bodies, Spatial, Hydrology) │ +│ (fusedQueries · hydrate · regions · wells · aquifers) │ └────────────────┬────────────────────────────────────────────┘ │ ▼ @@ -81,65 +91,77 @@ This finds all facilities with industry code 3253 and returns their names. ▼ ┌─────────────────────────────────────────────────────────────┐ │ Knowledge Graphs │ -│ (RDF Triples in GraphDB) │ +│ (RDF triples, served by QLever) │ └─────────────────────────────────────────────────────────────┘ ``` **The flow:** -1. User asks: "What samples are near facilities in Maine?" -2. Query pipeline breaks this into steps -3. Each step generates a SPARQL query -4. Query executes against the right endpoint -5. Results transform into map features -6. Map displays points/polygons +1. User builds a question from three blocks: "samples" + "near" + "landfills in Maine" +2. If that exact question is already cached, the answer comes back in one request +3. Otherwise the planner breaks it into steps +4. Each step generates a SPARQL query and runs against the right endpoint +5. A step that is too big for the engine is split and retried in slices +6. Results transform into map features +7. Map displays points, lines and polygons --- ## Folder Structure ``` -sawgraph-query-editor/ +explorer/ ├── src/ │ ├── components/ # React UI components │ │ ├── Dashboard/ # Pre-built query cards │ │ ├── QueryEditor/ # Block A / Relationship / Block C editors -│ │ ├── Map/ # Leaflet map + layers -│ │ ├── Pipeline/ # Pipeline progress visualization +│ │ ├── Map/ # Leaflet map + one layer component per entity type +│ │ ├── Pipeline/ # Progress strip, partial-results notice +│ │ ├── Publish/ # Share a question and its result by link +│ │ ├── DesignSystem/ # Design guide route +│ │ ├── common/ # FlatSelect, HierarchicalSelect, shared bits │ │ └── Layout/ # Header, sidebar, layout │ │ -│ ├── engine/ # THE CORE: Query pipeline logic -│ │ ├── planner.ts # Converts question → pipeline steps -│ │ ├── executor.ts # Executes steps sequentially -│ │ ├── sparqlClient.ts # Sends SPARQL to endpoints +│ ├── engine/ # THE CORE: query planning and execution +│ │ ├── planner.ts # Question → pipeline steps +│ │ ├── executor.ts # Runs steps, splits what the engine refuses +│ │ ├── scope.ts # How to slice a step that was too big +│ │ ├── sparqlClient.ts # Sends SPARQL, retries, 60s request timeout +│ │ ├── sparqlErrors.ts # Classifies failures (a 429 is usually a timeout) +│ │ ├── queryBreadth.ts # Pre-flight warning for questions that reliably fail +│ │ ├── cacheKey.ts # Canonical question → cache key +│ │ ├── wire.ts # What a cached result looks like on the wire │ │ ├── resultTransformer.ts # SPARQL rows → map features -│ │ └── templates/ # SPARQL query builders -│ │ ├── facilities.ts -│ │ ├── samples.ts -│ │ ├── waterBodies.ts -│ │ ├── spatial.ts # Region filters, near expansion -│ │ └── hydrology.ts # Upstream/downstream tracing +│ │ └── templates/ # SPARQL builders +│ │ ├── fusedQueries.ts # The main one: spatial + hydrological joins +│ │ ├── hydrate.ts # Fetch details for a known list of IRIs +│ │ ├── regions.ts # Dropdown discovery queries +│ │ ├── downstreamSamples.ts +│ │ ├── wells.ts · aquifers.ts +│ │ ├── facilities.ts · samples.ts # Shared fragments, not whole queries +│ │ └── spatial.ts # Region boundary geometry │ │ -│ ├── store/ -│ │ └── queryStore.ts # Zustand state (question + results) +│ ├── api/ # Talks to our own API (not to SPARQL) +│ │ ├── resultCacheClient.ts +│ │ └── publishClient.ts │ │ -│ ├── hooks/ -│ │ └── useDiscoveryQueries.ts # React Query for dropdown data -│ │ -│ ├── types/ -│ │ ├── query.ts # AnalysisQuestion, filters -│ │ └── sparql.ts # SPARQL response types -│ │ -│ └── constants/ -│ ├── endpoints.ts # SPARQL endpoint URLs -│ ├── prefixes.ts # SPARQL namespace prefixes -│ └── regions.ts # US states with data +│ ├── store/queryStore.ts # Zustand: the question, results, view state +│ ├── storage/ # localStorage: saved questions, publish tokens +│ ├── hooks/ # React Query + pipeline hooks +│ ├── types/ # AnalysisQuestion, MapFeature, SPARQL rows +│ └── constants/ # Endpoints, prefixes, regions, prebuilt queries +│ +├── server/ # Express + Postgres API (deployed separately) +│ └── src/ +│ ├── resultCache.ts # Gzipped results in Postgres, with TTLs +│ ├── routes/results.ts # Public read, token-gated write +│ └── routes/publish.ts # Published questions │ -└── docs/ - ├── ARCHITECTURE.md # This file - ├── DISCOVERY.md # Predicate inventories + debugging findings - ├── CONVENTIONS.md # Coding standards and patterns - ├── changelog/ # Weekly changelog files (YYYY-Www.md) - └── plans/ # Planning workflow (drafts → active → done) +├── scripts/ # Maintainer tools (tsx) +│ ├── warm-cache.mts # Run the dashboard questions, upload the results +│ ├── check-cache-key.mts # Assertions on cache-key canonicalisation +│ └── query-matrix.mts # Measure every query shape, write the CSV +│ +└── docs/ # See CLAUDE.md for the full map ``` **Key directories:** @@ -147,6 +169,7 @@ sawgraph-query-editor/ - **`components/`** — React UI. Organized by screen area. - **`store/`** — Zustand for global state (the current question and results). - **`hooks/`** — React Query for async data fetching (dropdown population). +- **`server/`** — The only part that is not a static bundle. Holds the cache. --- @@ -157,79 +180,123 @@ sawgraph-query-editor/ User selects in the UI: - **Block A** (target): "Samples" - **Relationship**: "near" -- **Block C** (anchor): "Facilities with NAICS 3253" -- **Region**: "Maine" +- **Block C** (anchor): "Landfills" (NAICS 562212) +- **Region**: "Penobscot County, Maine" -This creates an `AnalysisQuestion` object: +This creates an `AnalysisQuestion` object (`src/types/query.ts`): ```typescript { blockA: { type: 'samples', - sampleFilters: { substances: [...], materialTypes: [...] }, - region: { stateCode: '23', countyCodes: ['23019'] } + region: { + stateCode: '23', + countyCodes: ['23019'], + countyLabels: { '23019': 'Penobscot County, Maine' } // display only + } }, - relationship: { type: 'near' }, + relationship: { type: 'near', hops: 1 }, blockC: { type: 'facilities', - facilityFilters: { industryCodes: ['3253'] }, - region: { stateCode: '23' } + facilityFilters: { industryCodes: ['562212'] } } } ``` +Six entity types are available for either block: `samples`, `facilities`, +`waterBodies`, `wells`, `aquifers`, `streams`. Four relationships: `near` +(with `hops`), `within`, `downstream` and `upstream` (each with an optional +`maxDistanceKm`). + +The `*Labels` maps exist only to render chips in the editor. They never reach a +query, and `cacheKey.ts` strips them, so re-picking the same county with +different label text still hits the cache. + ### 2. Planner Creates Pipeline Steps -`planner.ts` converts the question into a sequence of steps: +`planner.ts` converts the question into a sequence of steps. For the question +above: ```typescript [ - Step 1: GET_S2_FOR_ANCHOR (Find S2 cells with NAICS 3253 facilities) - Step 2: FILTER_S2_TO_REGION (Keep only Maine S2 cells) - Step 3: EXPAND_S2_NEAR (Expand to neighboring S2 cells ~10km) - Step 4: FILTER_S2_POST_SPATIAL (Filter expanded cells to target region) - Step 5: FIND_TARGET_ENTITIES (Find samples in those S2 cells) - Step 6: GET_ANCHOR_DETAILS (Get facility details for map) - Step 7: GET_REGION_BOUNDARIES (Get Maine boundary polygon) + FIND_TARGET_IRIS // federation — which samples are near a landfill? + FIND_ANCHOR_IRIS // federation — which landfills have a sample nearby? + HYDRATE_TARGET_BY_IRI // federation — details for those samples + HYDRATE_ANCHOR_BY_IRI // federation — details for those landfills + GET_REGION_BOUNDARIES // spatialkg — the county outline to draw ] ``` +The full vocabulary is seven step types (`planner.ts` `PipelineStepType`). Two +more appear for hydrological questions: `GET_FLOWLINE_GEOMETRIES` draws the +river reaches, and `GET_SAMPLE_DETAILS` exists but is no longer emitted — +per-sample observations are fetched on demand when a popup opens +(`useSampleDetails.ts`), because fetching them up front cost 18–37 MB per run. + Each step specifies: - **Type** (what kind of operation) - **Endpoint** (which knowledge graph to query) - **Description** (shown to user during execution) -- **Query builder** (function that generates SPARQL) +- **Query builder** — `(context, scope?) => string` +- **`divide`** (optional) — how to slice this step if it is too big +- **`optional`** (optional) — if true, a failure here does not abort the run + +**Find first, then hydrate.** The discovery steps return bare IRIs and nothing +else; the hydrate steps take that list and fetch geometry, labels and +measurements for exactly those entities. Keeping them apart is what stopped an +ID-finding query from building every measurement in the state and throwing it +away — see `docs/QUERY-MATRIX.md` Part 5. -### 3. Executor Runs Steps Sequentially +### 3. Executor Runs the Steps -`executor.ts` runs each step in order: +`executor.ts` runs steps in order, but each step is more than one request. ```typescript -for (const step of steps) { - // 1. Build SPARQL query using context from previous steps - const query = step.buildQuery(context); +// Simplified from executor.ts runStep() +const queue: (Scope | undefined)[] = [undefined]; // undefined = the whole query + +while (queue.length) { + const scope = queue.shift(); + try { + rows = await executeSparql(step.endpoint, step.buildQuery(context, scope)); + merge(rows); // deduped by JSON.stringify(row) + } catch (err) { + if (isSplittable(err) && step.divide) { + queue.unshift(...await step.divide(scope)); // try it in smaller pieces + } else { + failed.push(scope?.label ?? 'whole query'); + } + } + if (Date.now() - stepStart > STEP_CEILING_MS) { // 300s per step + skipped.push(...remaining); + break; + } +} +``` - // 2. Execute against the endpoint - const results = await executeSparql(step.endpoint, query); +**Try whole, then split.** Every step is attempted in one request first. Only +the slices that actually fail get divided, so a question that fits pays nothing +for the machinery. - // 3. Update context for next step - if (step produces S2 cells) { - context.s2Cells = results.map(r => r.s2cell); - } +**The slice is chosen per question** (`scope.ts` `chooseAxis`). Which axis is +right flips between states: Maine has 4,528 samples and 2,976 facilities, +Illinois has 78 and 22,574 — so there is no fixed answer to "which side should +we chunk". `chooseAxis` probes both sides in parallel, uses whichever it can +enumerate, and falls back to splitting by county. A slice that still fails is +`halve`d until it cannot be divided further. - // 4. Store results - context.results[step.type] = results; +**A run can succeed with pieces missing.** `PartialFailure` distinguishes +*failed* slices (refused even at minimum size — the question needs changing) +from *skipped* ones (the 300s ceiling ran out — running it again may finish). +`PartialResultsNotice.tsx` names them: "York County, Maine could not be +answered". - // 5. Early exit if no S2 cells (empty result) - if (context.s2Cells.length === 0) break; -} -``` +**Early exit.** If `FIND_TARGET_IRIS` returns nothing, the run stops there — +there is no point hydrating an empty list. -**Key concept: Threading S2 cells through steps** -- Step 1 finds S2 cells `['kwgr:s2.level13.123', 'kwgr:s2.level13.456']` -- Step 2 filters them to `['kwgr:s2.level13.123']` -- Step 3 expands to `['kwgr:s2.level13.123', 'kwgr:s2.level13.789']` -- Step 5 uses those cells to find samples +**What threads between steps** is `context.targetIris` / `context.anchorIris`, +the entity IRIs found by the discovery steps. (It used to be S2 cells; see +Key Design Decision 2.) ### 4. Result Transformer → Map Features @@ -265,11 +332,17 @@ Handles Point, LineString, Polygon, MultiPolygon geometries. ### 5. Map Renders Layers -React components in `components/Map/` render features: -- `SampleLayer` — orange circles -- `FacilityLayer` — blue markers -- `WaterBodyLayer` — cyan polygons/lines -- `RegionLayer` — gray boundary polygons +React components in `components/Map/` render features, one per entity type: +- `SampleLayer` — sample points, coloured by concentration +- `FacilityLayer` — facility markers +- `WaterBodyLayer` — water body polygons and lines +- `WellLayer` — wells +- `StreamLayer` — river reaches from `GET_FLOWLINE_GEOMETRIES` +- `AquiferBoundaryLayer` — aquifer polygons +- `RegionBoundaryLayer` — county and state outlines + +`useMapLayers.ts` decides which to build by row shape: a `spWKT` column means +samples, `facWKT` facilities, `wbWKT` water bodies. --- @@ -277,78 +350,104 @@ React components in `components/Map/` render features: ### What is a Pipeline Step? -Each step is an object: +Each step is an object (`planner.ts`): ```typescript { - type: 'GET_S2_FOR_ANCHOR', + type: 'FIND_TARGET_IRIS', endpoint: 'federation', - description: 'Finding S2 cells containing matching facilities', - buildQuery: (context) => { - // Generate SPARQL using: - // - User's filters (NAICS codes) - // - Previous step results (S2 cells from context) - return `SELECT ?s2cell WHERE { ... }` - } + description: 'Finding nearby samples', + buildQuery: (context, scope) => buildFusedNearQuery({ ... }), + divide: (scope) => /* smaller scopes to try instead */, } ``` -### Example: "Samples near facilities" Pipeline +`scope` is what makes a step splittable: `undefined` means "the whole thing", +and anything else narrows it to a list of anchor IRIs, target IRIs, or counties. -Let's trace a full pipeline execution. +### Example: "Samples near landfills" Pipeline -#### User Question: -"What samples in Penobscot County, Maine are near facilities with NAICS 3253?" +The question: *what samples in Penobscot County, Maine are near a landfill +(NAICS 562212)?* -#### Step 1: GET_S2_FOR_ANCHOR (Find facility S2 cells) +#### Step 1: FIND_TARGET_IRIS **Endpoint:** `federation` -**SPARQL Generated:** +**SPARQL generated** (prefixes omitted): ```sparql -SELECT DISTINCT ?s2cell WHERE { - ?s2cell rdf:type kwg-ont:S2Cell_Level13 ; - kwg-ont:sfContains ?facility . - ?facility fio:ofIndustry naics:NAICS-3253 . -} GROUP BY ?s2cell +SELECT DISTINCT (?spC AS ?iri) WHERE { + ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + ?s2anchor kwg-ont:sfContains ?facilityA . + ?facilityA fio:ofIndustry ?industryCodeA . + ?industryCodeA a naics:NAICS-IndustryCode . + VALUES ?selectedIndustryA { naics:NAICS-562212 } + FILTER(?industryCodeA = ?selectedIndustryA + || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) + + ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . + ?s2target rdf:type kwg-ont:S2Cell_Level13 ; + spatial:connectedTo kwgr:administrativeRegion.USA.23019 . + ?spC rdf:type coso:SamplePoint ; + spatial:connectedTo ?s2target . +} ``` -**What this does:** -- Find all S2 Level 13 cells -- That contain facilities -- With NAICS industry code 3253 +**What this does** — all of it in one query: +- find the S2 cells holding a landfill (`?s2anchor`) +- step one cell outwards (`sfTouches`), which is the "near" in the question +- keep only neighbours inside Penobscot County +- return the sample points in them + +The `FILTER ... EXISTS ... fio:subcodeOf` is what makes picking a parent NAICS +code also match its children. + +**Result:** 14 sample point IRIs. + +#### Step 2: FIND_ANCHOR_IRIS + +The mirror image — the same join, returning `?facilityA` instead. This is not +redundant: it answers "which landfills actually had a sample nearby", so the map +draws only the facilities that took part. -**Result:** 1,534 S2 cells (nationwide with NAICS 3253 facilities) +**Result:** 5 facility IRIs. -#### Step 2: FILTER_S2_TO_REGION (Filter to Maine) +#### Steps 3–4: HYDRATE_*_BY_IRI -**Endpoint:** `spatialkg` +Now that the IDs are known, fetch what the map needs for exactly those, with +the IRIs pinned in a `VALUES` block (`hydrate.ts`): -**SPARQL Generated:** ```sparql -SELECT ?s2cell WHERE { - ?s2neighbor spatial:connectedTo kwgr:administrativeRegion.USA.23 . - VALUES ?s2neighbor { kwgr:s2.level13.123 kwgr:s2.level13.456 ... } - ?s2neighbor kwg-ont:sfTouches | owl:sameAs ?s2cell . -} +SELECT (COUNT(DISTINCT ?observation) AS ?resultCount) + (MAX(?numericResult) AS ?max) + (GROUP_CONCAT(DISTINCT ?substance; separator="; ") AS ?substances) + ?sp ?spWKT ?s2cell +WHERE { + VALUES ?sp { <...samplePoint1> <...samplePoint2> ... } + ?sp spatial:connectedTo ?s2cell ; + geo:hasGeometry/geo:asWKT ?spWKT . + ?observation coso:observedAtSamplePoint ?sp ; + coso:ofDSSToxSubstance ?substance ; + coso:hasResult ?result . + ... +} GROUP BY ?sp ?spWKT ?s2cell ``` -**What this does:** -- Take the 1,534 S2 cells from Step 1 -- Find which ones are connected to Maine (FIPS code 23) -- Return those cells + their touching neighbors +**Result:** 13 sample rows, 5 facility rows. (13, not 14 — one sample point has +no observation matching the filters.) + +#### Step 5: GET_REGION_BOUNDARIES -**Result:** 0 S2 cells (no NAICS 3253 facilities in Maine) +**Endpoint:** `spatialkg` — the county outline to draw under the points. -**Pipeline exits early** — no point continuing if no S2 cells remain. +**Result:** 16 geometry rows. Whole pipeline: **26.6 s**. -#### If there were results... the pipeline would continue: +#### When a step finds nothing -**Step 3:** Expand S2 cells to neighbors (~10km radius) -**Step 4:** Filter expanded cells to target region (Penobscot County) -**Step 5:** Find samples in those S2 cells -**Step 6:** Get facility details for map display -**Step 7:** Get county boundary polygon +Ask the same question with NAICS 3253 (paint manufacturing) instead and Step 1 +returns zero IRIs — there are none in Penobscot County. The run stops there in +**1.2 s** rather than hydrating an empty list, and the UI shows "no results" +rather than an error. An empty answer is a valid answer. ### Why S2 Cells? @@ -370,6 +469,80 @@ Level 30 = ~1 cm² --- +## Bounded Execution + +The graph is served by **QLever**, which gives a query 30 seconds and then kills +it. The most important thing to know about this: **it reports that timeout as +HTTP 429 "Too Many Requests"**, with the real cause only in the JSON body. It is +not rate limiting, and backing off does not help. + +`sparqlErrors.ts` classifies what comes back: + +| Kind | How it arrives | Splitting helps? | +| --- | --- | --- | +| `timeout` | 429 + "Operation timed out" / "Sort operation was canceled" | yes | +| `out-of-memory` | 500 + "Tried to allocate X, but only Y were available" | yes | +| `payload-too-large` | 413 / 502 — our request body was too big | yes | +| `sibling-failure` | 500 + "Waited for a result from another thread" | no — just retry | +| `network` | fetch rejected, or a 200 whose JSON was truncated | no | + +`isSplittable(kind)` is what the executor consults before dividing a step. + +Two guards sit around every request: a **60 s client-side timeout** +(`sparqlClient.ts`) so a hung request cannot stall a run, and one automatic +retry on retryable kinds — a repeat query starts warm, and 26.5 s cold vs 1.5 s +warm has been measured on the same query. + +`queryBreadth.ts` catches a few shapes before they are ever sent: statewide, +broad NAICS, no substance filter is a combination that reliably fails, and the +editor warns rather than spending 30 s proving it. + +**The measurements for all of this live in `docs/QUERY-MATRIX.md`** — Part 4 is +the error catalogue, Parts 6 and 7 the before/after. They are not repeated here +because they are re-measured as the graph changes. + +--- + +## The Result Cache + +A dashboard question takes seconds to compute and gives the same answer to +everyone who asks it. So the answer is stored and served directly: +**37 ms cached against 6,604 ms live** on a warm engine, with identical rows. + +**The key** (`cacheKey.ts`) is a SHA-256 of the canonicalised question. What +canonicalisation does matters more than the hash: +- display-only fields (`countyLabels` and friends) are stripped +- filter arrays are sorted — clicking three substances in a different order is + the same question +- empty objects and arrays collapse to "not set", so a filter set and then + cleared still hits +- everything else is kept verbatim. A field dropped from the key is a wrong + answer served; a field kept unnecessarily is only a cache miss. + +`WIRE_VERSION` and `DATA_VERSION` prefix the key so a change to the stored shape, +or a knowledge-graph reload, makes every existing entry unreachable at once. + +**What is stored** (`wire.ts`): successes only. An error is nearly always +transient endpoint load, and freezing one would turn a bad minute into a bad +month; an empty result is cheap to recompute. Only the four keys the map +actually renders are kept — the intermediate IRI lists ran to 22.6 MB on a +statewide well question and are never drawn. + +**Who can write.** Reads are public; writes are not. The publisher writes the +result it has just computed, authenticated by the `editToken` the server issued +for that publication. The maintainer script `scripts/warm-cache.mts` writes with +`CACHE_WRITE_TOKEN`. Nothing else can put an entry in front of someone else's +map. + +**Storage** (`server/src/resultCache.ts`): gzipped into a Postgres `BYTEA` +column and served with `Content-Encoding: gzip` — never decompressed on the +server. Capped at 25 MB. Complete results live 30 days; partial ones 6 hours, +because a partial result is a snapshot of a bad moment. + +Add `?cache=off` to any URL to force a live run. + +--- + ## SPARQL Queries ### SPARQL Basics @@ -402,48 +575,39 @@ The `?` variables get bound to actual values from the graph. ### How Our Templates Work -Each template function builds a SPARQL string. Example from `facilities.ts`: +Templates are functions that return a SPARQL string. The main one is +`fusedQueries.ts`, and its central idea is a helper that binds one entity inside +an S2 cell: ```typescript -export function buildFacilityS2Query(filters?: FacilityFilters): string { - const industryValuesClause = buildIndustryValues(filters?.industryCodes); - - return ` - ${PREFIXES} - SELECT DISTINCT ?s2cell WHERE { - ?s2cell rdf:type kwg-ont:S2Cell_Level13 ; - kwg-ont:sfContains ?facility . - ?facility fio:ofIndustry ?industryGroup ; - fio:ofIndustry ?industryCode . - ?industryCode a naics:NAICS-IndustryCode . - ${industryValuesClause} - } GROUP BY ?s2cell - `; +// fusedQueries.ts — simplified +function bindEntityInCell(block: EntityBlock, cellVar: string, suffix: string) { + switch (block.type) { + case 'facilities': + return `?${cellVar} kwg-ont:sfContains ?facility${suffix} . + ${industryFilter(block.facilityFilters)}`; + case 'samples': + return `?sp${suffix} rdf:type coso:SamplePoint ; + spatial:connectedTo ?${cellVar} . + ${sampleFilters(block.sampleFilters)}`; + // wells, aquifers, streams, water bodies... + } } ``` -**If user selects NAICS code "3253":** - -`industryValuesClause` becomes: -```sparql -VALUES ?industryCode { naics:NAICS-3253 } -``` +Both blocks of a question go through it, once for the anchor cell and once for +the target cell, and the relationship supplies the path between the two cells. +That is the whole trick: "near" is `sfTouches`, and a trace is a flow-path join. -**Final query:** -```sparql -PREFIX fio: -PREFIX naics: -PREFIX kwg-ont: +**One guard is worth knowing about.** `bindEntityInCell` takes a +`sampleObservations` flag. An ID-finding query needs the sample *points*; a +detail query needs every observation on them. Serving both callers from one +branch is what made a query to find sample IDs build every measurement in the +state and discard it — the bug behind most of `QUERY-MATRIX.md` Part 5. -SELECT DISTINCT ?s2cell WHERE { - ?s2cell rdf:type kwg-ont:S2Cell_Level13 ; - kwg-ont:sfContains ?facility . - ?facility fio:ofIndustry ?industryGroup ; - fio:ofIndustry ?industryCode . - ?industryCode a naics:NAICS-IndustryCode . - VALUES ?industryCode { naics:NAICS-3253 } -} GROUP BY ?s2cell -``` +The older `facilities.ts` and `samples.ts` are no longer whole-query builders. +They survive as fragment helpers — `buildIndustryValues()`, +`buildSampleFilterClauses()` — called from inside the fused builders. ### Common SPARQL Patterns @@ -502,31 +666,41 @@ Extracts "23" from "kwgr:administrativeRegion.USA.23". - Easy to test — mock step results - Easy to change strategy — edit planner, executor stays the same -### 2. Why Thread S2 Cells Between Steps? +### 2. Why Fuse the Join Into One Query -**Problem:** Can't do cross-endpoint joins in SPARQL (federation endpoint has limitations). +**The original design** threaded S2 cells between steps: find the cells holding +facilities on one endpoint, filter them to a region on another, expand to +neighbours, then look for samples in what was left. S2 cells were the join key +because a cross-endpoint join seemed impossible. -**Solution:** Use S2 cells as a "join key" passed through pipeline steps: -1. Find facility S2 cells in `federation` -2. Filter them in `spatialkg` (has admin region data) -3. Find samples in those cells in `sawgraph` +**What replaced it:** the `federation` endpoint does the join itself, so the +whole chain is one query (`fusedQueries.ts`). S2 cells are still the join +*mechanism* — `?s2anchor`, `?s2target` and the `sfTouches` between them — but +they are variables inside a single query rather than lists carried between +requests. -**Benefits:** -- Works around federation limitations -- Fast (S2 cells are pre-indexed) -- Flexible (any entity can link via S2 cells) +**Why it is better:** +- No intermediate list to transfer. A statewide cell list ran to megabytes. +- The engine can plan the whole join, instead of being handed a `VALUES` block + of cells and no context. +- Fewer requests, so fewer chances to hit the 30 s limit. + +**What it costs:** a fused query is one indivisible unit of work, so when it is +too big there is no natural seam. That is exactly what `scope.ts` exists to +supply — see [Bounded Execution](#bounded-execution). ### 3. Why Zustand + React Query? **Zustand** (`queryStore.ts`) — Global state for: -- Current question (Block A/B/C) -- Pipeline results -- UI state (view mode, progress) +- The current question, plus a baseline and a snapshot for the edit modal +- Pipeline results, step progress, and where the result came from + (`resultProvenance` — live or cache, and when it was computed) +- UI state (view mode, modals, tour) **React Query** (`useDiscoveryQueries.ts`) — Async data fetching for: -- Dropdown options (NAICS codes, substances, etc.) -- Cached with `staleTime: Infinity` (doesn't change) -- Hardcoded fallbacks if endpoints fail +- Dropdown options (NAICS codes, substances, material types, counties) +- Long `staleTime` per hook, since this vocabulary changes on graph reloads +- Hardcoded fallbacks if endpoints fail, so the editor still works **Benefits:** - Separation of concerns (query state vs dropdown data) @@ -568,7 +742,9 @@ Extracts "23" from "kwgr:administrativeRegion.USA.23". ## The Endpoints -All endpoints are SPARQL query interfaces to different parts of the knowledge graph. +All endpoints are SPARQL query interfaces to different parts of the knowledge +graph, served by QLever. The counts below come from `docs/SCHEMA.md`, which is +where they get re-verified after a graph reload. ### fiokg **Contains:** Facility data @@ -580,7 +756,8 @@ All endpoints are SPARQL query interfaces to different parts of the knowledge gr - `geo:hasGeometry/geo:asWKT` → Point location - `kwg-ont:sfWithin` → S2 cells, admin regions -**Used for:** Facility details (Step 6 in pipelines) +**Used for:** the NAICS industry dropdown only (`useDiscoveryQueries.ts`). +Facility queries in the pipeline run on `federation` — see below. ### sawgraph **Contains:** PFAS sample and observation data @@ -592,7 +769,8 @@ All endpoints are SPARQL query interfaces to different parts of the knowledge gr - `coso:measurementValue` → Concentration (ng/L) - `spatial:connectedTo` → S2 cells (via SamplePoint) -**Used for:** Sample retrieval, concentration data +**Used for:** the substance and material-type dropdowns. Sample data reaches +the pipeline through `federation`. ### spatialkg **Contains:** S2 cells, admin regions, spatial index @@ -604,7 +782,8 @@ All endpoints are SPARQL query interfaces to different parts of the knowledge gr - `kwg-ont:sfTouches` → Neighboring cells - `kwg-ont:hasFIPS` → FIPS codes -**Used for:** Region filtering, near expansion, boundaries +**Used for:** the county dropdown and `GET_REGION_BOUNDARIES`. Region filtering +and neighbour expansion now happen inside the fused query on `federation`. ### hydrologykg **Contains:** Water bodies, flow paths, wells @@ -616,14 +795,17 @@ All endpoints are SPARQL query interfaces to different parts of the knowledge gr - `nhdplusv2:hasCOMID` → NHDPlus identifiers - `schema:name` → Water body names -**Used for:** Water body queries, upstream/downstream tracing +**Used for:** the hydrology data that the fused trace queries join against. ### federation **Contains:** Nothing directly — it queries across all graphs **How it works:** SPARQL federation joins data from multiple endpoints in a single query **Caveat:** Performs owl:sameAs reasoning, inflating facility counts (1.3M real → 4.9M with aliases) -**Used for:** Facility S2 lookup (Step 1), cross-graph queries +**Used for:** almost everything. Every discovery step and every hydrate step +runs here (`planner.ts`), because a fused query needs facilities, samples, +spatial and hydrology data in one place. Only `GET_REGION_BOUNDARIES` goes +elsewhere. Treat this as the primary endpoint, not a special case. --- @@ -631,107 +813,141 @@ All endpoints are SPARQL query interfaces to different parts of the knowledge gr ### Pattern 1: Find entities in a region -```typescript -// Step 1: Find S2 cells with entity -SELECT ?s2cell WHERE { - ?s2cell kwg-ont:sfContains ?entity . - ?entity rdf:type SomeClass . -} - -// Step 2: Filter to region -SELECT ?s2cell WHERE { - VALUES ?s2cell { /* cells from step 1 */ } - ?s2cell spatial:connectedTo kwgr:administrativeRegion.USA.23 . -} - -// Step 3: Get entity details -SELECT ?entity ?wkt ?name WHERE { - VALUES ?s2cell { /* cells from step 2 */ } - ?s2cell kwg-ont:sfContains ?entity . - ?entity geo:hasGeometry/geo:asWKT ?wkt ; - rdfs:label ?name . -} +```sparql +?s2cell rdf:type kwg-ont:S2Cell_Level13 ; + spatial:connectedTo kwgr:administrativeRegion.USA.23019 . # the county +?sp rdf:type coso:SamplePoint ; + spatial:connectedTo ?s2cell . ``` +The region is a starting point, not a post-filter: the cells are selected by +county first, so the engine never looks outside it. + ### Pattern 2: Spatial relationship (near) -```typescript -// Find S2 cells with anchor entity -// Filter to region -// Expand to neighboring cells (via kwg-ont:sfTouches) -// Filter neighbors to target region -// Find target entities in expanded cells +```sparql +# anchor side +?s2anchor kwg-ont:sfContains ?facilityA . +?facilityA fio:ofIndustry naics:NAICS-562212 . + +# the "near" — one hop of neighbouring cells +?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . + +# target side +?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ``` +`hops` repeats the middle line. At four or more hops `neighborPath()` drops the +`owl:sameAs` alternation, because the path expands as 2^N and runs the engine +out of memory. + ### Pattern 3: Hydrological relationship (downstream) -```typescript -// Find S2 cells with anchor (facilities) -// Find flow paths in those cells -// Follow hyf:downstreamFlowPathTC (transitive closure) -// Find S2 cells connected to downstream flow paths -// Find target entities (samples) in those cells +```sparql +# anchor cells → the flow paths passing through them +?s2anchor kwg-ont:sfContains ?facilityA . +?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . +?s2neighbor spatial:connectedTo ?upstream_flowline . +?upstream_flowline rdf:type hyf:HY_FlowPath . + +# follow the network downstream +?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . + +# back to cells, and to what is in them +?s2target spatial:connectedTo ?ds_flowline . +?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ``` +`hyf:downstreamFlowPathTC` is the pre-computed transitive closure, 408M triples. +`A TC B` means **B is downstream of A**, and it is reflexive — ` TC ` +returns a row, so a `?` quantifier after it is redundant. + +Unbounded, this follows the river to the sea. `maxDistanceKm` wraps it in a +subquery that sums `nhdplusv2:hasFlowPathLength` along the path and drops +anything past the budget, then extends one segment further so the drawn line +does not stop mid-channel. On one Maine question, a 30 km bound cut 15,782 +reaches to 3,705 while keeping all 616 facilities. + --- ## Debugging Tips -### 1. Check docs/DISCOVERY.md +### 1. Read the docs first -- Predicate inventories (what predicates exist on each entity type) -- Known bugs, data coverage gaps, debugging findings (merged from FINDINGS.md) +- **`docs/SCHEMA.md`** — does this predicate exist, and on what? Predicate + inventories with triple counts, per endpoint. +- **`docs/QUERY-MATRIX.md`** — Part 4 tells you what an HTTP status actually + means. A 429 is almost never rate limiting. +- **`docs/DEBUGGING.md`** — bugs already diagnosed, with their root causes. -### 2. Inspect Pipeline Steps +### 2. Bypass the cache -In browser DevTools, set breakpoint in `executor.ts` and log each step's query: +A result that looks stale may be cached. Add `?cache=off` to the URL to force a +live run. + +### 3. Inspect pipeline steps + +Set a breakpoint in `executor.ts` and log the query as built: ```typescript -console.log(step.description); -console.log(query); -console.log(results); +console.log(step.type, step.description); +console.log(step.buildQuery(context, scope)); // note: scope is the 2nd arg +console.log(rows.length); ``` -### 3. Test SPARQL Queries Directly +### 4. Test a query directly + +Copy it from the console and run it against the endpoint the step used — they +are listed in `src/constants/endpoints.ts`. Most discovery steps run on +`federation`: -Copy a query from the console, run it at: ``` -https://apps.okn.us/fiokg/sparql +https://apps.okn.us/federation/sparql ``` -### 4. Check S2 Cell Counts +### 5. If a step returns nothing -If a step returns 0 results, check if S2 cells are empty: +Check the IRI lists, not S2 cells: ```typescript -console.log('S2 cells after step:', context.s2Cells.length); +console.log('target IRIs:', context.targetIris.length); +console.log('anchor IRIs:', context.anchorIris.length); ``` -### 5. Validate Predicates +An empty `FIND_TARGET_IRIS` ends the run and shows "no results". That is often +the correct answer — confirm the data exists before treating it as a bug. -Use DISCOVERY.md to check if a predicate exists. Example: -- Using `kwg-ont:sfContains` for water bodies? ❌ Zero triples -- Should use `spatial:connectedTo` ✅ 274K triples +### 6. Run the whole matrix + +`npm run query-matrix` re-measures every query shape and writes +`docs/query-matrix.csv`. Slow, but it is how a regression gets proven rather +than suspected. --- ## Summary **The app in one sentence:** -A React SPA that converts natural language questions into multi-step SPARQL query pipelines, executes them against distributed knowledge graph endpoints, and visualizes geospatial results on a map. +A React SPA that lets you build a spatial question from three blocks, compiles +it into SPARQL, runs it against distributed knowledge graph endpoints — slicing +the work when it is too big for them — and draws the answer on a map. **Key concepts:** - **Knowledge graphs** — Triples connecting entities - **SPARQL** — Query language for graphs -- **S2 cells** — Spatial index for fast geo queries -- **Pipeline** — Multi-step query execution -- **Federation** — Cross-graph querying +- **S2 cells** — Spatial index, and the join key between entity types +- **Pipeline** — Planner builds steps, executor runs and splits them +- **Federation** — One query across several graphs **Architecture highlights:** -- Planner creates steps, Executor runs them -- S2 cells thread between steps as "join keys" -- Templates generate SPARQL with user filters +- Planner creates steps, executor runs them and slices what the engine refuses +- Find IRIs first, hydrate them second — never build detail you will discard +- Spatial and hydrological joins are fused into one federated query +- Successful results are cached and served in ~37 ms instead of seconds +- A run can succeed with pieces missing, and says which pieces - Result transformer parses WKT → GeoJSON - Zustand for question state, React Query for dropdown data +**Six entity types:** samples, facilities, water bodies, wells, aquifers, streams + **13 states have data:** AL, AZ, AR, IL, IN, KS, ME, MA, MN, NH, OH, SC, VT diff --git a/docs/query-matrix-current.csv b/docs/query-matrix-current.csv deleted file mode 100644 index 518c1ae..0000000 --- a/docs/query-matrix-current.csv +++ /dev/null @@ -1,2 +0,0 @@ -runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksFailed,chunksSkipped,chunksMax -2026-09-14T11:47,37d9a4f,M1,"samples near(1) samples [ME]",samples,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,30262,4398,0,ok,"",0,0,0 From 9ecbbe025848d9cc7a2fd66ee7e794182f36e48f Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 16:56:57 -0400 Subject: [PATCH 30/66] docs: archive the two finished execution plans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both shipped: Phases 1-2 in PR #38, the result cache in #40 and #42. Moved to done/ with completion dates and the links to the moved file repointed. Two things they carried that are NOT done are now recorded as such rather than implied by the folder they sat in: the okn.us email about the 30s limit (drafted, never sent), and server-side execution, which was dropped on purpose — the publisher's browser has already computed the result, so handing that over beat re-running the pipeline on the server, and it removed single-flight entirely. --- docs/QUERY-MATRIX.md | 2 +- docs/changelog/2026-W38.md | 2 +- ...2026-09-13-query-execution-architecture.md | 28 +++++++++++++++---- .../2026-09-14-phase-3-result-cache.md | 6 ++-- .../plans/drafts/2026-09-13-team-email-429.md | 2 +- docs/plans/drafts/2026-09-14-team-email.md | 2 +- src/engine/scope.ts | 2 +- 7 files changed, 30 insertions(+), 14 deletions(-) rename docs/plans/{active => done}/2026-09-13-query-execution-architecture.md (94%) rename docs/plans/{active => done}/2026-09-14-phase-3-result-cache.md (99%) diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 7043e88..3f6836b 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -376,7 +376,7 @@ cache of our own. ## Part 6 — After Phases 1 and 2 (measured 2026-09-14) Phases 1 and 2 of -[the execution plan](./plans/active/2026-09-13-query-execution-architecture.md) +[the execution plan](./plans/done/2026-09-13-query-execution-architecture.md) are implemented: the pipeline no longer fetches popup detail up front, and any query the engine refuses is split into slices that fit and merged back together. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index fa093f5..2a29b3c 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -30,7 +30,7 @@ The sweep is what caught three defects in the first implementation: a missing client-side timeout (single requests hung for 959s and 1,918s), a budget rule that killed runs which were succeeding, and partial-result reporting that blamed size for work that had merely run out of budget. - *Files:* `docs/QUERY-MATRIX.md` (new), `docs/query-matrix.csv` (new), `docs/query-matrix-after.csv` (new), `scripts/query-matrix.mts` (new), `docs/DEBUGGING.md`, `docs/plans/active/2026-09-13-query-execution-architecture.md` (new) + *Files:* `docs/QUERY-MATRIX.md` (new), `docs/query-matrix.csv` (new), `docs/query-matrix-after.csv` (new), `scripts/query-matrix.mts` (new), `docs/DEBUGGING.md`, `docs/plans/done/2026-09-13-query-execution-architecture.md` (new) 5. **Cached Results — Shared Links Stop Re-Running the Pipeline** (2026-09-14) Opening a published link re-ran the entire SPARQL pipeline in the visitor's browser — 26–218 seconds, sometimes failing outright — to rebuild an answer that does not change. That is the flow behind the original "Something went wrong" report. diff --git a/docs/plans/active/2026-09-13-query-execution-architecture.md b/docs/plans/done/2026-09-13-query-execution-architecture.md similarity index 94% rename from docs/plans/active/2026-09-13-query-execution-architecture.md rename to docs/plans/done/2026-09-13-query-execution-architecture.md index c35b908..39e78c7 100644 --- a/docs/plans/active/2026-09-13-query-execution-architecture.md +++ b/docs/plans/done/2026-09-13-query-execution-architecture.md @@ -1,6 +1,9 @@ # Query Execution Architecture -**Status**: active — Phases 1 and 2 implemented and verified (2026-09-14); Phase 3 shipped as a result cache, see 2026-09-14-phase-3-result-cache.md +**Status**: done +**Completed**: 2026-09-14 — Phases 1 and 2 implemented and verified; Phase 3 +shipped as a result cache instead of server-side execution, see +[`2026-09-14-phase-3-result-cache.md`](./2026-09-14-phase-3-result-cache.md) **Created**: 2026-09-13 **Reference sheet**: [`docs/QUERY-MATRIX.md`](../../QUERY-MATRIX.md) — every question the UI can build, measured against the live endpoints. This plan is verified against @@ -363,7 +366,8 @@ Re-run the matrix harness after each phase and diff against - [x] Per-sample popup fetch (`hooks/useSampleDetails.ts`); `GET_SAMPLE_DETAILS` deleted from the pipeline - [x] Error cases distinguished (`engine/sparqlErrors.ts` → `PipelineProgressStrip`) - [ ] Email okn.us: access token to raise the 30s limit; materialized downstream relation - (draft ready at `docs/plans/drafts/2026-09-13-team-email-429.md`, not sent) + (draft ready at `docs/plans/drafts/2026-09-13-team-email-429.md`, not sent — + see "Carried forward" below) **Phase 2 — done 2026-09-13** - [x] `LIMIT 201` side-probe + axis selection (`engine/scope.ts`) @@ -373,10 +377,22 @@ Re-run the matrix harness after each phase and diff against - [x] `MAX_INLINE_SAMPLE_IRIS` and the inline-vs-re-derive fork deleted, along with `buildFusedSampleAggregateQuery` / `buildFusedSampleDetailsQuery` -**Phase 3 — server execution and cache** -- [ ] `POST /api/query` + `query_cache` table (question hash + data version) -- [ ] Single-flight; client switches to the API with a debug flag for direct SPARQL -- [ ] Precompute on publish; nightly prewarm of the 8 dashboard questions +**Phase 3 — shipped as a result cache, not server-side execution** + +Moving execution to the server was dropped deliberately. The publisher's browser +has *already computed* the result, so handing that over is far cheaper than +re-running the pipeline server-side, and it removes the single-flight and +queueing problems entirely. Measured 37ms cached vs 6,604ms live. + +- [x] Publish-time result caching + maintainer prewarm — see the Phase 3 plan +- [x] Precompute on publish; prewarm of the 8 dashboard questions + (`scripts/warm-cache.mts`, run from the Actions tab) +- [ ] ~~`POST /api/query` + single-flight~~ — not needed; revisit only if a + question appears that no browser can finish + +**Carried forward, not done** +- [ ] Email okn.us: access token to raise the 30s limit; materialized downstream + relation (draft at `docs/plans/drafts/2026-09-13-team-email-429.md`) ### Results after implementing Phases 1 and 2 (measured 2026-09-14) diff --git a/docs/plans/active/2026-09-14-phase-3-result-cache.md b/docs/plans/done/2026-09-14-phase-3-result-cache.md similarity index 99% rename from docs/plans/active/2026-09-14-phase-3-result-cache.md rename to docs/plans/done/2026-09-14-phase-3-result-cache.md index 22562c8..a29f2f4 100644 --- a/docs/plans/active/2026-09-14-phase-3-result-cache.md +++ b/docs/plans/done/2026-09-14-phase-3-result-cache.md @@ -1,11 +1,11 @@ # Phase 3 — Cache what's already computed -**Status**: active +**Status**: done **Created**: 2026-09-14 -**Completed**: +**Completed**: 2026-09-14 (PRs #40, #42) Phase 3 of [the query execution -plan](../active/2026-09-13-query-execution-architecture.md). Phases 1 and 2 +plan](./2026-09-13-query-execution-architecture.md). Phases 1 and 2 (PR #38) bounded how much work one query does; this one stops us doing the same work twice. diff --git a/docs/plans/drafts/2026-09-13-team-email-429.md b/docs/plans/drafts/2026-09-13-team-email-429.md index 5c23f78..2db0377 100644 --- a/docs/plans/drafts/2026-09-13-team-email-429.md +++ b/docs/plans/drafts/2026-09-13-team-email-429.md @@ -103,7 +103,7 @@ the unconstrained second block. Adding an industry or a region there fixes it. The full picture is in `docs/QUERY-MATRIX.md`, and the plan for the remaining work — running the pipeline on our own API server with a shared result cache, so the first person to ask a question pays the cost and nobody else does — is in -`docs/plans/active/2026-09-13-query-execution-architecture.md`. +`docs/plans/done/2026-09-13-query-execution-architecture.md`. --- diff --git a/docs/plans/drafts/2026-09-14-team-email.md b/docs/plans/drafts/2026-09-14-team-email.md index a942f2e..02946eb 100644 --- a/docs/plans/drafts/2026-09-14-team-email.md +++ b/docs/plans/drafts/2026-09-14-team-email.md @@ -1,7 +1,7 @@ # Draft email to the team — the Explorer is working again *Draft for review, not sent. Plain-language version; the detailed write-up is in -`docs/QUERY-MATRIX.md` and the plans under `docs/plans/active/`.* +`docs/QUERY-MATRIX.md` and the plans under `docs/plans/`.* --- diff --git a/src/engine/scope.ts b/src/engine/scope.ts index 8a4021a..7c9b259 100644 --- a/src/engine/scope.ts +++ b/src/engine/scope.ts @@ -6,7 +6,7 @@ import { buildDiscoverCountiesQuery } from './templates/regions'; // A Scope is a slice of one pipeline step's work. `undefined` scope means "the // whole thing" — the executor always tries that first and only slices when the -// engine refuses (docs/plans/active/2026-09-13-query-execution-architecture.md). +// engine refuses (docs/plans/done/2026-09-13-query-execution-architecture.md). // // Exactly one of the three slicing fields is set on any given scope; which one // is decided per question by `chooseAxis`, because the right axis flips between From b4c73be9e1fadd275550bd5e8f7ec3183f56d934 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 17:55:25 -0400 Subject: [PATCH 31/66] feat: weekly dashboard health check with a status page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Answers "when did this break?" with a date instead of a guess. Runs the eight dashboard questions through the real pipeline every Monday for both main and development, and records status, duration, and row counts per rendered layer. Storage is docs/health/history.jsonl, committed by the workflow: one JSON line per question per run. Git is the time series — no table, no auth, no new infrastructure — and `git log -p` dates a regression exactly. STATUS.md is regenerated from it and renders on GitHub as the status page. Row-count drift is shown, not alarmed. The knowledge graph reloads and numbers move for real reasons; the point is that when something looks wrong there is a date to point at. A status regression — worked last week, errors now — fails the workflow and opens an issue, because a red X in a weekly job is easy to miss for another week. Every failure is retried once. The first run of this script reported three questions as broken in 3-13s each; all three succeeded immediately afterwards at 22-52s. The endpoint is shared and gets busy, and a check that opens an issue on one bad request would be ignored within a month. A retry that was needed is recorded (`attempts`), so a question degrading while still passing is visible. Never reads or writes the result cache: a cached answer would report on the cache rather than on the graph. No secrets, so it can run from any fork. Seeded with one development run (8 of 8 working, 259s). No main row yet — this branch's code is not main's, and labelling it so would be a lie. The first workflow run records main's. Note the schedule only fires once this is on the default branch. --- .github/workflows/health-check.yml | 130 ++++++++++++++ README.md | 1 + docs/health/STATUS.md | 33 ++++ docs/health/history.jsonl | 8 + package.json | 3 +- scripts/health-check.mts | 266 +++++++++++++++++++++++++++++ 6 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/health-check.yml create mode 100644 docs/health/STATUS.md create mode 100644 docs/health/history.jsonl create mode 100644 scripts/health-check.mts diff --git a/.github/workflows/health-check.yml b/.github/workflows/health-check.yml new file mode 100644 index 0000000..2c1fbf3 --- /dev/null +++ b/.github/workflows/health-check.yml @@ -0,0 +1,130 @@ +name: Dashboard health + +# Runs the eight dashboard questions against the live endpoints once a week and +# writes down what happened: worked or not, how long, how many rows. The point +# is dating a regression. Without this, "the Indiana question broke sometime in +# the last month" is the best anyone can say. +# +# Both branches are measured because they hit the same SPARQL endpoints — so a +# difference between main and development is a difference in *our* code. +# +# No secrets. This never reads or writes the result cache: a cached answer would +# report on the cache rather than on the graph. +# +# The schedule only fires once this file is on the default branch (main) — +# GitHub ignores cron in workflows that live only on a feature branch. + +on: + schedule: + - cron: '0 6 * * 1' # Mondays, 06:00 UTC + workflow_dispatch: + +# These queries are heavy on a shared endpoint. Never two runs at once. +concurrency: + group: health-check + cancel-in-progress: false + +permissions: + contents: write # commit the history file and status page + issues: write # open an issue when a question regresses + +jobs: + measure: + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - name: Check out development (the branch results are committed to) + uses: actions/checkout@v4 + with: + ref: development + + - name: Check out main alongside it + uses: actions/checkout@v4 + with: + ref: main + path: main-ref + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + + # react-leaflet's peer range does not include React 19 (see CLAUDE.md) + - run: npm ci --legacy-peer-deps + + - name: Measure development + id: dev + # bash, not the default sh-with-e: without pipefail the exit code would + # be tee's, and a regression would sail through as a pass. + shell: bash + run: npm run health-check -- development | tee dev.log + continue-on-error: true + + - name: Install main's dependencies + working-directory: main-ref + run: npm ci --legacy-peer-deps + + # Runs main's code, but appends to development's history file so both + # branches land in one commit and one status page. + - name: Measure main + id: main + working-directory: main-ref + shell: bash + run: npm run health-check -- main --out "$GITHUB_WORKSPACE/docs/health/history.jsonl" | tee "$GITHUB_WORKSPACE/main.log" + continue-on-error: true + + - name: Commit the results + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git add docs/health/ + if git diff --cached --quiet; then + echo "Nothing changed." + else + git commit -m "chore: dashboard health $(date -u +%Y-%m-%d)" + git push + fi + + - name: Summary + if: always() + run: | + { + echo "### Dashboard health" + echo + echo '```' + tail -24 dev.log 2>/dev/null || echo "development: no output" + echo + tail -24 main.log 2>/dev/null || echo "main: no output" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + # Exit code 2 from the script means a question that worked last week does + # not work now. An issue rather than just a red X, because a red X in a + # weekly job is easy to miss for another week. + - name: Open an issue for regressions + if: steps.dev.outcome == 'failure' || steps.main.outcome == 'failure' + env: + GH_TOKEN: ${{ github.token }} + run: | + { + echo "The weekly health check found a dashboard question that worked before and does not now." + echo + echo "See [the run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) and [docs/health/STATUS.md](${{ github.server_url }}/${{ github.repository }}/blob/development/docs/health/STATUS.md)." + echo + for log in dev.log main.log; do + [ -f "$log" ] || continue + echo "### ${log%.log}" + echo '```' + sed -n '/REGRESSIONS/,$p' "$log" 2>/dev/null | head -40 + echo '```' + done + } > issue.md + gh issue create \ + --title "Dashboard health: a question regressed ($(date -u +%Y-%m-%d))" \ + --body-file issue.md \ + --label bug + + - name: Fail if a question regressed + if: steps.dev.outcome == 'failure' || steps.main.outcome == 'failure' + run: exit 1 diff --git a/README.md b/README.md index a236343..065d28b 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ Inside `docs/`: | `ARCHITECTURE.md` | System design, module boundaries, data flow | | `SCHEMA.md` | Predicate inventories, class counts, endpoint roles | | `QUERY-MATRIX.md` | Every query shape, measured — plus the error catalogue (Part 4) | +| `health/STATUS.md` | Weekly dashboard health: working, timings, row-count drift | | `DEBUGGING.md` | Documented bugs with root causes and fixes | | `CONVENTIONS.md` | Coding standards, endpoint selection rules | | `wiki/` | One page per filter dropdown; source of truth for the GitHub Wiki | diff --git a/docs/health/STATUS.md b/docs/health/STATUS.md new file mode 100644 index 0000000..347bea4 --- /dev/null +++ b/docs/health/STATUS.md @@ -0,0 +1,33 @@ +# Dashboard health + +_Generated by `npm run health-check` — see the weekly workflow in +`.github/workflows/health-check.yml`. Every run goes through the live pipeline, +never the result cache._ + +**Targets** are the entities the question asks for, **anchors** the ones it +relates them to, **reaches** the river segments drawn for a trace. Region +boundaries are recorded in the history but not shown — they are the county +outline, not an answer. + +A moved count is not automatically a bug: the knowledge graph reloads and +numbers change for real reasons. It is flagged so that when something *does* +look wrong, there is a date to point at. + +## development + +**8 of 8 working** · 2026-09-14 21:44 UTC · `9ecbbe0` + +| | Question | Time | Targets | Anchors | Reaches | Change since last run | +| --- | --- | ---: | ---: | ---: | ---: | --- | +| ✅ | Samples Near Agricultural Chemical Facilities in Maine | 22s | 29 | 11 | — | _first run_ | +| ✅ | Samples Near Landfills & DOD Sites in Penobscot and Knox County | 11s | 60 | 8 | — | _first run_ | +| ✅ | Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County | 4s | 103 | 6 | — | _first run_ | +| ✅ | Samples Downstream of Waste Treatment Facilities in Indiana | 14s | 123 | 882 | 15696 | _first run_ | +| ✅ | Maine Private Wells Near Landfills & DoD Sites | 19s | 751 | 38 | — | _first run_ | +| ✅ | Maine Private Wells Near Wastewater Treatment Facilities | 14s | 2431 | 135 | — | _first run_ | +| ✅ | Maine Private Wells Near Airports & Air Transportation Sites (AFFF) | 14s | 4425 | 174 | — | _first run_ | +| ✅ | PFHpA Groundwater Samples Downstream from Facilities in Cumberland County | 159s | 49 | 268 | 362 | _first run_ | + +--- + +Full history: [`history.jsonl`](./history.jsonl) — one JSON line per question per run. diff --git a/docs/health/history.jsonl b/docs/health/history.jsonl new file mode 100644 index 0000000..f65349a --- /dev/null +++ b/docs/health/history.jsonl @@ -0,0 +1,8 @@ +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"samples-near-agchem-maine","title":"Samples Near Agricultural Chemical Facilities in Maine","attempts":1,"status":"success","ms":22053,"counts":{"FIND_TARGET_ENTITIES":29,"GET_ANCHOR_DETAILS":11,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"samples-near-landfill-dod-penobscot-knox","title":"Samples Near Landfills & DOD Sites in Penobscot and Knox County","attempts":1,"status":"success","ms":11482,"counts":{"FIND_TARGET_ENTITIES":60,"GET_ANCHOR_DETAILS":8,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"waterbodies-near-landfill-dod-penobscot-knox","title":"Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County","attempts":1,"status":"success","ms":4451,"counts":{"FIND_TARGET_ENTITIES":103,"GET_ANCHOR_DETAILS":6,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"samples-downstream-waste-indiana","title":"Samples Downstream of Waste Treatment Facilities in Indiana","attempts":1,"status":"success","ms":14399,"counts":{"FIND_TARGET_ENTITIES":123,"GET_ANCHOR_DETAILS":882,"GET_REGION_BOUNDARIES":92,"GET_FLOWLINE_GEOMETRIES":15696},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"wells-near-landfill-dod-maine","title":"Maine Private Wells Near Landfills & DoD Sites","attempts":1,"status":"success","ms":19223,"counts":{"FIND_TARGET_ENTITIES":751,"GET_ANCHOR_DETAILS":38,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"wells-near-wwtp-maine","title":"Maine Private Wells Near Wastewater Treatment Facilities","attempts":1,"status":"success","ms":14266,"counts":{"FIND_TARGET_ENTITIES":2431,"GET_ANCHOR_DETAILS":135,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"wells-near-airports-maine","title":"Maine Private Wells Near Airports & Air Transportation Sites (AFFF)","attempts":1,"status":"success","ms":14222,"counts":{"FIND_TARGET_ENTITIES":4425,"GET_ANCHOR_DETAILS":174,"GET_REGION_BOUNDARIES":16},"partialFailed":[],"partialSkipped":[],"error":null} +{"runAt":"2026-09-14T21:44:17.124Z","ref":"development","commit":"9ecbbe0","id":"facilities-downstream-pfhpa-gw-cumberland","title":"PFHpA Groundwater Samples Downstream from Facilities in Cumberland County","attempts":1,"status":"success","ms":159024,"counts":{"FIND_TARGET_ENTITIES":49,"GET_ANCHOR_DETAILS":268,"GET_REGION_BOUNDARIES":16,"GET_FLOWLINE_GEOMETRIES":362},"partialFailed":[],"partialSkipped":[],"error":null} diff --git a/package.json b/package.json index 7512cef..a34947f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "preview": "vite preview", "warm-cache": "tsx scripts/warm-cache.mts", "check-cache-key": "tsx scripts/check-cache-key.mts", - "query-matrix": "tsx scripts/query-matrix.mts" + "query-matrix": "tsx scripts/query-matrix.mts", + "health-check": "tsx scripts/health-check.mts" }, "dependencies": { "@tanstack/react-query": "^5.90.21", diff --git a/scripts/health-check.mts b/scripts/health-check.mts new file mode 100644 index 0000000..9fd71d3 --- /dev/null +++ b/scripts/health-check.mts @@ -0,0 +1,266 @@ +// Runs the dashboard questions and writes down what happened, so a regression +// has a date attached to it instead of being noticed weeks later. +// +// npx tsx scripts/health-check.mts [--out docs/health/history.jsonl] +// npx tsx scripts/health-check.mts --render-only # rebuild STATUS.md, no queries +// +// Deliberately takes no token and writes nothing to the API. It is pure +// measurement: every run goes through the real pipeline against the live +// endpoints, never the result cache, because a cached answer would tell us +// about the cache rather than the graph. +// +// Exit codes: 0 fine, 1 the script itself broke, 2 a question that worked last +// time does not work now. +// +// Every failure is retried once. Measured while building this: three questions +// failed in the first run (3-13s each) and all three succeeded immediately +// afterwards at 22-52s. The endpoint is shared and gets busy, and a check that +// opens an issue on a single bad request would cry wolf until it was ignored. +import { execSync } from 'node:child_process'; +import { appendFileSync, mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { PREBUILT_QUERIES } from '../src/constants/prebuiltQueries'; +import { planPipeline } from '../src/engine/planner'; +import { executePipeline } from '../src/engine/executor'; + +// The keys useMapLayers renders (wire.ts RENDERED_KEYS). Counting anything else +// would flag drift in intermediate bookkeeping the user never sees. +const COUNTED = ['FIND_TARGET_ENTITIES', 'GET_ANCHOR_DETAILS', 'GET_REGION_BOUNDARIES', 'GET_FLOWLINE_GEOMETRIES'] as const; + +interface HealthRecord { + runAt: string; + ref: string; + commit: string; + id: string; + title: string; + status: 'success' | 'empty' | 'error'; + ms: number; + counts: Record; + partialFailed: string[]; + partialSkipped: string[]; + error: string | null; + // 2 means the first try failed. Worth recording: a question that needs the + // retry every week is degrading even while it still counts as working. + attempts: number; +} + +const renderOnly = process.argv.includes('--render-only'); +const ref = renderOnly ? '' : process.argv[2]; +const outArg = process.argv.indexOf('--out'); +const HISTORY = outArg > -1 ? process.argv[outArg + 1] : 'docs/health/history.jsonl'; +const STATUS = `${dirname(HISTORY)}/STATUS.md`; + +if (!ref && !renderOnly) { + console.error('Usage: health-check.mts [--out path] | --render-only'); + process.exit(1); +} + +const commit = (() => { + try { + return execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim(); + } catch { + return 'unknown'; + } +})(); + +function readHistory(): HealthRecord[] { + if (!existsSync(HISTORY)) return []; + return readFileSync(HISTORY, 'utf8') + .split('\n') + .filter(Boolean) + .map((line) => JSON.parse(line) as HealthRecord); +} + +const history = readHistory(); +// The run this one is compared against: the most recent for the same branch. +const previousRunAt = [...new Set(history.filter((r) => r.ref === ref).map((r) => r.runAt))].sort().pop(); +const previous = new Map(history.filter((r) => r.ref === ref && r.runAt === previousRunAt).map((r) => [r.id, r])); + +if (renderOnly) { + writeFileSync(STATUS, renderStatus(history)); + console.log(`Rebuilt ${STATUS} from ${history.length} records.`); + process.exit(0); +} + +const runAt = new Date().toISOString(); +const records: HealthRecord[] = []; + +console.log(`Dashboard health — ${ref} @ ${commit}, ${PREBUILT_QUERIES.length} questions\n`); + +for (const prebuilt of PREBUILT_QUERIES) { + const started = Date.now(); + process.stdout.write(` ${prebuilt.title.slice(0, 54).padEnd(56)}`); + + let record = await attempt(prebuilt, 1); + if (record.status === 'error') { + process.stdout.write('retrying… '); + record = await attempt(prebuilt, 2); + } + record.ms = Date.now() - started; + + records.push(record); + console.log(`${icon(record)} ${(record.ms / 1000).toFixed(0).padStart(4)}s ${summarise(record, previous.get(record.id))}`); +} + +mkdirSync(dirname(HISTORY), { recursive: true }); +appendFileSync(HISTORY, records.map((r) => JSON.stringify(r)).join('\n') + '\n'); +writeFileSync(STATUS, renderStatus([...history, ...records])); + +// A question that worked last week and does not work now. Drift in row counts +// is not a regression: the knowledge graph reloads, and numbers move for +// legitimate reasons. Only a status going backwards is worth waking someone for. +// A question with no previous record cannot have regressed — a first run, or a +// newly added question, must not open an issue for something that was never +// seen working. +const regressions = records.filter((r) => { + const was = previous.get(r.id); + return r.status === 'error' && was !== undefined && was.status !== 'error'; +}); +const working = records.filter((r) => r.status !== 'error').length; + +console.log(`\n${working} of ${records.length} working, ${(records.reduce((n, r) => n + r.ms, 0) / 1000).toFixed(0)}s total`); +console.log(`History: ${HISTORY} Status page: ${STATUS}`); + +if (regressions.length) { + console.log(`\nREGRESSIONS (${regressions.length}):`); + for (const r of regressions) { + const was = previous.get(r.id); + console.log(` ${r.title}`); + console.log(` now: error — ${r.error}`); + console.log(` was: ${was!.status} in ${(was!.ms / 1000).toFixed(0)}s on ${was!.runAt.slice(0, 10)}`); + } + process.exit(2); +} + +async function attempt(prebuilt: (typeof PREBUILT_QUERIES)[number], n: number): Promise { + const started = Date.now(); + const base = { runAt, ref, commit, id: prebuilt.id, title: prebuilt.title, attempts: n }; + try { + const result = await executePipeline(planPipeline(prebuilt.question), prebuilt.question, () => {}); + const counts: Record = {}; + if (result.status === 'success') { + for (const key of COUNTED) if (result.data[key]?.length) counts[key] = result.data[key].length; + } + return { + ...base, + status: result.status, + ms: Date.now() - started, + counts, + partialFailed: result.status === 'success' ? (result.partial ?? []).flatMap((p) => p.failed) : [], + partialSkipped: result.status === 'success' ? (result.partial ?? []).flatMap((p) => p.skipped) : [], + error: result.status === 'error' ? result.message.slice(0, 200) : null, + }; + } catch (err) { + // A thrown error is still a data point — the question is broken either way. + return { + ...base, + status: 'error', + ms: Date.now() - started, + counts: {}, + partialFailed: [], + partialSkipped: [], + error: err instanceof Error ? err.message.slice(0, 200) : String(err), + }; + } +} + +function icon(r: HealthRecord): string { + return r.status === 'success' ? (r.partialFailed.length || r.partialSkipped.length ? '⚠️' : '✅') : r.status === 'empty' ? '⬜' : '❌'; +} + +function total(r: HealthRecord): number { + return Object.values(r.counts).reduce((n, v) => n + v, 0); +} + +function summarise(r: HealthRecord, was?: HealthRecord): string { + if (r.status === 'error') return (r.error ?? '').slice(0, 50); + const now = total(r); + if (!was || was.status === 'error') return `${now} rows`; + const drift = now - total(was); + return drift === 0 ? `${now} rows` : `${now} rows (${drift > 0 ? '+' : ''}${drift})`; +} + +function renderStatus(all: HealthRecord[]): string { + const refs = [...new Set(all.map((r) => r.ref))].sort(); + const out = [ + '# Dashboard health', + '', + '_Generated by `npm run health-check` — see the weekly workflow in', + '`.github/workflows/health-check.yml`. Every run goes through the live pipeline,', + 'never the result cache._', + '', + '**Targets** are the entities the question asks for, **anchors** the ones it', + 'relates them to, **reaches** the river segments drawn for a trace. Region', + 'boundaries are recorded in the history but not shown — they are the county', + 'outline, not an answer.', + '', + 'A moved count is not automatically a bug: the knowledge graph reloads and', + 'numbers change for real reasons. It is flagged so that when something *does*', + 'look wrong, there is a date to point at.', + '', + ]; + + for (const r of refs) { + const runs = [...new Set(all.filter((x) => x.ref === r).map((x) => x.runAt))].sort(); + const latest = all.filter((x) => x.ref === r && x.runAt === runs[runs.length - 1]); + const prior = new Map(all.filter((x) => x.ref === r && x.runAt === runs[runs.length - 2]).map((x) => [x.id, x])); + if (!latest.length) continue; + + const ok = latest.filter((x) => x.status !== 'error').length; + out.push( + `## ${r}`, + '', + `**${ok} of ${latest.length} working** · ${latest[0].runAt.slice(0, 16).replace('T', ' ')} UTC · \`${latest[0].commit}\``, + '', + '| | Question | Time | Targets | Anchors | Reaches | Change since last run |', + '| --- | --- | ---: | ---: | ---: | ---: | --- |', + ); + for (const x of latest) { + const was = prior.get(x.id); + const cell = (k: string) => (x.status === 'error' ? '—' : (x.counts[k] ?? 0) || '—'); + out.push( + `| ${icon(x)} | ${x.title} | ${(x.ms / 1000).toFixed(0)}s | ${cell('FIND_TARGET_ENTITIES')} | ${cell('GET_ANCHOR_DETAILS')} | ${cell('GET_FLOWLINE_GEOMETRIES')} | ${change(x, was)} |`, + ); + } + out.push(''); + + const notes = latest.filter((x) => x.partialFailed.length || x.partialSkipped.length); + if (notes.length) { + out.push('**Incomplete answers:**', ''); + for (const x of notes) { + const bits = [ + x.partialFailed.length ? `could not answer ${x.partialFailed.join(', ')}` : '', + x.partialSkipped.length ? `ran out of time before ${x.partialSkipped.join(', ')}` : '', + ].filter(Boolean); + out.push(`- ${x.title} — ${bits.join('; ')}`); + } + out.push(''); + } + + const errors = latest.filter((x) => x.status === 'error'); + if (errors.length) { + out.push('**Errors:**', ''); + for (const x of errors) out.push(`- ${x.title} — \`${x.error}\``); + out.push(''); + } + } + + out.push('---', '', `Full history: [\`${HISTORY.split('/').pop()}\`](./${HISTORY.split('/').pop()}) — one JSON line per question per run.`, ''); + return out.join('\n'); +} + +function change(now: HealthRecord, was?: HealthRecord): string { + if (!was) return '_first run_'; + if (was.status !== now.status) return `**was ${was.status}** on ${was.runAt.slice(0, 10)}`; + if (now.status === 'error') return 'still failing'; + const drift = total(now) - total(was); + if (drift === 0) return '—'; + const perKey = COUNTED.filter((k) => (now.counts[k] ?? 0) !== (was.counts[k] ?? 0)) + .map((k) => `${label(k)} ${was.counts[k] ?? 0} → ${now.counts[k] ?? 0}`) + .join(', '); + return `**${perKey}**`; +} + +function label(key: string): string { + return { FIND_TARGET_ENTITIES: 'targets', GET_ANCHOR_DETAILS: 'anchors', GET_REGION_BOUNDARIES: 'boundaries', GET_FLOWLINE_GEOMETRIES: 'reaches' }[key] ?? key; +} From e03aa92d318bc688baadbf2345228047da8e7af0 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 18:23:58 -0400 Subject: [PATCH 32/66] ci: serialise every workflow that queries the graph MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit health-check and warm-cache ran the same eight heavy questions under different concurrency groups, so a warm run started by hand could land on top of the weekly health cron. Shared group name fixes it: the second queues. This is the exact condition that made three questions look broken while the health check was being built — something else was querying at the same time, and all three passed on retry seconds later. --- .github/workflows/health-check.yml | 9 +++++++-- .github/workflows/warm-cache.yml | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/health-check.yml b/.github/workflows/health-check.yml index 2c1fbf3..4912ef1 100644 --- a/.github/workflows/health-check.yml +++ b/.github/workflows/health-check.yml @@ -19,9 +19,14 @@ on: - cron: '0 6 * * 1' # Mondays, 06:00 UTC workflow_dispatch: -# These queries are heavy on a shared endpoint. Never two runs at once. +# One job at a time across *every* workflow that queries the graph — this group +# name is shared with warm-cache.yml on purpose. Both run the same eight heavy +# questions, and a warm run started by hand on a Monday morning would otherwise +# land on top of the health cron. That is not hypothetical: three questions were +# recorded as broken while this was being built, purely because something else +# was querying at the same time, and all three passed on retry. concurrency: - group: health-check + group: sawgraph-endpoint cancel-in-progress: false permissions: diff --git a/.github/workflows/warm-cache.yml b/.github/workflows/warm-cache.yml index af529a8..7bc61c0 100644 --- a/.github/workflows/warm-cache.yml +++ b/.github/workflows/warm-cache.yml @@ -31,10 +31,12 @@ on: type: boolean default: false -# One warm run at a time — these queries are heavy on a shared endpoint, and two -# concurrent runs would compete for the same graph engine. +# One job at a time across *every* workflow that queries the graph — shared with +# health-check.yml, so a warm run and the weekly health check queue rather than +# compete for the same graph engine. Warming both environments now serialises +# too, which costs a few minutes and buys clean measurements. concurrency: - group: warm-cache-${{ inputs.environment }} + group: sawgraph-endpoint cancel-in-progress: false jobs: From ff8ad0ca3830ad01a7806a0572f5f92d78f94df6 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 18:39:03 -0400 Subject: [PATCH 33/66] docs: record what a matrix sweep actually costs, per mode The header claimed 40 minutes. True for raw mode; an engine-mode sweep measured 144 minutes, and ~95 once the two requests that hung for 1918s and 959s are discounted, since the 60s client cap means they cannot hang that way again. Also names where the time goes: M2 and M3 are 50 of the 124 queries and roughly two thirds of the clock. --- scripts/query-matrix.mts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 7017f1e..987c543 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -12,10 +12,21 @@ // M3 upstream all pairs | M4 distance sweep | M5 dashboard queries // M6 six states | M7 no region | M8 filters | M9 county scopes // -// A full sweep is ~156 queries and takes roughly 40 minutes; each query is -// capped at 45s client-side. Run phases one at a time and sequentially — running -// them in parallel distorts timings and provokes failures that are artefacts of -// your own load. +// How long it takes depends entirely on MODE, and the difference is large: +// +// raw ~156 step-queries, ~37 min (measured 2026-09-14) +// engine 124 full pipelines, ~95 min (measured 2026-09-14 at 144 min, but +// 48 of those were two requests that hung for 1918s and 959s before +// sparqlClient gained its 60s cap — those shapes now fail fast) +// +// Nearly all of it is M2 and M3: the downstream and upstream sweeps are 50 of +// the 124 queries and about two thirds of the wall time. M1, M7 and M9 together +// finish in under four minutes. +// +// Run phases one at a time and sequentially — running them in parallel distorts +// timings and provokes failures that are artefacts of your own load. If you run +// this while a GitHub workflow is querying, you will measure the contention. +// Each query is capped at 45s client-side per request. // // Results are cache-sensitive: the engine answers the same query 10-20x faster // when warm, so run a sweep twice (cold, then warm) before trusting a number. From 39de9fa8947c5d45d6d3d1101d637005bca619d3 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 18:58:54 -0400 Subject: [PATCH 34/66] docs: one dated file per matrix sweep, with a generated index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `query-matrix-after.csv` named a moment rather than a date — after the Phase 1-2 fix, which was six commits ago — and nothing said when either file was last run except git log. The next sweep would have had to be `-after-after`. Sweeps now live in docs/query-matrix/ as YYYY-MM-DD-.csv, so `ls` answers "when was this last run" and comparing two is a diff of two paths. The harness writes there by default; no env var to remember, and it refuses to truncate a file that already has rows rather than guarding one hardcoded filename. `--index` regenerates README.md from the CSVs themselves: sweep, mode, commit, how many shapes passed, and what broke or got fixed since the previous sweep in the same mode. Runs no queries. Writing the index turned up two things worth having: - Scoring a clean raw sweep as 7 of 124 passing. The two modes report outcome in different columns — `engine` writes the pipeline status, `raw` writes the HTTP code and puts the verdict in errorClass. Handled, and commented. - A real inconsistency in QUERY-MATRIX.md Part 7: the engine CSV has 9 error rows where the table claims 3. Both are honest about their moment, but only the CSV is re-derivable, and six of the nine are known to have been fixed after the capture. 7.5 now says so plainly and names them, instead of mentioning only the partial counts. The layout is the fix for that class of confusion: a sweep now carries its own date and commit, and the index shows the movement between sweeps. --- README.md | 1 + docs/ARCHITECTURE.md | 2 +- docs/DEBUGGING.md | 2 +- docs/QUERY-MATRIX.md | 35 ++++- ...2026-09-13-query-execution-architecture.md | 4 +- .../2026-09-14-engine.csv} | 0 .../2026-09-14-raw-baseline.csv} | 0 docs/query-matrix/README.md | 22 +++ scripts/query-matrix.mts | 141 ++++++++++++++++-- 9 files changed, 186 insertions(+), 21 deletions(-) rename docs/{query-matrix-after.csv => query-matrix/2026-09-14-engine.csv} (100%) rename docs/{query-matrix.csv => query-matrix/2026-09-14-raw-baseline.csv} (100%) create mode 100644 docs/query-matrix/README.md diff --git a/README.md b/README.md index 065d28b..8386aa4 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ Inside `docs/`: | `SCHEMA.md` | Predicate inventories, class counts, endpoint roles | | `QUERY-MATRIX.md` | Every query shape, measured — plus the error catalogue (Part 4) | | `health/STATUS.md` | Weekly dashboard health: working, timings, row-count drift | +| `query-matrix/` | One CSV per sweep, dated, with a generated index | | `DEBUGGING.md` | Documented bugs with root causes and fixes | | `CONVENTIONS.md` | Coding standards, endpoint selection rules | | `wiki/` | One page per filter dropdown; source of truth for the GitHub Wiki | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 78d4bdf..e59cba1 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -920,7 +920,7 @@ the correct answer — confirm the data exists before treating it as a bug. ### 6. Run the whole matrix `npm run query-matrix` re-measures every query shape and writes -`docs/query-matrix.csv`. Slow, but it is how a regression gets proven rather +`docs/query-matrix/2026-09-14-raw-baseline.csv`. Slow, but it is how a regression gets proven rather than suspected. --- diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index fae9c30..4c28864 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -291,7 +291,7 @@ query the engine refuses is split into slices and merged **Prevention**: benchmark against more than Maine, and re-run `npm run query-matrix` after any engine change, diffing against -`docs/query-matrix.csv`. +`docs/query-matrix/2026-09-14-raw-baseline.csv`. --- diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 3f6836b..fb11c5e 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -2,7 +2,7 @@ **Baseline measured**: 2026-09-13, against the live `apps.okn.us` endpoints **Re-measured after Phases 1 + 2**: 2026-09-14 (Part 6) -**Raw data**: [`query-matrix.csv`](./query-matrix.csv) — one row per query executed, importable into a spreadsheet +**Raw data**: [`query-matrix/`](./query-matrix/) — one row per query executed, importable into a spreadsheet **Harness**: [`scripts/query-matrix.mts`](../scripts/query-matrix.mts) — re-run it and diff the CSV after any engine change This is the reference sheet. Every claim here is a measurement, not an estimate. @@ -484,7 +484,7 @@ reason. The whole matrix re-run through the real engine (`QUERY_MATRIX_MODE=engine`), so splitting, merging, partial results and the step budget were all exercised — -not just the raw SPARQL. Raw data: `docs/query-matrix-after.csv`. +not just the raw SPARQL. Raw data: `docs/query-matrix/2026-09-14-engine.csv`. **124 shapes compared. Of the 37 that failed at baseline, 34 now work. No regressions.** @@ -562,13 +562,32 @@ a slice never attempted were both reported as "too large". They need opposite advice — narrow the question vs. just run it again — and are now tracked and worded separately. -### 7.5 Caveat on the recorded partial counts +### 7.5 The recorded CSV is older than the counts above -`query-matrix-after.csv` was captured *before* the budget fix, so its -`partialSlices` numbers are pessimistic: they count slices skipped by a rule -that has since been replaced. The one case re-measured afterwards -(`wells near(4)`) went from 11 missing to **0**. Several other partials in that -file are likely complete now; they have not been re-run. +`query-matrix/2026-09-14-engine.csv` was captured *before* the budget fix, and +the gap is wider than it first looked. **The file has 9 error rows; the table +above says 3.** Both are honest about the moment they describe — the counts came +from the code as it stands, the CSV from the code a few commits earlier — but +only one of them is re-derivable, and it is not the table. + +Six of those nine are known to have been fixed by changes made after the +capture: + +| Shape in the CSV | Why it is stale | +| --- | --- | +| `samples ↓ facilities [17]` (Illinois) | the budget fix; 7.4 records it completing in 248s | +| five `upstream` shapes | two of them hung for 1918s and 959s, which the 60s client cap in `sparqlClient.ts` now prevents | + +The `partialSlices` numbers are pessimistic for the same reason: they count +slices skipped by a rule that has since been replaced. `wells near(4)` went from +11 missing to **0** when re-measured. + +**What to do about it:** run a fresh engine sweep (~95 min) and let the new +dated file supersede this one. Until then, treat the table as current and the +CSV as an artefact of 2026-09-14. This is precisely the confusion the per-sweep +file naming and the generated index in `query-matrix/README.md` exist to prevent +from recurring — a sweep is now stamped with its own commit, and the index shows +what moved between one sweep and the next. --- diff --git a/docs/plans/done/2026-09-13-query-execution-architecture.md b/docs/plans/done/2026-09-13-query-execution-architecture.md index 39e78c7..d907e7c 100644 --- a/docs/plans/done/2026-09-13-query-execution-architecture.md +++ b/docs/plans/done/2026-09-13-query-execution-architecture.md @@ -332,7 +332,7 @@ the monolith where a monolith could produce one.** ### 8.3 Gate for calling this done Re-run the matrix harness after each phase and diff against -`docs/query-matrix.csv`: +`docs/query-matrix/2026-09-14-raw-baseline.csv`: - No shape may move from ✅/⚠️ to ❌. - All 37 ❌ rows must become ✅ or ⚠️. @@ -422,4 +422,4 @@ Two mechanisms were added during implementation that the plan did not anticipate side would drop out-of-region contributors (`3f50251`). **Verification gate for each phase:** re-run the matrix harness and compare -against `docs/query-matrix.csv`. No shape may regress; the ❌ rows must turn ✅. +against `docs/query-matrix/2026-09-14-raw-baseline.csv`. No shape may regress; the ❌ rows must turn ✅. diff --git a/docs/query-matrix-after.csv b/docs/query-matrix/2026-09-14-engine.csv similarity index 100% rename from docs/query-matrix-after.csv rename to docs/query-matrix/2026-09-14-engine.csv diff --git a/docs/query-matrix.csv b/docs/query-matrix/2026-09-14-raw-baseline.csv similarity index 100% rename from docs/query-matrix.csv rename to docs/query-matrix/2026-09-14-raw-baseline.csv diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md new file mode 100644 index 0000000..9774aa2 --- /dev/null +++ b/docs/query-matrix/README.md @@ -0,0 +1,22 @@ +# Query matrix sweeps + +Every run of `npm run query-matrix`, newest first. One CSV per sweep, named +for the day it ran — so `ls` answers "when was this last run", and comparing +two sweeps is a `diff` of two paths. + +``` +QUERY_MATRIX_MODE=engine npx tsx scripts/query-matrix.mts M1 init # start a sweep +QUERY_MATRIX_MODE=engine npx tsx scripts/query-matrix.mts M2 # each later phase +npx tsx scripts/query-matrix.mts --index # rebuild this file +``` + +`raw` posts each step's SPARQL directly and writes one row per step; `engine` +runs the real pipeline, one row per query, and is the mode to use after an +engine change. The two are not comparable row for row. + +| Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | +| --- | --- | --- | ---: | ---: | ---: | --- | +| [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | +| [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | + +Generated 2026-09-14. diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 987c543..6c7c293 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -2,7 +2,7 @@ // the live endpoints and writes one CSV row per query. // // This is the tool behind docs/QUERY-MATRIX.md. Re-run it after any change to -// the query engine and diff the output against docs/query-matrix.csv — no shape +// the query engine and diff the output against docs/query-matrix/2026-09-14-raw-baseline.csv — no shape // may regress from working to failing. // // npx tsx scripts/query-matrix.mts M1 init # first phase truncates the CSV @@ -32,7 +32,7 @@ // when warm, so run a sweep twice (cold, then warm) before trusting a number. import { execSync } from 'node:child_process'; -import { appendFileSync, writeFileSync } from 'node:fs'; +import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'; import { planPipeline } from '../src/engine/planner'; import { executePipeline } from '../src/engine/executor'; import { ENDPOINTS } from '../src/constants/endpoints'; @@ -53,14 +53,30 @@ const COMMIT = (() => { try { return execSync('git rev-parse --short HEAD').toString().trim(); } catch { return 'unknown'; } })(); -// Default output is the *baseline* file, which is committed history — an `init` -// run truncates whatever it points at, so writing there needs to be deliberate. -const OUT = process.env.QUERY_MATRIX_OUT ?? 'docs/query-matrix.csv'; -if (process.argv[3] === 'init' && OUT === 'docs/query-matrix.csv' && !process.env.QUERY_MATRIX_OVERWRITE_BASELINE) { +// One file per sweep, named for the day it ran and the mode it ran in. The name +// is the metadata: `ls docs/query-matrix/` answers "when was this last run", and +// comparing two sweeps is `diff` of two paths. An earlier layout used +// `query-matrix/2026-09-14-engine.csv`, which named a moment rather than a date and went +// stale the week after it was written. +const DIR = 'docs/query-matrix'; +const OUT = process.env.QUERY_MATRIX_OUT ?? `${DIR}/${RUN_AT.slice(0, 10)}-${MODE}.csv`; + +// Regenerate the index and stop. Cheap, runs no queries. +if (process.argv[2] === '--index') { + writeIndex(); + process.exit(0); +} + +mkdirSync(DIR, { recursive: true }); + +// `init` truncates. Every sweep file is committed history the moment it lands, +// so refuse to overwrite one that already has rows — including today's, if a +// sweep is already in progress and you meant to append the next phase. +if (process.argv[3] === 'init' && existsSync(OUT) && readFileSync(OUT, 'utf8').split('\n').length > 2 && !process.env.QUERY_MATRIX_OVERWRITE) { console.error( - 'Refusing to truncate the committed baseline docs/query-matrix.csv.\n' + - 'Set QUERY_MATRIX_OUT=docs/query-matrix-after.csv (or another path) for a new sweep,\n' + - 'or QUERY_MATRIX_OVERWRITE_BASELINE=1 if you really mean to replace the baseline.', + `Refusing to truncate ${OUT}, which already has rows.\n` + + 'Drop `init` to append the next phase of the same sweep,\n' + + 'or set QUERY_MATRIX_OVERWRITE=1 to start it over.', ); process.exit(1); } @@ -234,3 +250,110 @@ if (phase === 'M9') { // county-scoped (smallest realistic) + multi-county for (const [label, counties] of [['1 county (Cumberland)', ['23005']], ['3 counties', ['23005','23019','23003']]] as [string, string[]][]) await run('M9', `samples downstream facilities [${label}]`, mk('samples', 'downstream', 'facilities', undefined, '23', counties), { blockA: 'samples', rel: 'downstream', hops: '', blockC: 'facilities', region: label, filters: 'none' }, 0); } + +// --- the index ------------------------------------------------------------- +// +// One row per sweep: when, which commit, how many query shapes passed, and what +// moved since the previous sweep in the same mode. Regenerate with +// `npx tsx scripts/query-matrix.mts --index` — it reads the CSVs, runs nothing. + +interface Sweep { + file: string; + date: string; + mode: string; + commit: string; + // label -> worst status seen for that query. Raw mode writes one row per + // step, so a query is only a pass if every one of its steps passed. + byLabel: Map; +} + +function readSweeps(): Sweep[] { + if (!existsSync(DIR)) return []; + return readdirSync(DIR) + .filter((f) => f.endsWith('.csv') && statSync(`${DIR}/${f}`).size > 0) + .sort() + .map((file) => { + const lines = readFileSync(`${DIR}/${file}`, 'utf8').split('\n').filter(Boolean); + const header = lines[0].split(','); + const iCommit = header.indexOf('commit'); + const iLabel = header.indexOf('label'); + const iStatus = header.indexOf('status'); + const iClass = header.indexOf('errorClass'); + const byLabel = new Map(); + let commit = ''; + for (const line of lines.slice(1)) { + const cols = line.split(','); + // Labels are quoted and contain no commas (csv() strips whitespace runs + // and quotes), so a plain split is safe here. + const label = (cols[iLabel] ?? '').replace(/"/g, ''); + // The two modes report outcome differently: `engine` writes the + // pipeline status, `raw` writes the HTTP code and puts the verdict in + // errorClass. Reading the wrong one scores a clean raw sweep as 7 of + // 124 passing, which is how this was caught. + const raw = cols[iStatus] ?? ''; + const status = /^\d+$/.test(raw) ? (cols[iClass] === 'ok' ? 'success' : 'error') : raw; + if (iCommit > -1 && cols[iCommit]) commit = cols[iCommit]; + const worse = (a: string, b: string) => (a === 'error' || b === 'error' ? 'error' : a === 'empty' || b === 'empty' ? 'empty' : 'success'); + byLabel.set(label, byLabel.has(label) ? worse(byLabel.get(label)!, status) : status); + } + const [, date, mode] = file.match(/^(\d{4}-\d{2}-\d{2})-(.+)\.csv$/) ?? [, file, '?']; + return { file, date: date!, mode: mode!, commit: commit || 'unrecorded', byLabel }; + }); +} + +function writeIndex(): void { + const sweeps = readSweeps(); + const out = [ + '# Query matrix sweeps', + '', + 'Every run of `npm run query-matrix`, newest first. One CSV per sweep, named', + 'for the day it ran — so `ls` answers "when was this last run", and comparing', + 'two sweeps is a `diff` of two paths.', + '', + '```', + 'QUERY_MATRIX_MODE=engine npx tsx scripts/query-matrix.mts M1 init # start a sweep', + 'QUERY_MATRIX_MODE=engine npx tsx scripts/query-matrix.mts M2 # each later phase', + 'npx tsx scripts/query-matrix.mts --index # rebuild this file', + '```', + '', + '`raw` posts each step\'s SPARQL directly and writes one row per step; `engine`', + 'runs the real pipeline, one row per query, and is the mode to use after an', + 'engine change. The two are not comparable row for row.', + '', + '| Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep |', + '| --- | --- | --- | ---: | ---: | ---: | --- |', + ]; + + for (let i = sweeps.length - 1; i >= 0; i--) { + const s = sweeps[i]; + const pass = [...s.byLabel.values()].filter((v) => v === 'success').length; + const fail = [...s.byLabel.values()].filter((v) => v === 'error').length; + const prev = sweeps.slice(0, i).reverse().find((p) => p.mode === s.mode); + out.push( + `| [\`${s.date}\`](./${s.file}) | ${s.mode} | \`${s.commit}\` | ${s.byLabel.size} | ${pass} | ${fail} | ${delta(s, prev)} |`, + ); + } + + out.push('', `Generated ${new Date().toISOString().slice(0, 10)}.`, ''); + writeFileSync(`${DIR}/README.md`, out.join('\n')); + console.log(`Wrote ${DIR}/README.md — ${sweeps.length} sweep(s).`); +} + +function delta(now: Sweep, prev?: Sweep): string { + if (!prev) return '_first sweep in this mode_'; + const fixed: string[] = []; + const broke: string[] = []; + for (const [label, status] of now.byLabel) { + const was = prev.byLabel.get(label); + if (was === undefined) continue; + if (was === 'error' && status !== 'error') fixed.push(label); + if (was !== 'error' && status === 'error') broke.push(label); + } + const added = [...now.byLabel.keys()].filter((l) => !prev.byLabel.has(l)).length; + const bits = [ + broke.length ? `**${broke.length} broke** (${broke.slice(0, 2).join(', ')}${broke.length > 2 ? ', …' : ''})` : '', + fixed.length ? `${fixed.length} fixed` : '', + added ? `${added} new shape${added > 1 ? 's' : ''}` : '', + ].filter(Boolean); + return bits.length ? bits.join(' · ') : 'no change'; +} From a0fdaca222c23eab649fd3b942fa8594a6caa2de Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 19:20:42 -0400 Subject: [PATCH 35/66] fix: put the commit in the sweep filename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two sweeps on the same day collided — today's fresh engine sweep would have targeted 2026-09-14-engine.csv, which the 2026-09-14 sweep already occupies, and the truncation guard would have blocked it. Date + mode + commit fixes that and does two more things: every phase of one sweep derives the same path with no state file to remember which sweep is in progress, and the index can name the commit even for a file whose rows predate the commit column. Commit mid-sweep and later phases land in a new file, which is the honest outcome — the code changed underneath them. --- .../2026-09-14-engine-39de9fa.csv | 1 + scripts/query-matrix.mts | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 docs/query-matrix/2026-09-14-engine-39de9fa.csv diff --git a/docs/query-matrix/2026-09-14-engine-39de9fa.csv b/docs/query-matrix/2026-09-14-engine-39de9fa.csv new file mode 100644 index 0000000..594bab7 --- /dev/null +++ b/docs/query-matrix/2026-09-14-engine-39de9fa.csv @@ -0,0 +1 @@ +runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksFailed,chunksSkipped,chunksMax diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 6c7c293..96ea0db 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -59,7 +59,13 @@ const COMMIT = (() => { // `query-matrix/2026-09-14-engine.csv`, which named a moment rather than a date and went // stale the week after it was written. const DIR = 'docs/query-matrix'; -const OUT = process.env.QUERY_MATRIX_OUT ?? `${DIR}/${RUN_AT.slice(0, 10)}-${MODE}.csv`; +// Date, mode and commit. The commit is in the name for two reasons: two sweeps +// on the same day would otherwise collide (which happened the first time this +// layout was used), and every phase of one sweep derives the same path without +// needing a state file to remember which sweep is in progress. Commit mid-sweep +// and the remaining phases land in a new file — which is the honest outcome, +// since the code changed underneath them. +const OUT = process.env.QUERY_MATRIX_OUT ?? `${DIR}/${RUN_AT.slice(0, 10)}-${MODE}-${COMMIT}.csv`; // Regenerate the index and stop. Cheap, runs no queries. if (process.argv[2] === '--index') { @@ -271,7 +277,7 @@ function readSweeps(): Sweep[] { if (!existsSync(DIR)) return []; return readdirSync(DIR) .filter((f) => f.endsWith('.csv') && statSync(`${DIR}/${f}`).size > 0) - .sort() + .sort((a, b) => a.localeCompare(b) || statSync(`${DIR}/${a}`).mtimeMs - statSync(`${DIR}/${b}`).mtimeMs) .map((file) => { const lines = readFileSync(`${DIR}/${file}`, 'utf8').split('\n').filter(Boolean); const header = lines[0].split(','); @@ -296,8 +302,16 @@ function readSweeps(): Sweep[] { const worse = (a: string, b: string) => (a === 'error' || b === 'error' ? 'error' : a === 'empty' || b === 'empty' ? 'empty' : 'success'); byLabel.set(label, byLabel.has(label) ? worse(byLabel.get(label)!, status) : status); } - const [, date, mode] = file.match(/^(\d{4}-\d{2}-\d{2})-(.+)\.csv$/) ?? [, file, '?']; - return { file, date: date!, mode: mode!, commit: commit || 'unrecorded', byLabel }; + // `2026-09-14-engine-a119e16.csv` -> date, mode, commit. Older files have + // no commit in the name; fall back to the column, then to admitting it. + const m = file.match(/^(\d{4}-\d{2}-\d{2})-(.+?)(?:-([0-9a-f]{7,40}))?\.csv$/); + return { + file, + date: m?.[1] ?? file, + mode: m?.[2] ?? '?', + commit: m?.[3] || commit || 'unrecorded', + byLabel, + }; }); } From 9128aa9f4d58ee5859ac2e13e0d779b5debf01e4 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Mon, 14 Sep 2026 19:21:06 -0400 Subject: [PATCH 36/66] fix: engine-mode sweeps crashed on the first query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The progress line still printed `partialSlices`, a variable removed when the partial count was split into failed and skipped. Engine mode has been unable to complete a single query since — the CSV row is written before the log line, so it left exactly one row behind and then threw. Caught by running a sweep, which is the only thing that exercises this path. --- docs/query-matrix/2026-09-14-engine-39de9fa.csv | 1 - scripts/query-matrix.mts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 docs/query-matrix/2026-09-14-engine-39de9fa.csv diff --git a/docs/query-matrix/2026-09-14-engine-39de9fa.csv b/docs/query-matrix/2026-09-14-engine-39de9fa.csv deleted file mode 100644 index 594bab7..0000000 --- a/docs/query-matrix/2026-09-14-engine-39de9fa.csv +++ /dev/null @@ -1 +0,0 @@ -runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksFailed,chunksSkipped,chunksMax diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 96ea0db..b1069dc 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -153,7 +153,7 @@ async function runViaEngine( result.status, ms, rows, 0, errorClass, csv(detail), chunksFailed, chunksSkipped, chunksMax].join(',') + '\n', ); console.log( - `${matrix} ${label.padEnd(44).slice(0, 44)} ${result.status.padEnd(8)} ${String(ms).padStart(7)}ms rows=${String(rows).padStart(5)} chunks=${chunksMax} partial=${partialSlices}`, + `${matrix} ${label.padEnd(44).slice(0, 44)} ${result.status.padEnd(8)} ${String(ms).padStart(7)}ms rows=${String(rows).padStart(5)} chunks=${chunksMax} failed=${chunksFailed} skipped=${chunksSkipped}`, ); } From 6578707e2a979cb73c2327a917dc99a06234b82b Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 15 Sep 2026 10:58:08 -0400 Subject: [PATCH 37/66] docs: record the contaminated sweep, and stop the index lying about order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 14-hour sweep is committed with a note saying not to trust it, because the index honestly reports it as "25 broke" and that reads as a catastrophe rather than as a measurement of our own load. M4 spent eight hours on twenty queries and every phase after it inherited a degraded endpoint — M5 failed two dashboard questions at 1101s and 490s that the health check recorded at 14s and 19s the evening before. Two index bugs the sweep exposed: - **Order was by filename**, so two sweeps on the same day sorted wrongly (`-9128aa9.csv` precedes `.csv`) and the delta column came out inverted: shapes the newer sweep had fixed were reported as newly broken. Now ordered by the first runAt in the file, falling back to mtime for the pre-column files. - **No way to disqualify a sweep.** A `.note` beside the CSV now renders under the table, so the caveat sits next to the numbers it qualifies instead of in a document nobody opens first. That is the mistake QUERY-MATRIX.md Part 7.5 already made once. The sweep itself earned its keep twice over: it found engine mode had been crashing on its first query since partialSlices was split, and it is the evidence that the 300s step ceiling does not hold. --- .../2026-09-14-engine-9128aa9.csv | 125 ++++++++++++++++++ .../2026-09-14-engine-9128aa9.csv.note | 20 +++ docs/query-matrix/README.md | 27 +++- scripts/query-matrix.mts | 29 +++- 4 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 docs/query-matrix/2026-09-14-engine-9128aa9.csv create mode 100644 docs/query-matrix/2026-09-14-engine-9128aa9.csv.note diff --git a/docs/query-matrix/2026-09-14-engine-9128aa9.csv b/docs/query-matrix/2026-09-14-engine-9128aa9.csv new file mode 100644 index 0000000..adf0559 --- /dev/null +++ b/docs/query-matrix/2026-09-14-engine-9128aa9.csv @@ -0,0 +1,125 @@ +runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg,chunksFailed,chunksSkipped,chunksMax +2026-09-14T23:21,9128aa9,M1,"samples near(1) samples [ME]",samples,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,1897,4398,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"samples near(1) facilities [ME]",samples,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,16629,2273,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"samples near(1) waterBodies [ME]",samples,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,1721,2199,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"samples near(1) wells [ME]",samples,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,5885,4279,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"samples near(1) aquifers [ME]",samples,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,2023,2759,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"facilities near(1) samples [ME]",facilities,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,3228,1358,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"facilities near(1) facilities [ME]",facilities,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,2982,2976,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"facilities near(1) waterBodies [ME]",facilities,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,996,1591,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"facilities near(1) wells [ME]",facilities,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,3429,2900,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"facilities near(1) aquifers [ME]",facilities,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,2472,1728,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"waterBodies near(1) samples [ME]",waterBodies,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,2056,591,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"waterBodies near(1) facilities [ME]",waterBodies,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1158,1015,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"waterBodies near(1) waterBodies [ME]",waterBodies,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,3162,6612,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"waterBodies near(1) wells [ME]",waterBodies,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,9147,3553,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"waterBodies near(1) aquifers [ME]",waterBodies,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,1582,3165,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"wells near(1) samples [ME]",wells,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,54516,14897,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"wells near(1) facilities [ME]",wells,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,2400,25668,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"wells near(1) waterBodies [ME]",wells,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,2756,52861,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"wells near(1) wells [ME]",wells,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,9327,83038,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"wells near(1) aquifers [ME]",wells,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,3507,40080,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"aquifers near(1) samples [ME]",aquifers,near,1,samples,ME,"none",FIND_TARGET_IRIS,engine,success,8542,899,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"aquifers near(1) facilities [ME]",aquifers,near,1,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1393,1504,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"aquifers near(1) waterBodies [ME]",aquifers,near,1,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,704,3712,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"aquifers near(1) wells [ME]",aquifers,near,1,wells,ME,"none",FIND_TARGET_IRIS,engine,success,995,3659,0,ok,"",0,0,0 +2026-09-14T23:21,9128aa9,M1,"aquifers near(1) aquifers [ME]",aquifers,near,1,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,833,4972,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"samples downstream samples [ME]",samples,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,10646,3214,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"samples downstream facilities [ME]",samples,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,13555,2412,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"samples downstream waterBodies [ME]",samples,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,19306,2610,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"samples downstream wells [ME]",samples,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,29650,3202,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"samples downstream aquifers [ME]",samples,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,23254,2741,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"facilities downstream samples [ME]",facilities,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,17971,1657,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"facilities downstream facilities [ME]",facilities,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,308336,0,0,failed,"SPARQL timeout (429): Operation timed out. Last operation: Join on ?s2neighbor",0,0,16 +2026-09-14T23:23,9128aa9,M2,"facilities downstream waterBodies [ME]",facilities,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,223509,1608,0,ok-partial,"",1,0,16 +2026-09-14T23:23,9128aa9,M2,"facilities downstream wells [ME]",facilities,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,302239,1986,0,ok,"",0,0,16 +2026-09-14T23:23,9128aa9,M2,"facilities downstream aquifers [ME]",facilities,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,194273,1743,0,ok,"",0,0,16 +2026-09-14T23:23,9128aa9,M2,"waterBodies downstream samples [ME]",waterBodies,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,11476,1511,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"waterBodies downstream facilities [ME]",waterBodies,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1068534,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,16 +2026-09-14T23:23,9128aa9,M2,"waterBodies downstream waterBodies [ME]",waterBodies,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,65438,6095,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"waterBodies downstream wells [ME]",waterBodies,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,error,1099025,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-14T23:23,9128aa9,M2,"waterBodies downstream aquifers [ME]",waterBodies,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,788639,2661,0,ok-partial,"",0,7,16 +2026-09-14T23:23,9128aa9,M2,"wells downstream samples [ME]",wells,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,50790,28920,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"wells downstream facilities [ME]",wells,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,307324,26435,0,ok-partial,"",0,3,16 +2026-09-14T23:23,9128aa9,M2,"wells downstream waterBodies [ME]",wells,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,298088,44112,0,ok-partial,"",1,0,16 +2026-09-14T23:23,9128aa9,M2,"wells downstream wells [ME]",wells,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,341777,14936,0,ok-partial,"",1,10,16 +2026-09-14T23:23,9128aa9,M2,"wells downstream aquifers [ME]",wells,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,321213,39847,0,ok,"",0,0,16 +2026-09-14T23:23,9128aa9,M2,"aquifers downstream samples [ME]",aquifers,downstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,14004,2599,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"aquifers downstream facilities [ME]",aquifers,downstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,29797,3242,0,ok,"",0,0,0 +2026-09-14T23:23,9128aa9,M2,"aquifers downstream waterBodies [ME]",aquifers,downstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,159808,4192,0,ok-partial,"",1,0,16 +2026-09-14T23:23,9128aa9,M2,"aquifers downstream wells [ME]",aquifers,downstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,279301,4159,0,ok,"",0,0,16 +2026-09-14T23:23,9128aa9,M2,"aquifers downstream aquifers [ME]",aquifers,downstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,301406,3117,0,ok-partial,"",3,1,23 +2026-09-15T01:08,9128aa9,M3,"samples upstream samples [ME]",samples,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,12518,3221,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"samples upstream facilities [ME]",samples,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,14391,2739,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"samples upstream waterBodies [ME]",samples,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,11728,6072,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"samples upstream wells [ME]",samples,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,26239,47730,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"samples upstream aquifers [ME]",samples,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,12787,4650,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"facilities upstream samples [ME]",facilities,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,error,1888462,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T01:08,9128aa9,M3,"facilities upstream facilities [ME]",facilities,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,667593,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T01:08,9128aa9,M3,"facilities upstream waterBodies [ME]",facilities,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,257998,6168,0,ok-partial,"",1,0,16 +2026-09-15T01:08,9128aa9,M3,"facilities upstream wells [ME]",facilities,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,307088,37199,0,ok-partial,"",0,6,16 +2026-09-15T01:08,9128aa9,M3,"facilities upstream aquifers [ME]",facilities,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,232861,4698,0,ok,"",0,0,16 +2026-09-15T01:08,9128aa9,M3,"waterBodies upstream samples [ME]",waterBodies,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,9492,3064,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"waterBodies upstream facilities [ME]",waterBodies,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,13720,2770,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"waterBodies upstream waterBodies [ME]",waterBodies,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,22484,6504,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"waterBodies upstream wells [ME]",waterBodies,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,27243,51437,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"waterBodies upstream aquifers [ME]",waterBodies,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,15010,4764,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"wells upstream samples [ME]",wells,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,45085,3221,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"wells upstream facilities [ME]",wells,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,272145,2812,0,ok,"",0,0,16 +2026-09-15T01:08,9128aa9,M3,"wells upstream waterBodies [ME]",wells,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,290678,6466,0,ok-partial,"",1,0,16 +2026-09-15T01:08,9128aa9,M3,"wells upstream wells [ME]",wells,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,success,343277,32973,0,ok-partial,"",1,6,16 +2026-09-15T01:08,9128aa9,M3,"wells upstream aquifers [ME]",wells,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,success,307068,4768,0,ok,"",0,0,16 +2026-09-15T01:08,9128aa9,M3,"aquifers upstream samples [ME]",aquifers,upstream,,samples,ME,"none",FIND_TARGET_IRIS,engine,success,24929,2935,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"aquifers upstream facilities [ME]",aquifers,upstream,,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,18398,1919,0,ok,"",0,0,0 +2026-09-15T01:08,9128aa9,M3,"aquifers upstream waterBodies [ME]",aquifers,upstream,,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,1063826,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,16 +2026-09-15T01:08,9128aa9,M3,"aquifers upstream wells [ME]",aquifers,upstream,,wells,ME,"none",FIND_TARGET_IRIS,engine,error,986071,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T01:08,9128aa9,M3,"aquifers upstream aquifers [ME]",aquifers,upstream,,aquifers,ME,"none",FIND_TARGET_IRIS,engine,error,1076740,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(0) facilities [ME]",samples,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1347976,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(0) wells [ME]",samples,near,0,wells,ME,"none",FIND_TARGET_IRIS,engine,success,2813,3254,0,ok,"",0,0,0 +2026-09-15T03:37,9128aa9,M4,"wells near(0) facilities [ME]",wells,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,1107,5462,0,ok,"",0,0,0 +2026-09-15T03:37,9128aa9,M4,"waterBodies near(0) facilities [ME]",waterBodies,near,0,facilities,ME,"none",FIND_TARGET_IRIS,engine,success,507,352,0,ok,"",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(0) waterBodies [ME]",samples,near,0,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,success,639,709,0,ok,"",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(2) facilities [ME]",samples,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1779805,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(2) wells [ME]",samples,near,2,wells,ME,"none",FIND_TARGET_IRIS,engine,error,1869081,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"wells near(2) facilities [ME]",wells,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1790972,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"waterBodies near(2) facilities [ME]",waterBodies,near,2,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,2095006,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(2) waterBodies [ME]",samples,near,2,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,1889011,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(3) facilities [ME]",samples,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1936941,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(3) wells [ME]",samples,near,3,wells,ME,"none",FIND_TARGET_IRIS,engine,error,1239174,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"wells near(3) facilities [ME]",wells,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,2047655,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"waterBodies near(3) facilities [ME]",waterBodies,near,3,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1887823,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(3) waterBodies [ME]",samples,near,3,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,2073841,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(4) facilities [ME]",samples,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1954842,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(4) wells [ME]",samples,near,4,wells,ME,"none",FIND_TARGET_IRIS,engine,error,1088531,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"wells near(4) facilities [ME]",wells,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,1968807,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"waterBodies near(4) facilities [ME]",waterBodies,near,4,facilities,ME,"none",FIND_TARGET_IRIS,engine,error,2036863,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T03:37,9128aa9,M4,"samples near(4) waterBodies [ME]",samples,near,4,waterBodies,ME,"none",FIND_TARGET_IRIS,engine,error,2047950,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Samples Near Agricultural Chemical Facilities in Maine",samples,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,64008,31,0,ok,"",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Samples Near Landfills & DOD Sites in Penobscot and Knox County",samples,near,1,facilities,23019|23013,"prebuilt",PIPELINE,engine,success,10841,61,0,ok,"",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County",waterBodies,near,1,facilities,23019|23013,"prebuilt",PIPELINE,engine,success,28220,103,0,ok,"",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Samples Downstream of Waste Treatment Facilities in Indiana",samples,downstream,,facilities,18,"prebuilt",PIPELINE,engine,error,1101215,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Maine Private Wells Near Landfills & DoD Sites",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,error,490020,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Maine Private Wells Near Wastewater Treatment Facilities",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,15860,2431,0,ok,"",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: Maine Private Wells Near Airports & Air Transportation Sites (AFFF)",wells,near,1,facilities,23,"prebuilt",PIPELINE,engine,success,33706,4425,0,ok,"",0,0,0 +2026-09-15T11:41,9128aa9,M5,"PREBUILT: PFHpA Groundwater Samples Downstream from Facilities in Cumberland County",samples,downstream,,facilities,23005,"prebuilt",PIPELINE,engine,success,159028,362,0,ok,"",0,0,3 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [17]",samples,downstream,,facilities,17,"none",FIND_TARGET_IRIS,engine,success,225067,58,0,ok,"",0,0,5 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [18]",samples,downstream,,facilities,18,"none",FIND_TARGET_IRIS,engine,success,19659,234,0,ok,"",0,0,0 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [25]",samples,downstream,,facilities,25,"none",FIND_TARGET_IRIS,engine,success,296403,216,0,ok,"",0,0,16 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [33]",samples,downstream,,facilities,33,"none",FIND_TARGET_IRIS,engine,error,912577,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [01]",samples,downstream,,facilities,01,"none",FIND_TARGET_IRIS,engine,error,945830,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T12:13,9128aa9,M6,"samples downstream facilities [50]",samples,downstream,,facilities,50,"none",FIND_TARGET_IRIS,engine,success,36134,17,0,ok,"",0,0,0 +2026-09-15T12:54,9128aa9,M7,"samples near facilities [NO REGION]",samples,near,1,facilities,none,"none",FIND_TARGET_IRIS,engine,success,1544,4770,0,ok,"",0,0,0 +2026-09-15T12:54,9128aa9,M7,"samples downstream facilities [NO REGION]",samples,downstream,,facilities,none,"none",FIND_TARGET_IRIS,engine,error,1075258,0,0,failed,"SPARQL timeout (0): No response within 60s",0,0,0 +2026-09-15T12:54,9128aa9,M7,"wells near facilities [NO REGION]",wells,near,1,facilities,none,"none",FIND_TARGET_IRIS,engine,success,32370,219026,0,ok,"",0,0,0 +2026-09-15T13:12,9128aa9,M8,"substance filter (PFOS)",samples,near,1,facilities,ME,"substance",FIND_TARGET_IRIS,engine,success,301018,70,0,ok-partial,"",0,15,16 +2026-09-15T13:12,9128aa9,M8,"material filter (GW)",samples,near,1,facilities,ME,"material",FIND_TARGET_IRIS,engine,empty,12739,0,0,empty,"No results at step: Finding nearby samples",0,0,0 +2026-09-15T13:12,9128aa9,M8,"concentration range 10-1000",samples,near,1,facilities,ME,"range",FIND_TARGET_IRIS,engine,success,1793,947,0,ok,"",0,0,0 +2026-09-15T13:12,9128aa9,M8,"exclude non-detects",samples,near,1,facilities,ME,"nondetect",FIND_TARGET_IRIS,engine,success,2231,1892,0,ok,"",0,0,0 +2026-09-15T13:12,9128aa9,M8,"substance + downstream",samples,downstream,,facilities,ME,"substance+ds",FIND_TARGET_IRIS,engine,success,314751,9,0,ok-partial,"",0,20,22 +2026-09-15T13:12,9128aa9,M8,"NAICS 2-digit (whole sector 31)",samples,near,1,facilities,ME,"naics-sector",FIND_TARGET_IRIS,engine,success,12646,334,0,ok,"",0,0,0 +2026-09-15T13:12,9128aa9,M8,"aquifer type filter",samples,near,1,aquifers,ME,"aquifer-type",FIND_TARGET_IRIS,engine,success,30421,2759,0,ok,"",0,0,0 +2026-09-15T13:12,9128aa9,M8,"waterbody ftype filter",samples,near,1,waterBodies,ME,"wb-ftype",FIND_TARGET_IRIS,engine,success,2352,1583,0,ok,"",0,0,0 +2026-09-15T13:24,9128aa9,M9,"samples near(1) facilities [1 county (Cumberland)]",samples,near,1,facilities,1 county (Cumberland),"none",FIND_TARGET_IRIS,engine,success,1278,430,0,ok,"",0,0,0 +2026-09-15T13:24,9128aa9,M9,"samples near(1) facilities [3 counties]",samples,near,1,facilities,3 counties,"none",FIND_TARGET_IRIS,engine,success,1449,1048,0,ok,"",0,0,0 +2026-09-15T13:24,9128aa9,M9,"samples downstream facilities [1 county (Cumberland)]",samples,downstream,,facilities,1 county (Cumberland),"none",FIND_TARGET_IRIS,engine,success,10653,339,0,ok,"",0,0,0 +2026-09-15T13:24,9128aa9,M9,"samples downstream facilities [3 counties]",samples,downstream,,facilities,3 counties,"none",FIND_TARGET_IRIS,engine,success,15336,902,0,ok,"",0,0,0 diff --git a/docs/query-matrix/2026-09-14-engine-9128aa9.csv.note b/docs/query-matrix/2026-09-14-engine-9128aa9.csv.note new file mode 100644 index 0000000..a197ea2 --- /dev/null +++ b/docs/query-matrix/2026-09-14-engine-9128aa9.csv.note @@ -0,0 +1,20 @@ +**Do not read the 29 failures as real.** This sweep measured its own load. + +M4 (the multi-hop distance sweep) ran for **eight hours on twenty queries**, +recording 1348-2095s each against a 300s step ceiling — recorded time equals +wall time, so those are genuine elapsed seconds, not a suspended process. Every +phase after M4 inherited a degraded endpoint: M5 failed two *dashboard* +questions at 1101s and 490s that `docs/health/history.jsonl` shows succeeding at +**14s and 19s** the evening before. + +What this sweep is good for: it proved engine mode had been crashing on its +first query since `partialSlices` was split into failed/skipped, and it is the +evidence that the 300s ceiling does not hold. Both are worth more than the CSV. + +What it is not good for: any pass/fail or timing comparison. Re-run once the +ceiling is fixed, under `caffeinate -i` or in Actions so it is not hostage to +one laptop, and let the new file supersede this one. + +The sweep also split across two files at UTC midnight — `runAt` is UTC while the +runner logged local time — and was merged back by hand. The runner should fix +the output path once and export it, as the warm-sweep runner does. diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md index 9774aa2..74ab21a 100644 --- a/docs/query-matrix/README.md +++ b/docs/query-matrix/README.md @@ -16,7 +16,32 @@ engine change. The two are not comparable row for row. | Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | | --- | --- | --- | ---: | ---: | ---: | --- | +| [`2026-09-14`](./2026-09-14-engine-9128aa9.csv) | engine | `9128aa9` | 124 | 94 | 29 | **25 broke** (waterBodies downstream facilities [ME], waterBodies downstream wells [ME], …) · 5 fixed | | [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | -Generated 2026-09-14. +## Notes + +**[`2026-09-14-engine-9128aa9.csv`](./2026-09-14-engine-9128aa9.csv)** — **Do not read the 29 failures as real.** This sweep measured its own load. + +M4 (the multi-hop distance sweep) ran for **eight hours on twenty queries**, +recording 1348-2095s each against a 300s step ceiling — recorded time equals +wall time, so those are genuine elapsed seconds, not a suspended process. Every +phase after M4 inherited a degraded endpoint: M5 failed two *dashboard* +questions at 1101s and 490s that `docs/health/history.jsonl` shows succeeding at +**14s and 19s** the evening before. + +What this sweep is good for: it proved engine mode had been crashing on its +first query since `partialSlices` was split into failed/skipped, and it is the +evidence that the 300s ceiling does not hold. Both are worth more than the CSV. + +What it is not good for: any pass/fail or timing comparison. Re-run once the +ceiling is fixed, under `caffeinate -i` or in Actions so it is not hostage to +one laptop, and let the new file supersede this one. + +The sweep also split across two files at UTC midnight — `runAt` is UTC while the +runner logged local time — and was merged back by hand. The runner should fix +the output path once and export it, as the warm-sweep runner does. + + +Generated 2026-09-15. diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index b1069dc..1d81f90 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -277,8 +277,13 @@ function readSweeps(): Sweep[] { if (!existsSync(DIR)) return []; return readdirSync(DIR) .filter((f) => f.endsWith('.csv') && statSync(`${DIR}/${f}`).size > 0) - .sort((a, b) => a.localeCompare(b) || statSync(`${DIR}/${a}`).mtimeMs - statSync(`${DIR}/${b}`).mtimeMs) - .map((file) => { + // Order by when the sweep actually ran, not by filename. Two sweeps on the + // same day sort wrongly by name — `-9128aa9.csv` precedes `.csv` — which + // silently inverted the delta column: shapes the newer sweep had fixed were + // reported as newly broken. + .map((file) => ({ file, at: sweepStartedAt(file) })) + .sort((a, b) => a.at.localeCompare(b.at)) + .map(({ file }) => { const lines = readFileSync(`${DIR}/${file}`, 'utf8').split('\n').filter(Boolean); const header = lines[0].split(','); const iCommit = header.indexOf('commit'); @@ -315,6 +320,14 @@ function readSweeps(): Sweep[] { }); } +// When a sweep ran. The first row's runAt is authoritative; files written +// before that column existed fall back to their mtime. +function sweepStartedAt(file: string): string { + const first = readFileSync(`${DIR}/${file}`, 'utf8').split('\n')[1] ?? ''; + const stamp = first.split(',')[0]; + return /^\d{4}-\d{2}-\d{2}T/.test(stamp) ? stamp : new Date(statSync(`${DIR}/${file}`).mtimeMs).toISOString(); +} + function writeIndex(): void { const sweeps = readSweeps(); const out = [ @@ -348,6 +361,18 @@ function writeIndex(): void { ); } + // A sweep can be invalid for reasons no column can express — the endpoint was + // under load, a phase ran away, the run spanned an outage. Drop a `.note` + // file beside the CSV and it shows up here, next to the numbers it qualifies, + // rather than in a document nobody opens before trusting a figure. + const noted = sweeps.filter((x) => existsSync(`${DIR}/${x.file}.note`)).reverse(); + if (noted.length) { + out.push('', '## Notes', ''); + for (const x of noted) { + out.push(`**[\`${x.file}\`](./${x.file})** — ${readFileSync(`${DIR}/${x.file}.note`, 'utf8').trim()}`, ''); + } + } + out.push('', `Generated ${new Date().toISOString().slice(0, 10)}.`, ''); writeFileSync(`${DIR}/README.md`, out.join('\n')); console.log(`Wrote ${DIR}/README.md — ${sweeps.length} sweep(s).`); From 15baaf358de8b237aa660845e0c70273bde01e16 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 15 Sep 2026 11:09:32 -0400 Subject: [PATCH 38/66] docs: record the contaminated sweep, and stop the index lying about order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The overnight re-sweep is unusable: M4 spent 484 minutes on 20 queries against a 300s step ceiling, and every phase after it measured a degraded endpoint — M5 failed two dashboard questions that health/history.jsonl shows succeeding at 14s and 19s hours earlier. Kept as 2026-09-14-engine-contaminated-9128aa9.csv rather than deleted, because it is the evidence for the ceiling overrun. Naming it that way also keeps it out of the 'engine' series, so the index does not compute a delta against September from numbers that do not mean anything. Part 7.6 records what happened, including the two mechanical faults already fixed (engine mode crashing on partialSlices, and a sweep splitting across two files at UTC midnight) and what to establish before re-running. --- docs/QUERY-MATRIX.md | 45 +++++++++++++++++++ ...026-09-14-engine-contaminated-9128aa9.csv} | 0 docs/query-matrix/README.md | 26 +---------- 3 files changed, 46 insertions(+), 25 deletions(-) rename docs/query-matrix/{2026-09-14-engine-9128aa9.csv => 2026-09-14-engine-contaminated-9128aa9.csv} (100%) diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index fb11c5e..2a2f6f2 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -591,6 +591,51 @@ what moved between one sweep and the next. --- +## Part 7.6 — The 2026-09-14 re-sweep, and why it is unusable + +A full engine sweep was run overnight to supersede 7.5's stale CSV. It is kept +as `query-matrix/2026-09-14-engine-contaminated-9128aa9.csv` — named for what it +is, so nobody reads its 29 failures as measurements. What went wrong is worth +recording, because it is a trap anyone re-running this will hit. + +**The step ceiling did not hold, and one phase ate eight hours.** M4 (the +multi-hop distance sweep) spent 484 minutes on 20 queries, 16 of which failed: + +| Shape | Recorded | +| --- | --- | +| `waterBodies near(2) facilities [ME]` | 2095s | +| `samples near(3) waterBodies [ME]` | 2074s | +| `wells near(3) facilities [ME]` | 2048s | + +`STEP_CEILING_MS` is 300s and these are single-step runs, so the expected bound +is ~300s plus one in-flight slice. Recorded time equals wall-clock time for +every phase, so these are genuine elapsed seconds, not a suspended process. +**Cause not yet established.** `divide()` issuing its own probe queries after the +ceiling check accounts for roughly 11 minutes per iteration, not 35. + +**Everything after M4 inherited a degraded endpoint.** M5 failed two *dashboard* +questions at 1101s and 490s which `health/history.jsonl` records succeeding at +14s and 19s the evening before. Once a phase runs away, every later phase is +measuring our own load — exactly what the harness header warns about. + +**Two mechanical faults, both fixed:** + +- Engine mode crashed on its first query: the progress line still referenced + `partialSlices`, removed when the count was split into failed/skipped. Engine + mode had been unusable since that commit, which is why 7.5's CSV could never + have been refreshed. +- The sweep split across two files. `runAt` is UTC and the runner logs local + time, so a sweep starting at 19:21 local crossed UTC midnight at phase M3 and + began writing to the next day's filename. Fix: the runner computes + `QUERY_MATRIX_OUT` once and exports it, so every phase shares one path. + +**Before re-running:** find out why the ceiling misses, run under +`caffeinate -i` or in Actions rather than on a laptop, and treat any phase that +exceeds its expected bound as a reason to stop the sweep rather than push on — +a runaway phase invalidates everything after it. + +--- + ## Part 8 — Distance-bounded traces (2026-09-14) PR #41 added an optional `maxDistanceKm` to downstream and upstream questions: diff --git a/docs/query-matrix/2026-09-14-engine-9128aa9.csv b/docs/query-matrix/2026-09-14-engine-contaminated-9128aa9.csv similarity index 100% rename from docs/query-matrix/2026-09-14-engine-9128aa9.csv rename to docs/query-matrix/2026-09-14-engine-contaminated-9128aa9.csv diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md index 74ab21a..2280932 100644 --- a/docs/query-matrix/README.md +++ b/docs/query-matrix/README.md @@ -16,32 +16,8 @@ engine change. The two are not comparable row for row. | Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | | --- | --- | --- | ---: | ---: | ---: | --- | -| [`2026-09-14`](./2026-09-14-engine-9128aa9.csv) | engine | `9128aa9` | 124 | 94 | 29 | **25 broke** (waterBodies downstream facilities [ME], waterBodies downstream wells [ME], …) · 5 fixed | +| [`2026-09-14`](./2026-09-14-engine-contaminated-9128aa9.csv) | engine-contaminated | `9128aa9` | 124 | 94 | 29 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | -## Notes - -**[`2026-09-14-engine-9128aa9.csv`](./2026-09-14-engine-9128aa9.csv)** — **Do not read the 29 failures as real.** This sweep measured its own load. - -M4 (the multi-hop distance sweep) ran for **eight hours on twenty queries**, -recording 1348-2095s each against a 300s step ceiling — recorded time equals -wall time, so those are genuine elapsed seconds, not a suspended process. Every -phase after M4 inherited a degraded endpoint: M5 failed two *dashboard* -questions at 1101s and 490s that `docs/health/history.jsonl` shows succeeding at -**14s and 19s** the evening before. - -What this sweep is good for: it proved engine mode had been crashing on its -first query since `partialSlices` was split into failed/skipped, and it is the -evidence that the 300s ceiling does not hold. Both are worth more than the CSV. - -What it is not good for: any pass/fail or timing comparison. Re-run once the -ceiling is fixed, under `caffeinate -i` or in Actions so it is not hostage to -one laptop, and let the new file supersede this one. - -The sweep also split across two files at UTC midnight — `runAt` is UTC while the -runner logged local time — and was merged back by hand. The runner should fix -the output path once and export it, as the warm-sweep runner does. - - Generated 2026-09-15. From cbd8d3f1fc599d73007af38eed0c7c62faba63b8 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 15 Sep 2026 18:26:08 -0400 Subject: [PATCH 39/66] fix: the sample popup named substances by a different rule than the dropdown The dropdown fell back to the source parameter's name, the popup did not, so the same substance read as "10-H-Perfluorodecanoic acid" in one place and as a bare DTXSID10630918 in the other. 33 of the 172 DSSTox substances in the graph carry no label of their own; every one is named by the parameter that points at it with comptox:sameAsDSSToxSubstance. substanceLabel() now holds the whole priority order and both places call it. The popup query projects the label parts rather than picking a winner in SPARQL, and aggregates each one, so a substance with two labels can no longer duplicate its observation's row. Repeat observations of one substance within a sample are real: a fish tissue composite of 7 taxa has 7 values per substance, and the graph attaches the taxa to the sample rather than the observation, so nothing tells the rows apart. The table groups them onto one row instead of rendering 7 identical looking ones. --- docs/wiki/Dropdowns Substance.md | 13 +++ package.json | 1 + scripts/check-substance-labels.mts | 104 ++++++++++++++++++++++ src/components/Map/MapPopup.tsx | 6 +- src/constants/substances.ts | 39 ++++++++ src/engine/resultTransformer.ts | 30 +++++-- src/engine/templates/downstreamSamples.ts | 22 +++-- src/hooks/useDiscoveryQueries.ts | 18 +--- src/types/map.ts | 9 +- 9 files changed, 210 insertions(+), 32 deletions(-) create mode 100644 scripts/check-substance-labels.mts diff --git a/docs/wiki/Dropdowns Substance.md b/docs/wiki/Dropdowns Substance.md index 4edcb7b..c489cc0 100644 --- a/docs/wiki/Dropdowns Substance.md +++ b/docs/wiki/Dropdowns Substance.md @@ -157,6 +157,19 @@ at [`SampleFilters.tsx:22`](https://github.com/SAWGraph/explorer-app/blob/main/s Selecting an option stores both the substance URI and its display label on the question, so the Analysis Question sentence can say "PFOA" instead of a DSSTox URI. +### One rule, two places + +The whole priority order, `skos:altLabel`, then `rdfs:label`, then the source parameter's +name with `***retired***` resolved, then the DTXSID, lives in `substanceLabel()` in +`src/constants/substances.ts`. The map popup's sample table uses the same function. + +It did not always. The dropdown had the source parameter step and the popup did not, so the +same substance read as "10-H-Perfluorodecanoic acid" in the dropdown and as a bare +`DTXSID10630918` in the popup, which looked like a broken query rather than a missing label. +The popup's query now projects the label parts instead of picking a winner in SPARQL, and +aggregates each one, which also stops a substance with two labels from duplicating its +observation's row. `npm run check-substance-labels` asserts the order. + ## If it looks wrong **Exactly seven PFAS substances and no counts.** You are looking at `FALLBACK_SUBSTANCES`. diff --git a/package.json b/package.json index a34947f..765d4c4 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview", "warm-cache": "tsx scripts/warm-cache.mts", "check-cache-key": "tsx scripts/check-cache-key.mts", + "check-substance-labels": "tsx scripts/check-substance-labels.mts", "query-matrix": "tsx scripts/query-matrix.mts", "health-check": "tsx scripts/health-check.mts" }, diff --git a/scripts/check-substance-labels.mts b/scripts/check-substance-labels.mts new file mode 100644 index 0000000..323b6b0 --- /dev/null +++ b/scripts/check-substance-labels.mts @@ -0,0 +1,104 @@ +// Self-check for the substance naming rule and for the popup's per-substance +// grouping (src/constants/substances.ts, src/engine/resultTransformer.ts). +// +// npx tsx scripts/check-substance-labels.mts +// +// Both are silent when wrong. A drifting naming rule shows the same substance +// as "10-H-Perfluorodecanoic acid" in the filter dropdown and as a bare +// "DTXSID10630918" in the map popup, which reads as a broken query. Grouping +// that keys on the label instead of the URI merges two substances that happen +// to share a name; grouping that forgets to append merges away real results. +import assert from 'node:assert/strict'; +import { substanceLabel, resolveRetired } from '../src/constants/substances'; +import { buildSamplePointDetail } from '../src/engine/resultTransformer'; +import type { SparqlRow } from '../src/types/sparql'; + +let checks = 0; +function check(name: string, fn: () => void) { + fn(); + checks++; + void name; +} + +const PFDA = 'http://w3id.org/DSSTox/v1/DTXSID10630918'; + +// The naming rule, in priority order. +check('short form wins', () => + assert.equal( + substanceLabel({ uri: PFDA, shortLabel: 'PFDA', label: 'Perfluorodecanoic acid', paramLabel: 'x' }), + 'PFDA', + ), +); +check('full name when there is no short form', () => + assert.equal(substanceLabel({ uri: PFDA, label: 'Perfluorodecanoic acid' }), 'Perfluorodecanoic acid'), +); +// 33 of the 172 DSSTox substances in the graph carry no label of their own; +// every one of them is named by its source parameter. +check('source parameter names the unlabelled substances', () => + assert.equal( + substanceLabel({ uri: PFDA, paramLabel: '10-H-Perfluorodecanoic acid' }), + '10-H-Perfluorodecanoic acid', + ), +); +check('DTXSID is the last resort', () => assert.equal(substanceLabel({ uri: PFDA }), 'DTXSID10630918')); + +// Retired source parameters name their own replacement. +check('retired parameter resolves to its replacement', () => + assert.equal(resolveRetired('PFOS***retired***use Perfluorooctanesulfonate'), 'Perfluorooctanesulfonate'), +); +check('retired parameter with no replacement keeps its name', () => + assert.equal(resolveRetired('PFOS ***retired***'), 'PFOS'), +); + +// The popup's grouping. These rows mirror sample +// d.wqp.sample.INSTOR_WQX-AB35759FISHPREP at sample point INSTOR_WQX-8112: +// two observations of one substance, same date, same unit, differing only in +// value, which is what looked like a duplicated row. +const row = (over: Partial): SparqlRow => + ({ + sp: 'https://geoconnex.us/iow/wqp/INSTOR_WQX-8112', + spWKT: 'POINT(-86.9 39.7)', + samplePointName: 'UMK030-0023', + sample: 'sample.AB35759FISHPREP', + sampleIdentifier: 'INSTOR_WQX-AB35759.FISHPREP', + date: '2020-01-17', + unit_sym: 'μg/kg', + ...over, + }) as SparqlRow; + +const detail = buildSamplePointDetail([ + row({ observation: 'o1', substanceUri: PFDA, substanceParamLabel: '10-H-Perfluorodecanoic acid', result_value: '0.249' }), + row({ observation: 'o2', substanceUri: PFDA, substanceParamLabel: '10-H-Perfluorodecanoic acid', result_value: '0.285' }), + row({ observation: 'o3', substanceUri: 'http://w3id.org/DSSTox/v1/DTXSID3031864', substanceShortLabel: 'PFOS', result_value: '3.16' }), + // A non-detect: no numeric value, so it is not a result to list. + row({ observation: 'o4', substanceUri: 'http://w3id.org/DSSTox/v1/DTXSID3040148', substanceShortLabel: 'PFDS', result_value: 'non-detect' }), +]); + +assert.ok(detail, 'expected a detail object'); +check('one sample section', () => assert.equal(detail.samples.length, 1)); +const obs = detail.samples[0].observations; +check('repeat observations collapse to one row per substance', () => assert.equal(obs.length, 2)); +check('both values are kept', () => + assert.deepEqual(obs[0], { + substance: '10-H-Perfluorodecanoic acid', + substanceUri: PFDA, + results: [0.249, 0.285], + unit: 'μg/kg', + }), +); +check('grouping keys on the URI, not the label', () => assert.equal(obs[1].substance, 'PFOS')); +check('max is reported with the shared label', () => + assert.equal(detail.maxResult?.substance, 'PFOS'), +); +check('max is the largest value', () => assert.equal(detail.maxResult?.value, 3.16)); + +// Two substances sharing a display name must stay on separate rows. +const shared = buildSamplePointDetail([ + row({ observation: 'o1', substanceUri: 'http://w3id.org/DSSTox/v1/DTXSID1', substanceShortLabel: 'PFOS', result_value: '1' }), + row({ observation: 'o2', substanceUri: 'http://w3id.org/DSSTox/v1/DTXSID2', substanceShortLabel: 'PFOS', result_value: '2' }), +]); +check('same name, different URI, two rows', () => + assert.equal(shared?.samples[0].observations.length, 2), +); + +console.log(`substance labels: ${checks} checks passed`); diff --git a/src/components/Map/MapPopup.tsx b/src/components/Map/MapPopup.tsx index 649a028..9fb40c5 100644 --- a/src/components/Map/MapPopup.tsx +++ b/src/components/Map/MapPopup.tsx @@ -162,10 +162,10 @@ function SampleSection({ sample }: { sample: SampleRecord }) { - {sample.observations.map((obs, j) => ( - + {sample.observations.map((obs) => ( + {obs.substance} - {obs.result} {obs.unit} + {obs.results.join(', ')} {obs.unit} ))} diff --git a/src/constants/substances.ts b/src/constants/substances.ts index 1b8965e..ef3c8f3 100644 --- a/src/constants/substances.ts +++ b/src/constants/substances.ts @@ -5,6 +5,45 @@ export interface Substance { count?: number; } +// One naming rule for substances, used by both the filter dropdown and the +// sample popup. They disagreed before: the dropdown fell back to the source +// parameter's name while the popup did not, so the same substance showed as +// "10-H-Perfluorodecanoic acid" in the dropdown and as a bare "DTXSID10630918" +// in the popup. +// +// Most DSSTox substances carry their own labels, but 33 of the 172 in the graph +// carry none at all; every one of those is named by the source parameter that +// points at it with comptox:sameAsDSSToxSubstance. Nothing is left bare. +export interface SubstanceLabelParts { + uri: string; + // skos:altLabel on the DSSTox substance, the short form ("PFOS") + shortLabel?: string; + // rdfs:label on the DSSTox substance, the full chemical name + label?: string; + // rdfs:label on the source parameter that declares sameAsDSSToxSubstance + paramLabel?: string; +} + +// Some source parameters carry a superseded name of the form +// "***retired***use ", which names its own replacement. +export function resolveRetired(label?: string): string | undefined { + if (!label) return undefined; + if (label.includes('***retired***use ')) return label.split('***retired***use ')[1].trim(); + return label.split('***retired***')[0].replace(/[\s\-,]+$/, ''); +} + +// Prefer the short form, then the full name, then the source parameter's name, +// and fall back to the DTXSID. +export function substanceLabel(parts: SubstanceLabelParts): string { + return ( + parts.shortLabel || + parts.label || + resolveRetired(parts.paramLabel) || + parts.uri.split('/').pop() || + parts.uri + ); +} + // Fallback substances if discovery query fails (DSSTox URIs) export const FALLBACK_SUBSTANCES: Substance[] = [ { uri: 'http://w3id.org/DSSTox/v1/DTXSID3031864', label: 'Perfluorooctanesulfonic acid', shortLabel: 'PFOS' }, diff --git a/src/engine/resultTransformer.ts b/src/engine/resultTransformer.ts index 9178fa6..5c48825 100644 --- a/src/engine/resultTransformer.ts +++ b/src/engine/resultTransformer.ts @@ -1,6 +1,7 @@ import type { SparqlRow } from '../types/sparql'; import type { MapFeature, SamplePointDetail, SampleRecord, SampleObservation } from '../types/map'; import type { LatLngExpression } from 'leaflet'; +import { substanceLabel } from '../constants/substances'; function parseWKTPoint(wkt: string): LatLngExpression | null { const match = wkt.match(/POINT\s*\(\s*([-\d.]+)\s+([-\d.]+)\s*\)/i); @@ -235,22 +236,37 @@ export function buildSamplePointDetail(rows: SparqlRow[]): SamplePointDetail | n for (const [sampleUri, sampleRows] of bySample) { const first = sampleRows[0]; - const observations: SampleObservation[] = []; + // One row per substance, not per observation: see SampleObservation. + const bySubstance = new Map(); for (const r of sampleRows) { const val = parseFloat(r.result_value); if (isNaN(val)) continue; - observations.push({ - substance: r.substance || '', - result: val, - unit: r.unit_sym || '', + const uri = r.substanceUri || ''; + const substance = substanceLabel({ + uri, + shortLabel: r.substanceShortLabel, + label: r.substanceLabel, + paramLabel: r.substanceParamLabel, }); + const existing = bySubstance.get(uri); + if (existing) { + existing.results.push(val); + } else { + bySubstance.set(uri, { + substance, + substanceUri: uri, + results: [val], + unit: r.unit_sym || '', + }); + } + // Track overall max if (!maxResult || val > maxResult.value) { maxResult = { - substance: r.substance || '', + substance, value: val, unit: r.unit_sym || '', sampleId: first.sampleIdentifier || '', @@ -259,6 +275,8 @@ export function buildSamplePointDetail(rows: SparqlRow[]): SamplePointDetail | n } } + const observations = [...bySubstance.values()]; + samples.push({ sampleUri, sampleId: first.sampleIdentifier || '', diff --git a/src/engine/templates/downstreamSamples.ts b/src/engine/templates/downstreamSamples.ts index cb1a108..7acdce6 100644 --- a/src/engine/templates/downstreamSamples.ts +++ b/src/engine/templates/downstreamSamples.ts @@ -44,8 +44,10 @@ export function buildSampleRetrievalByIriQuery( `; } -// ?substance is the displayed label (URI projection conflicts with the label -// path on observations). Substance URI filter is applied via ?substanceUri. +// Projects the substance's label parts rather than one display label: the +// naming rule lives in substanceLabel() so the popup and the filter dropdown +// cannot drift apart again. Aggregating them (SAMPLE/MIN) also keeps a +// substance with two labels from duplicating its observation's row. export function buildSampleDetailByIriQuery( spIris: string[], filters?: SampleFilters, @@ -68,7 +70,10 @@ export function buildSampleDetailByIriQuery( (GROUP_CONCAT(DISTINCT ?sampleId; separator="; ") as ?sampleIdentifier) ?observation ?date - ?substance + ?substanceUri + (SAMPLE(?shortLabel) as ?substanceShortLabel) + (SAMPLE(?fullLabel) as ?substanceLabel) + (MIN(?paramLabel) as ?substanceParamLabel) ?result_value ?unit_sym (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator=", ") as ?sampleType) @@ -85,9 +90,10 @@ export function buildSampleDetailByIriQuery( coso:ofDSSToxSubstance ?substanceUri ; coso:hasResult ?result . ${substanceClause} - OPTIONAL { ?substanceUri skos:altLabel ?altLabel } - OPTIONAL { ?substanceUri rdfs:label ?rdfLabel } - BIND(COALESCE(?altLabel, ?rdfLabel, REPLACE(STR(?substanceUri), "^.*[#/]", "")) AS ?substance) + OPTIONAL { ?substanceUri skos:altLabel ?shortLabel } + OPTIONAL { ?substanceUri rdfs:label ?fullLabel } + OPTIONAL { ?sourceParam comptox:sameAsDSSToxSubstance ?substanceUri ; + rdfs:label ?paramLabel } ?result coso:measurementUnit ?unit . ${resultValueClauses()} OPTIONAL { ?unit qudt:symbol ?unit_sym0 } @@ -96,7 +102,7 @@ export function buildSampleDetailByIriQuery( OPTIONAL { ?sample dcterms:identifier ?sampleId } ${filterClauses} } - GROUP BY ?sp ?spWKT ?sample ?observation ?date ?substance ?result_value ?unit_sym - ORDER BY ?sp ?sample ?substance DESC(?date) + GROUP BY ?sp ?spWKT ?sample ?observation ?date ?substanceUri ?result_value ?unit_sym + ORDER BY ?sp ?sample ?substanceUri DESC(?date) `; } diff --git a/src/hooks/useDiscoveryQueries.ts b/src/hooks/useDiscoveryQueries.ts index db9afb7..8053703 100644 --- a/src/hooks/useDiscoveryQueries.ts +++ b/src/hooks/useDiscoveryQueries.ts @@ -12,7 +12,7 @@ import { buildDiscoverMaineUsesQuery, } from '../engine/templates/regions'; import { FALLBACK_NAICS, type NaicsIndustry } from '../constants/naics'; -import { FALLBACK_SUBSTANCES, type Substance } from '../constants/substances'; +import { FALLBACK_SUBSTANCES, substanceLabel, type Substance } from '../constants/substances'; import { FALLBACK_MATERIAL_TYPES, MATERIAL_GROUP_BY_PRIO, type MaterialType } from '../constants/materialTypes'; import { FALLBACK_WELL_CLASSIFICATIONS, @@ -105,14 +105,6 @@ function regionKey(region?: RegionParam): string { return codes.join(','); } -// Some source parameters carry a superseded name of the form -// "***retired***use ", which names its own replacement. -function resolveRetired(label?: string): string | undefined { - if (!label) return undefined; - if (label.includes('***retired***use ')) return label.split('***retired***use ')[1].trim(); - return label.split('***retired***')[0].replace(/[\s\-,]+$/, ''); -} - export function useSubstances(region?: RegionParam) { const key = regionKey(region); return useQuery({ @@ -125,11 +117,9 @@ export function useSubstances(region?: RegionParam) { if (rows.length === 0) return key ? [] : FALLBACK_SUBSTANCES; return rows.map((r) => ({ uri: r.substance, - label: - r.label || - resolveRetired(r.param_label) || - r.substance.split('/').pop() || - r.substance, + // The shared rule, minus the short form: SampleFilters prefers + // shortLabel itself when rendering an option. + label: substanceLabel({ uri: r.substance, label: r.label, paramLabel: r.param_label }), shortLabel: r.short_label, count: r.num ? Number(r.num) : undefined, })); diff --git a/src/types/map.ts b/src/types/map.ts index 7d16624..321eea6 100644 --- a/src/types/map.ts +++ b/src/types/map.ts @@ -17,7 +17,14 @@ export interface MapFeature { export interface SampleObservation { substance: string; - result: number; + substanceUri: string; + // One entry per coso:ContaminantObservation. A substance can legitimately + // have more than one result within a single sample: WQP records repeat + // measurements (a fish tissue composite of two taxa, for instance) as + // separate observations that differ only in value, with no property that + // tells them apart. Listing them on one row keeps them from reading as + // duplicated rows. + results: number[]; unit: string; } From c35d72247382481f0fb7e43fc4e72eaf537f37f2 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 15 Sep 2026 20:01:12 -0400 Subject: [PATCH 40/66] fix: pipeline step labels named only one of the two blocks Reported as a wrong-ordering bug: the first notification on "samples in Indiana downstream of airport facilities" said "Finding downstream samples", which read as though the airports had not been queried yet. The order is correct. That step is a single fused federated query that resolves the facilities, the hydrology trace and the samples together, and projects only the samples. Naming one side hid the other. Every discovery label now names both blocks, in the words of the question the user asked: "Finding samples downstream of facilities" and "Finding facilities with samples downstream of them". The label is keyed off the block a step returns, not off its target/anchor role, because that mapping flips for upstream questions and the labels would otherwise come out swapped for a third of the question space. The hydrate labels drop the planner's "target"/"anchor" jargon, and the entity nouns now come from questionGenerator's vocabulary, so waterBodies renders as "surface water bodies" rather than the raw type name. check-step-labels asserts all 108 entity x entity x relationship shapes. The dashboard only exercises 4 of them and never exercises upstream. --- docs/QUERY-MATRIX.md | 12 +-- package.json | 1 + scripts/check-step-labels.mts | 181 +++++++++++++++++++++++++++++++++ src/engine/planner.ts | 40 +++++++- src/utils/questionGenerator.ts | 38 +++++-- 5 files changed, 254 insertions(+), 18 deletions(-) create mode 100644 scripts/check-step-labels.mts diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 2a2f6f2..8d1ec84 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -395,12 +395,12 @@ query the engine refuses is split into slices that fit and merged back together. Per-step, "ME samples downstream of airports", two sequential warm passes: ``` -Finding downstream samples 4,391ms 1,172 rows -Finding facilities with downstream samples 4,283ms 190 rows -Loading downstream stream geometries 1,070ms 4,661 rows -Loading target samples details 6,257ms 999 rows -Loading anchor facilities details 579ms 190 rows -Loading region boundaries 135ms 16 rows +Finding samples downstream of facilities 4,391ms 1,172 rows +Finding facilities with samples downstream of them 4,283ms 190 rows +Loading downstream stream geometries 1,070ms 4,661 rows +Loading details for samples 6,257ms 999 rows +Loading details for facilities 579ms 190 rows +Loading region boundaries 135ms 16 rows TOTAL 16.7s (second pass 16.1s) ``` diff --git a/package.json b/package.json index a34947f..40aea0b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview", "warm-cache": "tsx scripts/warm-cache.mts", "check-cache-key": "tsx scripts/check-cache-key.mts", + "check-step-labels": "tsx scripts/check-step-labels.mts", "query-matrix": "tsx scripts/query-matrix.mts", "health-check": "tsx scripts/health-check.mts" }, diff --git a/scripts/check-step-labels.mts b/scripts/check-step-labels.mts new file mode 100644 index 0000000..2871da9 --- /dev/null +++ b/scripts/check-step-labels.mts @@ -0,0 +1,181 @@ +// Self-check for the user-facing pipeline step labels (src/engine/planner.ts). +// +// npx tsx scripts/check-step-labels.mts +// +// The dashboard exercises 4 of the 108 entity x entity x relationship shapes +// the editor can build, and never exercises `upstream` at all. That matters +// here because the planner's anchor/target mapping flips for `upstream`: the +// step that returns block A is FIND_TARGET_IRIS for near and downstream, and +// FIND_ANCHOR_IRIS for upstream. A label keyed off the target/anchor role +// instead of off the block the step returns comes out swapped for a third of +// the question space, and nothing in the app would catch it. +// +// No network: planPipeline only builds query strings. +import assert from 'node:assert/strict'; +import { planPipeline } from '../src/engine/planner'; +import { entityTypeLabel } from '../src/utils/questionGenerator'; +import type { AnalysisQuestion, EntityType, SpatialRelationship } from '../src/types/query'; + +const ENTITY_TYPES: EntityType[] = [ + 'samples', + 'facilities', + 'waterBodies', + 'wells', + 'aquifers', + 'streams', +]; +// The three RelationshipSelector offers. 'within' is in the type union but is +// never selectable and never planned for. +const RELATIONSHIPS: SpatialRelationship['type'][] = ['near', 'downstream', 'upstream']; + +const question = ( + a: EntityType, + rel: SpatialRelationship['type'], + c: EntityType, + withRegion = true, +): AnalysisQuestion => + ({ + blockA: withRegion ? { type: a, region: { stateCode: '23' } } : { type: a }, + relationship: { type: rel, ...(rel === 'near' ? { hops: 1 } : {}) }, + blockC: { type: c }, + }) as AnalysisQuestion; + +let checks = 0; +let combinations = 0; + +for (const a of ENTITY_TYPES) { + for (const c of ENTITY_TYPES) { + for (const rel of RELATIONSHIPS) { + const where = `${a} ${rel} ${c}`; + const steps = planPipeline(question(a, rel, c)); + combinations++; + + const labels = steps.map((s) => s.description); + + // Nothing unlabelled, and no raw camelCase type name leaking through. + for (const label of labels) { + assert.ok(label.trim().length > 0, `empty description: ${where}`); + for (const type of ENTITY_TYPES) { + if (type !== entityTypeLabel(type)) { + assert.ok(!label.includes(type), `raw type name "${type}" in "${label}": ${where}`); + } + } + } + + // Both discovery labels name both blocks. + const aLabel = entityTypeLabel(a); + const cLabel = entityTypeLabel(c); + const target = steps.find((s) => s.type === 'FIND_TARGET_IRIS')!; + const anchor = steps.find((s) => s.type === 'FIND_ANCHOR_IRIS')!; + for (const step of [target, anchor]) { + assert.ok( + step.description.includes(aLabel) && step.description.includes(cLabel), + `discovery label names only one block: "${step.description}" (${where})`, + ); + } + + // The step that returns block A carries the block-A phrasing. This is the + // assertion that catches the upstream flip: "with ... them" marks the + // step that returns block C. + const returnsBlockA = rel === 'upstream' ? anchor : target; + const returnsBlockC = rel === 'upstream' ? target : anchor; + assert.ok( + !returnsBlockA.description.includes(' with '), + `step returning block A got the block C phrasing: "${returnsBlockA.description}" (${where})`, + ); + assert.ok( + returnsBlockC.description.includes(' with '), + `step returning block C got the block A phrasing: "${returnsBlockC.description}" (${where})`, + ); + + // Hydrate labels name their own entity type and drop the planner jargon. + for (const step of steps) { + if (step.type === 'HYDRATE_TARGET_BY_IRI' || step.type === 'HYDRATE_ANCHOR_BY_IRI') { + assert.ok( + !/\b(target|anchor)\b/.test(step.description), + `planner jargon in "${step.description}": ${where}`, + ); + } + } + + // Step set, per the conditions in buildFusedSteps. Pinned so a label + // change is never mistaken for a step change. + const types = steps.map((s) => s.type); + const wantsFlowlines = rel !== 'near' && a !== 'streams' && c !== 'streams'; + assert.equal( + types.includes('GET_FLOWLINE_GEOMETRIES'), + wantsFlowlines, + `flowline step presence wrong: ${where}`, + ); + assert.ok(types.includes('GET_REGION_BOUNDARIES'), `region step missing: ${where}`); + assert.equal(steps.length, wantsFlowlines ? 6 : 5, `step count wrong: ${where}`); + + // Without a region the boundary step goes away, and 4 is the floor. + const noRegion = planPipeline(question(a, rel, c, false)); + assert.ok( + !noRegion.some((s) => s.type === 'GET_REGION_BOUNDARIES'), + `region step present without a region: ${where}`, + ); + assert.equal(noRegion.length, wantsFlowlines ? 5 : 4, `step count wrong, no region: ${where}`); + + checks += 6; + } + } +} + +// The reported question, spelled out. planner.ts maps downstream to +// anchor=blockC, so FIND_TARGET_IRIS is the step that returns the samples. +const reported = planPipeline({ + blockA: { type: 'samples', region: { stateCode: '18' } }, + relationship: { type: 'downstream' }, + blockC: { type: 'facilities', facilityFilters: { industryCodes: ['488119', '481111'] } }, +} as AnalysisQuestion); +assert.deepEqual( + reported.map((s) => s.description), + [ + 'Finding samples downstream of facilities', + 'Finding facilities with samples downstream of them', + 'Loading downstream stream geometries', + 'Loading details for samples', + 'Loading details for facilities', + 'Loading region boundaries', + ], +); +checks++; + +// Same question upstream: the labels must swap steps, not swap words. +const up = planPipeline({ + blockA: { type: 'samples', region: { stateCode: '18' } }, + relationship: { type: 'upstream' }, + blockC: { type: 'facilities' }, +} as AnalysisQuestion); +assert.equal( + up.find((s) => s.type === 'FIND_ANCHOR_IRIS')!.description, + 'Finding samples upstream from facilities', +); +assert.equal( + up.find((s) => s.type === 'FIND_TARGET_IRIS')!.description, + 'Finding facilities with samples upstream from them', +); +checks += 2; + +// One sample of the table, for the eyeball pass that assertions cannot do. +if (process.argv.includes('--print')) { + for (const rel of RELATIONSHIPS) { + for (const [a, c] of [ + ['samples', 'facilities'], + ['waterBodies', 'facilities'], + ['facilities', 'facilities'], + ['streams', 'wells'], + ] as [EntityType, EntityType][]) { + console.log(`\n${a} ${rel} ${c}`); + for (const [i, s] of planPipeline(question(a, rel, c)).entries()) { + console.log(` Step ${i + 1}: ${s.description}`); + } + } + } +} + +console.log( + `step labels: ${combinations} combinations, ${checks} checks passed (--print to see the labels)`, +); diff --git a/src/engine/planner.ts b/src/engine/planner.ts index 41fe888..cc42743 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -1,6 +1,7 @@ import type { AnalysisQuestion, EntityBlock } from '../types/query'; import type { EndpointKey } from '../constants/endpoints'; import type { SparqlRow } from '../types/sparql'; +import { entityTypeLabel } from '../utils/questionGenerator'; import { buildFusedNearQuery, buildFusedHydrologyQuery, @@ -24,6 +25,16 @@ import { type Scope, } from './scope'; +// Reads the way the user chose it: these are the three labels in +// RELATIONSHIP_TYPES (src/components/QueryEditor/RelationshipSelector.tsx). +// 'within' is in the type union but is never offered and never planned for. +const RELATIONSHIP_PREPOSITION: Record = { + near: 'near', + downstream: 'downstream of', + upstream: 'upstream from', + within: 'within', +}; + export type PipelineStepType = | 'FIND_TARGET_IRIS' | 'FIND_ANCHOR_IRIS' @@ -102,7 +113,13 @@ function hydrateStep( block.type === 'samples' || block.type === 'wells' ? 'federation' : entityEndpoint(block); - const description = `Loading ${side === 'target' ? 'target' : 'anchor'} ${block.type} details`; + // "target"/"anchor" are planner concepts, and which block they name flips + // between relationship types, so they have no business in a user-facing + // label. Wells are the one case where this understates the work: their step + // re-derives the whole set server-side (see above) rather than loading + // details of what discovery found. The label describes what the step + // delivers, which is what the progress strip is for. + const description = `Loading details for ${entityTypeLabel(block.type)}`; return { type, @@ -253,18 +270,33 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { return halve(scope) ?? refineRegionScope(axisContext, scope); }; - const verb = relationship.type === 'near' ? 'nearby' : relationship.type; + // Both discovery steps are one fused query that resolves block A and block C + // together, so a label naming only one side reads as though the other had not + // been queried yet — which is exactly how it was reported. Name both, in the + // words of the question the user asked ("What are ?"). + // + // Which step returns which block is not fixed: the anchor/target mapping + // above puts block A on the target side for near and downstream, and on the + // anchor side for upstream. Key the label off the block the step returns, not + // off its target/anchor role, or the upstream labels come out swapped. + const prep = RELATIONSHIP_PREPOSITION[relationship.type]; + const aLabel = entityTypeLabel(blockA.type); + const cLabel = entityTypeLabel(blockC.type); + const findingA = `Finding ${aLabel} ${prep} ${cLabel}`; + const findingC = `Finding ${cLabel} with ${aLabel} ${prep} them`; + const targetIsBlockA = relationship.type !== 'upstream'; + steps.push({ type: 'FIND_TARGET_IRIS', endpoint: 'federation', - description: `Finding ${verb} ${targetBlock.type}`, + description: targetIsBlockA ? findingA : findingC, buildQuery: (_ctx, scope) => buildIriQuery('target', scope), divide: divideDiscovery, }); steps.push({ type: 'FIND_ANCHOR_IRIS', endpoint: 'federation', - description: `Finding ${anchorBlock.type} with ${verb} ${targetBlock.type}`, + description: targetIsBlockA ? findingC : findingA, buildQuery: (_ctx, scope) => buildIriQuery('anchor', scope), divide: divideDiscovery, }); diff --git a/src/utils/questionGenerator.ts b/src/utils/questionGenerator.ts index 40a689e..432aad6 100644 --- a/src/utils/questionGenerator.ts +++ b/src/utils/questionGenerator.ts @@ -1,6 +1,7 @@ import type { AnalysisQuestion, EntityBlock, + EntityType, SpatialRelationship, RegionFilter, SampleFilters, @@ -57,6 +58,27 @@ function describeConcentration(f?: SampleFilters): string { return ''; } +// The plural noun for an entity type, with no filters applied. Shared with the +// pipeline step labels (src/engine/planner.ts) so the progress strip says +// "surface water bodies" rather than the raw camelCase type name, and so the +// two places cannot drift into two different vocabularies. +export function entityTypeLabel(type: EntityType): string { + switch (type) { + case 'samples': + return 'samples'; + case 'facilities': + return 'facilities'; + case 'waterBodies': + return 'surface water bodies'; + case 'streams': + return 'streams'; + case 'wells': + return 'wells'; + case 'aquifers': + return 'aquifers'; + } +} + function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { switch (block.type) { case 'samples': { @@ -84,7 +106,7 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { const parts: string[] = []; if (subItems.length) parts.push(subItems.join('/')); if (matItems.length) parts.push(matItems.join('/')); - return (parts.length ? `${parts.join(' ')} samples` : 'samples') + conc; + return (parts.length ? `${parts.join(' ')} samples` : entityTypeLabel('samples')) + conc; } // Postfix form for long/all selections — reads naturally. @@ -106,7 +128,7 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { ), ); } - return (clauses.length ? `samples with ${clauses.join(' and ')}` : 'samples') + conc; + return (clauses.length ? `samples with ${clauses.join(' and ')}` : entityTypeLabel('samples')) + conc; } case 'facilities': { const codes = block.facilityFilters?.industryCodes; @@ -124,7 +146,7 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { // NAICS roots still trigger this even though Manufacturing/Retail/ // Transportation dedupe to fewer short labels. if (totals?.industries !== undefined && topLevel.length === totals.industries) { - return 'facilities'; + return entityTypeLabel('facilities'); } // Prefer curated short sector names; fall back to official label. const seen = new Set(); @@ -146,17 +168,17 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { ); return `${summary} facilities`; } - return 'facilities'; + return entityTypeLabel('facilities'); } case 'waterBodies': - return 'surface water bodies'; + return entityTypeLabel('waterBodies'); case 'streams': { const ftypes = block.streamFilters?.ftypes ?? []; - if (!ftypes.length) return 'streams'; + if (!ftypes.length) return entityTypeLabel('streams'); return `${summarize(ftypes, undefined, 'stream types', 'stream type', '/', 'any')} streams`; } case 'wells': - return 'wells'; + return entityTypeLabel('wells'); case 'aquifers': { const kinds = block.aquiferFilters?.aquiferTypes ?? []; const labels: Record = { @@ -167,7 +189,7 @@ function describeEntity(block: EntityBlock, totals?: QuestionTotals): string { if (kinds.length === 1 && labels[kinds[0]]) { return `${labels[kinds[0]]} aquifers`; } - return 'aquifers'; + return entityTypeLabel('aquifers'); } } } From f28f38906ace0e020e49aee6d66b6c5f7855cfd6 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Tue, 15 Sep 2026 22:23:17 -0400 Subject: [PATCH 41/66] fix: facility popups link to EPA FRS only Requested by Torsten: "just a reminder to have the links in the popups for facilities point to the EPA FRS sites only (not the w3id.org/fio links)". The facility name linked to its w3id.org/fio IRI with EPA FRS as a secondary link beside it, and the industry row linked to a w3id.org/fio/v1/naics IRI. Both resolve to raw ontology terms, which is not what someone clicking a facility on a map is after. The name now carries the FRS link and the NAICS code is plain text. The registry id is parsed strictly instead of by taking the last dot-separated segment. The graph holds d.Record.. entities under fio:ofIndustry whose trailing segment is a program id, and the old split would have built a confident link to the wrong FRS page. Checked against the endpoint: only FRS-Facility entities carry the geometry and label the facility query needs, so those records never reach a popup today, and 3,000 sampled renderable facilities all resolve to a registry id. A facility without one degrades to plain text rather than a dead link, since there is no second link left. --- src/components/Map/MapPopup.tsx | 42 +++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/components/Map/MapPopup.tsx b/src/components/Map/MapPopup.tsx index 649a028..953489c 100644 --- a/src/components/Map/MapPopup.tsx +++ b/src/components/Map/MapPopup.tsx @@ -175,6 +175,24 @@ function SampleSection({ sample }: { sample: SampleRecord }) { ); } +// The FRS registry id out of a facility IRI, e.g. +// http://w3id.org/fio/v1/epa-frs-data#d.FRS-Facility.110000344681 -> 110000344681. +// +// Matched strictly rather than by taking the last dot-separated segment. The +// graph also holds d.Record.. entities under fio:ofIndustry whose +// trailing segment is a program id, not a registry id, and a loose split would +// build a confident link to the wrong FRS page. Those records carry no geometry +// so they never reach a popup today, but this is now the only link here and +// there is no second link to fall back to. +function frsRegistryId(uri: string): string | null { + const match = uri.match(/#d\.FRS-Facility\.(\d+)$/); + return match ? match[1] : null; +} + +function frsUrl(registryId: string): string { + return `https://frs-public.epa.gov/ords/frs_public2/fii_query_detail.disp_program_facility?p_registry_id=${registryId}`; +} + function extractIlWellId(uri: string): string | null { const match = uri.match(/ISGS-Well\.(\d{12})/); return match ? match[1] : null; @@ -188,8 +206,12 @@ export function MapPopupContent({ feature, isOpen = true }: MapPopupProps) { } if (props.type === 'facility') { - const registryId = feature.id.split('.').pop() || ''; - const epaUrl = `https://frs-public.epa.gov/ords/frs_public2/fii_query_detail.disp_program_facility?p_registry_id=${registryId}`; + // EPA FRS is the only link in this popup, by request: the w3id.org/fio IRIs + // resolve to raw ontology terms, which is not what someone clicking a + // facility in a map popup is after. The facility name carries the link and + // the NAICS code is plain text. + const registryId = frsRegistryId(feature.id); + const label = `${props.name || 'Facility'}${registryId ? ` (${registryId})` : ''}`; return (
@@ -197,11 +219,12 @@ export function MapPopupContent({ feature, isOpen = true }: MapPopupProps) { @@ -209,9 +232,8 @@ export function MapPopupContent({ feature, isOpen = true }: MapPopupProps) { )} From 90f8e5d8a32470c7c40455772a13586293fa1bcf Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 16 Sep 2026 12:53:15 -0400 Subject: [PATCH 42/66] fix: upstream questions traced the wrong way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "What facilities are upstream from streams?" answered the mirror question: the streams upstream of the facilities. The fused templates only trace one way — the target comes out `direction` of the anchor — and the planner paired anchor=blockA (correct: the anchor must be the side the question filtered, or seeding scans every stream in the country and times out) with direction='upstream', which reads as "target C upstream of anchor A". The anchor is always the upstream side of the question, so the trace is always downstream from it. Verified on hydrologykg that hyf:downstreamFlowPath is oriented as named: for ?a downstreamFlowPath ?b, a's linestring ends exactly where b's begins. Correcting the direction makes the unbounded shape much heavier, and chooseAxis had no axis left for a single-county question — both probes are past PROBE_LIMIT and one county cannot be split further — so it failed outright after 64s. Added a last-resort bulk probe: a side with a region or filters is still enumerable above the cheap probe limit, and 411 Cook County facilities chunk into slices that run in seconds. Measured end to end through the real pipeline: Cook facilities upstream from streams 214s, 411 facilities + 1290 streams same, bounded to 10km / 50km 25s / 12s Cook facilities near streams 11s (unchanged) ME samples downstream from landfills 38s (unchanged) Also dropped the direction word from the flowline step's label: those geometries are the path between the two sides, traced downstream from the anchor whichever way the question was phrased. --- src/engine/planner.ts | 21 ++++++++++++--- src/engine/scope.ts | 59 +++++++++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/engine/planner.ts b/src/engine/planner.ts index cc42743..3697768 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -208,6 +208,10 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { // - near: anchor=blockC, target=blockA // - downstream: anchor=blockC, target=blockA (samples downstream of facilities) // - upstream: anchor=blockA, target=blockC + // + // The anchor is the side the fused templates seed from, and seeding an + // unfiltered side (every stream in the country) times out — so the anchor is + // the side the question filtered, which for an upstream question is block A. let anchorBlock: EntityBlock; let targetBlock: EntityBlock; if (relationship.type === 'upstream') { @@ -218,6 +222,14 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { targetBlock = blockA; } + // The templates only trace one way: the target comes out `direction` of the + // anchor. With the anchor always on the upstream side of the question — C for + // "A downstream from C", A for "A upstream from C" — the trace is always + // downstream from it. Passing 'upstream' here alongside anchor=blockA, as + // this did, answered the mirror question: streams upstream of the facilities + // instead of the facilities upstream of the streams. + const traceDirection = 'downstream' as const; + const anchorRegion = getRegionCodes(anchorBlock); const targetRegion = getRegionCodes(targetBlock); const anchorRegionOpt = anchorRegion.length ? anchorRegion : undefined; @@ -248,7 +260,7 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { } return buildFusedHydrologyQuery({ ...shared, - direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', + direction: traceDirection, maxDistanceKm: relationship.maxDistanceKm, }); }; @@ -309,12 +321,15 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { steps.push({ type: 'GET_FLOWLINE_GEOMETRIES', endpoint: 'federation', - description: `Loading ${relationship.type} stream geometries`, + // No direction in the name: these are the flowlines between the two + // sides, traced downstream from the anchor whichever way the question + // was phrased. + description: 'Loading stream geometries', // Runs after FIND_ANCHOR_IRIS so it can trace from the resolved anchors. buildQuery: (ctx, scope) => buildFusedFlowlineQuery({ anchor: anchorBlock, - direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', + direction: traceDirection, anchorIris: scope?.anchorIris ?? ctx.anchorIris, maxDistanceKm: relationship.maxDistanceKm, }), diff --git a/src/engine/scope.ts b/src/engine/scope.ts index 7c9b259..bb7f462 100644 --- a/src/engine/scope.ts +++ b/src/engine/scope.ts @@ -26,6 +26,11 @@ export interface Scope { // probe cheap; above it we fall through to the next axis. const PROBE_LIMIT = 201; +// Last-resort probe. A side with a region or filters can be enumerated in bulk +// even when it is past PROBE_LIMIT — 411 Cook County facilities chunk into 17 +// slices that each run in seconds, where the whole question times out. +const BULK_PROBE_LIMIT = 5001; + // Measured chunk sizes that comfortably clear the 30s budget: 25 anchor // facilities ran 2.8–3.0s, 20 Illinois samples 12.7s, 4 Maine counties ~6s each. // These are only starting points — any chunk that still fails gets halved. @@ -110,22 +115,37 @@ export async function chooseAxis(ctx: AxisContext): Promise { : ctx.anchorRegion?.length ? 'anchor' : null; - if (!side) return null; - - const codes = side === 'target' ? ctx.targetRegion! : ctx.anchorRegion!; - const counties = await expandToCounties(codes); - if (counties.length < 2) return null; - - // Name each slice after its county. When one of these fails the user sees - // "York County, Maine could not be answered" rather than "1 too large", - // which is the difference between a fact and a puzzle — the county is the - // one thing they can act on. - const names = countyNames(side === 'target' ? ctx.targetBlock : ctx.anchorBlock); - return chunk(counties, REGION_CHUNK).map((group) => ({ - label: group.map((code) => names.get(code) ?? code).join(', '), - regionCodes: group, - regionSide: side, - })); + + if (side) { + const codes = side === 'target' ? ctx.targetRegion! : ctx.anchorRegion!; + const counties = await expandToCounties(codes); + // Name each slice after its county. When one of these fails the user sees + // "York County, Maine could not be answered" rather than "1 too large", + // which is the difference between a fact and a puzzle — the county is the + // one thing they can act on. + if (counties.length >= 2) { + const names = countyNames(side === 'target' ? ctx.targetBlock : ctx.anchorBlock); + return chunk(counties, REGION_CHUNK).map((group) => ({ + label: group.map((code) => names.get(code) ?? code).join(', '), + regionCodes: group, + regionSide: side, + })); + } + } + + // A single county with too many entities to probe cheaply: enumerate them in + // bulk and chunk. Anchor first — that is the side the trace seeds from. + for (const s of ['anchor', 'target'] as const) { + const block = s === 'anchor' ? ctx.anchorBlock : ctx.targetBlock; + const region = s === 'anchor' ? ctx.anchorRegion : ctx.targetRegion; + const iris = await probeSide(block, region, ctx.endpoint, BULK_PROBE_LIMIT); + if (!iris) continue; + return chunk(iris, ENTITY_CHUNK).map((slice, i) => ({ + label: `${block.type} batch ${i + 1}`, + ...(s === 'anchor' ? { anchorIris: slice } : { targetIris: slice }), + })); + } + return null; } // Last resort for a region slice that is down to a single county and still too @@ -169,6 +189,7 @@ async function probeSide( block: EntityBlock, regionCodes: string[] | undefined, endpoint: EndpointKey, + limit: number = PROBE_LIMIT, ): Promise { // No region and no filters means every entity of that type in the graph — // certainly past the probe limit, and the probe itself would scan nationwide. @@ -176,12 +197,12 @@ async function probeSide( const rows = await executeSparql( endpoint, - buildEntityProbeQuery(block, regionCodes, PROBE_LIMIT), + buildEntityProbeQuery(block, regionCodes, limit), { cache: true }, ); const iris = [...new Set(rows.map((r) => r.iri).filter(Boolean))]; - // A full probe means "too many to enumerate" — we only know there are ≥200. - if (iris.length >= PROBE_LIMIT || iris.length < 2) return null; + // A full probe means "too many to enumerate" — we only know there are ≥limit. + if (iris.length >= limit || iris.length < 2) return null; return iris; } From 48192cacdd0f8281b933c8e0f4be9fc895813ded Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 16 Sep 2026 13:17:51 -0400 Subject: [PATCH 43/66] fix: well hydration re-derived the trace the old way buildFusedWellQuery is the one hydration path that re-derives the whole spatial trace server-side (a statewide well set is 20k+ IRIs, too many to inline), and it decided its own direction from relationship.type. With the discovery steps corrected to trace downstream from the anchor, it would have re-derived the mirror set: the well layer drawn on the map would not have been the wells discovery found. Before the direction fix the two agreed, both wrong; this keeps them agreeing and right. The planner now passes the direction it used, and relationshipMode is gone with its only caller. Added scripts/check-trace-direction.mts, which asserts across all 180 planner shapes that every query carrying hyf:downstreamFlowPathTC traces downstream from the seed, and that 'near' questions never trace at all. It reads the emitted SPARQL rather than the flag, so it covers all three builders that trace: discovery, the flowline layer, and well hydration. Confirmed it fails on the code before each of the two fixes. --- scripts/check-trace-direction.mts | 122 +++++++++++++++++++++++++++ src/engine/planner.ts | 8 +- src/engine/templates/fusedQueries.ts | 14 ++- 3 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 scripts/check-trace-direction.mts diff --git a/scripts/check-trace-direction.mts b/scripts/check-trace-direction.mts new file mode 100644 index 0000000..f021bbc --- /dev/null +++ b/scripts/check-trace-direction.mts @@ -0,0 +1,122 @@ +// Self-check for the direction of every hydrology trace the planner can build +// (src/engine/planner.ts, src/engine/templates/fusedQueries.ts). +// +// npx tsx scripts/check-trace-direction.mts +// +// The templates trace one way only: the target comes out `direction` of the +// anchor, seeded from the anchor's S2 cells. The planner puts the anchor on the +// upstream side of the question — block C for "A downstream from C", block A +// for "A upstream from C" — so every trace it builds must run *downstream from +// the seed*. Pairing anchor=blockA with direction='upstream', which the planner +// did until 2026-09-16, answered the mirror question for all 36 upstream +// shapes, and nothing in the app looked wrong enough to catch it: both layers +// still rendered, still near the right rivers. +// +// Three builders trace, and a question can use all three at once (discovery, +// the supporting flowline layer, and well hydration, which re-derives the trace +// server-side instead of hydrating by IRI). They have to agree, so this checks +// the SPARQL they emit rather than the direction flag they were handed. +// +// No network: the pipeline steps only build query strings. +import assert from 'node:assert/strict'; +import { planPipeline, type PipelineContext } from '../src/engine/planner'; +import type { AnalysisQuestion, EntityType, SpatialRelationship } from '../src/types/query'; + +const ENTITY_TYPES: EntityType[] = [ + 'samples', + 'facilities', + 'waterBodies', + 'wells', + 'aquifers', + 'streams', +]; +const HYDROLOGY: SpatialRelationship['type'][] = ['downstream', 'upstream']; + +// Every way the templates write the transitive closure. The chain variable that +// comes *first* is the upstream one, so the seed has to be on the left. +const FORWARD = [ + '?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline', // discovery, unbounded + '?upstream_flowline hyf:downstreamFlowPathTC ?_flMid', // discovery, bounded + '?_flSeed hyf:downstreamFlowPathTC ?_flMid', // flowline layer, bounded + 'hyf:downstreamFlowPathTC ?flowline', // flowline layer, unbounded +]; +const REVERSED = [ + '?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline', + '?_flEnd hyf:downstreamFlowPathTC ?_flMid', + '?flowline hyf:downstreamFlowPathTC ?downstream_flowline', +]; + +const context = (): PipelineContext => ({ + question: {} as AnalysisQuestion, + // The flowline step traces from the anchors discovery resolved; give it two + // so its query is built rather than skipped. + targetIris: ['https://example.org/t1', 'https://example.org/t2'], + anchorIris: ['https://example.org/a1', 'https://example.org/a2'], + results: {}, +}); + +let checks = 0; +let combinations = 0; + +for (const a of ENTITY_TYPES) { + for (const c of ENTITY_TYPES) { + for (const rel of HYDROLOGY) { + for (const maxDistanceKm of [undefined, 30]) { + const question: AnalysisQuestion = { + blockA: { type: a, region: { stateCode: '23' } }, + relationship: { type: rel, ...(maxDistanceKm ? { maxDistanceKm } : {}) }, + blockC: { type: c }, + }; + const where = `${a} ${rel} ${c}${maxDistanceKm ? ` (${maxDistanceKm}km)` : ''}`; + combinations++; + + let traced = 0; + for (const step of planPipeline(question)) { + const sparql = step.buildQuery(context()); + if (!sparql.includes('downstreamFlowPathTC')) continue; + traced++; + + for (const pattern of REVERSED) { + assert.ok( + !sparql.includes(pattern), + `${step.type} traces upstream from the seed ("${pattern}"): ${where}`, + ); + checks++; + } + assert.ok( + FORWARD.some((pattern) => sparql.includes(pattern)), + `${step.type} has no recognisable trace pattern: ${where}`, + ); + checks++; + } + + // A hydrology question that traced nowhere would pass the loop above + // by doing nothing at all. + assert.ok(traced > 0, `no step traced: ${where}`); + checks++; + } + } + } +} + +// And the relationship the user picked must still reach the templates intact: +// 'near' never traces. +for (const a of ENTITY_TYPES) { + for (const c of ENTITY_TYPES) { + const question: AnalysisQuestion = { + blockA: { type: a, region: { stateCode: '23' } }, + relationship: { type: 'near', hops: 1 }, + blockC: { type: c }, + }; + combinations++; + for (const step of planPipeline(question)) { + assert.ok( + !step.buildQuery(context()).includes('downstreamFlowPathTC'), + `near question traces flow paths: ${a} near ${c} (${step.type})`, + ); + checks++; + } + } +} + +console.log(`trace direction: ${combinations} combinations, ${checks} checks passed`); diff --git a/src/engine/planner.ts b/src/engine/planner.ts index 3697768..b1469f0 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -95,6 +95,7 @@ interface FusedContext { anchorBlock: EntityBlock; targetBlock: EntityBlock; relationship: AnalysisQuestion['relationship']; + direction: 'downstream' | 'upstream'; anchorRegion?: string[]; targetRegion?: string[]; } @@ -138,6 +139,7 @@ function hydrateStep( anchor: fused.anchorBlock, target: fused.targetBlock, relationship: fused.relationship, + direction: fused.direction, anchorRegion: fused.anchorRegion, targetRegion: fused.targetRegion, wellSide: side === 'target' ? 'target' : 'anchor', @@ -321,10 +323,7 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { steps.push({ type: 'GET_FLOWLINE_GEOMETRIES', endpoint: 'federation', - // No direction in the name: these are the flowlines between the two - // sides, traced downstream from the anchor whichever way the question - // was phrased. - description: 'Loading stream geometries', + description: `Loading ${relationship.type} stream geometries`, // Runs after FIND_ANCHOR_IRIS so it can trace from the resolved anchors. buildQuery: (ctx, scope) => buildFusedFlowlineQuery({ @@ -345,6 +344,7 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { anchorBlock, targetBlock, relationship, + direction: traceDirection, anchorRegion: anchorRegionOpt, targetRegion: targetRegionOpt, }; diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index b8b01c3..90c8a89 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -332,14 +332,6 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ${targetPin}${targetPart}`; } -function relationshipMode( - rel: SpatialRelationship, -): 'near' | 'downstream' | 'upstream' { - if (rel.type === 'downstream') return 'downstream'; - if (rel.type === 'upstream') return 'upstream'; - return 'near'; -} - export interface FusedBaseOpts { anchor: EntityBlock; target: EntityBlock; @@ -436,6 +428,10 @@ export function buildFusedHydrologyQuery(opts: FusedHydrologyOpts): string { export interface FusedWellSideOpts extends FusedBaseOpts { relationship: SpatialRelationship; + // Which way the discovery steps traced. This step re-derives the same trace, + // so it has to be told, not re-derive it from relationship.type — that is + // what made the well layer disagree with the IRIs discovery had found. + direction: 'downstream' | 'upstream'; wellSide: 'anchor' | 'target'; } @@ -451,7 +447,7 @@ export function buildFusedWellQuery(opts: FusedWellSideOpts): string { target: opts.target, anchorRegion: opts.anchorRegion, targetRegion: opts.targetRegion, - mode: relationshipMode(opts.relationship), + mode: opts.relationship.type === 'near' ? 'near' : opts.direction, hops: opts.relationship.hops, maxDistanceKm: opts.relationship.maxDistanceKm, }); From 5d1a67ca27a1486c47619c70d8e7a37e2d88548a Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 16 Sep 2026 14:25:59 -0400 Subject: [PATCH 44/66] docs: record the upstream direction bug, and make the self-checks run DEBUGGING.md gets the full entry: root cause, why it survived from the first commit, the measured size of the error (840 rows where the correct answer is 2,797), and the prevention lessons. ARCHITECTURE.md gains the one thing it never stated, which is the rule the bug broke: the anchor is always the upstream side of the question, so the trace always runs downstream from the seed, and which block that is flips for upstream. QUERY-MATRIX.md 3.3 is marked as measuring the mirror question, with a matching .note beside the sweep CSV, because those 25 rows read as a baseline and are not one. New Part 9 records what the corrected direction costs (214s unbounded, 12-25s bounded), the fourth slicing axis that stops it failing outright, and how the predicate orientation was verified from flowline geometry rather than from a linked pair, which the Part 8 note rightly warns against. Also wires the self-checks into CI. All four were runnable and none ran unless someone remembered to; that is the actual reason this bug lived as long as it did, so leaving them manual would be recording the lesson and not applying it. Lint stays advisory until its 15 pre-existing errors are cleared. --- .github/workflows/checks.yml | 60 ++++++++ docs/ARCHITECTURE.md | 56 +++++++- docs/DEBUGGING.md | 140 +++++++++++++++++++ docs/QUERY-MATRIX.md | 80 +++++++++++ docs/changelog/2026-W38.md | 24 ++++ docs/query-matrix/2026-09-14-engine.csv.note | 9 ++ docs/query-matrix/README.md | 17 ++- package.json | 1 + 8 files changed, 382 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/checks.yml create mode 100644 docs/query-matrix/2026-09-14-engine.csv.note diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000..410a89e --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,60 @@ +name: Checks + +# The repo's self-checks, on every pull request. They were all runnable before +# this file existed and none of them ran unless someone remembered to, which is +# how an engine bug that every one of these styles of check would have caught +# (upstream tracing the relation backwards, see docs/DEBUGGING.md 2026-09-16) +# survived from the first commit to 2026-09-16. +# +# Everything here is offline and takes seconds. No secrets, no SPARQL, no +# endpoint concurrency group: the live-endpoint workflows (health-check.yml, +# warm-cache.yml) are the ones that have to queue. + +on: + pull_request: + push: + branches: [main, development] + workflow_dispatch: + +jobs: + checks: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + + # react-leaflet's peer range does not include React 19 (see CLAUDE.md) + - run: npm ci --legacy-peer-deps + + - name: Build (tsc -b && vite build) + run: npm run build + + # Each of these asserts something that is silent when wrong: a wrong + # answer, a mislabelled step, a cache key that collides. They fail the + # build rather than reporting, because a self-check nobody is obliged to + # read is a self-check that does not exist. + - name: Trace direction + run: npm run check-trace-direction + + - name: Cache key + run: npm run check-cache-key + + - name: Step labels + run: npm run check-step-labels + + - name: Substance labels + run: npm run check-substance-labels + + # Not blocking yet: `npm run lint` reports 15 pre-existing errors, all in + # components and none related to the engine. Make this a required step in + # the same change that clears them, not before, or the signal is noise + # from day one. + - name: Lint (advisory) + run: npm run lint + continue-on-error: true diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e59cba1..6928896 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -247,6 +247,28 @@ measurements for exactly those entities. Keeping them apart is what stopped an ID-finding query from building every measurement in the state and throwing it away — see `docs/QUERY-MATRIX.md` Part 5. +**Which block seeds the trace, and which way it runs.** The templates know +nothing about block A and block C. They take an *anchor* (the side the query +seeds from, bound into `?s2anchor`) and a *target*, and they trace in one +direction only: the target comes out `direction` of the anchor. So the planner +has to decide two separate things, and they are not independent. + +| Relationship | Anchor is | Target is | Trace runs | Why the anchor is forced | +| --- | --- | --- | --- | --- | +| `A near C` | block C | block A | n/a | symmetric, either side works | +| `A downstream from C` | block C | block A | downstream | C is the upstream side | +| `A upstream from C` | **block A** | block C | **downstream** | A is the upstream side, and seeding from an unfiltered C ("every stream in the country") times out | + +Read the table by its last column and the rule is one line: **the anchor is +always the upstream side of the question, so the trace always runs downstream +from the seed.** Which block that is flips for `upstream`, which is the reason +the two decisions have to be made separately rather than passing +`relationship.type` through as the direction. Doing exactly that answered the +mirror question for every upstream shape until 2026-09-16 +(`docs/DEBUGGING.md`, 2026-09-16), and it is guarded now by +`scripts/check-trace-direction.mts`, which reads the emitted SPARQL rather than +the flag, because three separate builders trace and they all have to agree. + ### 3. Executor Runs the Steps `executor.ts` runs steps in order, but each step is more than one request. @@ -281,9 +303,15 @@ for the machinery. **The slice is chosen per question** (`scope.ts` `chooseAxis`). Which axis is right flips between states: Maine has 4,528 samples and 2,976 facilities, Illinois has 78 and 22,574 — so there is no fixed answer to "which side should -we chunk". `chooseAxis` probes both sides in parallel, uses whichever it can -enumerate, and falls back to splitting by county. A slice that still fails is -`halve`d until it cannot be divided further. +we chunk". `chooseAxis` probes both sides in parallel (`LIMIT 201`, cheap), uses +whichever it can enumerate, and falls back to splitting by county. When even +that runs out — a question already scoped to a *single* county, with both sides +past the cheap probe limit — it probes the filtered side once more with a much +higher limit and chunks that. That last resort exists because a single county +is not divisible and the run would otherwise fail outright: 411 Cook County +facilities enumerate fine and chunk into slices of 25 that each answer in +seconds. A slice that still fails is `halve`d until it cannot be divided +further. **A run can succeed with pieces missing.** `PartialFailure` distinguishes *failed* slices (refused even at minimum size — the question needs changing) @@ -522,6 +550,19 @@ canonicalisation does matters more than the hash: `WIRE_VERSION` and `DATA_VERSION` prefix the key so a change to the stored shape, or a knowledge-graph reload, makes every existing entry unreachable at once. +**Nothing in the key describes the engine**, which matters when a fix changes +what a question *means* rather than what it stores. Cached answers to the old +meaning stay reachable for their full 30 days and will be served in preference +to running the corrected query. After a semantics fix, purge the affected +entries by question shape rather than bumping `WIRE_VERSION`, which would throw +away every unaffected entry too: + +```sql +DELETE FROM query_results WHERE question->'relationship'->>'type' = 'upstream'; +SELECT id, title, author FROM published_workflows + WHERE question->'relationship'->>'type' = 'upstream'; -- frozen under publish: +``` + **What is stored** (`wire.ts`): successes only. An error is nearly always transient endpoint load, and freezing one would turn a bad minute into a bad month; an empty result is cheap to recompute. Only the four keys the map @@ -868,6 +909,15 @@ anything past the budget, then extends one segment further so the drawn line does not stop mid-channel. On one Maine question, a 30 km bound cut 15,782 reaches to 3,705 while keeping all 616 facilities. +**Upstream questions use this same pattern, unchanged.** There is no upstream +query. "A upstream from C" seeds from block A and traces downstream to block C, +which is the same relation read from the other end. The templates can build a +reversed trace (`?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline`) and +the planner never asks for one: a reversed trace is only correct if the seed is +the *downstream* side, and the seed is never that side, because the side that +seeds is the side the question filtered. See the anchor/target table under +[Planner Creates Pipeline Steps](#2-planner-creates-pipeline-steps). + --- ## Debugging Tips diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 4c28864..1d8cf8a 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -359,3 +359,143 @@ entries cached earlier stay reachable. - The same reasoning applies to `WIRE_VERSION` in that file: bump it when the set of stored result keys changes, or cached entries will be missing data the map expects. + +--- + +## 2026-09-16 — "Upstream from" answered the mirror question (FIXED) + +**Component**: `src/engine/planner.ts` — `buildFusedSteps`, and +`src/engine/templates/fusedQueries.ts` — `buildFusedWellQuery` + +**Symptom**: reported by Torsten: "the upstream query seems to be switched: I +asked for facilities upstream of stream but seem to get stream upstream of +facilities." Every `upstream` question returned the relation read backwards. +Nothing errored, both layers drew, and the streams were real rivers beside real +facilities. + +**Root cause**: the templates trace one way only. The anchor is bound into +`?s2anchor`, the seed flowline hangs off it, and the target comes out +`direction` of the anchor: + +```sparql +downstream mode: ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline # target below anchor +upstream mode: ?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline # target above anchor +``` + +So the planner decides two things: which block is the anchor (which side seeds) +and which way to trace from it. For `upstream` the anchor has to be block A, +because seeding from an unfiltered block C means every stream in the country and +times out. The anchor was right; the direction was not: + +```ts +if (relationship.type === 'upstream') { anchorBlock = blockA; targetBlock = blockC; } // correct +... +direction: relationship.type === 'downstream' ? 'downstream' : 'upstream', // wrong +``` + +Two flips were required and one was applied. In one line: the code treated *the +name of the relationship the user picked* and *the direction to trace from the +seed* as the same value, and they are the same only when the seed is block C. + +Not a regression from the fused refactor. `d9ba5a6` carried the bug across +faithfully, comment and all; the S2-cell pipeline it replaced did the same thing +(`getS2Step(blockA)` then `traceUpstreamStep()` then `findEntitiesStep(blockC)`), +and `git log -S buildUpstreamTraceQuery --reverse` puts that in the initial +commit. Upstream had never worked. + +**How wrong**: "samples in Maine upstream from landfills", measured live. + +| | Distinct samples | +| --- | --- | +| Before | 840 | +| After | 2,797 | +| In both | 777 | + +72% of the correct answer was missing and 63 rows were false positives. The old +answer was, in effect, the *downstream* relation, so "samples upstream from +landfills" and "samples downstream from landfills" were two names for one +question (404 of 474 rows shared, the rest explained by the seed-side tolerance +below). + +For facility-shaped answers the answer layer barely moves — Cook County returns +411 facilities either way, because "upstream of some stream" and "downstream of +some stream" are both nearly vacuous — so the stream layer was the only visible +tell. That is what was noticed, and it is why no screenshot review ever caught +it. + +**Caught**: by a user, on a shape nothing automated runs. The 9 prebuilt +dashboard questions are 7 `near` and 2 `downstream`, zero `upstream`, so the +weekly health check and the warm cache never touched it. `docs/QUERY-MATRIX.md` +3.3 *did* measure all 36 upstream shapes and passed them: a mirror answer +returns a plausible row count in a plausible time, and the sweep records status, +duration and rows, never semantics. + +**Fix**: name the decision and make it once. + +```ts +const isUpstream = relationship.type === 'upstream'; +const anchorBlock: EntityBlock = isUpstream ? blockA : blockC; +const targetBlock: EntityBlock = isUpstream ? blockC : blockA; +// The anchor is always the upstream side of the question, so the trace always +// runs downstream from it. +const traceDirection = 'downstream' as const; +``` + +Two further things came out of the fix: + +- **A second copy of the rule.** `buildFusedWellQuery` re-derives the whole + trace server-side (a statewide well set is 20k+ IRIs, too many to inline) and + decided its own direction from `relationship.type` via `relationshipMode()`. + Before the fix it agreed with discovery, both wrong. After it, the well layer + would have been a different set from the wells discovery found. The planner + now passes the direction it used and `relationshipMode` is deleted with its + only caller. +- **The corrected question is much heavier**, and it first failed outright: + `chooseAxis` had no axis left for a single-county question (both probes past + `PROBE_LIMIT`, one county not splittable), so the step errored after 64s + instead of slicing. `scope.ts` gained a last-resort bulk probe. + +**Verified** end to end through the real pipeline, and in the app on the PR +preview: Cook County facilities upstream from streams draws 402 facilities and +1,290 flowlines running down the Des Plaines, the Illinois and the Mississippi +past St. Louis. Before the fix the same question drew the headwater tributaries +north of Chicago and nothing downstream of it. + +| Question | Before | After | +| --- | --- | --- | +| Cook facilities upstream from streams, any distance | 1.3s, wrong direction | 214s | +| same, bounded 10 km / 50 km | n/a | 25s / 12s | +| Cook facilities near streams | 11s | 11s | +| ME samples downstream from landfills | 38s | 38s | + +**Prevention** — the general lessons: + +- **A flag that reads like a pass-through is not one.** + `rel.type === 'downstream' ? 'downstream' : 'upstream'` looks like it forwards + the user's choice. It was duplicated at two call sites, so the decision had no + name and no home. Anything with two independent flips has to name both. +- **Do not overload one variable with a semantic role and an execution + property.** `anchor` means both "which side of the question" and "which side + seeds, and therefore which side is cheap". One meaning was updated without + the other, which is what overloaded variables do. +- **Plausible output is not verification.** The only assertion that would have + caught this is one about the *query*, not the result. That is + `scripts/check-trace-direction.mts`: across all 180 planner shapes, every + query carrying `hyf:downstreamFlowPathTC` must trace downstream from the seed, + and a `near` question must not trace at all. It reads the emitted SPARQL, so + it covers all three builders that trace (discovery, the flowline layer, well + hydration) rather than trusting the flag each was handed. Confirmed to fail on + the code before each of the two fixes. +- **The dashboard is not coverage.** A third of the question space had no + automated exercise of any kind. Where a shape cannot be afforded in CI, an + offline assertion about the generated query is the cheap substitute. +- **A semantics fix does not invalidate the cache.** `cacheKey` hashes the + question, not the engine, and complete results live 30 days, so wrong answers + keep being served after the fix deploys. Purge by question shape (see + `docs/ARCHITECTURE.md`, The Result Cache). + +**Known, and not a bug**: the seed side gets a one-cell tolerance the target +side does not (`?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor` before +attaching to a flowline). So "A upstream from C" and "C downstream from A" are +not exactly reciprocal even now, which is part of the 840 vs 474 gap above. +Making them reciprocal means applying that tolerance to both sides or neither. diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 8d1ec84..7ade3fc 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -154,6 +154,14 @@ Failure breakdown: 20 × timeout at 30s, 15 × engine out-of-memory, ### 3.3 Upstream from — every entity pair +> **These 25 numbers measured the wrong question, and are kept only as a +> record.** Until 2026-09-16 every `upstream` shape traced the relation +> backwards (`docs/DEBUGGING.md`, 2026-09-16), so each cell below is the time +> and row count for the *mirror* question. Status and timing do not carry over: +> the corrected direction is materially more expensive when block C is +> unfiltered. See Part 9. Every `near` and `downstream` number in this document +> is unaffected. + | Block A ↓ / Block C → | Samples | Facilities | Water bodies | Wells | Aquifers | | --- | --- | --- | --- | --- | --- | | **Samples** | ✅ 13.1s (3221) | ✅ 13.7s (2739) | ✅ 13.5s (6072) | ⚠️ 24.3s (47730) | ✅ 12.6s (4650) | @@ -741,3 +749,75 @@ questions that set a distance. reaches coincided (0 of 50 shared one). Braided channels mean "is A upstream of B" has no clean yes/no answer — so do not use a single pair to reason about trace direction. + +--- + +## Part 9 — The corrected upstream direction (2026-09-16) + +Upstream questions traced the relation backwards from the first commit until +2026-09-16. The root cause, the size of the error and the guard that now +prevents it are in `docs/DEBUGGING.md` (2026-09-16); this part is what the fix +costs to run, since that is what this document is for. + +### 9.1 What it costs + +Measured end to end through the real pipeline, Cook County, IL, NAICS 325 + 326: + +| Question | Before (wrong direction) | After | +| --- | --- | --- | +| facilities upstream from streams, any distance | 1.3s | **214s**, 411 facilities + 1,290 flowlines | +| facilities upstream from streams, 50 km | n/a | 12s, 411 facilities | +| facilities upstream from streams, 10 km | n/a | 25s, 393 facilities | +| facilities near streams (control) | 11s | 11s | +| ME samples downstream from landfills (control) | 38s | 38s | + +The asymmetry is real and worth understanding before reading Part 3.3 as a +baseline. The old direction, from Cook County, asked "what drains *into* these +facilities", which in a headwater county is a small set. The corrected direction +asks "what do they drain into", and from Chicago that is the Illinois River, the +Mississippi and everything to the Gulf: 1,290 reaches. Same engine, same +question shape, 150x the work. + +**A distance bound is the practical answer**, not a tidier rendering of the same +thing. At 50 km the answer is the same 411 facilities in an eighth of the time, +because the facility set is almost insensitive to the bound: nearly every +facility near a stream is upstream of *something*. Unbounded upstream against an +unfiltered block C is close to a vacuous question with a very expensive answer. + +### 9.2 It first failed rather than ran slowly + +The corrected query timed out at 64s and the run errored, because +`chooseAxis` had nothing left to slice: both probes were past `PROBE_LIMIT` +(411 facilities, and streams are unbounded), and the question was already scoped +to a single county, which cannot be split. `scope.ts` now probes the filtered +side once more at a much higher limit and chunks it (25 per slice, 17 slices). +That is what turns the 64s failure into the 214s answer above. + +This is the fourth axis, and it only engages when the other three have declined, +so no shape that already worked can slow down. + +### 9.3 Part 3.3 needs re-measuring + +All 25 upstream rows in the last sweep (`docs/query-matrix/2026-09-14-engine.csv`) +measured the mirror question, as does every upstream shape the editor can build +(36 of them, including streams as a block type, which the sweep does not cover). Expect the re-sweep to move them: shapes with an +unfiltered block C get more expensive, and some that passed will not. The 72 +`near` and `downstream` shapes should be unchanged, which is the useful control +when reading the diff. + +### 9.4 How the trace direction was verified + +Not by reasoning about a pair of linked reaches. The note at the end of Part 8 +is right that braided channels make a single pair useless for that. + +NHD flowline geometries are digitised from upstream to downstream, so the +orientation can be read off the coordinates directly: for `?a hyf:downstreamFlowPath ?b` +on `hydrologykg`, a's last coordinate is exactly b's first coordinate. + +``` +comid/1001 -> comid/1005 a_end == b_start: true a_start == b_end: false +``` + +So `A TC B` means B is downstream of A, as the predicate name says, and as Part +8 already concluded by a different route. This is the cheaper check to repeat if +it is ever in doubt again. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 2a29b3c..4c4e2b9 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -76,3 +76,27 @@ Caught while warming that question for a demo; the upload was stopped before it wrote and the cache verified clean, so nothing needed purging. The key is now built by removing the one field known to be irrelevant rather than listing the ones known to matter — a field wrongly included costs a cache miss, one wrongly dropped serves the wrong answer, and only the second is silent. Unbounded traces keep their previous key, so entries cached earlier stay reachable. *Files:* `src/engine/cacheKey.ts`, `scripts/check-cache-key.mts` (19 checks), `docs/DEBUGGING.md` + +10. **Fixed: "Upstream From" Answered the Mirror Question** (2026-09-16) + Reported by Torsten: "I asked for facilities upstream of stream but seem to get stream upstream of facilities." He was right, and it had never worked. Every `upstream` question, for every combination of entity types, returned the relation read backwards, from the first commit until now. + + The templates trace one way only: the anchor is the side the query seeds from, and the target comes out `direction` of the anchor. So the planner decides two things, and they are not independent. For an upstream question the anchor has to be block A, because seeding from an unfiltered block C means every stream in the country and times out; that part was right. The direction was still being derived from the name of the relationship the user picked, and those two are only the same thing when the seed is block C. Two flips were required and one was applied. + + Measured on "samples in Maine upstream from landfills": the old answer returned **840 samples where the correct answer is 2,797**, overlapping in 777. So 72% of the real answer was missing and 63 rows were false positives. Worse, the wrong answer *was* the downstream relation, so "samples upstream from landfills" and "samples downstream from landfills" were two names for one question and the real upstream question could not be asked at all. + + Nothing caught it for three reasons worth recording. The 9 prebuilt dashboard questions are 7 `near` and 2 `downstream` and zero `upstream`, so no health check, warm-cache run or demo ever exercised a third of the question space. `docs/QUERY-MATRIX.md` 3.3 did measure all 25 upstream shapes and passed them, because a mirror answer returns a plausible row count in a plausible time and the sweep records status, duration and rows, never meaning. And the output stays believable: for facility-shaped answers the answer layer barely moves (Cook County returns 411 facilities either way, since "upstream of some stream" and "downstream of some stream" are both nearly vacuous), so the stream layer was the only visible tell. + + Two things fell out of the fix. `buildFusedWellQuery` held a second copy of the same rule, because it re-derives the whole trace server-side rather than hydrating by IRI; before the fix it agreed with discovery, both wrong, and after it the well layer would have been a different set from the wells discovery found. And the corrected query is much heavier, which first made it fail rather than run slowly: `chooseAxis` had no axis left for a question already scoped to one county, so `scope.ts` gained a last-resort bulk probe (411 Cook County facilities chunk into 17 slices of 25). Cook County facilities upstream from streams now answers in 214s unbounded, or 12 to 25s with a distance bound, drawing 402 facilities and the 1,290 reaches running down the Des Plaines, the Illinois and the Mississippi past St. Louis. `near` and `downstream` timings are unchanged. + + Verified in the app on the PR preview, not just in the engine. The direction of `hyf:downstreamFlowPathTC` was confirmed independently from geometry: NHD flowlines are digitised upstream to downstream, so for `?a hyf:downstreamFlowPath ?b`, a's last coordinate is exactly b's first. + + *Files:* `src/engine/planner.ts`, `src/engine/scope.ts`, `src/engine/templates/fusedQueries.ts`, `scripts/check-trace-direction.mts` (new, 2,068 checks), `.github/workflows/checks.yml` (new), `package.json`, `docs/DEBUGGING.md`, `docs/ARCHITECTURE.md`, `docs/QUERY-MATRIX.md` + +11. **The Self-Checks Now Run on Every Pull Request** (2026-09-16) + Four offline self-checks existed (`check-cache-key`, `check-step-labels`, `check-substance-labels`, and the new `check-trace-direction`) and none of them ran unless someone remembered to type the command. Entry 10 is what that costs: a bug that an assertion about the generated query would have caught on the day it was written instead survived from the first commit, because the only thing looking at upstream questions was a person looking at a map. + + `Checks` runs the build and all four on every PR and on pushes to `main` and `development`. They are blocking, since a self-check nobody is obliged to read is a self-check that does not exist. Everything in it is offline and takes seconds, so it carries no secrets and does not join the endpoint concurrency group that the live-query workflows share. + + `npm run lint` is in the workflow but advisory, because it reports 15 pre-existing errors, all in components. It should be made blocking in the same change that clears them, not before. + + *Files:* `.github/workflows/checks.yml` (new), `package.json` diff --git a/docs/query-matrix/2026-09-14-engine.csv.note b/docs/query-matrix/2026-09-14-engine.csv.note new file mode 100644 index 0000000..f0d136b --- /dev/null +++ b/docs/query-matrix/2026-09-14-engine.csv.note @@ -0,0 +1,9 @@ +**The 25 `upstream` rows measured the wrong question.** Every upstream shape +traced the relation backwards until 2026-09-16 (`docs/DEBUGGING.md`, +2026-09-16), so their status, timing and row counts describe the mirror +question. They are not a baseline: the corrected direction is materially more +expensive where block C is unfiltered. See `docs/QUERY-MATRIX.md` Part 9, and +re-sweep. + +The other 99 rows (62 `near`, 37 `downstream`) are unaffected, and are the control when +diffing this file against the next sweep. diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md index 2280932..2ad26a5 100644 --- a/docs/query-matrix/README.md +++ b/docs/query-matrix/README.md @@ -16,8 +16,21 @@ engine change. The two are not comparable row for row. | Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | | --- | --- | --- | ---: | ---: | ---: | --- | -| [`2026-09-14`](./2026-09-14-engine-contaminated-9128aa9.csv) | engine-contaminated | `9128aa9` | 124 | 94 | 29 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | +| [`2026-09-14`](./2026-09-14-engine-contaminated-9128aa9.csv) | engine-contaminated | `9128aa9` | 124 | 94 | 29 | _first sweep in this mode_ | + +## Notes + +**[`2026-09-14-engine.csv`](./2026-09-14-engine.csv)** — **The 25 `upstream` rows measured the wrong question.** Every upstream shape +traced the relation backwards until 2026-09-16 (`docs/DEBUGGING.md`, +2026-09-16), so their status, timing and row counts describe the mirror +question. They are not a baseline: the corrected direction is materially more +expensive where block C is unfiltered. See `docs/QUERY-MATRIX.md` Part 9, and +re-sweep. + +The other 99 rows (62 `near`, 37 `downstream`) are unaffected, and are the control when +diffing this file against the next sweep. + -Generated 2026-09-15. +Generated 2026-09-16. diff --git a/package.json b/package.json index a374540..04c703b 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "warm-cache": "tsx scripts/warm-cache.mts", "check-cache-key": "tsx scripts/check-cache-key.mts", "check-step-labels": "tsx scripts/check-step-labels.mts", + "check-trace-direction": "tsx scripts/check-trace-direction.mts", "check-substance-labels": "tsx scripts/check-substance-labels.mts", "query-matrix": "tsx scripts/query-matrix.mts", "health-check": "tsx scripts/health-check.mts" From 3fa9caf449b825a18b536f0b1a02ad8cf3d13357 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Wed, 16 Sep 2026 19:55:44 -0400 Subject: [PATCH 45/66] feat(dashboard): upstream questions, and four distinct shapes on the landing page The direction fix is only visible to someone who builds their own question: no prebuilt asked an upstream question, so a third of the query space had no presence on the dashboard and no coverage in the weekly health check. Replaces the Cumberland PFHpA question with its mirror. It traced downstream from every facility in the graph, unfiltered, so the answer was "these samples have some facility upstream somewhere". Asked the other way it is source attribution, and it returns the same answer size (49 samples / 265 facilities against the old 49 / 268). Adds the Cook County chemical and plastics question that surfaced the bug, bounded to 50 km: 33s on a healthy endpoint, 72s on a busy one. Unbounded it takes 214s and draws the Mississippi to the Gulf, which is correct and useless. Drops the airports wells question, the most diffuse of the three at 4,425 wells. Orders the first four (the landing page, Dashboard.tsx slice(0, 4)) as four different shapes rather than four variations on "samples near facilities": upstream, near, downstream, upstream, with samples, streams and facilities each as the thing being asked about. A wells-upstream question was attempted and dropped: it timed out on all four scopings measured, always on the wells side. Direction is not the cause, "wells downstream of landfills" builds the same query. Wells as the far end of a trace is the expensive shape, which is why all three existing wells questions use proximity. --- .github/workflows/health-check.yml | 2 +- docs/changelog/2026-W38.md | 15 +++ src/constants/prebuiltQueries.ts | 156 +++++++++++++++-------------- 3 files changed, 99 insertions(+), 74 deletions(-) diff --git a/.github/workflows/health-check.yml b/.github/workflows/health-check.yml index 4912ef1..0ce8d0f 100644 --- a/.github/workflows/health-check.yml +++ b/.github/workflows/health-check.yml @@ -1,6 +1,6 @@ name: Dashboard health -# Runs the eight dashboard questions against the live endpoints once a week and +# Runs every dashboard question against the live endpoints once a week and # writes down what happened: worked or not, how long, how many rows. The point # is dating a regression. Without this, "the Indiana question broke sometime in # the last month" is the best anyone can say. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 4c4e2b9..3a02d06 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -100,3 +100,18 @@ `npm run lint` is in the workflow but advisory, because it reports 15 pre-existing errors, all in components. It should be made blocking in the same change that clears them, not before. *Files:* `.github/workflows/checks.yml` (new), `package.json` + +12. **Dashboard: Upstream Questions, and One Fewer Way to Ask the Same Thing** (2026-09-16) + Entry 10 fixed the upstream direction, and nothing on the dashboard asked an upstream question, so a third of the query space stayed invisible to anyone who does not build their own. Three changes, all measured against the live endpoints first. + + **"PFHpA Groundwater Samples Downstream from Facilities in Cumberland County" is now its mirror**, "Facilities Upstream from PFHpA Groundwater Contamination in Cumberland County". The old question traced downstream from *every facility in the graph*, with no industry filter, so the answer amounted to "these samples have some facility upstream somewhere", which is true of nearly everything. Asked the other way it is source attribution: given groundwater that tested positive, which facilities in the county sit upstream of it. Same county, same substance, same concentration band, same answer size (49 samples, 265 facilities against the old 49 and 268), and the trace it draws is the path between them. + + **Added "Chemical & Plastics Manufacturers Upstream from Streams in Cook County, IL"** (NAICS 325 and 326, bounded to 50 km of flow), the question that surfaced the direction bug, and the only Illinois entry on a mostly-Maine dashboard. Measured at 33s on a healthy endpoint and 72s on a busy one, returning 526 reaches and 732 facility rows. Unbounded it is 214s and draws the Mississippi to the Gulf, which is correct and useless; the bound is what makes it a dashboard question. + + **Dropped "Maine Private Wells Near Airports & Air Transportation Sites"**, the most diffuse of the three wells questions at 4,425 wells. + + The four cards on the landing page are now four different question shapes rather than four variations on "samples near facilities": upstream, near, downstream, upstream, with samples, streams and facilities each as the thing being asked about, highest-value question first. The rest sit behind "Explore More Prebuilt Analyses" as before. + + **A wells-upstream question was attempted and abandoned**, which is worth recording so nobody tries it again without knowing. "Maine landfills and DoD sites upstream from private wells" timed out on all four scopings measured (statewide and Penobscot-only, 10 km and 30 km), always on the wells side. The direction is not the problem: "wells downstream of landfills" builds the identical query, since the planner seeds from the filtered facilities either way. Wells as the far end of a hydrology trace is simply the expensive shape, which is why all three existing wells questions use proximity. + + *Files:* `src/constants/prebuiltQueries.ts`, `.github/workflows/health-check.yml` diff --git a/src/constants/prebuiltQueries.ts b/src/constants/prebuiltQueries.ts index c31ad40..0b0aeb8 100644 --- a/src/constants/prebuiltQueries.ts +++ b/src/constants/prebuiltQueries.ts @@ -8,24 +8,37 @@ export interface PrebuiltQuery { question: AnalysisQuestion; } +// Order matters: Dashboard.tsx renders the first four on the landing page and +// the rest behind "Explore More". Those four are deliberately four different +// question shapes — all three relationships, and wells, samples and streams as +// the thing being asked about — rather than four variations on "samples near +// facilities", which is what a reader took to be the whole tool. export const PREBUILT_QUERIES: PrebuiltQuery[] = [ { - id: 'samples-near-agchem-maine', - title: 'Samples Near Agricultural Chemical Facilities in Maine', + id: 'facilities-upstream-pfhpa-gw-cumberland', + title: 'Facilities Upstream from PFHpA Groundwater Contamination in Cumberland County', description: - 'Find PFAS sample points located near pesticide, fertilizer, and agricultural chemical manufacturing facilities (NAICS 3253) across the state of Maine.', - tags: ['Samples', 'Facilities', 'Near', 'Maine', 'NAICS 3253'], + 'Given groundwater that tested positive for PFHpA (10-1000 ng/L) in Cumberland County, Maine, trace the river network back the other way: which facilities in the county sit upstream of that contamination, and are therefore candidate sources.', + tags: ['Facilities', 'Samples', 'Upstream', 'PFHpA', 'Groundwater', 'Cumberland'], question: { blockA: { - type: 'samples', - region: { stateCode: '23' }, + type: 'facilities', + region: { stateCode: '23', countyCodes: ['23005'], countyLabels: { '23005': 'Cumberland County, Maine' } }, }, - relationship: { type: 'near', hops: 1 }, + relationship: { type: 'upstream' }, blockC: { - type: 'facilities', - facilityFilters: { - industryCodes: ['3253'], - industryLabels: { '3253': 'Pesticide, Fertilizer, and Other Agricultural Chemical Manufacturing' }, + type: 'samples', + // Both blocks carry the county. The question this replaced scoped the + // samples and left the facilities open; mirroring it moved the scope to + // the facilities and left *samples* open, which asks the trace to reach + // every PFHpA groundwater sample in the graph. + region: { stateCode: '23', countyCodes: ['23005'], countyLabels: { '23005': 'Cumberland County, Maine' } }, + sampleFilters: { + substances: ['http://w3id.org/DSSTox/v1/DTXSID1037303'], + substanceLabels: { 'http://w3id.org/DSSTox/v1/DTXSID1037303': 'PFHpA' }, + materialTypes: ['http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.GW'], + minConcentration: 10, + maxConcentration: 1000, }, }, }, @@ -55,101 +68,101 @@ export const PREBUILT_QUERIES: PrebuiltQuery[] = [ }, }, { - id: 'waterbodies-near-landfill-dod-penobscot-knox', - title: 'Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County', + id: 'samples-downstream-waste-indiana', + title: 'Samples Downstream of Waste Treatment Facilities in Indiana', description: - 'Locate surface water bodies (lakes, ponds, reservoirs) near Solid Waste Landfills (NAICS 562212) and National Security / DOD facilities (NAICS 928110) in Penobscot and Knox counties, Maine.', - tags: ['Surface Water Bodies', 'Facilities', 'Near', 'Penobscot', 'Knox', 'Landfill'], + 'Trace downstream flow paths from Waste Treatment and Disposal facilities (NAICS 5622) in Indiana to find PFAS sample points in potentially affected areas.', + tags: ['Samples', 'Facilities', 'Downstream', 'Indiana', 'Waste Treatment'], question: { blockA: { - type: 'waterBodies', - region: { stateCode: '23', countyCodes: ['23019', '23013'], countyLabels: { '23019': 'Penobscot County, Maine', '23013': 'Knox County, Maine' } }, + type: 'samples', + region: { stateCode: '18' }, }, - relationship: { type: 'near', hops: 1 }, + relationship: { type: 'downstream' }, blockC: { type: 'facilities', facilityFilters: { - industryCodes: ['562212', '928110'], - industryLabels: { - '562212': 'Solid Waste Landfill', - '928110': 'National Security', - }, + industryCodes: ['5622'], + industryLabels: { '5622': 'Waste Treatment and Disposal' }, }, }, }, }, { - id: 'samples-downstream-waste-indiana', - title: 'Samples Downstream of Waste Treatment Facilities in Indiana', + id: 'facilities-upstream-streams-cook', + title: 'Chemical & Plastics Manufacturers Upstream from Streams in Cook County, IL', description: - 'Trace downstream flow paths from Waste Treatment and Disposal facilities (NAICS 5622) in Indiana to find PFAS sample points in potentially affected areas.', - tags: ['Samples', 'Facilities', 'Downstream', 'Indiana', 'Waste Treatment'], + 'Which Chemical Manufacturing (NAICS 325) and Plastics and Rubber Products Manufacturing (NAICS 326) facilities in Cook County, Illinois sit upstream of a stream, within 50 km of flow, and which reaches they drain into.', + tags: ['Facilities', 'Streams', 'Upstream', 'Illinois', 'Cook', 'NAICS 325', 'NAICS 326', '50 km'], question: { blockA: { - type: 'samples', - region: { stateCode: '18' }, - }, - relationship: { type: 'downstream' }, - blockC: { type: 'facilities', + region: { stateCode: '17', countyCodes: ['17031'], countyLabels: { '17031': 'Cook County, Illinois' } }, facilityFilters: { - industryCodes: ['5622'], - industryLabels: { '5622': 'Waste Treatment and Disposal' }, + industryCodes: ['325', '326'], + industryLabels: { + '325': 'Chemical Manufacturing', + '326': 'Plastics and Rubber Products Manufacturing', + }, }, }, + relationship: { type: 'upstream', maxDistanceKm: 50 }, + blockC: { + type: 'streams', + }, }, }, { - id: 'wells-near-landfill-dod-maine', - title: 'Maine Private Wells Near Landfills & DoD Sites', + id: 'samples-near-agchem-maine', + title: 'Samples Near Agricultural Chemical Facilities in Maine', description: - 'Locate Maine private wells (MGS) within proximity of Solid Waste Landfills (NAICS 562212) and National Security / DoD facilities (NAICS 928110) statewide — the two facility classes most often implicated in Maine PFAS investigations.', - tags: ['Wells', 'Facilities', 'Near', 'Maine', 'Landfill', 'DoD'], + 'Find PFAS sample points located near pesticide, fertilizer, and agricultural chemical manufacturing facilities (NAICS 3253) across the state of Maine.', + tags: ['Samples', 'Facilities', 'Near', 'Maine', 'NAICS 3253'], question: { blockA: { - type: 'wells', + type: 'samples', region: { stateCode: '23' }, }, relationship: { type: 'near', hops: 1 }, blockC: { type: 'facilities', facilityFilters: { - industryCodes: ['562212', '928110'], - industryLabels: { - '562212': 'Solid Waste Landfill', - '928110': 'National Security', - }, + industryCodes: ['3253'], + industryLabels: { '3253': 'Pesticide, Fertilizer, and Other Agricultural Chemical Manufacturing' }, }, }, }, }, { - id: 'wells-near-wwtp-maine', - title: 'Maine Private Wells Near Wastewater Treatment Facilities', + id: 'waterbodies-near-landfill-dod-penobscot-knox', + title: 'Surface Water Bodies Near Landfills & DOD Sites in Penobscot and Knox County', description: - 'Identify Maine private wells (MGS) near sewage treatment facilities (NAICS 221320). Biosolid land-application from these POTWs is the dominant PFAS exposure pathway driving Maine well-sampling priorities.', - tags: ['Wells', 'Facilities', 'Near', 'Maine', 'Wastewater', 'Biosolids'], + 'Locate surface water bodies (lakes, ponds, reservoirs) near Solid Waste Landfills (NAICS 562212) and National Security / DOD facilities (NAICS 928110) in Penobscot and Knox counties, Maine.', + tags: ['Surface Water Bodies', 'Facilities', 'Near', 'Penobscot', 'Knox', 'Landfill'], question: { blockA: { - type: 'wells', - region: { stateCode: '23' }, + type: 'waterBodies', + region: { stateCode: '23', countyCodes: ['23019', '23013'], countyLabels: { '23019': 'Penobscot County, Maine', '23013': 'Knox County, Maine' } }, }, relationship: { type: 'near', hops: 1 }, blockC: { type: 'facilities', facilityFilters: { - industryCodes: ['221320'], - industryLabels: { '221320': 'Sewage Treatment Facilities' }, + industryCodes: ['562212', '928110'], + industryLabels: { + '562212': 'Solid Waste Landfill', + '928110': 'National Security', + }, }, }, }, }, { - id: 'wells-near-airports-maine', - title: 'Maine Private Wells Near Airports & Air Transportation Sites (AFFF)', + id: 'wells-near-landfill-dod-maine', + title: 'Maine Private Wells Near Landfills & DoD Sites', description: - 'Find Maine private wells (MGS) near airports and air transportation operations (NAICS 488119, 481111). Aqueous Film-Forming Foam (AFFF) used in airport firefighting is a leading legacy source of PFOS / PFOA in groundwater.', - tags: ['Wells', 'Facilities', 'Near', 'Maine', 'Airports', 'AFFF'], + 'Locate Maine private wells (MGS) within proximity of Solid Waste Landfills (NAICS 562212) and National Security / DoD facilities (NAICS 928110) statewide — the two facility classes most often implicated in Maine PFAS investigations.', + tags: ['Wells', 'Facilities', 'Near', 'Maine', 'Landfill', 'DoD'], question: { blockA: { type: 'wells', @@ -159,36 +172,33 @@ export const PREBUILT_QUERIES: PrebuiltQuery[] = [ blockC: { type: 'facilities', facilityFilters: { - industryCodes: ['488119', '481111'], + industryCodes: ['562212', '928110'], industryLabels: { - '488119': 'Other Airport Operations', - '481111': 'Scheduled Passenger Air Transportation', + '562212': 'Solid Waste Landfill', + '928110': 'National Security', }, }, }, }, }, { - id: 'facilities-downstream-pfhpa-gw-cumberland', - title: 'PFHpA Groundwater Samples Downstream from Facilities in Cumberland County', + id: 'wells-near-wwtp-maine', + title: 'Maine Private Wells Near Wastewater Treatment Facilities', description: - 'Find groundwater sample points that tested positive for PFHpA (10-1000 ng/L) located downstream of facilities in Cumberland County, Maine. Traces downstream hydrology flow paths.', - tags: ['Facilities', 'Samples', 'Downstream', 'PFHpA', 'Groundwater', 'Cumberland'], + 'Identify Maine private wells (MGS) near sewage treatment facilities (NAICS 221320). Biosolid land-application from these POTWs is the dominant PFAS exposure pathway driving Maine well-sampling priorities.', + tags: ['Wells', 'Facilities', 'Near', 'Maine', 'Wastewater', 'Biosolids'], question: { blockA: { - type: 'samples', - sampleFilters: { - substances: ['http://w3id.org/DSSTox/v1/DTXSID1037303'], - substanceLabels: { 'http://w3id.org/DSSTox/v1/DTXSID1037303': 'PFHpA' }, - materialTypes: ['http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.GW'], - minConcentration: 10, - maxConcentration: 1000, - }, - region: { stateCode: '23', countyCodes: ['23005'], countyLabels: { '23005': 'Cumberland County, Maine' } }, + type: 'wells', + region: { stateCode: '23' }, }, - relationship: { type: 'downstream' }, + relationship: { type: 'near', hops: 1 }, blockC: { type: 'facilities', + facilityFilters: { + industryCodes: ['221320'], + industryLabels: { '221320': 'Sewage Treatment Facilities' }, + }, }, }, }, From 9b21bf9ec45adea4dff646c8e824e28cfdb5bcbf Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Thu, 17 Sep 2026 00:00:20 -0400 Subject: [PATCH 46/66] style: one blue palette and Inter across the app The accent was two families that disagreed. --color-primary, --color-primary-300 and --color-primary-50 were never defined, so a dozen rules fell through to their hex fallbacks and rendered Tailwind violet next to Chakra blue. Fill the ramp, alias indigo onto primary, strip all 17 var(--token, #hex) fallbacks, and map the remaining bare hexes onto gray and status tokens. Map layer and relationship tag colors are untouched: they encode data categories, not chrome. Also switch the system font stack to Inter, with tabular figures so result counts stop jittering as they update. --- index.html | 5 + src/App.css | 173 ++++++++++++++----- src/components/DesignSystem/DesignSystem.css | 2 +- src/components/DesignSystem/DesignSystem.tsx | 16 +- src/index.css | 27 ++- 5 files changed, 164 insertions(+), 59 deletions(-) diff --git a/index.html b/index.html index e74a675..8b92eb4 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,11 @@ + + SAWGraph Query Editor diff --git a/src/App.css b/src/App.css index b843c52..8d9e1a6 100644 --- a/src/App.css +++ b/src/App.css @@ -74,6 +74,19 @@ gap: var(--space-md); } +.header-link { + display: flex; + align-items: center; + gap: var(--space-xs); + font-size: var(--text-base); + color: var(--color-gray-600); + text-decoration: none; +} + +.header-link:hover { + color: var(--color-primary-600); +} + /* Question Bar */ .question-bar { display: flex; @@ -164,12 +177,12 @@ .question-bar-name-input:focus { outline: none; border-color: var(--color-primary-600); - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); + box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb), 0.2); } .question-bar-rename-error { font-size: var(--text-xs); - color: var(--color-red-700, #b91c1c); + color: var(--color-red-700); } .question-bar-row { @@ -432,9 +445,9 @@ margin-top: 0.4rem; padding: 0.4rem 0.6rem; border-radius: var(--radius-sm); - background: #fff7ed; - border: 1px solid #fed7aa; - color: #9a3412; + background: var(--color-yellow-50); + border: 1px solid var(--color-yellow-400); + color: var(--color-yellow-800); font-size: var(--text-sm); line-height: 1.35; } @@ -940,7 +953,7 @@ .hs-select-all { position: sticky; top: 0; - background: var(--color-gray-50, #f9fafb); + background: var(--color-gray-50); border-bottom: 1px solid var(--color-gray-200); font-weight: 500; z-index: 1; @@ -1207,11 +1220,85 @@ padding: var(--space-3xl) var(--space-2xl); } -.dashboard-welcome { - font-size: var(--text-2xl); - font-weight: var(--font-light); - color: var(--color-gray-700); +.dashboard-hero { + background: linear-gradient( + 135deg, + var(--color-indigo-600), + var(--color-primary-700) + ); + color: #fff; + border-radius: var(--radius-lg); + padding: var(--space-2xl); margin: 0 0 var(--space-2xl); + position: relative; +} + +.dashboard-hero-close { + position: absolute; + top: var(--space-lg); + right: var(--space-lg); + display: flex; + padding: var(--space-xs); + background: none; + border: none; + border-radius: var(--radius-sm); + color: #fff; + opacity: 0.7; + cursor: pointer; +} + +.dashboard-hero-close:hover { + opacity: 1; + background: rgba(255, 255, 255, 0.18); +} + +.dashboard-hero-eyebrow { + margin: 0 0 var(--space-sm); + font-size: var(--text-sm); + font-weight: var(--font-semibold); + letter-spacing: 0.12em; + opacity: 0.8; +} + +.dashboard-hero h2 { + margin: 0 0 var(--space-md); + font-size: var(--text-2xl); + font-weight: var(--font-semibold); +} + +.dashboard-hero-body { + margin: 0; + font-size: var(--text-base); + line-height: 1.55; + /* ponytail: no measure cap, the band is only ~2 lines of copy. Put a + max-width back if the text ever grows past three lines. */ + opacity: 0.9; + padding-right: var(--space-2xl); +} + +.dashboard-hero-actions { + display: flex; + align-items: center; + gap: var(--space-lg); + margin-top: var(--space-xl); +} + +.dashboard-hero-cta { + background: #fff; + color: var(--color-gray-900); + border: none; + border-radius: var(--radius-md); + padding: var(--space-sm) 1.25rem; + font-size: var(--text-base); + font-weight: var(--font-semibold); + cursor: pointer; +} + +.dashboard-hero-link { + color: #fff; + font-size: var(--text-base); + text-decoration: underline; + cursor: pointer; } .dashboard-section { @@ -1392,7 +1479,7 @@ justify-content: center; width: 34px; height: 34px; - color: #333; + color: var(--color-gray-700); cursor: pointer; } @@ -1402,11 +1489,11 @@ gap: 2px; padding: 8px 12px 8px 8px; min-width: 170px; - border-top: 1px solid #ddd; + border-top: 1px solid var(--color-gray-300); } .custom-layer-panel:hover .custom-layer-panel__toggle { - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--color-gray-300); } .custom-layer-panel:hover .custom-layer-panel__body { @@ -1424,7 +1511,7 @@ } .custom-layer-panel__row:hover { - background: #f5f5f5; + background: var(--color-gray-100); } .custom-layer-panel__row input[type='checkbox'] { @@ -1432,7 +1519,7 @@ width: 14px; height: 14px; cursor: pointer; - accent-color: var(--color-primary, #4f46e5); + accent-color: var(--color-primary); } .custom-layer-panel__swatch { @@ -1443,7 +1530,7 @@ } .custom-layer-panel__label { - color: #333; + color: var(--color-gray-700); user-select: none; } @@ -1463,18 +1550,18 @@ justify-content: center; width: 34px; height: 34px; - color: #333; + color: var(--color-gray-700); cursor: pointer; } .basemap-selector__body { display: none; padding: 10px; - border-top: 1px solid #ddd; + border-top: 1px solid var(--color-gray-300); } .basemap-selector:hover .basemap-selector__toggle { - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--color-gray-300); } .basemap-selector:hover .basemap-selector__body { @@ -1502,11 +1589,11 @@ } .basemap-selector__tile:hover { - background: #f5f5f5; + background: var(--color-gray-100); } .basemap-selector__tile.is-active { - border-color: var(--color-primary, #4f46e5); + border-color: var(--color-primary); } .basemap-selector__thumb { @@ -1519,7 +1606,7 @@ .basemap-selector__label { font-size: 11px; - color: #333; + color: var(--color-gray-700); user-select: none; max-width: 64px; text-align: center; @@ -1668,7 +1755,7 @@ padding: 0.3rem 0.85rem; border-radius: 999px; border: 1px solid var(--color-gray-200); - background: var(--color-gray-50, #f9fafb); + background: var(--color-gray-50); font-size: var(--text-sm); color: var(--color-gray-700); cursor: pointer; @@ -1812,9 +1899,9 @@ .measure-control__toggle--active, .measure-control__toggle--active:hover { - background: var(--color-primary-600, #4f46e5); + background: var(--color-primary-600); color: white; - border-color: var(--color-primary-600, #4f46e5); + border-color: var(--color-primary-600); } .measure-control__readout { @@ -1984,11 +2071,11 @@ } .saved-row-menu-item-danger { - color: #b42318; + color: var(--color-red-700); } .saved-row-menu-item-danger:hover { - background: #fef3f2; + background: var(--color-red-100); } /* Save modal */ @@ -2017,7 +2104,7 @@ .save-modal-input:focus { outline: none; border-color: var(--color-primary-200); - box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15); + box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2); } .save-modal-hint { @@ -2045,8 +2132,8 @@ width: 56px; height: 56px; border-radius: 50%; - background: rgba(139, 92, 246, 0.12); - color: var(--color-primary-600, #7c3aed); + background: rgba(var(--color-primary-rgb), 0.12); + color: var(--color-primary-600); display: flex; align-items: center; justify-content: center; @@ -2096,8 +2183,8 @@ .publish-field-input:focus { outline: none; - border-color: var(--color-primary-300, #a78bfa); - box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15); + border-color: var(--color-primary-300); + box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2); } .publish-field-hint { @@ -2132,8 +2219,8 @@ } .tag-input:focus-within { - border-color: var(--color-primary-300, #a78bfa); - box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15); + border-color: var(--color-primary-300); + box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2); } .tag-chip { @@ -2141,7 +2228,7 @@ align-items: center; gap: 4px; padding: 2px 8px; - background: var(--color-gray-100, #f3f4f6); + background: var(--color-gray-100); border-radius: 999px; font-size: var(--text-sm); color: var(--color-gray-800); @@ -2189,7 +2276,7 @@ height: 64px; border-radius: 50%; background: rgba(34, 197, 94, 0.15); - color: #16a34a; + color: var(--color-green-700); display: flex; align-items: center; justify-content: center; @@ -2238,7 +2325,7 @@ align-items: center; gap: var(--space-md); padding: var(--space-sm) var(--space-lg); - background: var(--color-gray-50, #f9fafb); + background: var(--color-gray-50); border-bottom: 1px solid var(--color-gray-200); } @@ -2305,7 +2392,7 @@ width: 90%; max-width: 420px; padding: var(--space-xl); - background: linear-gradient(180deg, #d9ccff, #efeaff); + background: linear-gradient(180deg, var(--color-primary-200), var(--color-primary-100)); border-radius: var(--radius-lg); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25); text-align: center; @@ -2315,7 +2402,7 @@ margin: 0 0 var(--space-lg); font-size: var(--text-2xl, 1.5rem); font-weight: var(--font-semibold); - color: var(--color-gray-900, #111); + color: var(--color-gray-900); } .how-it-works-tracks { @@ -2387,8 +2474,8 @@ gap: 0.75rem; max-width: 560px; padding: 0.625rem 0.875rem; - background: var(--color-amber-50, #fffbeb); - border: 1px solid var(--color-amber-300, #fcd34d); + background: var(--color-yellow-50); + border: 1px solid var(--color-yellow-400); border-radius: var(--radius-md); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); font-size: var(--text-sm); @@ -2436,10 +2523,10 @@ .cached-result-notice button { flex-shrink: 0; padding: 0.25rem 0.625rem; - background: var(--color-primary-50, #eff6ff); + background: var(--color-primary-50); border: 1px solid var(--color-primary-200); border-radius: var(--radius-sm, 4px); - color: var(--color-primary-700, #1d4ed8); + color: var(--color-primary-700); font-size: var(--text-xs, 0.75rem); font-weight: 600; cursor: pointer; diff --git a/src/components/DesignSystem/DesignSystem.css b/src/components/DesignSystem/DesignSystem.css index fbb8785..7c959c4 100644 --- a/src/components/DesignSystem/DesignSystem.css +++ b/src/components/DesignSystem/DesignSystem.css @@ -406,7 +406,7 @@ } .ds-contrast-row--fail { - background: #fff5f5; + background: var(--color-red-100); } .ds-contrast-row--fail td:last-child { diff --git a/src/components/DesignSystem/DesignSystem.tsx b/src/components/DesignSystem/DesignSystem.tsx index 033d711..48f1a42 100644 --- a/src/components/DesignSystem/DesignSystem.tsx +++ b/src/components/DesignSystem/DesignSystem.tsx @@ -23,21 +23,24 @@ const COLOR_PALETTES = [ ], }, { - name: 'Primary (Blue)', + name: 'Primary (Blue), the only accent ramp', tokens: [ + { variable: '--color-primary-50', hex: '#f5fbff' }, { variable: '--color-primary-100', hex: '#ebf8ff' }, { variable: '--color-primary-200', hex: '#bee3f8' }, + { variable: '--color-primary-300', hex: '#90cdf4' }, + { variable: '--color-primary-400', hex: '#63b3ed' }, { variable: '--color-primary-600', hex: '#3182ce' }, { variable: '--color-primary-700', hex: '#2b6cb0' }, ], }, { - name: 'Indigo (Accent)', + name: 'Indigo (aliases of Primary, kept for old call sites)', tokens: [ - { variable: '--color-indigo-100', hex: '#ebf4ff' }, - { variable: '--color-indigo-300', hex: '#a3bffa' }, - { variable: '--color-indigo-600', hex: '#5a67d8' }, - { variable: '--color-indigo-700', hex: '#4c51bf' }, + { variable: '--color-indigo-100', hex: '#ebf8ff' }, + { variable: '--color-indigo-300', hex: '#90cdf4' }, + { variable: '--color-indigo-600', hex: '#3182ce' }, + { variable: '--color-indigo-700', hex: '#2b6cb0' }, ], }, { @@ -60,6 +63,7 @@ const COLOR_PALETTES = [ { name: 'Yellow (Warning)', tokens: [ + { variable: '--color-yellow-50', hex: '#fffbeb' }, { variable: '--color-yellow-100', hex: '#fefcbf' }, { variable: '--color-yellow-400', hex: '#ecc94b' }, { variable: '--color-yellow-800', hex: '#744210' }, diff --git a/src/index.css b/src/index.css index 3ebbb95..801ad00 100644 --- a/src/index.css +++ b/src/index.css @@ -1,12 +1,14 @@ :root { /* Typography */ font-family: + Inter, system-ui, -apple-system, - BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + /* Tabular figures so result counts and coordinates do not jitter. */ + font-variant-numeric: tabular-nums; line-height: 1.5; font-weight: 400; font-synthesis: none; @@ -42,17 +44,23 @@ --color-gray-100: #edf2f7; --color-gray-50: #f7fafc; - /* Primary (blue) */ + /* Primary (blue) — the one accent ramp for all UI chrome */ --color-primary-700: #2b6cb0; --color-primary-600: #3182ce; - --color-primary-100: #ebf8ff; + --color-primary-400: #63b3ed; + --color-primary-300: #90cdf4; --color-primary-200: #bee3f8; + --color-primary-100: #ebf8ff; + --color-primary-50: #f5fbff; + --color-primary: var(--color-primary-600); + --color-primary-rgb: 49, 130, 206; - /* Indigo (accent) */ - --color-indigo-700: #4c51bf; - --color-indigo-600: #5a67d8; - --color-indigo-300: #a3bffa; - --color-indigo-100: #ebf4ff; + /* ponytail: indigo used to be a second accent family. Aliased, not deleted, + so the ~15 existing call sites keep working. */ + --color-indigo-700: var(--color-primary-700); + --color-indigo-600: var(--color-primary-600); + --color-indigo-300: var(--color-primary-300); + --color-indigo-100: var(--color-primary-100); /* Green */ --color-green-700: #2f855a; @@ -67,6 +75,7 @@ /* Yellow (warning) */ --color-yellow-800: #744210; + --color-yellow-50: #fffbeb; --color-yellow-400: #ecc94b; --color-yellow-100: #fefcbf; @@ -104,7 +113,7 @@ /* Shadows */ --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.04); - --shadow-card-hover: 0 4px 12px rgba(90, 103, 216, 0.12); + --shadow-card-hover: 0 4px 12px rgba(var(--color-primary-rgb), 0.12); /* Base colors */ color: var(--color-gray-800); From 73bcce074a3d018fa9168852f174c3ebd51e0bf2 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Thu, 17 Sep 2026 00:00:35 -0400 Subject: [PATCH 47/66] feat(dashboard): intro band explaining what Explorer is Replaces the 'Welcome to Sawgraph!' heading with a band that says what the tool does: an interface for researchers to explore the knowledge graph without writing SPARQL. Two ways in, the existing How it works tour and a new analysis. Dismissable for the visit, deliberately not persisted. The header also gains a link to the SAWGraph project site, which had an empty right side on the dashboard. (Its CSS rides along with the palette commit; both live in App.css.) --- src/components/Dashboard/Dashboard.tsx | 54 ++++++++++++++++++++++++-- src/components/Layout/Header.tsx | 12 ++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/components/Dashboard/Dashboard.tsx b/src/components/Dashboard/Dashboard.tsx index 8ddd854..d320761 100644 --- a/src/components/Dashboard/Dashboard.tsx +++ b/src/components/Dashboard/Dashboard.tsx @@ -24,6 +24,7 @@ import { toSavedQueryParam } from '../../types/savedQuestion'; export function Dashboard() { const navigate = useNavigate(); const [searchOpen, setSearchOpen] = useState(false); + const [heroDismissed, setHeroDismissed] = useState(false); const [searchFilter, setSearchFilter] = useState('all'); const isTourOpen = useQueryStore((s) => s.isTourOpen); const openTour = useQueryStore((s) => s.openTour); @@ -62,7 +63,52 @@ export function Dashboard() { return (
-

Welcome to Sawgraph!

+ {!heroDismissed && ( +
+ +

SAWGraph Explorer

+

Explore PFAS contamination without writing a line of SPARQL

+

+ Explorer is an easy to use interface for researchers to explore + the SAWGraph knowledge graph without writing SPARQL. Pick an + entity, a relationship, and an anchor, say samples downstream of a + paper mill, and Explorer runs the queries and maps the answer. +

+ +
+ )}
@@ -145,7 +191,7 @@ export function Dashboard() {
Loading…
) : communityTop.length === 0 ? (
- No community analyses yet — publish one to see it here. + No community analyses yet. Publish one to see it here.
) : (
@@ -193,7 +239,9 @@ export function Dashboard() { } else { // Map/edit tours live on the editor route; hand off via the store. setPendingTour(id); - navigate(id === 'edit' ? '/q/new' : `/q/${PREBUILT_QUERIES[0].id}`); + navigate( + id === 'edit' ? '/q/new' : `/q/${PREBUILT_QUERIES[0].id}`, + ); } }} /> diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index a9d00b8..250952e 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -14,6 +14,18 @@ export function Header() {
+ + About the SAWGraph project + + {isEditor && ( - - {expanded &&

{query.description}

} - -
- Tags - {visibleTags.map((tag) => ( - - {tag} - - ))} - {hiddenCount > 0 && ( - +{hiddenCount} - )} + + + {expanded &&

{query.description}

} + +
+ Tags + {visibleTags.map((tag) => ( + + {tag} + + ))} + {hiddenCount > 0 && ( + +{hiddenCount} + )} +
+ + { + // No generated thumbnail yet: show the plain basemap for the region + // rather than a broken image. + const img = e.currentTarget; + const fallback = questionThumbnailUrl(query.question); + if (img.src !== fallback) img.src = fallback; + }} + />
); } diff --git a/src/constants/regionBounds.ts b/src/constants/regionBounds.ts new file mode 100644 index 0000000..9ccd082 --- /dev/null +++ b/src/constants/regionBounds.ts @@ -0,0 +1,67 @@ +import type { AnalysisQuestion, RegionFilter } from '../types/query'; + +/** [west, south, east, north] in WGS84 degrees. */ +export type Bbox = [number, number, number, number]; + +// ponytail: a hand-written table, not a boundary lookup. Every prebuilt +// question is scoped to one of these, and the thumbnail only needs to be +// recognisable. Add a row when a question uses a region that is not here; the +// fallback is the lower 48, which is honest about knowing nothing. +const COUNTY_BOUNDS: Record = { + '17031': [-88.27, 41.47, -87.52, 42.15], // Cook County, Illinois + '23005': [-70.65, 43.55, -69.85, 44.1], // Cumberland County, Maine + '23013': [-69.35, 43.75, -68.65, 44.35], // Knox County, Maine + '23019': [-69.35, 44.68, -68.0, 46.05], // Penobscot County, Maine +}; + +const STATE_BOUNDS: Record = { + '17': [-91.6, 36.9, -87.4, 42.6], // Illinois + '18': [-88.1, 37.7, -84.7, 41.8], // Indiana + '23': [-71.1, 42.9, -66.9, 47.5], // Maine +}; + +const LOWER_48: Bbox = [-125, 24, -66.9, 49.4]; + +function union(a: Bbox, b: Bbox): Bbox { + return [ + Math.min(a[0], b[0]), + Math.min(a[1], b[1]), + Math.max(a[2], b[2]), + Math.max(a[3], b[3]), + ]; +} + +function boundsFor(region: RegionFilter | undefined): Bbox | null { + if (!region) return null; + const counties = (region.countyCodes ?? []) + .map((code) => COUNTY_BOUNDS[code]) + .filter((b): b is Bbox => Boolean(b)); + if (counties.length > 0) return counties.reduce(union); + return (region.stateCode && STATE_BOUNDS[region.stateCode]) || null; +} + +/** Where a question looks, before any results come back. */ +export function boundsForQuestion(question: AnalysisQuestion): Bbox { + const a = boundsFor(question.blockA?.region); + const c = boundsFor(question.blockC?.region); + return a && c ? union(a, c) : (a ?? c ?? LOWER_48); +} + +/** + * Plain basemap of the question's region. Used only as the fallback for a card + * whose thumbnail has not been generated yet; the real thumbnails are built by + * scripts/build-thumbnails.mts and show the actual results. + */ +export function questionThumbnailUrl(question: AnalysisQuestion): string { + const bbox = boundsForQuestion(question); + // Pad so the region does not touch the frame. + const padX = (bbox[2] - bbox[0]) * 0.12; + const padY = (bbox[3] - bbox[1]) * 0.12; + const padded = [ + bbox[0] - padX, + bbox[1] - padY, + bbox[2] + padX, + bbox[3] + padY, + ].join(','); + return `https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/export?bbox=${padded}&bboxSR=4326&size=440,300&format=png&f=image`; +} From 8e9b67a5a6ae0b3a5fd22679c9e8c9f09f592d34 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Thu, 17 Sep 2026 00:19:34 -0400 Subject: [PATCH 51/66] fix(dashboard): thumbnail row layout leaked onto the community cards CommunityAnalysisCard shares .query-card, so putting display:flex there for the prebuilt thumbnail laid its title, author and tags out in a row. Move the row layout to .query-card-with-thumb, which only the prebuilt cards use. --- src/App.css | 11 ++++++++--- src/components/Dashboard/PrebuiltQueryCard.tsx | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/App.css b/src/App.css index 2c749b0..4e7f7d8 100644 --- a/src/App.css +++ b/src/App.css @@ -1384,9 +1384,6 @@ } .query-card { - display: flex; - align-items: flex-start; - gap: var(--space-lg); background: white; border: 1px solid var(--color-gray-200); border-radius: var(--radius-lg); @@ -1403,6 +1400,14 @@ box-shadow: var(--shadow-card-hover); } +/* Only the prebuilt cards carry a thumbnail. The community cards share + .query-card and stack their children, so the row layout lives here. */ +.query-card-with-thumb { + display: flex; + align-items: flex-start; + gap: var(--space-lg); +} + .query-card-body { flex: 1; min-width: 0; diff --git a/src/components/Dashboard/PrebuiltQueryCard.tsx b/src/components/Dashboard/PrebuiltQueryCard.tsx index 07632f4..8c01734 100644 --- a/src/components/Dashboard/PrebuiltQueryCard.tsx +++ b/src/components/Dashboard/PrebuiltQueryCard.tsx @@ -17,7 +17,7 @@ export function PrebuiltQueryCard({ query, onClick }: PrebuiltQueryCardProps) { const hiddenCount = query.tags.length - MAX_VISIBLE_TAGS; return ( -
+

{query.title}

From 66f3fda9b8a42080886e304f95c67d550ca7d93a Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Thu, 17 Sep 2026 20:54:04 -0400 Subject: [PATCH 52/66] fix(engine): stop two silent filters in the fused queries Both surfaced on "What facilities are upstream from PFOS samples in York and Cumberland counties (Maine)?", which failed at step 1 with 500 out-of-memory, sliced into its two counties, and failed both slices. Join order. buildFusedWhereBody always wrote the anchor side first, and an upstream question puts block A there. With no region and no industry filter on block A the query started from every facility in the graph and traced the national flowline network to find samples in two Maine counties. QLever does not search join orders exhaustively at these body sizes, so it follows the query text: writing the constrained side first is the whole fix, same triples and same variables in a different order. Measured across all 72 hydrology shape/config pairs: 5 rescued, 0 regressions, 0 rows lost, faster in 50 of 66 comparable runs. Distance-bounded traces and IRI-pinned slices keep the anchor-first order, the first because boundedTrace embeds the seed twice and was never measured reordered, the second because a pin already made the anchor the small side. Observation joins. bindEntityInCell emitted the whole observation chain whenever any sample filter was set, including coso:measurementUnit, which a non-detect does not have. A substance-only question with "include non-detects" ticked therefore dropped every non-detect: 774 of 1,688 Cumberland PFOS observations, turning 23 sample points and 13 facilities into 32 and 15 once only the joins an active filter reads are emitted. The same required join hid 2,860 of 3,334 popup rows in buildSampleDetailByIriQuery; moving it after resultValueClauses() with the symbol lookup nested inside costs what it did before. buildEntityProbeQuery now uses the same lean bind, since the probe list becomes the chunk membership and a narrowing join there removes entities from every slice. scripts/check-query-joins.mts asserts both rules on the emitted SPARQL (265 checks) and runs in CI. docs/DEBUGGING.md records the measurements and the two designs that were tried and rejected, including the sub-SELECT that rescued 5 shapes and broke 7. --- .github/workflows/checks.yml | 3 + docs/DEBUGGING.md | 66 ++++ ...7-fused-seed-side-and-observation-joins.md | 313 ++++++++++++++++++ package.json | 1 + scripts/check-query-joins.mts | 230 +++++++++++++ src/engine/templates/downstreamSamples.ts | 15 +- src/engine/templates/fusedQueries.ts | 156 +++++++-- 7 files changed, 753 insertions(+), 31 deletions(-) create mode 100644 docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md create mode 100644 scripts/check-query-joins.mts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 410a89e..38cc134 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -51,6 +51,9 @@ jobs: - name: Substance labels run: npm run check-substance-labels + - name: Query join order and observation joins + run: npm run check-query-joins + # Not blocking yet: `npm run lint` reports 15 pre-existing errors, all in # components and none related to the engine. Make this a required step in # the same change that clears them, not before, or the signal is noise diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 1d8cf8a..c32d310 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -499,3 +499,69 @@ side does not (`?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor` before attaching to a flowline). So "A upstream from C" and "C downstream from A" are not exactly reciprocal even now, which is part of the 840 vs 474 gap above. Making them reciprocal means applying that tolerance to both sides or neither. + +--- + +## 2026-09-17: Two silent filters in the fused queries, join order and the unit join + +Both found while running "What facilities are upstream from PFOS samples in York +and Cumberland counties (Maine)?" with the facilities block left empty. The +pipeline failed at step 1 after 116.3s with `500 out-of-memory` ("tried to +allocate 204.8 MB, only 159.3 MB available"), sliced into the two counties, and +both slices failed the same way. + +**Join order (fixed).** `buildFusedWhereBody` always wrote the anchor side +first, and for an upstream question the planner puts block A on the anchor side. +With no region and no industry filter on block A, the query started from every +facility in the graph and traced the national flowline network to look for +samples in two Maine counties. + +QLever does not search join orders exhaustively at these body sizes (12-14 +triples), so it follows the query text. Writing the constrained side first is +the whole fix: same triples, same variables, different order. Measured across +all 72 hydrology shape/config pairs, one county scope: 5 shapes rescued, 0 +regressions, 0 rows lost, faster in 50 of 66 comparable runs. + +Two things this is *not*, both measured, so nobody re-derives them: + +- **Not volume.** Rows materialised through the trace from Cumberland seeds: + samples + PFOS 872,385, facilities 681,299, wells 4,183,432. The samples seed + materialises more than the facilities seed and succeeds where it fails. +- **Not a sub-SELECT.** Fencing the constrained side in a sub-SELECT rescues the + same 5 shapes but breaks 7 that work today, all OOM: a sub-SELECT is an + optimiser barrier, so it forces one plan and forbids every other. A variant + that carried only the distinct cells through the fence and re-joined the + entity last failed the same 7, three of them degrading from OOM into 60s + timeouts. + +**The unit join (fixed).** `bindEntityInCell` emitted the entire observation +chain whenever *any* sample filter was set, including +`?result coso:measurementUnit ?unit`. A non-detect has no +`coso:measurementUnit` (`templates/samples.ts` documents this, and the by-IRI +templates already gated it behind `needsUnitJoin`), so a substance-only question +with "include non-detects" ticked silently dropped every non-detect. Cumberland +PFOS observations: 1,688 total, 914 with a unit, 774 non-detect with none. At +sample-point level, 23 points and 13 facilities became 32 and 15 once the joins +a substance filter actually reads were the only ones emitted. + +The same required join was hiding non-detects in the popup's observation table +(`buildSampleDetailByIriQuery`): on sample point 64220, **474 of 3,334 rows**, +the missing 2,860 all non-detects. `OPTIONAL` in place OOMs at 819.7 MB; joining +it after `resultValueClauses()` with the symbol lookup nested inside costs what +it did before (6.88s vs 6.59s). + +**Lessons** + +- **Every required triple is also a filter.** Joining detail the query only + displays, or that an inactive filter would have read, deletes rows. Both bugs + here are one habit: an all-or-nothing gate that conflated "the user set a + filter" with "fetch the whole record". +- **Textual triple order is a semantic-free change with a non-semantic-free + cost.** It cannot alter the answer, and it decided whether this question + answered at all. That makes it cheap to try and worth asserting: + `scripts/check-query-joins.mts` reads the emitted SPARQL and fails if the + unconstrained side leads, or if the unit join appears without a concentration + range. +- **Measure the fix against the shapes it touches, not the one that prompted + it.** The sub-SELECT looked like a 48% median win on the question at hand and + was a net regression across the shape space. diff --git a/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md b/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md new file mode 100644 index 0000000..8bf613a --- /dev/null +++ b/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md @@ -0,0 +1,313 @@ +# Seed the fused trace from the constrained side, and only join the observation detail a filter needs + +**Status**: active +**Created**: 2026-09-17 + +## Problem + +Two independent defects in `src/engine/templates/fusedQueries.ts`, both found while +running "What facilities are upstream from PFOS samples in York and Cumberland +counties (Maine)?" (facilities block empty, samples block PFOS + ME + two counties, +include non-detects on). + +**P1, seed side.** `buildFusedWhereBody` always emits the anchor block first, and +for an upstream question the planner puts block A on the anchor side +(`planner.ts:215`). Block A here has no region and no industry filter, so the query +starts from every facility in the graph and traces the national flowline network to +look for samples in two Maine counties. Measured: the pipeline fails at step 1 after +116.3s with `500 out-of-memory` ("tried to allocate 204.8 MB, only 159.3 MB +available"), retries as two county slices, and both slices fail the same way. +Wrapping the constrained side (samples + region + substance) in a sub-SELECT and +joining outward returns the answer in 18.6s cold. Full pipeline with the fix: +100.0s cold, 8.9s warm, complete. + +**P2, observation joins.** `bindEntityInCell` returns the full observation chain for +a samples block whenever `hasSampleFilters` is true, regardless of which filters are +set: `analyzedSample`, `hasResult`, `sampleOfMaterialType`, the material label, and +`coso:measurementUnit`. A substance-only filter needs two triples. Worse, the unit +join is a silent filter: a non-detect has no `coso:measurementUnit` (documented at +`samples.ts:11`, and the by-IRI templates already gate it behind `needsUnitJoin`), so +fused discovery drops non-detects even when the user asked to include them. Measured +on Cumberland PFOS observations: 1,688 observation rows, 914 with a unit, 774 +non-detect with no unit. At sample-point level on a pinned comparison case +(Cumberland, NAICS 5622) the shipped query returns 23 sample points and 13 +facilities; without the unneeded joins it returns 32 and 15, a superset with zero +losses either way. + +## Approach + +**P1: write the constrained side first in the flat body. No sub-SELECT.** + +`buildFusedWhereBody` emits the anchor block, then the trace, then the target block. +When the anchor side has no region, no block filters and no IRI pin and the target +side has at least one of those, emit the target block, then the trace, then the +anchor block. Same triples, same variables, different textual order. Nothing else +changes: no sub-SELECT, no new option on the builders, no executor retry. + +Two earlier designs were measured and rejected, in this order: + +1. *Wrap the constrained side in a sub-SELECT.* Rescues 5 shapes, breaks 7 that work + today, all `500 out-of-memory`. A sub-SELECT is an optimiser barrier in QLever: it + has to be materialised before anything joins to it and the planner cannot reorder + across it, so it forces one plan and forbids every other. +2. *Keep the sub-SELECT but project only the distinct cells, re-joining the target + entity last.* Same 7 shapes still fail, three of them degrading from OOM into 60s + timeouts. Entity multiplicity through the trace was not the cause either. + +What the measurements actually point at is that **textual triple order changes +QLever's plan for these bodies**. They run 12 to 14 triples, past the point where the +planner searches join orders exhaustively, so it falls back on something that follows +the query text. Writing the unconstrained side first is what produces the bad plan; +moving the constrained side to the top is the entire fix. + +Volume is not the discriminator, which is worth recording so nobody re-derives it. +Rows materialised through the trace, Cumberland seeds: samples + PFOS 872,385; +facilities 681,299; wells 4,183,432. The samples seed materialises more than the +facilities seed and succeeds where it fails. + +**P2: emit only the joins the active filters read.** + +Replace the all-or-nothing `hasSampleFilters` gate with a per-filter requirement set +for the IRI-finding queries: + +| filter set | joins needed | +| --- | --- | +| `substances` | `?observation coso:observedAtSamplePoint`, `coso:ofDSSToxSubstance` | +| `materialTypes` | the above + `coso:analyzedSample`, `coso:sampleOfMaterialType` | +| `minConcentration` / `maxConcentration` | + `coso:hasResult`, `qudt:quantityValue`, `coso:measurementUnit` | +| `includeNondetects: false` | + `coso:hasResult` and the non-detect binds | +| none | no observation joins (today's `sampleObservations: false`) | + +The material *label* join (`?matType rdfs:label`) is never needed for filtering, only +for display, so it goes in every discovery case. Hydrate queries keep the full block: +they project `?matTypeLabel`, `?unit` and `?result_value`. + +While in there, fix the adjacent `near` wart this exposed: `buildFusedNearQuery` +passes `anchorSampleObservations: opts.project !== 'anchor'`, so the *non-projected* +samples side keeps the whole chain even with zero filters. Verified: anchor samples +with no filters, `project: 'target'` emits the chain and the unit join. The same +per-filter rule removes it. + +## Tasks + +- [x] `fusedQueries.ts`: `sideIsConstrained` (region / block filters / IRI pin per side) and the target-first hydrology body when the anchor is unconstrained +- [x] `fusedQueries.ts`: replace the `hasSampleFilters` gate in `bindEntityInCell` with `sampleJoinsNeeded`, per-filter; hydrate callers keep the full block +- [x] `buildFusedNearQuery`: drop the `project !== side` heuristic, pass `false` for both sides +- [x] `buildEntityProbeQuery`: same lean bind, so the probe sees what discovery sees (the probe list becomes the chunk membership) +- [x] `buildSampleDetailByIriQuery`: the unit join moved after `resultValueClauses()` with the symbol lookup nested inside, so popups stop hiding non-detects +- [x] `scripts/check-query-joins.mts` (265 checks): join order across all 72 hydrology shapes x 2 projections, the pinned and distance-bounded exceptions, the per-filter join rule on hydrology and near, and that no prebuilt reorders. Wired into `package.json` and `.github/workflows/checks.yml` +- [x] `docs/DEBUGGING.md`: both bugs, with the measurements and the two rejected designs +- [ ] re-run `npm run health-check` and record the row-count movement in `docs/health/STATUS.md` +- [ ] `npm run query-matrix` sweep, then `--index`, to price both fixes across the shape space +- [ ] update `docs/QUERY-MATRIX.md` (error catalogue: the OOM that this removes) +- [ ] decide on the retry variant below + +## Verified after implementing (2026-09-17) + +`check-trace-direction` (2,068 checks), `check-step-labels` (651), +`check-cache-key` (19), `check-substance-labels` (13) and the new +`check-query-joins` (265) all pass. `tsc -b` clean; `npm run lint` still reports +the same 15 pre-existing component errors as the unmodified tree. + +Live, through the real builder, single-county spot checks matched the sweep +exactly where the sweep was comparable: `facilities <- facilities` 4 rows, +`waterBodies <- facilities` 146, `wells <- aquifers` 7,434. The two samples +shapes returned 307 and 351 rather than the sweep's 339 and 384, which is P2 +working: sweep 2's flat variant predated it and dropped the substance filter +entirely, so its counts were unfiltered. 307 and 351 match sweep 1, which +applied the filter. + +Popup detail on sample point 64220: **3,334 rows, 2,860 non-detect, 8.8s**, up +from 474 rows. + +**The screenshot question now answers, but not quickly.** End to end through the +pipeline: **245.5s, status success**, where before it was a hard error. It is +slow because the two-county query still exceeds the budget as one flat request +(62s timeout, reproducible), so the executor rescues it by slicing into the two +counties, and each county takes 15-16s per projection. The slices now succeed, +which is why the run completes at all; before the fix they inherited the +anchor-first order and failed too. + +## The retry variant, measured and not implemented + +The sub-SELECT was rejected as a *default* because it breaks 7 shapes. As a +*retry after a splittable failure* it cannot regress anything that succeeds, and +on this question it is worth a great deal: + +| Query | Time | Rows | +| --- | --- | --- | +| flat reorder, both counties | 62.0s timeout | fails | +| sub-SELECT, both counties | **7.3s** | 503 | +| flat reorder, Cumberland only | 15.2s | 307 | +| sub-SELECT, Cumberland only | **1.4s** | 307 | + +That is 245.5s of slice-and-retry versus one 7.3s request. It needs a +`buildRetryQuery` hook on `PipelineStep` and one branch in the executor's +failure path, ahead of `chooseAxis`. Deliberately left out of this change: it is +a new execution mechanism rather than a template fix, and it should be measured +across the shape space on its own. + +## Measured regression sweep (2026-09-17) + +All 36 hydrology entity-type pairs, two configurations each (region + filters on the +target side with the anchor wide open, and the mirror), `project: 'target'`, +Cumberland County, unbounded trace. Shipped query versus proposed query, comparing +IRI sets and time. 72 comparisons per sweep, run twice: once for the rejected +sub-SELECT design, once for the flat reorder that this plan now proposes. + +| | sub-SELECT (rejected) | flat reorder (proposed) | +| --- | ---: | ---: | +| Shipped succeeded | 66 | 66 | +| Proposed succeeded | 70 | **71** | +| Rescues (shipped failed, proposed worked) | 5 | **5** | +| Regressions (shipped worked, proposed failed) | **7** | **0** | +| Comparisons that lost a row | 0 | **0** | +| Median time change where both succeed | +48% | +9% | + +The +48% on the rejected design is inflated: several of its "wins" are shapes it then +broke. The flat reorder is faster in 50 of 66 comparable runs. + +The 5 rescues are the same in both sweeps, and they are the screenshot shape: +`samples <- facilities / waterBodies / wells / aquifers / streams [target-scoped]`. +Shipped OOMs or times out at 28.1s to 69.3s; the flat reorder answers in 7.9s to +12.8s. + +One shape fails both ways and is untouched by this plan: `wells <- wells +[target-scoped]`, ~80s timeout on both. + +The 7 shapes the sub-SELECT broke, all of which the flat reorder leaves working with +identical row sets: `facilities <- facilities`, `facilities <- aquifers`, `facilities +<- streams`, `waterBodies <- facilities`, `waterBodies <- aquifers`, `wells <- +facilities`, `wells <- aquifers`. + +Sweep 1 also confirmed P2 independently: every `X <- samples [anchor-scoped]` row +gained rows and lost none (+599 wells, +129 streams, +42 samples, +19 facilities, ++13 water bodies, +13 aquifers), which is the recovered non-detects. + +**What the sweeps do not cover**, and what the tasks above therefore still call for: +one run per combination against a memory-pressured endpoint, a single county scope, +one filter configuration, `project: 'target'` only, and no `maxDistanceKm`. Several +passing shapes land at 15-25s, close enough to the 30s ceiling that load decides the +outcome. Distance-bounded traces route through `boundedTrace`, which embeds the body +a second time and was not measured here. + +## Impact on other query shapes + +**P1 reaches 72 of the 108 shapes, but reorders almost none of them in practice.** +The edit is in the `mode !== 'near'` branch, shared by `buildFusedHydrologyQuery`, +`buildFusedWellQuery` and (via the duplicated seed) `boundedTrace`, so it covers all +36 downstream and all 36 upstream shapes including the well and flowline layers. The +36 `near` shapes take the other branch and are untouched. Whether a given question +actually changes depends on its filters, not its shape: I evaluated all eight +prebuilt dashboard questions and **none of them reorder**, because every one has a +constrained anchor (`facilities` with an industry filter, or a county). The reorder +fires for user-built questions that leave one side wide open, which is exactly the +screenshot case. + +**P2 reaches every shape with samples on a filtered side, `near` included.** +`bindEntityInCell` is shared by all three builders. Of the 108 shapes, 33 have +samples on at least one side. Row counts move upward wherever a substance-only or +material-only filter is set, because those questions stop dropping non-detects. Of +the prebuilt questions only `facilities-upstream-pfhpa-gw-cumberland` carries sample +filters, and it sets a 10-1000 ng/L range, so it keeps the unit join and its counts +should not move at all. The `near` cleanup was measured on +`samples-near-agchem-maine`: 5 facilities shipped, 5 facilities trimmed, 8.05s vs +7.74s, so no movement there either. + +**P2 does not reintroduce the OOM the old note feared.** The `ponytail` comment at +`fusedQueries.ts:90` says dropping the unit join "triples the matched rows and the +endpoint OOMs on statewide pipelines". Re-measured on a statewide Maine PFOS +downstream question: shipped asks for 825.6 MB (project=target) / 712.1 MB +(project=anchor) and OOMs; trimmed asks for 409.6 MB and still OOMs. Trimming +*lowers* the peak allocation. The statewide shape fails either way, which is a +chunking problem, not this one. The comment should be replaced with these numbers. + +**Chunking behaviour is unchanged.** Both fixes are template-level. `chooseAxis`, +`halve` and the step budget keep working as they do now; P1 only makes the whole +query succeed more often, so slicing runs less. + +## Are we making the P2 mistake anywhere else? + +Audited every site that touches the sample observation chain. + +1. **`downstreamSamples.ts:97`, `buildSampleDetailByIriQuery` (popup detail): yes, + same bug, larger effect.** `?result coso:measurementUnit ?unit .` is required, so + the observation table in a sample popup silently omits every non-detect. Measured + on `me-egad-data#d.egad.samplePoint.64220`: **474 rows as shipped, 3,334 rows with + the unit join made optional, of which 2,860 are non-detects**. The naive fix + (`OPTIONAL { ?result coso:measurementUnit ?unit }` in place) OOMs at 819.7 MB. + Moving the join after `resultValueClauses()` and nesting the symbol lookup inside + it works at the same cost as today: 6.88s vs 6.59s, 3,334 rows. Worth doing in + this plan or immediately after it. +2. **`downstreamSamples.ts:40`, `buildSampleRetrievalByIriQuery` (sample hydration): + correct already.** Gated behind `needsUnitJoin(filters)`. Its other required joins + are legitimate: hydration lost exactly 1 of 547 discovered sample points in the + measured run, and that point has no `geo:asWKT` at all, so it cannot be drawn. +3. **`regions.ts` discovery queries (substance, material, county, industry dropdowns): + clean.** None of them join `coso:measurementUnit` or `coso:hasResult`; the + substance and material counts shown in the dropdowns are not deflated. +4. **`hydrate.ts` facility / water body / stream / aquifer queries: no observation + joins.** `buildFacilitiesByIri` does require `rdfs:label` on both the facility and + its industry code, which would drop an unlabelled facility; not observed in this + run and out of scope here. + +## The same class of bug elsewhere (measured 2026-09-17) + +Beyond the observation chain, every required (non-`OPTIONAL`) join in the templates +was checked against live per-entity coverage in Cumberland County and statewide +Maine. Three findings, one of them larger than P2. + +**1. The facility layer shows about a quarter of the facilities it could.** +`buildFacilitiesByIri` (`hydrate.ts:15`) and the facilities branch of +`bindEntityInCell` both require `fio:ofIndustry` and `?industryCode a +naics:NAICS-IndustryCode`, whether or not the user picked an industry. Maine, cells +to layer: + +| Required joins, cumulative | Facilities | +| --- | ---: | +| `fio:Facility` in ME S2 cells | 11,954 | +| + `geo:asWKT` (legitimate, cannot map without it) | 10,164 | +| + `rdfs:label` | 10,164 | +| + `fio:ofIndustry` | 3,601 | +| + `?ic a naics:NAICS-IndustryCode` | 2,718 | +| + `?ic rdfs:label` (what we ship) | 2,718 | + +So the industry-code requirement costs **7,446 of 10,164 mappable Maine facilities, +73%**. Cumberland alone: 2,595 in cells, 2,203 mappable, 603 shipped. The excluded +ones are not junk records: sampling them returns SEBAGO LAKE WATER TREATMENT +FACILITY, AMERICOLD LOGISTICS PLANT # 80573, KOCH MATERIALS. A water treatment plant +is exactly what a PFAS question is looking for. + +Both label joins are free (100% of geometry-carrying facilities have them), so they +are waste rather than a filter, and the NAICS type assertion costs a further 883 on +its own. Fixing this is a bigger behaviour change than P2 and deserves its own plan, +but it is the same mistake: a join added for display or for a filter that is not set. + +**2. `?s2cell` is projected by three hydrate queries and read by nothing.** +`buildFacilitiesByIri`, `buildSampleRetrievalByIriQuery` and `buildWaterBodiesByIri` +all select it; grep finds no consumer outside `templates/` and `engine/scope.ts`. +Its join is required, so it filters, and because it appears in `DISTINCT` / +`GROUP BY`, an entity touching several cells is returned several times. + +**3. Two suspects came back clean, worth recording so nobody re-checks them.** +Flowline `nhdplusv2:hasFTYPE` and geometry are at **434,501 of 434,501** graph-wide, +so requiring them costs nothing. Sample-side labels are complete too: of 576 +Cumberland sample points, 575 have geometry, 571 have an observation, and all 571 +have the lab-sample label, material type, material label and `coso:fromSamplePoint` +that the hydrate and detail queries require. The one sample point the pipeline drops +has no `geo:asWKT` at all. + +## Notes + +- Equivalence evidence for P1: on a pinned case the current template survives + (Cumberland, NAICS 5622), current and reordered return identical IRI sets both ways + when the observation joins are held constant (23 samples / 13 facilities, zero + diff). That is the check to re-run after implementing, since it separates P1 from + P2. +- Endpoint capacity is volatile. One repeat of the two-county query OOM'd trying to + allocate 1.6 MB, and York alone measured 9.5s standalone but 2.4s after Cumberland + warmed the shared sub-results. Treat single cold timings as plus or minus 10s, and + re-measure warm and cold separately. +- The screenshot question returns 3,013 facilities for two counties because block A + has no industry filter. Correct, but it is also 4 flowline batches and 37s of the + 100s cold run. Not part of this plan. diff --git a/package.json b/package.json index 2be375f..32ff0f9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "check-step-labels": "tsx scripts/check-step-labels.mts", "check-trace-direction": "tsx scripts/check-trace-direction.mts", "check-substance-labels": "tsx scripts/check-substance-labels.mts", + "check-query-joins": "tsx scripts/check-query-joins.mts", "query-matrix": "tsx scripts/query-matrix.mts", "health-check": "tsx scripts/health-check.mts" }, diff --git a/scripts/check-query-joins.mts b/scripts/check-query-joins.mts new file mode 100644 index 0000000..bac9f63 --- /dev/null +++ b/scripts/check-query-joins.mts @@ -0,0 +1,230 @@ +// Self-check for the two rules in +// docs/plans/done/2026-09-17-fused-seed-side-and-observation-joins.md. +// +// npx tsx scripts/check-query-joins.mts +// +// 1. Join order. QLever follows the query text at these body sizes, so the +// constrained side of a hydrology question has to be written first. Leading +// with an unfiltered side is what made "facilities upstream from PFOS +// samples in York and Cumberland" fail with 500 out-of-memory. +// +// 2. Observation joins. Every required triple is also a filter. A samples block +// may only join the observation detail its active filters actually read: the +// coso:measurementUnit join in particular deletes non-detects, which have no +// unit, and it was being emitted for substance-only questions that had +// "include non-detects" ticked. +// +// No network: these only build query strings. +import assert from 'node:assert/strict'; +import { planPipeline } from '../src/engine/planner'; +import { buildFusedHydrologyQuery, buildFusedNearQuery } from '../src/engine/templates/fusedQueries'; +import { PREBUILT_QUERIES } from '../src/constants/prebuiltQueries'; +import type { AnalysisQuestion, EntityBlock, EntityType, SampleFilters } from '../src/types/query'; + +const ENTITY_TYPES: EntityType[] = [ + 'samples', + 'facilities', + 'waterBodies', + 'wells', + 'aquifers', + 'streams', +]; +const PFOS = 'http://w3id.org/DSSTox/v1/DTXSID3031864'; +const GROUNDWATER = 'http://w3id.org/sawgraph/v1/me-egad#sampleMaterialType.GW'; + +let checks = 0; +const check = (cond: boolean, msg: string) => { + assert.ok(cond, msg); + checks++; +}; + +// Which side the body leads with. The first variable after WHERE { decides the +// plan; anything else in the body can follow. +function leadsWith(query: string): 'anchor' | 'target' | 'other' { + const body = query.slice(query.indexOf('WHERE {') + 'WHERE {'.length).trimStart(); + if (body.startsWith('?s2target') || body.startsWith('?ds_flowline')) return 'target'; + if (body.startsWith('?s2anchor')) return 'anchor'; + // A pinned side is inlined as VALUES before anything else. + if (body.startsWith('VALUES ?sp') || body.startsWith('VALUES ?facility')) return 'other'; + return 'other'; +} + +const filtersFor = (type: EntityType): Partial => { + switch (type) { + case 'samples': + return { sampleFilters: { substances: [PFOS], includeNondetects: true } }; + case 'facilities': + return { facilityFilters: { industryCodes: ['5622'] } }; + case 'waterBodies': + return { waterBodyFilters: { ftypes: ['StreamRiver'] } }; + case 'streams': + return { streamFilters: { ftypes: ['StreamRiver'] } }; + case 'aquifers': + return { aquiferFilters: { aquiferTypes: ['bedrock'] } }; + case 'wells': + return {}; + } +}; + +// --- 1. Join order, every hydrology pair, both projections. +for (const targetType of ENTITY_TYPES) { + for (const anchorType of ENTITY_TYPES) { + for (const project of ['target', 'anchor'] as const) { + const scopedTarget = buildFusedHydrologyQuery({ + anchor: { type: anchorType }, + target: { type: targetType, ...filtersFor(targetType) }, + targetRegion: ['23005'], + project, + direction: 'downstream', + }); + check( + leadsWith(scopedTarget) === 'target', + `${targetType} <- ${anchorType} (project ${project}): target is the only constrained side, so it must lead the body`, + ); + + const scopedAnchor = buildFusedHydrologyQuery({ + anchor: { type: anchorType, ...filtersFor(anchorType) }, + target: { type: targetType }, + anchorRegion: ['23005'], + project, + direction: 'downstream', + }); + check( + leadsWith(scopedAnchor) === 'anchor', + `${targetType} <- ${anchorType} (project ${project}): anchor is the constrained side, so the body must keep the anchor-first order`, + ); + + // An IRI pin from chunking counts as constrained: re-seeding from the + // other side would throw the slice away. + const pinned = buildFusedHydrologyQuery({ + anchor: { type: anchorType }, + target: { type: targetType, ...filtersFor(targetType) }, + targetRegion: ['23005'], + anchorIris: ['http://example.org/facility/1'], + project, + direction: 'downstream', + }); + check( + leadsWith(pinned) !== 'target', + `${targetType} <- ${anchorType} (project ${project}): an anchorIris pin must keep the anchor-first order`, + ); + } + } +} + +// Distance-bounded traces embed the seed a second time inside boundedTrace and +// were never measured reordered, so they keep the anchor-first order. +for (const targetType of ENTITY_TYPES) { + const bounded = buildFusedHydrologyQuery({ + anchor: { type: 'facilities' }, + target: { type: targetType, ...filtersFor(targetType) }, + targetRegion: ['23005'], + project: 'target', + direction: 'downstream', + maxDistanceKm: 50, + }); + check( + leadsWith(bounded) === 'anchor', + `${targetType} <- facilities, bounded: distance-bounded traces keep the anchor-first order`, + ); +} + +// --- 2. Observation joins, driven by the filters that are actually set. +const UNIT_JOIN = 'coso:measurementUnit'; +const OBS_JOIN = 'coso:observedAtSamplePoint'; +const MATERIAL_JOIN = 'coso:sampleOfMaterialType'; +const MATERIAL_LABEL = '?matTypeLabelC'; + +interface JoinCase { + name: string; + filters: SampleFilters | undefined; + unit: boolean; + observation: boolean; + material: boolean; +} + +const joinCases: JoinCase[] = [ + { name: 'no filters', filters: undefined, unit: false, observation: false, material: false }, + { + name: 'substance only', + filters: { substances: [PFOS], includeNondetects: true }, + unit: false, + observation: true, + material: false, + }, + { + name: 'material only', + filters: { materialTypes: [GROUNDWATER] }, + unit: false, + observation: true, + material: true, + }, + { + name: 'concentration range', + filters: { substances: [PFOS], minConcentration: 10, maxConcentration: 1000 }, + unit: true, + observation: true, + material: false, + }, + { + name: 'detects only', + filters: { substances: [PFOS], includeNondetects: false }, + unit: false, + observation: true, + material: false, + }, +]; + +for (const c of joinCases) { + const queries = [ + ['hydrology', buildFusedHydrologyQuery({ + anchor: { type: 'facilities', facilityFilters: { industryCodes: ['5622'] } }, + target: { type: 'samples', sampleFilters: c.filters }, + anchorRegion: ['23005'], + project: 'target', + direction: 'downstream', + })], + ['near', buildFusedNearQuery({ + anchor: { type: 'facilities', facilityFilters: { industryCodes: ['5622'] } }, + target: { type: 'samples', sampleFilters: c.filters }, + hops: 1, + project: 'anchor', + })], + ] as const; + + for (const [kind, query] of queries) { + check( + query.includes(UNIT_JOIN) === c.unit, + `${kind}, ${c.name}: the unit join must appear only for a concentration range (it deletes non-detects)`, + ); + check( + query.includes(OBS_JOIN) === c.observation, + `${kind}, ${c.name}: the observation join must appear only when a filter reads it`, + ); + check( + query.includes(MATERIAL_JOIN) === c.material, + `${kind}, ${c.name}: the material join must appear only when material types are picked`, + ); + check( + !query.includes(MATERIAL_LABEL), + `${kind}, ${c.name}: the material label is display-only and must never appear in an IRI-finding query`, + ); + } +} + +// --- 3. The prebuilt dashboard questions must not change plan. +for (const prebuilt of PREBUILT_QUERIES) { + const question: AnalysisQuestion = prebuilt.question; + if (question.relationship.type === 'near') continue; + const step = planPipeline(question)[0]; + const query = step.buildQuery( + { question, targetIris: [], anchorIris: [], results: {} } as never, + undefined, + ); + check( + leadsWith(query) === 'anchor', + `${prebuilt.id}: every prebuilt has a constrained anchor, so none of them may reorder`, + ); +} + +console.log(`query joins: ${checks} checks passed`); diff --git a/src/engine/templates/downstreamSamples.ts b/src/engine/templates/downstreamSamples.ts index 7acdce6..5178bda 100644 --- a/src/engine/templates/downstreamSamples.ts +++ b/src/engine/templates/downstreamSamples.ts @@ -6,6 +6,17 @@ function spValues(spIris: string[]): string { return spIris.map(wrapUri).join(' '); } +// A non-detect has no coso:measurementUnit, so requiring the unit join hid +// every non-detect from the popup's observation table: on sample point 64220, +// 474 of 3,334 rows survived and the other 2,860 were non-detects. Making it +// OPTIONAL in place OOMs (819.7MB); joining it after resultValueClauses() with +// the symbol lookup nested inside costs the same as before, 6.88s vs 6.59s. +// ?unit_sym stays bound either way because it is a GROUP BY key. +const UNIT_SYMBOL_CLAUSES = `OPTIONAL { ?result coso:measurementUnit ?unit . + OPTIONAL { ?unit qudt:symbol ?unit_sym0 } } + BIND(COALESCE(?unit_sym0, + IF(BOUND(?unit), REPLACE(STR(?unit), "^.*[#/]", ""), "")) AS ?unit_sym)`; + export function buildSampleRetrievalByIriQuery( spIris: string[], filters?: SampleFilters, @@ -94,10 +105,8 @@ export function buildSampleDetailByIriQuery( OPTIONAL { ?substanceUri rdfs:label ?fullLabel } OPTIONAL { ?sourceParam comptox:sameAsDSSToxSubstance ?substanceUri ; rdfs:label ?paramLabel } - ?result coso:measurementUnit ?unit . ${resultValueClauses()} - OPTIONAL { ?unit qudt:symbol ?unit_sym0 } - BIND(COALESCE(?unit_sym0, REPLACE(STR(?unit), "^.*[#/]", "")) AS ?unit_sym) + ${UNIT_SYMBOL_CLAUSES} OPTIONAL { ?observation sosa:resultTime ?date } OPTIONAL { ?sample dcterms:identifier ?sampleId } ${filterClauses} diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 90c8a89..ae66adb 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -2,6 +2,7 @@ import { PREFIXES } from '../../constants/prefixes'; import type { EntityBlock, FacilityFilters, + SampleFilters, AquiferFilters, StreamFilters, SpatialRelationship, @@ -45,25 +46,37 @@ function buildAquiferTypeFilterSuffixed(filters: AquiferFilters | undefined, suf // is supplied so the same helper can fill either ?s2anchor or ?s2target). // `suffix` disambiguates internal variables so same-type anchor+target queries // don't collide. -// True when the sample block actually constrains observations. When it does not, -// the IRI-finding queries can skip the observation join entirely. -export function hasSampleFilters(block: EntityBlock): boolean { - const f = block.type === 'samples' ? block.sampleFilters : undefined; - if (!f) return false; - return Boolean( - f.substances?.length || - f.materialTypes?.length || - f.minConcentration != null || - f.maxConcentration != null || - f.includeNondetects === false, - ); +// The observation joins a samples block needs to *filter*, which is a smaller +// set than the joins it needs to *display*. Every required triple is also a +// filter, so asking for detail the filters never read deletes rows: the unit +// join is the worst of them, because a non-detect has no coso:measurementUnit +// (see needsUnitJoin in ./samples) and requiring it dropped 774 of 1,688 +// Cumberland PFOS observations while "include non-detects" was ticked. +function sampleJoinsNeeded(filters: SampleFilters | undefined) { + const range = filters?.minConcentration != null || filters?.maxConcentration != null; + // buildSampleFilterClauses reads ?numericResult / ?nonDetect for both of + // these, and resultValueClauses is what binds them. + const result = range || filters?.includeNondetects === false; + return { + substance: Boolean(filters?.substances?.length), + material: Boolean(filters?.materialTypes?.length), + result, + // The ng/L comparison is the only thing that reads the unit. + unit: range, + observation: Boolean(filters?.substances?.length || filters?.materialTypes?.length || result), + }; } -// `sampleObservations: false` drops the observation/material/result joins from a -// samples block. Only the IRI-finding queries may pass it: they project just the +// `sampleObservations: false` drops the observation joins from a samples block +// outright. Only the IRI-finding queries may pass it: they project just the // sample-point IRI, and re-deriving every observation there is what pushes the // hydrology queries past QLever's 30s limit / memory ceiling (429/500). The -// hydrate queries still project those vars and must keep the full block. +// hydrate queries still project ?matTypeLabel / ?unit / ?result_value and must +// keep the full block. +// +// With `false` and an active sample filter the block is rebuilt from +// sampleJoinsNeeded: enough to honour the filter, nothing that only feeds a +// popup. export function bindEntityInCell( block: EntityBlock, s2Var: string, @@ -82,16 +95,37 @@ export function bindEntityInCell( ${industry}`; } case 'samples': { - if (!sampleObservations) { - return `?sp${suffix} rdf:type coso:SamplePoint ; + const point = `?sp${suffix} rdf:type coso:SamplePoint ; spatial:connectedTo ${s2Var} .`; - } const filters = buildSampleFilterClauses(block.sampleFilters, suffix); - // ponytail: coso:measurementUnit exists only on detects, so the join below - // also excludes non-detects. Dropping it is correct but triples the matched - // rows and the endpoint OOMs on statewide pipelines. Revisit if capacity grows. - return `?sp${suffix} rdf:type coso:SamplePoint ; - spatial:connectedTo ${s2Var} . + + if (!sampleObservations) { + const need = sampleJoinsNeeded(block.sampleFilters); + if (!need.observation) return point; + const parts = [ + point, + `?observation${suffix} coso:observedAtSamplePoint ?sp${suffix} .`, + ]; + if (need.substance) { + parts.push(`?observation${suffix} coso:ofDSSToxSubstance ?substance${suffix} .`); + } + if (need.material) { + // The material lives on the analysed sample, not the observation. + parts.push(`?observation${suffix} coso:analyzedSample ?sample${suffix} . + ?sample${suffix} coso:sampleOfMaterialType ?matType${suffix} .`); + } + if (need.result) { + parts.push(`?observation${suffix} coso:hasResult ?result${suffix} . + ${resultValueClauses(suffix)}`); + } + if (need.unit) { + parts.push(`?result${suffix} coso:measurementUnit ?unit${suffix} .`); + } + parts.push(filters); + return parts.join('\n '); + } + + return `${point} ?observation${suffix} rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp${suffix} ; coso:ofDSSToxSubstance ?substance${suffix} ; @@ -148,7 +182,11 @@ export function buildEntityProbeQuery( limit: number, ): string { const entityVar = entityIriVar(block, 'P'); - const bind = bindEntityInCell(block, '?s2probe', 'P', hasSampleFilters(block)); + // `false`, like the IRI-finding queries: the probe lists entity IRIs, and the + // list it returns becomes the chunk membership (src/engine/scope.ts). A + // narrowing join here removes entities from every slice, so the probe has to + // see exactly what discovery sees. + const bind = bindEntityInCell(block, '?s2probe', 'P', false); const region = regionClause(regionCodes, '?s2probe', '?_regionP'); return ` ${PREFIXES} @@ -275,8 +313,11 @@ function boundedTrace( function buildFusedWhereBody(opts: FusedBodyOpts): string { // A sample block keeps its observation joins unless the caller drops them AND // no sample filter depends on them. - const anchorObs = (opts.anchorSampleObservations ?? true) || hasSampleFilters(opts.anchor); - const targetObs = (opts.targetSampleObservations ?? true) || hasSampleFilters(opts.target); + // No `|| hasSampleFilters(...)` override any more: bindEntityInCell now keeps + // exactly the joins an active filter reads, so a filtered side no longer has + // to fall back on the whole observation chain. + const anchorObs = opts.anchorSampleObservations ?? true; + const targetObs = opts.targetSampleObservations ?? true; const anchorBind = bindEntityInCell(opts.anchor, '?s2anchor', 'A', anchorObs); const targetBind = bindEntityInCell(opts.target, '?s2target', 'C', targetObs); const anchorPin = pinValues(entityIriVar(opts.anchor, 'A'), opts.anchorIris); @@ -327,11 +368,66 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ${tRegion} ${targetBind}`; + // Write the constrained side first. QLever's planner does not search join + // orders exhaustively at this size (12-14 triples), so it follows the query + // text, and leading with an unfiltered side makes it trace the national + // flowline graph: "facilities upstream from PFOS samples in York and + // Cumberland" OOMs at 116s with the anchor first and answers in 18.6s with + // the target first. Measured across all 72 hydrology shape/config pairs: 5 + // rescued, 0 regressions, 0 rows lost (docs/plans/…-fused-seed-side-….md). + // + // Bounded traces keep the anchor-first order: boundedTrace embeds `seed` a + // second time and that shape has not been measured either way. + if (!opts.maxDistanceKm && sideIsConstrained(opts, 'target') && !sideIsConstrained(opts, 'anchor')) { + // The target's own entity and filters come first, then the hop onto the + // river network. A streams target *is* the flowline, so it needs no hop. + const targetHead = + opts.target.type === 'streams' + ? `?ds_flowline rdf:type hyf:HY_FlowPath . + ${targetPart}` + : `?s2target rdf:type kwg-ont:S2Cell_Level13 . + ${tRegion} + ${targetBind} + ?s2target spatial:connectedTo ?ds_flowline .`; + + // spatial:connectedTo is stored both ways between cells and flowlines + // (1,391,903 pairs each direction, verified on federation), so reading it + // off the flowline here matches the same pairs as ?s2neighbor → flowline. + return `${targetPin}${targetHead} + ${trace} + ?upstream_flowline rdf:type hyf:HY_FlowPath ; + spatial:connectedTo ?s2neighbor . + ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . + ${anchorPin}?s2anchor rdf:type kwg-ont:S2Cell_Level13 . + ${aRegion} + ${anchorBind}`; + } + return `${seed} ${trace} ${targetPin}${targetPart}`; } +// A side is constrained when the question already narrows it: a region, any +// entity filter, or an IRI pin from chunking. Unconstrained means "every +// facility in the graph", which is the side that must not lead the query. +function sideIsConstrained(opts: FusedBodyOpts, side: 'anchor' | 'target'): boolean { + const block = side === 'anchor' ? opts.anchor : opts.target; + const region = side === 'anchor' ? opts.anchorRegion : opts.targetRegion; + const pins = side === 'anchor' ? opts.anchorIris : opts.targetIris; + if (pins?.length || region?.length) return true; + const filters = + block.sampleFilters ?? + block.facilityFilters ?? + block.waterBodyFilters ?? + block.wellFilters ?? + block.aquiferFilters ?? + block.streamFilters; + return Boolean( + filters && Object.values(filters).some((v) => (Array.isArray(v) ? v.length > 0 : v != null)), + ); +} + export interface FusedBaseOpts { anchor: EntityBlock; target: EntityBlock; @@ -358,8 +454,12 @@ export function buildFusedNearQuery(opts: FusedNearOpts): string { hops: opts.hops, anchorIris: opts.anchorIris, targetIris: opts.targetIris, - anchorSampleObservations: opts.project !== 'anchor', - targetSampleObservations: opts.project !== 'target', + // Both sides, not just the projected one: a near query projects a single + // IRI, so neither side needs observation detail beyond its own filters. + // Keying this off `project` left the *non*-projected samples side carrying + // the full chain even with no filters set. + anchorSampleObservations: false, + targetSampleObservations: false, }); const projectVar = opts.project === 'anchor' From b7bcc73c13f4a2a0c9e5c271b3bead6d2bcd1657 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 15:49:32 -0400 Subject: [PATCH 53/66] fix(engine): bound the flowline layer at both ends GET_FLOWLINE_GEOMETRIES traced a one-sided transitive closure: it seeded from the cells of every resolved anchor, widened each by sfTouches, and followed the network to its end. Nothing in the query referenced the targets, so an anchor sitting near a drainage divide pulled in the whole of the neighbouring basin. On "What facilities are upstream from PFOS samples in York County, ME" that drew 122 segments of the Merrimack and 21 of the Winnipesaukee, ~130km away in a basin no York sample drains from, plus the Presumpscot, the Suncook and the Powwow. Nothing looked broken. The map just had extra rivers on it, and they were real rivers. The closure is now intersected with the flowlines that reach the resolved targets. Measured live with the real answer sets (1,497 facilities, 200 sample points): 3,271 flowlines down to 2,516, in the same 7s. 755 removed, 0 added, so the fix can only take away flowlines that were never on a path from a facility to a sample. Of those, 684 are in a different basin and 71 lie below a sample, which is the one visible behaviour change: the drawn river now stops at the sample instead of running on to the sea. Written as an intersection of two DISTINCT closures. The direct membership test, `?flowline hyf:downstreamFlowPathTC? ?_flTarget`, leaves ?flowline unbound on the left and QLever times out joining on it (31s, "Join on ?flowline"). The reach is a bare TC rather than reflexive: `TC?` was measured and recovers 0 flowlines while costing 8s. The bounded branch gets the same intersection. At 25km it went 3,034 -> 2,516, matching the unbounded set, because connectivity dominates the distance cap at that range; at 5km the cap still bites (2,314), so the two constraints compose. The shipped bounded query still drew a Merrimack segment through its cap. scripts/check-flowline-scope.mts asserts both ends are bound for all 100 shapes that draw the layer, bounded and unbounded, and runs in CI. --- .github/workflows/checks.yml | 3 + package.json | 1 + scripts/check-flowline-scope.mts | 94 ++++++++++++++++++++++++++++ src/engine/planner.ts | 4 ++ src/engine/templates/fusedQueries.ts | 64 ++++++++++++++++++- 5 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 scripts/check-flowline-scope.mts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 38cc134..c7c38c8 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -42,6 +42,9 @@ jobs: - name: Trace direction run: npm run check-trace-direction + - name: Flowline scope + run: npm run check-flowline-scope + - name: Cache key run: npm run check-cache-key diff --git a/package.json b/package.json index 32ff0f9..80ec5ce 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "check-cache-key": "tsx scripts/check-cache-key.mts", "check-step-labels": "tsx scripts/check-step-labels.mts", "check-trace-direction": "tsx scripts/check-trace-direction.mts", + "check-flowline-scope": "tsx scripts/check-flowline-scope.mts", "check-substance-labels": "tsx scripts/check-substance-labels.mts", "check-query-joins": "tsx scripts/check-query-joins.mts", "query-matrix": "tsx scripts/query-matrix.mts", diff --git a/scripts/check-flowline-scope.mts b/scripts/check-flowline-scope.mts new file mode 100644 index 0000000..cd618f2 --- /dev/null +++ b/scripts/check-flowline-scope.mts @@ -0,0 +1,94 @@ +// Self-check: the supporting flowline layer must be bounded at BOTH ends. +// +// npx tsx scripts/check-flowline-scope.mts +// +// buildFusedFlowlineQuery traces a transitive closure out of the anchor cells. +// Left one-sided it runs to the end of the network, so an anchor near a +// drainage divide drags in the neighbouring basin: "facilities upstream from +// PFOS samples in York County, ME" drew 122 segments of the Merrimack and 21 +// of the Winnipesaukee, in a basin no York sample drains from. Nothing looked +// broken -- the map just had extra rivers on it, and they were real rivers. +// +// The fix intersects that closure with the set of flowlines that actually +// reach the resolved targets. This asserts the intersection is present in +// every shape that draws the layer, bounded and unbounded, so a future edit to +// either branch cannot drop it silently. +// +// No network: the pipeline steps only build query strings. +import assert from 'node:assert/strict'; +import { planPipeline, type PipelineContext } from '../src/engine/planner'; +import type { AnalysisQuestion, EntityType, SpatialRelationship } from '../src/types/query'; + +const ENTITY_TYPES: EntityType[] = [ + 'samples', + 'facilities', + 'waterBodies', + 'wells', + 'aquifers', + 'streams', +]; +const HYDROLOGY: SpatialRelationship['type'][] = ['downstream', 'upstream']; +// Unbounded, and one bounded value to cover the aggregate branch. +const DISTANCES: (number | undefined)[] = [undefined, 25]; + +const context = (): PipelineContext => ({ + question: {} as AnalysisQuestion, + targetIris: ['https://example.org/t1', 'https://example.org/t2'], + anchorIris: ['https://example.org/a1', 'https://example.org/a2'], + results: {}, +}); + +let checks = 0; +let drawn = 0; + +for (const blockA of ENTITY_TYPES) { + for (const blockC of ENTITY_TYPES) { + for (const rel of HYDROLOGY) { + for (const maxDistanceKm of DISTANCES) { + const question: AnalysisQuestion = { + blockA: { type: blockA }, + relationship: { type: rel, maxDistanceKm }, + blockC: { type: blockC }, + }; + const step = planPipeline(question).find((s) => s.type === 'GET_FLOWLINE_GEOMETRIES'); + // Skipped when a side is streams: those flowlines are the answer set. + if (!step) { + assert.ok( + blockA === 'streams' || blockC === 'streams', + `${blockA} ${rel} ${blockC}: no flowline step, but neither side is streams`, + ); + continue; + } + drawn++; + const sparql = step.buildQuery(context()); + const where = `${blockA} ${rel} ${blockC} ${maxDistanceKm ?? 'unbounded'}`; + + // The target IRIs have to reach the query, or the closure is one-sided. + assert.ok( + sparql.includes('https://example.org/t1'), + `${where}: flowline query does not bind the resolved targets`, + ); + // Both ends present: a closure out of the anchor cells, and a closure + // into the targets, joined on ?flowline. + assert.ok( + sparql.includes('?_flTarget spatial:connectedTo ?s2celltarget'), + `${where}: missing the target reach clause`, + ); + assert.match( + sparql, + /\?flowline hyf:downstreamFlowPathTC \?_flTarget|\?_flTarget hyf:downstreamFlowPathTC \?flowline/, + `${where}: target reach clause does not close on ?flowline`, + ); + // The reach clause must be a bare TC. `TC?` was measured: it recovers + // 0 flowlines and costs 8s on the York question. + assert.ok( + !sparql.includes('downstreamFlowPathTC? ?_flTarget'), + `${where}: reflexive target reach, measured to add nothing`, + ); + checks += 4; + } + } + } +} + +console.log(`flowline scope: ${drawn} shapes draw the layer, ${checks} checks passed`); diff --git a/src/engine/planner.ts b/src/engine/planner.ts index b1469f0..129cbcc 100644 --- a/src/engine/planner.ts +++ b/src/engine/planner.ts @@ -328,8 +328,12 @@ function buildFusedSteps(question: AnalysisQuestion): PipelineStep[] { buildQuery: (ctx, scope) => buildFusedFlowlineQuery({ anchor: anchorBlock, + target: targetBlock, direction: traceDirection, anchorIris: scope?.anchorIris ?? ctx.anchorIris, + // Never sliced: the target set bounds the trace, so a partial list + // would silently shrink the drawn network rather than split it. + targetIris: ctx.targetIris, maxDistanceKm: relationship.maxDistanceKm, }), initialScopes: (ctx) => iriScopes(ctx.anchorIris, 'anchor'), diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index ae66adb..9e74260 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -581,11 +581,63 @@ export function buildFusedWellQuery(opts: FusedWellSideOpts): string { export interface FusedFlowlineOpts { anchor: EntityBlock; + target: EntityBlock; direction: 'downstream' | 'upstream'; anchorIris: string[]; + targetIris: string[]; maxDistanceKm?: number; } +// Restricts the traced closure to flowlines that actually connect the anchors +// to the targets. Without it the trace is one-sided: it runs from the anchor +// cells to the end of the network, so an anchor sitting near a drainage divide +// drags in the whole of the neighbouring basin. On "facilities upstream from +// PFOS samples in York County, ME" that drew 122 segments of the Merrimack and +// 21 of the Winnipesaukee, ~130km away in a basin no York sample drains from. +// +// Written as an intersection of two DISTINCT closures rather than the direct +// `?flowline hyf:downstreamFlowPathTC? ?_flEnd` membership test: that form +// leaves ?flowline unbound on the left and QLever times out joining on it +// (31s, "Join on ?flowline"). The intersection runs in the same 7s the +// one-sided query took. +// +// The closure is strict on both ends, so the segment a target sits on is not +// drawn. Making the target side reflexive (`TC?`) was measured and recovers +// nothing (0 extra flowlines) while costing 8s, because that segment already +// arrives via another target upstream of it. +function targetReachClause(opts: FusedFlowlineOpts): string { + // ponytail: target IRIs inlined whole. Only anchors are sliced today + // (iriScopes/divideIriList in the planner); add target slicing if a question + // ever pushes this past the gateway's body limit. + const targetValues = `VALUES ${entityIriVar(opts.target, 'C')} { ${opts.targetIris + .map(wrapUri) + .join(' ')} }`; + // Filters stripped: the pinned IRIs are already the filtered answer set, so + // every filter clause here is a join that can only re-confirm what the VALUES + // list states. Passing the bare block rather than opts.target keeps this to + // the cell-membership triple. Measured on the York question: re-deriving the + // substance filter cost 1s of the 8 and changed nothing. + const targetBind = bindEntityInCell({ type: opts.target.type }, '?s2celltarget', 'C', false); + const reach = + opts.direction === 'downstream' + ? `?flowline hyf:downstreamFlowPathTC ?_flTarget .` + : `?_flTarget hyf:downstreamFlowPathTC ?flowline .`; + + return `{ + SELECT DISTINCT ?flowline WHERE { + { + SELECT DISTINCT ?s2celltarget WHERE { + ${targetValues} + ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . + ${targetBind} + } + } + ?_flTarget spatial:connectedTo ?s2celltarget . + ${reach} + } + }`; +} + // Returns flowline geometries traced from the anchor entities the pipeline // already resolved in FIND_ANCHOR_IRIS. // @@ -624,13 +676,20 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { spatial:connectedTo ?s2cellus . ?flowline hyf:downstreamFlowPathTC ?downstream_flowline .`; + const reachesTarget = targetReachClause(opts); + // Unbounded: the flowline set is the plain transitive closure. if (!opts.maxDistanceKm) { return ` ${PREFIXES} SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { - ${seedCells} - ${flowlinePattern} + { + SELECT DISTINCT ?flowline WHERE { + ${seedCells} + ${flowlinePattern} + } + } + ${reachesTarget} ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } @@ -682,6 +741,7 @@ export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } + ${reachesTarget} ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } From 813f0084b4a67b21c2ae5fffea91cefe7b4c8d78 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 16:43:31 -0400 Subject: [PATCH 54/66] docs(plans): draft the symmetric cell-widening fix The one-cell sfTouches expansion that connects an entity to the river network is applied to exactly one side of a hydrology trace, and which side is an artefact of how buildFusedWhereBody orders its blocks rather than a modelling decision. Measured in York County: 22% of PFOS sample points and 18% of facilities have no flowline in their own S2 cell, so whichever side is not widened silently loses about a fifth of its entities. On "What facilities are upstream from PFOS samples?" scoped to York County, widening the sample side instead of the facility side gives 324 sample points and 1,060 facilities against the shipped 200 and 1,497. The union of both is 330 and 1,507, and recovers 130 sample points of which 82 carry quantified PFOS detections up to 2,200 ng/L. Points with a confirmed detection go from 132 to 214. The plan proposes running both variants and unioning them, because widening both sides inside one query does not run: two formulations, flat and with the cell set materialised first, both fail with "tried to allocate 2.6 GB". Added cost is 2-3s rather than double, since the second variant caches at 1.3s while the shipped form does not. Drafted rather than active: it touches all 72 hydrology shapes, moves counts upward across them, and is the second executor change queued against the same code path as the retry hook in the 2026-09-17 plan. The two should be designed together so there is one mechanism rather than two similar ones. Also records two QLever measurement traps hit while producing the figures: a nested OPTIONAL containing a BIND returned a count of 0 alongside a non-zero MAX over the same variable, and an OPTIONAL used for predicate coverage under-reported silently. Every figure was re-derived with flat COUNT queries. --- .../2026-09-19-symmetric-cell-widening.md | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 docs/plans/drafts/2026-09-19-symmetric-cell-widening.md diff --git a/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md b/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md new file mode 100644 index 0000000..008e368 --- /dev/null +++ b/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md @@ -0,0 +1,202 @@ +# Apply the one-cell widening to both sides of a hydrology trace, not whichever side is written second + +**Status**: draft +**Created**: 2026-09-19 + +## Problem + +Entities link to S2 Level-13 cells (~1 km square). Flowlines link to cells. To +connect a facility or a sample to the river network, a flowline has to be in +that entity's cell. Frequently there is none: the sample sits 400 m from the +river, on the far side of a cell boundary. + +`buildFusedWhereBody` papers over this with a one-ring expansion, +`kwg-ont:sfTouches | owl:sameAs`. The defect is that it applies the expansion to +**exactly one side**, and which side is an artefact of query construction rather +than a modelling decision. Whichever side is not widened silently loses every +entity whose own cell happens to contain no flowline. + +Measured in York County (federation, 2026-09-19): + +| Side | Total | Flowline in own cell | Within one ring | Lost if not widened | +| --- | ---: | ---: | ---: | ---: | +| PFOS sample points | 361 | 282 (78%) | 360 (99.7%) | **78 (22%)** | +| Facilities | 1,639 | 1,343 (82%) | 1,632 (99.6%) | **289 (18%)** | + +So roughly one entity in five, on each side, is invisible to the trace without +the expansion. The gap is about the same size on both sides, which is why the +choice of side moves the answer so hard. + +Measured on "What facilities are upstream from PFOS samples?" (block A +facilities, unconstrained; block C samples, PFOS, York County ME), with the +observation chain trimmed on both variants so the non-detect bug of +`2026-09-17-fused-seed-side-and-observation-joins.md` is not confounding it: + +| Variant | Sample points | Facilities | +| --- | ---: | ---: | +| Widen the sample side | **324** | 1,060 | +| Widen the facility side (shipped) | 200 | **1,497** | +| Union of the two | **330** | **1,507** | + +Each variant rescues its own widened side and drops about a fifth of the other. + +The sample-side variant is the form the project's PI independently arrived at +while trying to fix an unrelated symptom, so this is not a hypothetical +preference: two people writing the same query reached for the expansion on +different sides, which is the clearest evidence that the current placement is +undocumented and accidental. + +## What the missing data actually is + +Of the 130 sample points the shipped query drops: + +| | Extra 130 | Shipped 200 | +| --- | ---: | ---: | +| Points with quantified PFOS detections | **82** | 132 | +| Detect observations | **139** | 370 | +| Points with non-detects | 58 | n/a | +| Max concentration | 2,200 ng/L | 7,400 ng/L | + +Sample points carrying a confirmed PFOS detection go from **132 to 214, up +62%**. The dropped points do not hold the single highest reading, but 2,200 +ng/L is roughly 110x Maine's 20 ng/L interim drinking water standard, so these +are not marginal traces. + +On the facility side the union adds only 10, because that side is already the +widened one. Effectively all of the recovery is on samples. + +Worth stating plainly for review: the 1 km approximation is **already +accepted** on the facility side. Applying it to the sample side introduces no +new assumption, it applies the existing one consistently. + +## Approach + +Run both variants and union the results. This is an **executor** change, not a +template fix: the SPARQL text of each variant already works, what is missing is +a pipeline that issues both and merges. + +The executor already merges slice results as a set, deduping on +`JSON.stringify(row)` (`src/engine/scope.ts`), so the merge path exists. What is +new is issuing a second variant of the same step deliberately rather than as a +failure retry. + +Sketch, to be firmed up during implementation: + +- `buildFusedWhereBody` takes a `widen: 'anchor' | 'target'` option. Default + `'anchor'`, which is today's behaviour, so nothing moves until the executor + asks for the second form. +- `PipelineStep` gains a way to declare a second query variant for the same + step, distinct from `initialScopes` (which splits one query) and from the + deferred `buildRetryQuery` hook (which replaces a failed query). +- The executor issues both, unions the row sets, and reports one step. + +## Tasks + +1. Add the `widen` option to `buildFusedWhereBody` and thread it through + `buildFusedHydrologyQuery` and `buildFusedWellQuery`. Default preserves + current output; assert that in `scripts/check-query-joins.mts`. +2. Decide the variant mechanism on `PipelineStep` and whether it shares + machinery with the deferred retry hook. See "Sequencing" below. +3. Executor: issue both variants, union, single step report. Partial failure of + one variant should degrade to the other's rows rather than failing the step, + matching how the flowline layer is already `optional`. +4. Extend `scripts/check-flowline-scope.mts` or add a sibling check asserting + both variants are emitted for all 72 hydrology shapes. +5. Re-run `npm run query-matrix` in engine mode and commit a dated CSV. Counts + will move upward across hydrology shapes; the sweep is how that is recorded + rather than discovered later. +6. Update `docs/QUERY-MATRIX.md` Part 3.2/3.3 costs, and `docs/SCHEMA.md` with + the cell-coverage numbers above, which are not currently written down + anywhere. + +## Impact on other query shapes + +**72 hydrology shapes. Zero `near` shapes.** Verified by building +`FIND_TARGET_IRIS` for all 108 shapes and grepping the emitted SPARQL: all 72 +downstream/upstream shapes emit +`kwg-ont:sfTouches | owl:sameAs ?s2neighbor`, none of the 36 `near` shapes do. +`near` uses the explicit user-chosen hop count (`neighborPath`), a different +mechanism that is not affected. + +Counts move **upward only** on the affected shapes, the same direction and for +the same class of reason as the non-detect fix in +`2026-09-17-fused-seed-side-and-observation-joins.md`. Dashboard and prebuilt +numbers will change. That is the fix landing, not a new defect. + +## Cost + +Three runs of each query, warm endpoint, federation: + +| Query | Run 1 | Run 2 | Run 3 | +| --- | ---: | ---: | ---: | +| Shipped, samples | 30.4s | 26.6s | 15.1s | +| Shipped, facilities | 15.4s | 14.4s | 18.1s | +| Sample-widened, samples | 19.2s | **1.4s** | **1.3s** | +| Sample-widened, facilities | 2.3s | **1.2s** | **1.4s** | + +Added cost is roughly **2 to 3 seconds**, not double, because the second +variant caches and the shipped one does not. QLever caches result sets up to a +size limit and the shipped form's intermediates appear to exceed it. That +pattern held across three runs of four queries but has not been confirmed +against QLever's cache configuration, so it should not be relied on until +someone checks it deliberately. + +## Rejected: widen both sides inside one query + +This is the theoretically correct form and it does not run. Two formulations +tried on the York question, both against federation: + +1. Flat, expansion on both sides in one body: `500`, "tried to allocate 2.6 GB, + but only 2.3 GB were available". The facility projection separately timed out + on "Join on ?s2flcell". +2. Target cell set materialised first in a `SELECT DISTINCT` sub-SELECT, then + expanded outward: same 2.6 GB allocation failure at 21s. + +The cell-by-flowline join is what blows up, and restructuring the query text +does not avoid it. This is why the approach above is a union of two queries +rather than one correct query. + +## Open questions + +1. **The union is an approximation.** It misses pairs where the sample *and* + the facility both need widening simultaneously. If the two are independent + that is roughly 4% of pairs, but this is an estimate and it **cannot be + validated**, because the true both-sides query does not run. Whether that is + acceptable is a call for the PI, not the engine. +2. **Is one ring the right radius?** Nothing measured justifies one hop over + two. One ring reaches 99.7% of samples and 99.6% of facilities in York, so + the marginal return looks small, but that is one county. +3. **The real fix may be upstream of the app.** Precomputing an + entity-to-nearest-flowline link in the graph would remove the cell-ring + guessing entirely and be exact rather than a 1 km approximation. That is a + graph-build change and a conversation with whoever maintains it, but it would + retire this plan rather than refine it. + +## Sequencing + +This is the second executor change queued against the same code path. The other +is the retry hook in +`2026-09-17-fused-seed-side-and-observation-joins.md` ("The retry variant, +measured and not implemented"), which needs `buildRetryQuery` on `PipelineStep` +and one branch in the executor's failure path. + +Both add a second query for one step. They should be designed together so the +codebase gets one mechanism rather than two similar ones, even if they ship +separately. + +Prerequisite: PR #55 (seed side and observation joins) and PR #56 (flowline +layer bounded at both ends) should merge first. The measurements above were all +taken on top of both. + +## Notes + +All figures measured against `https://apps.okn.us/federation/sparql` on +2026-09-19, on the branch carrying #55 and #56. + +Two measurement traps hit while producing these numbers, both worth knowing +before re-running any of this: QLever returned wrong results for nested +`OPTIONAL` blocks containing a `BIND` (a detect count came back 0 alongside a +non-zero `MAX` over the same variable), and it silently under-reported on an +`OPTIONAL` used to test predicate coverage. Every figure here was re-derived +with flat, separate `COUNT` queries. The same trap is already recorded against +aggregates over `UNION` at `fusedQueries.ts:222`. From 718193c32c59645d4e284180ba27e55d9c72cfb1 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 16:57:11 -0400 Subject: [PATCH 55/66] refactor(engine): one definition of "is this side constrained" Cleanup pass over the two fixes on this branch. No intended behaviour change except where noted; the York question emits a byte-identical body for steps 1 and 2 and the same 2,516 flowlines for step 3, verified live. sideIsConstrained was a third copy of a predicate the repo already had twice, in scope.ts as hasBlockFilters and in sparqlErrors.ts as isNarrowed. scope.ts asks the identical question to pick a chunking axis, so the two drifting apart means the executor slices on an axis the template already led with. scope.ts imports fusedQueries, so the shared predicate lands here as blockIsFiltered and scope.ts uses it. sparqlErrors keeps its own, which is this plus the region check. That copy also had a defect the original did not: a generic "any field is non-null" scan counts includeNondetects: true, which is the UI's default checked state and narrows nothing. A samples block with only that set was read as constrained and reordered the whole body. sampleJoinsNeeded already draws the line correctly, so samples delegate to it. Verified: that block now leads with ?s2anchor, includeNondetects: false and a substance filter still lead with ?s2target. buildFusedFlowlineQuery re-derived the anchor block over IRIs its own VALUES list had already pinned, which is exactly what targetReachClause eight lines below refuses to do. Same bare-block treatment now. For a facilities anchor that drops a redundant industry VALUES; for a samples anchor it drops the entire observation chain, including the coso:measurementUnit join this branch exists to keep out of queries that never read it. Also: pinValues instead of a fourth hand-rolled VALUES block (it guards the empty list, the inline form emitted "VALUES ?spC { }"); needsUnitJoin instead of restating the range predicate the comment already pointed at; a dead branch in check-query-joins where both arms returned 'other'; and the reflexive-reach assertion in check-flowline-scope, which matched the downstream spelling only and left the upstream shape unguarded by a check whose whole point is the TC? regression. Two stale comments corrected: the sampleObservations doc named hydrate queries that were deleted in 66f3fda, and buildFusedWhereBody still described the hasSampleFilters override the same commit removed. Deferred to the plan docs rather than done here, both recorded as tasks: emitting the body from an ordered fragment list instead of two hand-maintained renderings (worth doing with the widen option, which would otherwise make it four), and bounding targetReachClause by region when the target list is too large to inline. Also added a task to measure the distance-bounded shape reordered, since !maxDistanceKm is the one exclusion in the gate that is a "we did not look" rather than a measured "it was worse". --- ...7-fused-seed-side-and-observation-joins.md | 5 ++ .../2026-09-19-symmetric-cell-widening.md | 28 ++++++-- scripts/check-flowline-scope.mts | 6 +- scripts/check-query-joins.mts | 4 +- src/engine/scope.ts | 15 +---- src/engine/templates/fusedQueries.ts | 67 ++++++++++++------- 6 files changed, 78 insertions(+), 47 deletions(-) diff --git a/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md b/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md index 8bf613a..4870730 100644 --- a/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md +++ b/docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md @@ -100,6 +100,11 @@ per-filter rule removes it. - [ ] re-run `npm run health-check` and record the row-count movement in `docs/health/STATUS.md` - [ ] `npm run query-matrix` sweep, then `--index`, to price both fixes across the shape space - [ ] update `docs/QUERY-MATRIX.md` (error catalogue: the OOM that this removes) +- [ ] measure the distance-bounded shape reordered, and drop the `!maxDistanceKm` + exclusion if it holds. This is the one condition in the gate that is a "we + did not look", not a "we looked and it was worse": `boundedTrace` takes the + seed as a pre-rendered string and embeds it twice, so there was no seam to + reorder at. Left unmeasured it hardens into folklore. - [ ] decide on the retry variant below ## Verified after implementing (2026-09-17) diff --git a/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md b/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md index 008e368..49fa277 100644 --- a/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md +++ b/docs/plans/drafts/2026-09-19-symmetric-cell-widening.md @@ -95,17 +95,35 @@ Sketch, to be firmed up during implementation: 1. Add the `widen` option to `buildFusedWhereBody` and thread it through `buildFusedHydrologyQuery` and `buildFusedWellQuery`. Default preserves current output; assert that in `scripts/check-query-joins.mts`. -2. Decide the variant mechanism on `PipelineStep` and whether it shares + **Restructure the body emission first.** `buildFusedWhereBody` currently + writes the whole body out twice, once anchor-first and once target-first, + with the streams-target case spelled in both. Adding `widen` on top of that + gives 2 orders x 2 widen sides = four hand-maintained renderings of the same + triples. Emitting from an ordered list of named fragments (`anchorSide`, + `hop`, `trace`, `targetSide`) with `lead` and `widen` deciding order and ring + placement makes it one definition. Output equality is checkable by diffing + generated SPARQL for all 72 shapes before and after, which the check scripts + already build. Doing this as part of task 1 is much cheaper than doing it + after. +2. Bound `targetReachClause` by the target *region* rather than the IRI list + when the list exceeds a threshold. Today it inlines the entire resolved + target set into one `VALUES` with no cap and, unlike `anchorIris`, cannot be + sliced: `anchorIris` partitions the answer (union of slices = whole) while + `targetIris` is a bound (each slice is wrong on its own). A question + resolving a few thousand targets puts that whole list in the request body + with no `divide` to rescue it. This is a latent hard failure, not a slow + path. +3. Decide the variant mechanism on `PipelineStep` and whether it shares machinery with the deferred retry hook. See "Sequencing" below. -3. Executor: issue both variants, union, single step report. Partial failure of +4. Executor: issue both variants, union, single step report. Partial failure of one variant should degrade to the other's rows rather than failing the step, matching how the flowline layer is already `optional`. -4. Extend `scripts/check-flowline-scope.mts` or add a sibling check asserting +5. Extend `scripts/check-flowline-scope.mts` or add a sibling check asserting both variants are emitted for all 72 hydrology shapes. -5. Re-run `npm run query-matrix` in engine mode and commit a dated CSV. Counts +6. Re-run `npm run query-matrix` in engine mode and commit a dated CSV. Counts will move upward across hydrology shapes; the sweep is how that is recorded rather than discovered later. -6. Update `docs/QUERY-MATRIX.md` Part 3.2/3.3 costs, and `docs/SCHEMA.md` with +7. Update `docs/QUERY-MATRIX.md` Part 3.2/3.3 costs, and `docs/SCHEMA.md` with the cell-coverage numbers above, which are not currently written down anywhere. diff --git a/scripts/check-flowline-scope.mts b/scripts/check-flowline-scope.mts index cd618f2..7971574 100644 --- a/scripts/check-flowline-scope.mts +++ b/scripts/check-flowline-scope.mts @@ -81,8 +81,12 @@ for (const blockA of ENTITY_TYPES) { ); // The reach clause must be a bare TC. `TC?` was measured: it recovers // 0 flowlines and costs 8s on the York question. + // Bare `includes`, not the downstream spelling: the reflexive form is + // `?flowline TC? ?_flTarget` downstream and `?_flTarget TC? ?flowline` + // upstream, and matching only the first left the upstream shape + // unguarded by a check whose whole point is the `TC?` regression. assert.ok( - !sparql.includes('downstreamFlowPathTC? ?_flTarget'), + !sparql.includes('downstreamFlowPathTC?'), `${where}: reflexive target reach, measured to add nothing`, ); checks += 4; diff --git a/scripts/check-query-joins.mts b/scripts/check-query-joins.mts index bac9f63..59af898 100644 --- a/scripts/check-query-joins.mts +++ b/scripts/check-query-joins.mts @@ -44,8 +44,8 @@ function leadsWith(query: string): 'anchor' | 'target' | 'other' { const body = query.slice(query.indexOf('WHERE {') + 'WHERE {'.length).trimStart(); if (body.startsWith('?s2target') || body.startsWith('?ds_flowline')) return 'target'; if (body.startsWith('?s2anchor')) return 'anchor'; - // A pinned side is inlined as VALUES before anything else. - if (body.startsWith('VALUES ?sp') || body.startsWith('VALUES ?facility')) return 'other'; + // A pinned side leads with its VALUES block, so neither branch above matches. + // That is the 'other' case and the pinned assertions below allow for it. return 'other'; } diff --git a/src/engine/scope.ts b/src/engine/scope.ts index bb7f462..99b0a1f 100644 --- a/src/engine/scope.ts +++ b/src/engine/scope.ts @@ -1,7 +1,7 @@ import type { EntityBlock } from '../types/query'; import type { EndpointKey } from '../constants/endpoints'; import { executeSparql } from './sparqlClient'; -import { buildEntityProbeQuery } from './templates/fusedQueries'; +import { blockIsFiltered, buildEntityProbeQuery } from './templates/fusedQueries'; import { buildDiscoverCountiesQuery } from './templates/regions'; // A Scope is a slice of one pipeline step's work. `undefined` scope means "the @@ -42,17 +42,6 @@ const ENTITY_CHUNK = 25; const REGION_CHUNK = 1; export const IRI_CHUNK = 1000; // by-IRI hydration: 1,000 IRIs ≈ 70KB, 1.0–3.3s -function hasBlockFilters(block: EntityBlock): boolean { - const f = - block.sampleFilters ?? - block.facilityFilters ?? - block.waterBodyFilters ?? - block.wellFilters ?? - block.aquiferFilters ?? - block.streamFilters; - return Boolean(f && Object.values(f).some((v) => (Array.isArray(v) ? v.length > 0 : v != null))); -} - export function chunk(items: T[], size: number): T[][] { const out: T[][] = []; for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size)); @@ -193,7 +182,7 @@ async function probeSide( ): Promise { // No region and no filters means every entity of that type in the graph — // certainly past the probe limit, and the probe itself would scan nationwide. - if (!regionCodes?.length && !hasBlockFilters(block)) return null; + if (!regionCodes?.length && !blockIsFiltered(block)) return null; const rows = await executeSparql( endpoint, diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 9e74260..79a6c69 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -7,7 +7,7 @@ import type { StreamFilters, SpatialRelationship, } from '../../types/query'; -import { wrapUri, buildSampleFilterClauses, resultValueClauses } from './samples'; +import { wrapUri, buildSampleFilterClauses, resultValueClauses, needsUnitJoin } from './samples'; import { buildIndustryValues } from './facilities'; import { AQUIFER_TYPE_VALUES } from './aquifers'; import { buildWellCategoryFilter } from './wells'; @@ -53,7 +53,7 @@ function buildAquiferTypeFilterSuffixed(filters: AquiferFilters | undefined, suf // (see needsUnitJoin in ./samples) and requiring it dropped 774 of 1,688 // Cumberland PFOS observations while "include non-detects" was ticked. function sampleJoinsNeeded(filters: SampleFilters | undefined) { - const range = filters?.minConcentration != null || filters?.maxConcentration != null; + const range = needsUnitJoin(filters); // buildSampleFilterClauses reads ?numericResult / ?nonDetect for both of // these, and resultValueClauses is what binds them. const result = range || filters?.includeNondetects === false; @@ -70,9 +70,9 @@ function sampleJoinsNeeded(filters: SampleFilters | undefined) { // `sampleObservations: false` drops the observation joins from a samples block // outright. Only the IRI-finding queries may pass it: they project just the // sample-point IRI, and re-deriving every observation there is what pushes the -// hydrology queries past QLever's 30s limit / memory ceiling (429/500). The -// hydrate queries still project ?matTypeLabel / ?unit / ?result_value and must -// keep the full block. +// hydrology queries past QLever's 30s limit / memory ceiling (429/500). +// buildFusedWellQuery is the one caller left on the `true` default: it projects +// well columns from a body that may carry a samples block on the other side. // // With `false` and an active sample filter the block is rebuilt from // sampleJoinsNeeded: enough to honour the filter, nothing that only feeds a @@ -311,8 +311,6 @@ function boundedTrace( // anchor binding + spatial path (neighbor expansion for "near", hydrology trace // for downstream/upstream) + target binding + region clauses on each side. function buildFusedWhereBody(opts: FusedBodyOpts): string { - // A sample block keeps its observation joins unless the caller drops them AND - // no sample filter depends on them. // No `|| hasSampleFilters(...)` override any more: bindEntityInCell now keeps // exactly the joins an active filter reads, so a filtered side no longer has // to fall back on the whole observation chain. @@ -408,16 +406,21 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ${targetPin}${targetPart}`; } -// A side is constrained when the question already narrows it: a region, any -// entity filter, or an IRI pin from chunking. Unconstrained means "every -// facility in the graph", which is the side that must not lead the query. -function sideIsConstrained(opts: FusedBodyOpts, side: 'anchor' | 'target'): boolean { - const block = side === 'anchor' ? opts.anchor : opts.target; - const region = side === 'anchor' ? opts.anchorRegion : opts.targetRegion; - const pins = side === 'anchor' ? opts.anchorIris : opts.targetIris; - if (pins?.length || region?.length) return true; +// True when the question narrows this block at all. Exported because +// engine/scope.ts asks the same question to pick a chunking axis, and the two +// have to agree: if the template thinks a side is constrained and the executor +// thinks it is wide open, the executor slices on an axis the template already +// led with. engine/sparqlErrors.ts still keeps its own `isNarrowed`, which is +// this plus the region check. +// +// A samples block is the one type with a filter that defaults to set: +// `includeNondetects: true` is the UI's default checked state and narrows +// nothing, so only `=== false` counts. sampleJoinsNeeded above already draws +// that line; a generic "any field is non-null" scan does not, and read +// `includeNondetects: true` alone as a reason to reorder the whole body. +export function blockIsFiltered(block: EntityBlock): boolean { + if (block.type === 'samples') return sampleJoinsNeeded(block.sampleFilters).observation; const filters = - block.sampleFilters ?? block.facilityFilters ?? block.waterBodyFilters ?? block.wellFilters ?? @@ -428,6 +431,16 @@ function sideIsConstrained(opts: FusedBodyOpts, side: 'anchor' | 'target'): bool ); } +// A side is constrained when the question already narrows it: a region, any +// entity filter, or an IRI pin from chunking. Unconstrained means "every +// facility in the graph", which is the side that must not lead the query. +function sideIsConstrained(opts: FusedBodyOpts, side: 'anchor' | 'target'): boolean { + const block = side === 'anchor' ? opts.anchor : opts.target; + const region = side === 'anchor' ? opts.anchorRegion : opts.targetRegion; + const pins = side === 'anchor' ? opts.anchorIris : opts.targetIris; + return Boolean(pins?.length || region?.length) || blockIsFiltered(block); +} + export interface FusedBaseOpts { anchor: EntityBlock; target: EntityBlock; @@ -609,14 +622,12 @@ function targetReachClause(opts: FusedFlowlineOpts): string { // ponytail: target IRIs inlined whole. Only anchors are sliced today // (iriScopes/divideIriList in the planner); add target slicing if a question // ever pushes this past the gateway's body limit. - const targetValues = `VALUES ${entityIriVar(opts.target, 'C')} { ${opts.targetIris - .map(wrapUri) - .join(' ')} }`; + const targetValues = pinValues(entityIriVar(opts.target, 'C'), opts.targetIris); // Filters stripped: the pinned IRIs are already the filtered answer set, so // every filter clause here is a join that can only re-confirm what the VALUES - // list states. Passing the bare block rather than opts.target keeps this to - // the cell-membership triple. Measured on the York question: re-deriving the - // substance filter cost 1s of the 8 and changed nothing. + // list states. Passing the bare block rather than opts.target drops those + // clauses. Measured on the York question: re-deriving the substance filter + // cost 1s of the 8 and changed nothing. const targetBind = bindEntityInCell({ type: opts.target.type }, '?s2celltarget', 'C', false); const reach = opts.direction === 'downstream' @@ -651,12 +662,16 @@ function targetReachClause(opts: FusedFlowlineOpts): string { // leaving sample points with no stream under them. Binding the resolved IRIs // removes the guess and keeps this layer consistent with the facility layer. export function buildFusedFlowlineQuery(opts: FusedFlowlineOpts): string { - const anchorBind = bindEntityInCell(opts.anchor, '?s2anchor', 'A'); + // Bare block, same reasoning as targetReachClause: anchorIris is the resolved + // answer set, so the block's own filters can only re-confirm the VALUES list. + // For a facilities anchor that drops `fio:ofIndustry` plus a NAICS type scan + // per pinned IRI; for a samples anchor it drops the whole observation chain, + // including the coso:measurementUnit join this branch exists to keep out of + // queries that do not read it. + const anchorBind = bindEntityInCell({ type: opts.anchor.type }, '?s2anchor', 'A', false); // ponytail: inlined as VALUES rather than re-derived. Anchor sets are small // (tens), unlike the sample IRI lists that forced server-side fusion. - const anchorValues = `VALUES ${entityIriVar(opts.anchor, 'A')} { ${opts.anchorIris - .map(wrapUri) - .join(' ')} }`; + const anchorValues = pinValues(entityIriVar(opts.anchor, 'A'), opts.anchorIris); const seedCells = `{ SELECT DISTINCT ?s2cellus WHERE { From 18acb5b611c7d1ac239ced8e401e9a372967e186 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 18:26:34 -0400 Subject: [PATCH 56/66] docs: record the non-detect behaviour, the stream-layer bug, and the join rule The two fixes on this branch were recorded as bugs but not as behaviour. Someone reading the app had no way to learn what the "Include non-detects" checkbox does, and the wiki's only mention was three sentences saying it exists. Wiki: new page "Samples Non Detects", linked from the sidebar, Home and the Dropdowns index. What a non-detect is (it is a measurement, not a gap: the record carries detection limits instead of a value, which is why it has no coso:measurementUnit), that the box is ticked by default, and that expanding "+ Add Filters" writes nothing and leaves the SPARQL byte-identical. The behaviour the page exists for: the checkbox filters at two levels, not one. York County, all substances, 451 sample points and 23,530 observations ticked against 367 and 7,110 unticked. The 367 surviving points hold 21,822 observations between them, so unticking also strips 14,712 non-detect rows from popups that stay on the map. Non-detects are 70% of observations in York and 77% across Maine, so this is most of the data rather than a trim. Also the four-way point classification, and why 14 York points have no measurements at all: they are all EGAD soil sampling locations whose results are not loaded, while every well at the same site has 24 to 30 observations. DEBUGGING.md: a 2026-09-19 entry for the stream layer drawing the Merrimack, with the one-sided closure that caused it, the intersection that fixed it (755 flowlines removed, 0 added), and the two forms measured and rejected. Records that a distance cap is not a substitute, since the shipped bounded query drew a Merrimack segment through its own 25km cap. Also the includeNondetects: true defect from the cleanup pass, where the UI's default ticked state was read as a narrowed side and reordered the whole body. ARCHITECTURE.md: a new Key Design Decision on why each filter declares its own joins, since "every required triple is also a filter" is the principle behind both bugs and the thing a newcomer needs before writing a template. Pattern 3 gains a note that a closure needs both ends bound. Corrects an explanation I had wrong in three places. `TC?` recovering 0 extra flowlines is not because the segment arrives via another target; it is because hyf:downstreamFlowPathTC is already reflexive, which ARCHITECTURE.md Pattern 3 had said all along. Verified: X TC X holds for 2,104 of 2,104 York County flowlines, 434,501 self-pairs graph-wide. The measurement and the conclusion are unchanged, only the reason. One consequence worth having right: the segment a target sits on is drawn, and what the intersection excludes is the river below it. --- docs/ARCHITECTURE.md | 38 +++++- docs/DEBUGGING.md | 83 ++++++++++++++ docs/wiki/Dropdowns.md | 5 + docs/wiki/Home.md | 2 + docs/wiki/Samples Non Detects.md | 165 +++++++++++++++++++++++++++ docs/wiki/_Sidebar.md | 4 + scripts/check-flowline-scope.mts | 7 +- src/engine/templates/fusedQueries.ts | 10 +- 8 files changed, 306 insertions(+), 8 deletions(-) create mode 100644 docs/wiki/Samples Non Detects.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6928896..93d865e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -760,7 +760,31 @@ supply — see [Bounded Execution](#bounded-execution). - Easy to debug — copy query into SPARQL editor to test - Full control — no library limitations -### 5. Why Transform SPARQL Rows to Features? +### 5. Why Each Filter Declares Its Own Joins + +**Problem:** In SPARQL a triple pattern is an inner join, so *every required +triple is also a filter*. Asking for a field that some records lack deletes +those records, silently and with no filter anywhere in the query saying so. + +**What went wrong:** `bindEntityInCell` used one boolean — did the user set any +sample filter? — and if so fetched the whole measurement record. Ticking a +substance therefore pulled in `coso:measurementUnit`, and a non-detect has no +unit (there is no quantity to put a unit on; the record carries detection limits +instead). So a substance-only question dropped **774 of 1,688** Cumberland PFOS +observations while "Include non-detects" sat ticked. Non-detects are 77% of +Maine's observations, so this understated PFAS presence across the app, and +nothing looked broken: the map still drew, with fewer dots. + +**We chose:** `sampleJoinsNeeded` maps each active filter to the joins that +filter actually reads. Substance needs two triples. A concentration range +genuinely reads the unit, so that case keeps it. Nothing ever needs the material +*label*, which is display-only. + +**The rule to carry into new templates:** fetch what you project or filter on, +nothing else, and reach for `OPTIONAL` the moment a field is not universal. +`scripts/check-query-joins.mts` asserts this across all 108 shapes in CI. + +### 6. Why Transform SPARQL Rows to Features? **Problem:** SPARQL returns flat rows with WKT strings: ```javascript @@ -909,6 +933,18 @@ anything past the budget, then extends one segment further so the drawn line does not stop mid-channel. On one Maine question, a 30 km bound cut 15,782 reaches to 3,705 while keeping all 616 facilities. +**A closure needs both ends bound, and a distance cap is not a substitute.** The +pattern above is safe because it ends at `?spC`, a real target. The stream layer +(`buildFusedFlowlineQuery`) drew its geometry from the seed side only, with +nothing on the right of the closure, and that is not a narrower version of the +same query — it is a fan-out to the end of the network. An anchor near a +drainage divide brought back the neighbouring basin: on "facilities upstream +from PFOS samples in York County, ME", 122 segments of the Merrimack and 21 of +the Winnipesaukee, 130 km away. Intersecting the closure with the flowlines that +reach the resolved targets removed 755 flowlines and added 0. A 25 km cap did +*not* prevent it, because the wrong basin was inside the budget. See +DEBUGGING.md, 2026-09-19. + **Upstream questions use this same pattern, unchanged.** There is no upstream query. "A upstream from C" seeds from block A and traces downstream to block C, which is the same relation read from the other end. The templates can build a diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index c32d310..7597e78 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -565,3 +565,86 @@ it did before (6.88s vs 6.59s). - **Measure the fix against the shapes it touches, not the one that prompted it.** The sub-SELECT looked like a 48% median win on the question at hand and was a net regression across the shape space. + +## 2026-09-19: The stream layer drew rivers in a basin no sample drains from (FIXED) + +Reported from outside the team: "What facilities are upstream from PFOS samples?" +scoped to York County, ME drew the entire Merrimack River, which is in another +state and another watershed. + +**What was broken.** `GET_FLOWLINE_GEOMETRIES` is a separate query from +discovery, and it traced a one-sided transitive closure. It seeded from the +cells of every resolved anchor, widened each by `sfTouches`, and followed +`hyf:downstreamFlowPathTC` to the end of the network: + +```sparql +?upstream_flowline rdf:type hyf:HY_FlowPath ; + spatial:connectedTo ?s2cellus ; + hyf:downstreamFlowPathTC ?flowline . +``` + +Nothing in it references the target. An anchor sitting near a drainage divide +therefore pulled in the whole of the neighbouring basin. Drawn for that +question: 122 segments of the Merrimack, 40 of the Presumpscot, 37 of the +Suncook, 24 of Cohas Brook, 21 of the Winnipesaukee (~130km away), 16 of the +Powwow. + +**Where it was not.** The discovery query was innocent, which is why the first +guess was wrong. Filtering its own `?upstream_flowline` set for those names +returns zero rows. Only the layer query was one-sided. + +**The fix.** Intersect the closure with the flowlines that reach the resolved +targets. Measured with the real answer sets (1,497 facilities, 200 sample +points): 3,271 flowlines down to 2,516 in the same 7s, **755 removed and 0 +added**, so the change can only subtract flowlines that were never on a path +from a facility to a sample. Of the 755, 684 are in a different basin and 71 lie +below a sample, the latter being a deliberate behaviour change: the drawn river +now stops at the sample instead of running on to the sea. + +**Two forms measured and rejected.** + +- *The direct membership test*, `?flowline hyf:downstreamFlowPathTC? ?_flTarget`, + leaves `?flowline` unbound on the left and QLever times out at 31s ("Join on + ?flowline"). Two `SELECT DISTINCT` closures intersected on `?flowline` run in + the same 7s the one-sided query took. +- *A reflexive reach*, `TC?` instead of `TC` on the target side, recovers **0** + flowlines and costs 8s. `hyf:downstreamFlowPathTC` is already reflexive, so + `TC?` is the same relation spelled more expensively: `X TC X` holds for 2,104 + of 2,104 York County flowlines and there are 434,501 self-pairs graph-wide. + ARCHITECTURE.md Pattern 3 already said so. The segment a target sits on is + therefore drawn; what the intersection excludes is the river *below* it. + +**A distance bound is not a substitute.** The bounded branch got the same +intersection. At 25km it went 3,034 to 2,516, matching the unbounded set, +because connectivity dominates the cap at that range; at 5km the cap still bites +(2,314), so the two constraints compose. The shipped bounded query had been +drawing a Merrimack segment straight through its own 25km cap. + +`scripts/check-flowline-scope.mts` asserts both ends are bound for all 100 +shapes that draw the layer, bounded and unbounded. + +**Also fixed here: `includeNondetects: true` counted as a filter.** The +seed-side rule added on 2026-09-17 asked "is this side narrowed" with a generic +"any filter field is non-null" scan. `includeNondetects: true` is the UI's +default ticked state and narrows nothing, so a samples block carrying only that +was read as constrained and reordered the entire body. Ticking the checkbox and +un-ticking it back therefore changed the emitted SPARQL for a semantically +identical question. Samples now delegate to `sampleJoinsNeeded`, which already +drew the line at `=== false`. + +The same predicate existed three times (`scope.ts` as `hasBlockFilters`, +`sparqlErrors.ts` as `isNarrowed`, and the new copy). `scope.ts` asks it to pick +a chunking axis, so a drift means the executor slices on an axis the template +already led with. It is now one exported `blockIsFiltered`. + +**Lessons** + +- **A one-sided closure is not a filter, it is a fan-out.** Seeding from the + answer set feels bounded and is not: transitive closure from any seed reaches + the end of the network. If both ends of a relationship are known, bind both. +- **The query that produces the wrong output is not always the query that looks + wrong.** Three queries feed one map. Name-filtering each layer's own result + set located this in one step after a day of reading the wrong query. +- **"Stop at the cutoff" and "stop where it stops mattering" are different + bounds.** A distance cap looked like it should have prevented this and did + not, because the wrong basin was well within range. diff --git a/docs/wiki/Dropdowns.md b/docs/wiki/Dropdowns.md index 4d6bbfb..26737f3 100644 --- a/docs/wiki/Dropdowns.md +++ b/docs/wiki/Dropdowns.md @@ -103,4 +103,9 @@ material type URI says nothing about which bucket it belongs to. `buildTree` han For completeness, the Samples filter panel also has Min and Max concentration number inputs in ng/L, and an "Include non-detects" checkbox. None of them query anything; they are applied inside the pipeline queries. + +The non-detects checkbox is ticked by default and moves the answer more than any dropdown on +this page, because non-detects are 70 to 77% of the observations. It filters both which +sample points appear and which rows appear inside their popups. See +[Include non-detects](Samples%20Non%20Detects). [`SampleFilters.tsx`](https://github.com/SAWGraph/explorer-app/blob/main/src/components/QueryEditor/SampleFilters.tsx) diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index 4de9673..1d5d3ae 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -18,6 +18,8 @@ Where the options in each filter control come from. * [Industry](Dropdowns%20Industry) * [Industry counts](Dropdowns%20Industry%20Counts) * [County](Dropdowns%20County) +* [Include non-detects](Samples%20Non%20Detects), the Samples checkbox that moves the + numbers most ## Elsewhere in the repository diff --git a/docs/wiki/Samples Non Detects.md b/docs/wiki/Samples Non Detects.md new file mode 100644 index 0000000..ed0fd7d --- /dev/null +++ b/docs/wiki/Samples Non Detects.md @@ -0,0 +1,165 @@ +# Include non-detects + +A checkbox in the Samples filter panel. Ticked by default. It decides whether the answer +counts clean results as well as contaminated ones, and it moves the numbers more than any +other filter on the page, because **non-detects are most of the data**. + +## What a non-detect is + +A non-detect is a measurement, not a gap. The lab tested for the substance and found less +than it is able to see. The record carries the detection limits instead of a value: + +| | A detect | A non-detect | +| --- | --- | --- | +| `coso:measurementUnit` | `NanoGM-PER-L` | **absent** | +| numeric value | `0.632` | absent | +| `methodDetectionLimit` | `0.486 ng/L` | `0.449 ng/L` | +| `reportingLimit` | `1.93 ng/L` | `1.78 ng/L` | +| typed `coso:NonDetectQuantityValue` | no | yes | + +The missing unit is the important row. There is nothing to put a unit on, because no +quantity was measured. That absence used to delete the record from every query. See +[Debugging](https://github.com/SAWGraph/explorer-app/blob/main/docs/DEBUGGING.md), +2026-09-17. + +How common they are, measured on `federation`: + +| Scope | Detects | Non-detects | Non-detect share | +| --- | ---: | ---: | ---: | +| York County, all substances | 7,110 | 16,420 | **70%** | +| Maine, all substances | 134,572 | 453,476 | **77%** | + +## What the checkbox does + +It filters at **two** levels, and both matter. + +1. **Which sample points appear on the map.** A point survives only if it has at least one + detection left. +2. **Which rows appear inside a popup.** Points that survive still lose their non-detect + rows. + +York County, no substance selected: + +| | Ticked (default) | Unticked | +| --- | ---: | ---: | +| Sample points on the map | **451** | **367** | +| Observations in popups | **23,530** | **7,110** | +| Points with at least one detect | 451 includes all 367 | 367 | +| Points where everything came back clean | 70 shown | dropped | +| Points with no measurements in the graph | 14 shown | dropped | +| Non-detect readings | 16,420 shown | none shown | + +The second row is the one people miss. The 367 surviving points hold 21,822 observations +between them, but unticking shows only the 7,110 detects among those. A well with 30 +readings of which 2 were detections shows 2 rows, not 30. + +With a substance selected the same thing happens inside that substance. York County PFOS: +361 points ticked, 230 unticked. + +## What a dot on the map means + +This is the part worth saying out loud, because the two readings of the map are different +claims: + +* **Ticked**: a dot means *someone sampled here*. +* **Unticked**: a dot means *PFAS was found here*. + +The misleading part is the absence of a dot. With the box unticked, 70 York County +locations that were tested and came back clean look exactly like ground nobody ever +visited. For a contamination map that is usually the wrong default, which is why the box +starts ticked. + +## Every sample point, classified + +Mutually exclusive, York County, all substances: + +| State | Points | In the answer when unticked? | +| --- | ---: | --- | +| No measurements in the graph at all | 14 | no | +| Tested, everything was a non-detect | 70 | no | +| Mixed: some detects, some non-detects | 366 | yes | +| Only detects | 1 | yes | +| **Total** | **451** | 367 | + +The 14 with no measurements are real registered locations, not bad rows. They are all soil +sampling points (`SB-*`, `SS-*`, `YO-*` in EGAD) with coordinates, a parent site and a +feature type of `SOIL AUGER`, whose lab results are not in the graph. At their parent site +every drinking-water and monitoring well has 24 to 30 observations and every soil point has +zero, so the gap is systematic rather than random. They currently render with an empty +popup. + +There is a fourth possible result state in the code, `"non-quantified"`, a result that is +neither a number nor typed as a non-detect. It is defensive: zero occurrences in York +County and zero across Maine. + +## Opening the filter panel changes nothing + +The checkbox only exists once **+ Add Filters** is expanded, but expanding it is a +display-only action: + +```tsx + +``` + +`setShowFilters` is local component state and never touches the question. The box draws as +ticked because it reads `value?.includeNondetects !== false`, and with no filters set at all +that is `true`. The emitted SPARQL is byte-identical before and after, and **Apply** stays +disabled. + +## The SPARQL + +Ticked, with no other sample filter, the whole samples block is two lines. Nothing asks +about measurements, so nothing can filter on them: + +```sparql +?spC rdf:type coso:SamplePoint ; + spatial:connectedTo ?s2target . +``` + +Unticked adds the result chain and one explicit filter: + +```sparql +?observationC coso:observedAtSamplePoint ?spC . +?observationC coso:hasResult ?resultC . +OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } +OPTIONAL { ?resultC qudt:quantityValue ?_qvC . + ?_qvC rdf:type coso:NonDetectQuantityValue . + BIND(true AS ?nonDetectC) } +BIND(COALESCE(STR(?numericResultC), + IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) +FILTER(BOUND(?numericResultC)) +``` + +`FILTER(BOUND(?numericResultC))` is the exclusion. Note it is written as an explicit filter +rather than achieved by requiring a field non-detects lack, which is what the old code did +by accident. + +Two details that bite anyone writing these by hand: + +* **Do not use `coso:measurementValue`.** It is multi-valued on non-detects, returning both + `"non-detect"` and `"non-quantified"`, which duplicates every non-detect row and makes + `MAX()` return a string. The app derives its displayed value from `qudt:quantityValue` + instead. +* **Do not require `coso:measurementUnit` unless a concentration range needs it.** Requiring + it is indistinguishable from unticking this box, except silent. + +## If the numbers look wrong + +* **Counts jumped up after a deploy.** Expected. Before 2026-09-17 the checkbox did nothing + in either position: a required unit join removed non-detects regardless. Any figure taken + off the app before that understates PFAS presence. +* **A popup is empty.** Likely one of the 14 points with no measurements in the graph. +* **Unticking removed more than expected.** It removes readings, not just points. Check the + popup row counts, not only the dot count. + +## In the code + +[`SampleFilters.tsx`](https://github.com/SAWGraph/explorer-app/blob/main/src/components/QueryEditor/SampleFilters.tsx) +renders the checkbox. +[`fusedQueries.ts`](https://github.com/SAWGraph/explorer-app/blob/main/src/engine/templates/fusedQueries.ts) +decides which joins each filter needs, in `sampleJoinsNeeded`. +[`samples.ts`](https://github.com/SAWGraph/explorer-app/blob/main/src/engine/templates/samples.ts) +holds `needsUnitJoin` and `resultValueClauses`. +`scripts/check-query-joins.mts` asserts the rule across all 108 question shapes in CI. diff --git a/docs/wiki/_Sidebar.md b/docs/wiki/_Sidebar.md index 1fc47e6..12c9a07 100644 --- a/docs/wiki/_Sidebar.md +++ b/docs/wiki/_Sidebar.md @@ -11,6 +11,10 @@ * [Industry counts](Dropdowns%20Industry%20Counts) * [County](Dropdowns%20County) +**Samples** + +* [Include non-detects](Samples%20Non%20Detects) + **In the repo** * [Architecture](https://github.com/SAWGraph/explorer-app/blob/main/docs/ARCHITECTURE.md) diff --git a/scripts/check-flowline-scope.mts b/scripts/check-flowline-scope.mts index 7971574..6eea46b 100644 --- a/scripts/check-flowline-scope.mts +++ b/scripts/check-flowline-scope.mts @@ -79,9 +79,10 @@ for (const blockA of ENTITY_TYPES) { /\?flowline hyf:downstreamFlowPathTC \?_flTarget|\?_flTarget hyf:downstreamFlowPathTC \?flowline/, `${where}: target reach clause does not close on ?flowline`, ); - // The reach clause must be a bare TC. `TC?` was measured: it recovers - // 0 flowlines and costs 8s on the York question. - // Bare `includes`, not the downstream spelling: the reflexive form is + // The reach clause must be a bare TC. hyf:downstreamFlowPathTC is + // already reflexive, so `TC?` is the same relation spelled more + // expensively: measured at 0 extra flowlines and +8s. + // Bare `includes`, not the downstream spelling: the form is // `?flowline TC? ?_flTarget` downstream and `?_flTarget TC? ?flowline` // upstream, and matching only the first left the upstream shape // unguarded by a check whose whole point is the `TC?` regression. diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 79a6c69..49db8c2 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -614,10 +614,12 @@ export interface FusedFlowlineOpts { // (31s, "Join on ?flowline"). The intersection runs in the same 7s the // one-sided query took. // -// The closure is strict on both ends, so the segment a target sits on is not -// drawn. Making the target side reflexive (`TC?`) was measured and recovers -// nothing (0 extra flowlines) while costing 8s, because that segment already -// arrives via another target upstream of it. +// `TC?` on the target side was measured and recovers nothing (0 extra +// flowlines) while costing 8s. That is not a quirk: hyf:downstreamFlowPathTC is +// already reflexive (`X TC X` holds for 2,104 of 2,104 York County flowlines, +// 434,501 self-pairs graph-wide), so `TC?` is definitionally the same relation. +// The segment a target sits on is therefore drawn; what is excluded is the +// river below it. function targetReachClause(opts: FusedFlowlineOpts): string { // ponytail: target IRIs inlined whole. Only anchors are sliced today // (iriScopes/divideIriList in the planner); add target slicing if a question From 7302d7ce0f8b7dbbe1142655712f219e5627d947 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 18:33:53 -0400 Subject: [PATCH 57/66] docs(changelog): week 38 entries for the two silent filters and the stream layer Entry 13 covers the join order and the unit join fixed on 2026-09-17, including that dashboard counts will move up when it deploys and that figures taken off the app before that date understate PFAS presence. Entry 14 covers the stream layer drawing the Merrimack, the includeNondetects defect found while reviewing it, the new wiki page, and the cell-widening gap that is measured but deliberately not fixed here. --- docs/changelog/2026-W38.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 3a02d06..0849b12 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -115,3 +115,39 @@ **A wells-upstream question was attempted and abandoned**, which is worth recording so nobody tries it again without knowing. "Maine landfills and DoD sites upstream from private wells" timed out on all four scopings measured (statewide and Penobscot-only, 10 km and 30 km), always on the wells side. The direction is not the problem: "wells downstream of landfills" builds the identical query, since the planner seeds from the filtered facilities either way. Wells as the far end of a hydrology trace is simply the expensive shape, which is why all three existing wells questions use proximity. *Files:* `src/constants/prebuiltQueries.ts`, `.github/workflows/health-check.yml` + +13. **Fixed: Two Silent Filters in the Fused Queries** (2026-09-17) + Both surfaced on "What facilities are upstream from PFOS samples?" with block A left as plain Facilities and block C set to PFOS samples in York and Cumberland counties. The question failed at step 1 with `500 out-of-memory` after 116s, sliced into its two counties, and failed both slices. + + **Join order.** `buildFusedWhereBody` always wrote the anchor block first, and an upstream question puts block A there. With no region and no industry filter on block A, the query started from every facility in the graph and traced the national flowline network looking for samples in two Maine counties. QLever does not search join orders exhaustively at these body sizes, so it follows the query text: writing the constrained side first is the whole fix, same triples and same variables in a different order. Measured across all 72 hydrology shape and config pairs: **5 rescued, 0 regressions, 0 rows lost, faster in 50 of 66 comparable runs.** The reorder is deliberately narrow, firing only when one side is narrowed and the other is wide open, because the unconditional version was measured too and rescued the same 5 while breaking 7. "Narrowed" is not "small": a county of wells is narrowed and still enormous. + + **The unit join.** `bindEntityInCell` emitted the whole observation chain whenever any sample filter was set, including `coso:measurementUnit`. A non-detect has no unit recorded, because no quantity was measured; the record carries detection limits instead. So ticking a substance silently deleted every non-detect while "Include non-detects" sat ticked, and the checkbox did nothing in either position. Cumberland PFOS: **774 of 1,688 observations** dropped, turning 23 sample points and 13 facilities into 32 and 15. The same required join hid **2,860 of 3,334 rows** in the sample popup. Non-detects are 77% of Maine's observations, so this understated PFAS presence everywhere in the app, and nothing looked broken: the map still drew, with fewer dots. Any figure taken off the app before this date understates. + + Each filter now declares the joins it actually reads. A concentration range genuinely needs the unit and keeps it; nothing ever needs the material label. Expect dashboard counts to move **up** when this deploys. That is the fix landing, not a regression. + + `scripts/check-query-joins.mts` asserts both rules on the emitted SPARQL (265 checks) and runs in CI. `docs/DEBUGGING.md` records the measurements and the two designs tried and rejected, including the sub-SELECT that rescued 5 shapes and broke 7. + + *Files:* `src/engine/templates/fusedQueries.ts`, `src/engine/templates/downstreamSamples.ts`, `scripts/check-query-joins.mts` (new), `.github/workflows/checks.yml`, `package.json`, `docs/DEBUGGING.md`, `docs/plans/active/2026-09-17-fused-seed-side-and-observation-joins.md` (new) + +14. **Fixed: The Stream Layer Drew Rivers in a Basin No Sample Drains From** (2026-09-19) + Reported by the project's PI: the same York County question drew the entire Merrimack River, which is in another state and another watershed. + + The river layer is a separate query from discovery, and it traced a one-sided transitive closure. It seeded from the cells of every resolved facility, widened each by `sfTouches`, and followed the network to its end. Nothing in it referenced the samples at all, so a facility near a drainage divide pulled in the whole neighbouring basin: **122 segments of the Merrimack, 40 of the Presumpscot, 37 of the Suncook, 21 of the Winnipesaukee** about 130 km away. + + Worth recording where it was *not*, because the first guess was wrong and cost a day. The discovery query was innocent. Filtering its own flowline set for those river names returns zero rows. Only the layer query was one-sided. + + The closure is now intersected with the flowlines that reach the resolved samples. Measured with the real answer sets (1,497 facilities, 200 sample points): **3,271 flowlines down to 2,516 in the same 7s, 755 removed and 0 added**, so the change can only subtract flowlines that were never on a path from a facility to a sample. Of those 755, 684 are in a different basin and 71 lie below a sample, the latter a deliberate behaviour change: the drawn river now stops at the sample instead of running on to the sea. If the full river to the coast is wanted back, that is one clause and a decision, not a rebuild. + + A distance bound is not a substitute and was never going to be. The shipped bounded query had been drawing a Merrimack segment straight through its own 25 km cap, because the wrong basin was inside the budget. + + Two forms were measured and rejected. The direct membership test leaves `?flowline` unbound on the left and times out at 31s; two intersected subqueries run in the original 7s. A reflexive reach adds nothing, because `hyf:downstreamFlowPathTC` is already reflexive (`X TC X` holds for 2,104 of 2,104 York County flowlines). + + **Also fixed, found while reviewing the above:** the seed-side rule from entry 13 counted `includeNondetects: true` as a filter. That is the UI's default ticked state and narrows nothing, so a samples block carrying only that was read as a narrowed side and reordered the entire query. Ticking the checkbox and un-ticking it back therefore changed the emitted SPARQL for a question that had not changed. The same "is this side narrowed" predicate also existed in three places, one of which the executor uses to pick a chunking axis, so a drift between them would have had the executor slicing on a side the query already led with. Now one definition. + + **Documented, not only fixed.** A new wiki page, [Include non-detects](https://github.com/SAWGraph/explorer-app/blob/main/docs/wiki/Samples%20Non%20Detects.md), covers what the checkbox does now that it works: it filters at two levels, so unticking removes 84 of York County's 451 sample points *and* strips 14,712 non-detect readings from popups that stay on the map. Ticked, a dot means "someone sampled here"; unticked, it means "PFAS was found here", and the absence of a dot is what misleads. `docs/ARCHITECTURE.md` gains the principle behind both this entry and entry 13: in SPARQL every required triple is also a filter, so asking for detail you do not need silently deletes the rows that lack it. + + **Known gap, measured but not fixed.** To connect an entity to a river there has to be a river in its S2 cell (about 1 km across), and often there is not, so the query widens by one ring of neighbouring cells. That widening is applied to exactly one side, and which side is an accident of how the query is written. We widen the facility side, which costs **130 York County sample points, 82 of them carrying measured PFOS detections up to 2,200 ng/L**, roughly 110x Maine's interim drinking water standard. Widening both sides in one query does not run (2.6 GB allocation failure, two formulations tried). Drafted in `docs/plans/drafts/2026-09-19-symmetric-cell-widening.md`. + + `scripts/check-flowline-scope.mts` asserts both ends of the closure are bound for all 100 shapes that draw the layer (400 checks), bounded and unbounded, and runs in CI. + + *Files:* `src/engine/templates/fusedQueries.ts`, `src/engine/planner.ts`, `src/engine/scope.ts`, `scripts/check-flowline-scope.mts` (new), `.github/workflows/checks.yml`, `package.json`, `docs/DEBUGGING.md`, `docs/ARCHITECTURE.md`, `docs/wiki/Samples Non Detects.md` (new), `docs/wiki/_Sidebar.md`, `docs/wiki/Home.md`, `docs/wiki/Dropdowns.md`, `docs/plans/drafts/2026-09-19-symmetric-cell-widening.md` (new) From 002e529c79a0e511e7e19b1e9c6f3992ec83247d Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 19:31:45 -0400 Subject: [PATCH 58/66] fix(pipeline): align the timeline dot with the first line of its text The dot sat at the top of the content box rather than on the text beside it, and the running step carried its own padding, so a step visibly shifted when it started. Padding moves onto .timeline-content so every step has it, and the marker gains a matching top offset. --- src/App.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/App.css b/src/App.css index 4e7f7d8..87d1768 100644 --- a/src/App.css +++ b/src/App.css @@ -598,6 +598,9 @@ align-items: center; flex-shrink: 0; width: 24px; + /* ponytail: matches .timeline-content top padding + half a text line, so the dot + sits on the first line of text instead of the top of the box */ + padding-top: 0.5rem; } .timeline-dot { @@ -643,16 +646,15 @@ } .timeline-content { - padding-bottom: var(--space-md); flex: 1; min-width: 0; + padding: var(--space-xs) var(--space-sm); + margin-bottom: var(--space-sm); } .timeline-content--running { background: var(--color-primary-50); border-radius: var(--radius-sm); - padding: var(--space-xs) var(--space-sm); - margin: -2px 0 var(--space-md); } .timeline-desc { From e84a11f8636f36f9585eacb6219241dad9537ea0 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 23:52:49 -0400 Subject: [PATCH 59/66] test(matrix): sweep the flow-distance bound, which nothing covered `maxDistanceKm` appeared zero times in the harness. M4, which the header called a distance sweep, sweeps the `near` relationship's hop distance in miles; the hydrology relationship's flow-distance bound in km was swept by nothing, and the only bounded shape the matrix ever ran was one dashboard prebuilt in M5. Worse, `mk` attached the region to block A unconditionally. For an upstream question the planner maps block A to the anchor, so a region on A always left the anchor as the constrained side: the target-first join order was unreachable from this harness, and so was every bounded question that leaves block A wide open, which is the shape users build. `mk` now takes `{ km, regionOn }`, and MD runs four shapes bounded and unbounded with the region on each block. It measures both discovery steps rather than step 0 like M1-M4, because the two projections share a WHERE clause but not a fate: at 30 km the samples projection answered in 25s while the facilities projection ran out of memory at 32s, and a step-0-only phase would have called that working. The baseline (32 rows, 11 pass) shows the rule cleanly: a bounded query works when the region sits on the block that becomes the anchor and fails when it sits on the target. Upstream makes block A the anchor, downstream makes block C the anchor, and the mirror pair `facilities upstream(30km) samples [on A]` and `samples downstream(30km) facilities [on C]` return identical counts, 2,399 and 2,523. Wells is the exception and fails on all four bounded combinations for its own reasons, as in W38 entry 12. --- docs/query-matrix/2026-09-20-raw-002e529.csv | 33 +++++++++ docs/query-matrix/README.md | 3 +- scripts/query-matrix.mts | 75 ++++++++++++++++++-- 3 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 docs/query-matrix/2026-09-20-raw-002e529.csv diff --git a/docs/query-matrix/2026-09-20-raw-002e529.csv b/docs/query-matrix/2026-09-20-raw-002e529.csv new file mode 100644 index 0000000..dbcbcf6 --- /dev/null +++ b/docs/query-matrix/2026-09-20-raw-002e529.csv @@ -0,0 +1,33 @@ +runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg +2026-09-20T03:36,002e529,MD,"facilities upstream samples [ME on A] step0",facilities,upstream,,samples,ME on A,"none",FIND_TARGET_IRIS,federation,429,30442,0,111431,timeout-30s,"Operation timed out. Last operation: Join on ?ds_flowline" +2026-09-20T03:36,002e529,MD,"facilities upstream samples [ME on A] step1",facilities,upstream,,samples,ME on A,"none",FIND_ANCHOR_IRIS,federation,429,32609,0,111600,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T03:36,002e529,MD,"facilities upstream samples [ME on C] step0",facilities,upstream,,samples,ME on C,"none",FIND_TARGET_IRIS,federation,429,39826,0,108007,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:36,002e529,MD,"facilities upstream samples [ME on C] step1",facilities,upstream,,samples,ME on C,"none",FIND_ANCHOR_IRIS,federation,500,32117,0,108455,engine-oom,"Tried to allocate 1.7 GB, but only 499.5 MB were available" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) samples [ME on A] step0",facilities,upstream,,samples,ME on A,"30km",FIND_TARGET_IRIS,federation,200,22993,2399,238993,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) samples [ME on A] step1",facilities,upstream,,samples,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,8647,2523,244781,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) samples [ME on C] step0",facilities,upstream,,samples,ME on C,"30km",FIND_TARGET_IRIS,federation,429,30370,0,479268,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) samples [ME on C] step1",facilities,upstream,,samples,ME on C,"30km",FIND_ANCHOR_IRIS,federation,500,21553,0,479800,engine-oom,"Tried to allocate 2.1 GB, but only 1.2 GB were available" +2026-09-20T03:36,002e529,MD,"facilities upstream streams [ME on A] step0",facilities,upstream,,streams,ME on A,"none",FIND_TARGET_IRIS,federation,200,16106,9632,749884,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream streams [ME on A] step1",facilities,upstream,,streams,ME on A,"none",FIND_ANCHOR_IRIS,federation,200,1117,2858,277276,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream streams [ME on C] step0",facilities,upstream,,streams,ME on C,"none",FIND_TARGET_IRIS,federation,200,17928,9502,739652,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream streams [ME on C] step1",facilities,upstream,,streams,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,3760,4056,393482,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) streams [ME on A] step0",facilities,upstream,,streams,ME on A,"30km",FIND_TARGET_IRIS,federation,200,12374,9110,709410,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) streams [ME on A] step1",facilities,upstream,,streams,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,1583,2858,277276,ok,"" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) streams [ME on C] step0",facilities,upstream,,streams,ME on C,"30km",FIND_TARGET_IRIS,federation,429,32002,0,479100,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) streams [ME on C] step1",facilities,upstream,,streams,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,31369,0,478927,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T03:36,002e529,MD,"facilities upstream wells [ME on A] step0",facilities,upstream,,wells,ME on A,"none",FIND_TARGET_IRIS,federation,429,31171,0,117042,timeout-30s,"Operation timed out. Last operation: Join on ?ds_flowline" +2026-09-20T03:36,002e529,MD,"facilities upstream wells [ME on A] step1",facilities,upstream,,wells,ME on A,"none",FIND_ANCHOR_IRIS,federation,500,19623,0,117156,engine-oom,"Tried to allocate 1.6 GB, but only 911.8 MB were available" +2026-09-20T03:36,002e529,MD,"facilities upstream wells [ME on C] step0",facilities,upstream,,wells,ME on C,"none",FIND_TARGET_IRIS,federation,429,36758,0,111550,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:36,002e529,MD,"facilities upstream wells [ME on C] step1",facilities,upstream,,wells,ME on C,"none",FIND_ANCHOR_IRIS,federation,429,31463,0,111552,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) wells [ME on A] step0",facilities,upstream,,wells,ME on A,"30km",FIND_TARGET_IRIS,federation,429,30384,0,527792,timeout-30s,"Operation timed out. Last operation: Join on ?s2target" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) wells [ME on A] step1",facilities,upstream,,wells,ME on A,"30km",FIND_ANCHOR_IRIS,federation,429,31207,0,532435,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) wells [ME on C] step0",facilities,upstream,,wells,ME on C,"30km",FIND_TARGET_IRIS,federation,429,30329,0,522447,timeout-30s,"Operation timed out. Last operation: Join on ?s2anchor" +2026-09-20T03:36,002e529,MD,"facilities upstream(30km) wells [ME on C] step1",facilities,upstream,,wells,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,30501,0,527948,timeout-30s,"Operation timed out. Last operation: Join on ?upstream_flowline" +2026-09-20T03:36,002e529,MD,"samples downstream facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"none",FIND_TARGET_IRIS,federation,500,23256,0,108086,engine-oom,"Tried to allocate 2.6 GB, but only 2.4 GB were available" +2026-09-20T03:36,002e529,MD,"samples downstream facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"none",FIND_ANCHOR_IRIS,federation,429,31284,0,107969,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:36,002e529,MD,"samples downstream facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"none",FIND_TARGET_IRIS,federation,429,33385,0,111524,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T03:36,002e529,MD,"samples downstream facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,25171,2652,257294,ok,"" +2026-09-20T03:36,002e529,MD,"samples downstream(30km) facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"30km",FIND_TARGET_IRIS,federation,429,34451,0,478801,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?_flMid" +2026-09-20T03:36,002e529,MD,"samples downstream(30km) facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"30km",FIND_ANCHOR_IRIS,federation,500,27607,0,479804,engine-oom,"Tried to allocate 2.1 GB, but only 1.2 GB were available" +2026-09-20T03:36,002e529,MD,"samples downstream(30km) facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"30km",FIND_TARGET_IRIS,federation,200,22430,2399,238993,ok,"" +2026-09-20T03:36,002e529,MD,"samples downstream(30km) facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"30km",FIND_ANCHOR_IRIS,federation,200,8317,2523,244781,ok,"" diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md index 2ad26a5..f8b28ec 100644 --- a/docs/query-matrix/README.md +++ b/docs/query-matrix/README.md @@ -16,6 +16,7 @@ engine change. The two are not comparable row for row. | Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | | --- | --- | --- | ---: | ---: | ---: | --- | +| [`2026-09-20`](./2026-09-20-raw-002e529.csv) | raw | `002e529` | 32 | 11 | 21 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine-contaminated-9128aa9.csv) | engine-contaminated | `9128aa9` | 124 | 94 | 29 | _first sweep in this mode_ | @@ -33,4 +34,4 @@ The other 99 rows (62 `near`, 37 `downstream`) are unaffected, and are the contr diffing this file against the next sweep. -Generated 2026-09-16. +Generated 2026-09-20. diff --git a/scripts/query-matrix.mts b/scripts/query-matrix.mts index 1d81f90..2245c90 100644 --- a/scripts/query-matrix.mts +++ b/scripts/query-matrix.mts @@ -9,8 +9,13 @@ // npx tsx scripts/query-matrix.mts M2 # subsequent phases append // // Phases: M1 near(1) all 25 entity pairs | M2 downstream all pairs -// M3 upstream all pairs | M4 distance sweep | M5 dashboard queries +// M3 upstream all pairs | M4 near-hop distance | M5 dashboard queries // M6 six states | M7 no region | M8 filters | M9 county scopes +// MD flow-distance bounds +// +// M4 sweeps the `near` relationship's hop distance (miles). MD sweeps the +// hydrology relationship's flow-distance bound (km), which is a different +// control and was swept by nothing until MD existed. // // How long it takes depends entirely on MODE, and the difference is large: // @@ -202,11 +207,34 @@ async function run(matrix: string, label: string, q: AnalysisQuestion, meta: Rec } const TYPES: EntityType[] = ['samples', 'facilities', 'waterBodies', 'wells', 'aquifers']; -const mk = (a: EntityType, rel: 'near'|'downstream'|'upstream', c: EntityType, hops: number|undefined, state: string|undefined, counties?: string[]): AnalysisQuestion => ({ - blockA: { type: a, ...(state ? { region: { stateCode: state, ...(counties ? { countyCodes: counties } : {}) } } : {}) }, - relationship: { type: rel, ...(hops !== undefined ? { hops } : {}) }, - blockC: { type: c }, -} as AnalysisQuestion); +// `regionOn` picks which block carries the region, and defaults to 'A', which +// is what every phase written before MD assumed. That default is not neutral: +// for an upstream question the planner maps block A to the anchor, so a region +// on A always left the *anchor* as the constrained side, and the target-first +// join order — which only fires when the target is narrowed and the anchor is +// not — was unreachable from this harness. So was every bounded question that +// leaves block A wide open, which is the shape users actually build. +const mk = ( + a: EntityType, + rel: 'near'|'downstream'|'upstream', + c: EntityType, + hops: number|undefined, + state: string|undefined, + counties?: string[], + opts?: { km?: number; regionOn?: 'A' | 'C' }, +): AnalysisQuestion => { + const region = state ? { region: { stateCode: state, ...(counties ? { countyCodes: counties } : {}) } } : {}; + const onC = opts?.regionOn === 'C'; + return { + blockA: { type: a, ...(onC ? {} : region) }, + relationship: { + type: rel, + ...(hops !== undefined ? { hops } : {}), + ...(opts?.km !== undefined ? { maxDistanceKm: opts.km } : {}), + }, + blockC: { type: c, ...(onC ? region : {}) }, + } as AnalysisQuestion; +}; const phase = process.argv[2]; @@ -257,6 +285,41 @@ if (phase === 'M9') { // county-scoped (smallest realistic) + multi-county await run('M9', `samples downstream facilities [${label}]`, mk('samples', 'downstream', 'facilities', undefined, '23', counties), { blockA: 'samples', rel: 'downstream', hops: '', blockC: 'facilities', region: label, filters: 'none' }, 0); } +if (phase === 'MD') { // flow-distance bounds, both narrowing directions + // Four shapes, each run bounded and unbounded, with the region on block A and + // on block C, and on both discovery steps. Every axis here is one the bounded + // path can behave differently on, and none of them were covered before: + // + // - region on A vs C decides which side is constrained, which decides the + // join order. Bounded queries currently keep the anchor-first order + // whatever the answer, which is the thing under test. + // - both steps, not just step 0 like M1-M4. The two projections share a + // WHERE clause but not a fate: on "facilities upstream from PFOS samples + // in York" at 30 km, the samples projection answered in 25s while the + // facilities projection ran out of memory at 32s. Measuring step 0 alone + // would have recorded that shape as working. + // - the unbounded twin of every bounded row, so "did the bound remove rows" + // is answerable from this file alone rather than by joining against M2/M3, + // which scope their regions differently. + const SHAPES: [EntityType, 'upstream' | 'downstream', EntityType][] = [ + ['facilities', 'upstream', 'samples'], // block A wide open: what fails in the app today + ['facilities', 'upstream', 'streams'], // the one bounded dashboard question's shape + ['facilities', 'upstream', 'wells'], // the known-expensive far end (W38 entry 12) + ['samples', 'downstream', 'facilities'], // downstream, where A and C swap anchor/target + ]; + for (const [a, rel, c] of SHAPES) + for (const km of [undefined, 30]) + for (const regionOn of ['A', 'C'] as const) + for (const step of [0, 1]) + await run( + 'MD', + `${a} ${rel}${km ? `(${km}km)` : ''} ${c} [ME on ${regionOn}] step${step}`, + mk(a, rel, c, undefined, '23', undefined, { km, regionOn }), + { blockA: a, rel, hops: '', blockC: c, region: `ME on ${regionOn}`, filters: km ? `${km}km` : 'none' }, + step, + ); +} + // --- the index ------------------------------------------------------------- // // One row per sweep: when, which commit, how many query shapes passed, and what From ec221d9df044c1a423918f1928b8497a51b93cd1 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sat, 19 Sep 2026 23:59:33 -0400 Subject: [PATCH 60/66] fix(engine): seed the bounded trace from the constrained side The constrained-side-first reorder skipped distance-bounded queries, with a comment saying that shape had not been measured either way. Measured now: every bounded shape whose constrained side was the target failed, and the bound was the thing breaking them. "Facilities upstream from PFOS samples in York" with block A left wide open, at 30km: 429 in query planning at 30s on both projections. Unbounded, the same question answers. boundedTrace embeds its seed inside an aggregate that sums path lengths over two closure hops, so seeding the wide-open side sums them across the national flowline graph: 1,506,326 facilities. Seeded from the 132 samples instead, the same question answers in 20s and 3s, returning 132 samples and 918 facilities. The reorder is the same rule the unbounded path already followed, so the guard loses one clause. boundedTrace gains a seed side, and the trace, the GROUP BY and the "+1" fringe all follow it: the fringe still extends away from the seed, which means the physical end that gets the extra segment now follows the seed side. Checked across all 1,152 hydrology shape and config pairs: 144 queries change text, exactly the bounded ones whose constrained side is the target, and the other 1,008 are byte-identical. Correctness, before trusting the speed. Where both forms run, they return identical IRI sets on both projections. Against the unbounded answer the bounded one is a strict subset, 918 of 1,494 facilities with 0 added. Across 5, 10, 30 and 50km the answers nest, each bound's set contained in the next. Two checks had to change, and both were rebuilt rather than relaxed. check-query-joins asserted that bounded traces keep the anchor-first order, which was the defect; it now asserts the same constrained-side rule as every other shape, and separately that the aggregate seeds from that side too, since a query can read target-first while the cost stays where it was. check-trace-direction is the more delicate one. It kept `?_flEnd hyf:downstreamFlowPathTC ?_flMid` on a blacklist of reversed traces, and a target-seeded block writes that exact triple while tracing correctly. That string cannot decide it any more, so queries naming both ends are now checked by reachability: is there a directed path from the anchor's flowline to the target's. Verified by mutation - reintroducing the 2026-09-16 direction bug (traceDirection derived from the relationship name) still fails the check, and a half-applied reorder that moves the text but leaves the aggregate seeding from the anchor fails the new one. --- scripts/check-query-joins.mts | 68 ++++++++++++++++++++++------ scripts/check-trace-direction.mts | 59 ++++++++++++++++++++---- src/engine/templates/fusedQueries.ts | 65 ++++++++++++++++++++------ 3 files changed, 156 insertions(+), 36 deletions(-) diff --git a/scripts/check-query-joins.mts b/scripts/check-query-joins.mts index 59af898..d491807 100644 --- a/scripts/check-query-joins.mts +++ b/scripts/check-query-joins.mts @@ -49,6 +49,15 @@ function leadsWith(query: string): 'anchor' | 'target' | 'other' { return 'other'; } +// Which end the distance-bounded aggregate walks outward from, read off the +// innermost sub-SELECT that boundedTrace wraps its seed in. Unbounded queries +// have no such block and report 'none'. +function seedsFrom(query: string): 'anchor' | 'target' | 'none' { + if (query.includes('SELECT DISTINCT ?upstream_flowline WHERE {')) return 'anchor'; + if (query.includes('SELECT DISTINCT ?ds_flowline WHERE {')) return 'target'; + return 'none'; +} + const filtersFor = (type: EntityType): Partial => { switch (type) { case 'samples': @@ -112,21 +121,52 @@ for (const targetType of ENTITY_TYPES) { } } -// Distance-bounded traces embed the seed a second time inside boundedTrace and -// were never measured reordered, so they keep the anchor-first order. +// Distance-bounded traces follow the same rule, and lean on it harder: the +// bounded block embeds its seed inside an aggregate that sums path lengths, so +// seeding the wide-open side sums them across the national flowline graph. +// Every bounded shape whose constrained side was the target failed before the +// reorder covered them — 30s query-planning timeouts and 4.3 GB allocation +// failures, recorded in docs/query-matrix/2026-09-20-raw-002e529.csv. +// +// Both halves are checked. A query can read target-first while the aggregate +// inside still starts from the anchor, which would move the text and leave the +// cost exactly where it was. for (const targetType of ENTITY_TYPES) { - const bounded = buildFusedHydrologyQuery({ - anchor: { type: 'facilities' }, - target: { type: targetType, ...filtersFor(targetType) }, - targetRegion: ['23005'], - project: 'target', - direction: 'downstream', - maxDistanceKm: 50, - }); - check( - leadsWith(bounded) === 'anchor', - `${targetType} <- facilities, bounded: distance-bounded traces keep the anchor-first order`, - ); + for (const maxDistanceKm of [30, 50]) { + const targetScoped = buildFusedHydrologyQuery({ + anchor: { type: 'facilities' }, + target: { type: targetType, ...filtersFor(targetType) }, + targetRegion: ['23005'], + project: 'target', + direction: 'downstream', + maxDistanceKm, + }); + check( + leadsWith(targetScoped) === 'target', + `${targetType} <- facilities, bounded ${maxDistanceKm}km: target is the only constrained side, so it must lead the body`, + ); + check( + seedsFrom(targetScoped) === 'target', + `${targetType} <- facilities, bounded ${maxDistanceKm}km: the bounded aggregate must seed from the target too`, + ); + + const anchorScoped = buildFusedHydrologyQuery({ + anchor: { type: 'facilities', ...filtersFor('facilities') }, + target: { type: targetType }, + anchorRegion: ['23005'], + project: 'target', + direction: 'downstream', + maxDistanceKm, + }); + check( + leadsWith(anchorScoped) === 'anchor', + `${targetType} <- facilities, bounded ${maxDistanceKm}km: anchor is the constrained side, so the body must keep the anchor-first order`, + ); + check( + seedsFrom(anchorScoped) === 'anchor', + `${targetType} <- facilities, bounded ${maxDistanceKm}km: the bounded aggregate must seed from the anchor`, + ); + } } // --- 2. Observation joins, driven by the filters that are actually set. diff --git a/scripts/check-trace-direction.mts b/scripts/check-trace-direction.mts index f021bbc..d92a92d 100644 --- a/scripts/check-trace-direction.mts +++ b/scripts/check-trace-direction.mts @@ -42,10 +42,39 @@ const FORWARD = [ ]; const REVERSED = [ '?ds_flowline hyf:downstreamFlowPathTC ?upstream_flowline', - '?_flEnd hyf:downstreamFlowPathTC ?_flMid', '?flowline hyf:downstreamFlowPathTC ?downstream_flowline', ]; +// `?_flEnd hyf:downstreamFlowPathTC ?_flMid` used to sit in REVERSED. It cannot +// any more: a bounded block seeded from the target writes that exact triple +// while tracing perfectly correctly, because it walks outward from the target +// instead of from the anchor. One string is now correct or reversed depending +// on which side seeds, so the queries that name both ends are checked by +// reachability instead, which is what the string was standing in for. +// +// Both predicates carry direction, and `?a ?b` always means a flows into +// b: hyf:downstreamFlowPathTC is the closure, hyf:downstreamFlowPath? is one +// segment. Subject-first triples only, which is every trace in the discovery +// and well queries; the flowline layer writes one of its closures in a +// predicate-object list and keeps the string check above. +const FLOW_EDGE = /(\?\w+)\s+hyf:downstreamFlowPath(?:TC)?\??\s+(\?\w+)/g; + +function flowsInto(sparql: string, from: string, to: string): boolean { + const edges = new Map>(); + for (const [, a, b] of sparql.matchAll(FLOW_EDGE)) { + if (!edges.has(a)) edges.set(a, new Set()); + edges.get(a)!.add(b); + } + const seen = new Set([from]); + const queue = [from]; + while (queue.length) { + const v = queue.shift()!; + if (v === to) return true; + for (const n of edges.get(v) ?? []) if (!seen.has(n)) { seen.add(n); queue.push(n); } + } + return false; +} + const context = (): PipelineContext => ({ question: {} as AnalysisQuestion, // The flowline step traces from the anchors discovery resolved; give it two @@ -76,18 +105,30 @@ for (const a of ENTITY_TYPES) { if (!sparql.includes('downstreamFlowPathTC')) continue; traced++; - for (const pattern of REVERSED) { + if (sparql.includes('?upstream_flowline') && sparql.includes('?ds_flowline')) { + // The anchor's flowline has to reach the target's, whichever end + // the bounded block seeds from. This is the property the whole + // direction rule exists to protect: pairing anchor=blockA with + // direction='upstream' reverses the chain and fails here. + assert.ok( + flowsInto(sparql, '?upstream_flowline', '?ds_flowline'), + `${step.type} has no directed path from the anchor's flowline to the target's: ${where}`, + ); + checks++; + } else { + for (const pattern of REVERSED) { + assert.ok( + !sparql.includes(pattern), + `${step.type} traces upstream from the seed ("${pattern}"): ${where}`, + ); + checks++; + } assert.ok( - !sparql.includes(pattern), - `${step.type} traces upstream from the seed ("${pattern}"): ${where}`, + FORWARD.some((pattern) => sparql.includes(pattern)), + `${step.type} has no recognisable trace pattern: ${where}`, ); checks++; } - assert.ok( - FORWARD.some((pattern) => sparql.includes(pattern)), - `${step.type} has no recognisable trace pattern: ${where}`, - ); - checks++; } // A hydrology question that traced nowhere would pass the loop above diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 49db8c2..481b853 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -276,33 +276,61 @@ function fringePath(direction: 'downstream' | 'upstream', endVar: string, outVar // the cutoff, matching GROUP BY (seed, end) with no MIN. The per-flowline // number shown in popups is computed separately in buildFusedFlowlineQuery / // buildStreamsByIri, where MIN() picks the shortest qualifying path. +// `seedSide` decides which end the aggregate starts from, and it is a +// correctness-neutral, cost-critical choice: the block walks outward from its +// seed, so seeding the *unconstrained* side means summing path lengths over +// every flowline the graph has. "Facilities upstream from samples in York" with +// block A left wide open seeds 1,506,326 facilities and the engine gives up +// planning the query at 30s; seeded from the 132 samples the same question +// answers in 20s. Measured identical result sets where both forms run, and the +// bounded answer is a strict subset of the unbounded one (docs/QUERY-MATRIX.md +// MD, docs/DEBUGGING.md 2026-09-20). +// +// The "+1" fringe always extends *away* from the seed, so which physical end +// gets the extra segment follows the seed side. That is the same rule as +// before, not a new one: flipping the seed flips the fringe with it. function boundedTrace( seed: string, direction: 'downstream' | 'upstream', maxDistanceKm: number, + seedSide: 'anchor' | 'target' = 'anchor', ): string { + // Which variable the seed binds, and which one the trace has to reach. + const seedVar = seedSide === 'anchor' ? '?upstream_flowline' : '?ds_flowline'; + const farVar = seedSide === 'anchor' ? '?ds_flowline' : '?upstream_flowline'; + // Walking away from the seed. For an anchor seed that is the direction of the + // question; for a target seed it is the reverse, since the target sits at the + // far end of the same trace. + const walk = seedSide === 'anchor' ? direction : direction === 'downstream' ? 'upstream' : 'downstream'; + // Both forms write the seed-adjacent triple first and differ only in which + // way the chain runs. The anchor form's text is unchanged from before this + // parameter existed, so every query that kept the anchor-first order is + // byte-identical. const trace = - direction === 'downstream' - ? `?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . + walk === 'downstream' + ? `${seedVar} hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd .` - : `?_flEnd hyf:downstreamFlowPathTC ?_flMid . - ?_flMid hyf:downstreamFlowPathTC ?upstream_flowline .`; + : seedSide === 'anchor' + ? `?_flEnd hyf:downstreamFlowPathTC ?_flMid . + ?_flMid hyf:downstreamFlowPathTC ${seedVar} .` + : `?_flMid hyf:downstreamFlowPathTC ${seedVar} . + ?_flEnd hyf:downstreamFlowPathTC ?_flMid .`; return `{ SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { - SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { + SELECT ${seedVar} ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { - SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { - { SELECT DISTINCT ?upstream_flowline WHERE { ${seed} } } + SELECT ${seedVar} ?_flMid ?_flEnd WHERE { + { SELECT DISTINCT ${seedVar} WHERE { ${seed} } } ${trace} } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . - } GROUP BY ?upstream_flowline ?_flEnd + } GROUP BY ${seedVar} ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(${maxDistanceKm})) - ${fringePath(direction, '?_flEnd', '?ds_flowline')} + ${fringePath(walk, '?_flEnd', farVar)} } }`; } @@ -374,9 +402,13 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { // the target first. Measured across all 72 hydrology shape/config pairs: 5 // rescued, 0 regressions, 0 rows lost (docs/plans/…-fused-seed-side-….md). // - // Bounded traces keep the anchor-first order: boundedTrace embeds `seed` a - // second time and that shape has not been measured either way. - if (!opts.maxDistanceKm && sideIsConstrained(opts, 'target') && !sideIsConstrained(opts, 'anchor')) { + // A bounded trace is reordered the same way, and needs it more: boundedTrace + // embeds its seed a second time inside an aggregate, so seeding the wide-open + // side sums path lengths across the national flowline graph. Every bounded + // shape whose constrained side was the target failed before this (MD in + // docs/query-matrix): timeouts in query planning, or 4.3 GB allocation + // failures. Reordered, the same three shapes answer in seconds. + if (sideIsConstrained(opts, 'target') && !sideIsConstrained(opts, 'anchor')) { // The target's own entity and filters come first, then the hop onto the // river network. A streams target *is* the flowline, so it needs no hop. const targetHead = @@ -388,11 +420,18 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { ${targetBind} ?s2target spatial:connectedTo ?ds_flowline .`; + // The bounded block is rebuilt around the target seed. `trace` above is + // seeded from the anchor, which is the right choice only for the + // anchor-first order below. + const targetTrace = opts.maxDistanceKm + ? boundedTrace(targetHead, opts.mode, opts.maxDistanceKm, 'target') + : trace; + // spatial:connectedTo is stored both ways between cells and flowlines // (1,391,903 pairs each direction, verified on federation), so reading it // off the flowline here matches the same pairs as ?s2neighbor → flowline. return `${targetPin}${targetHead} - ${trace} + ${targetTrace} ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . From 4454b80eeb7fe290442654d002e11ad1d3ac7a7b Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 00:30:48 -0400 Subject: [PATCH 61/66] test(engine): golden-file snapshot of the SPARQL every shape generates The script existed since 2026-09-17 but was never committed, so package.json on feat/demo-questions-prewarmed registered `check-query-snapshots` against a file nobody else had and that branch's CI never ran it. Committing it here, with the grid extended to cover what this week showed it was blind to. Why it earns a place next to the six rule-checks: those assert properties of a query, so they see a shape only if someone thought to assert something about it. This one notices when a change moves a shape nobody was thinking about, which is the failure mode of a builder shared by every relationship. Three of the bugs fixed this week were invisible in behaviour and obvious in the emitted SPARQL. The grid gains two axes, both of which hid something real: Region placement. It put the region on block A always. For a downstream question that makes the target the constrained side, so the target-first join order was recorded; for an upstream question it makes the anchor constrained, so that path never was, and neither was the question behind #55 and #57 - block A wide open, block C scoped to a county. The flow-distance bound. A bounded trace is a different query rather than a filtered one: it seeds an aggregate. The grid had two bounded shapes, both with the region on block A. Measured on the fix in ec221d9: the old grid reports one moved shape, `VARIANT: downstream maxDistanceKm=10`. The new one reports 74, and buckets them as bounded 72, region on A 36, region on C 36. 6 x 6 x 3 x 2 unbounded, 6 x 6 x 2 x 2 bounded, plus 15 variants for hop counts, per-type filter blocks and the two questions that have actually broken in the app. 375 shapes. Two things keep the file readable rather than enormous. The PREFIX preamble is byte-identical in every query and was 66% of it, so it is stripped and recorded once; a change to the prefix list still moves exactly one entry. And query bodies are written once each in a table at the end and referenced by hash: 375 shapes reference 2,078 step queries but only 603 distinct ones, the region-boundary query alone being identical in 373 of them. Together those take the snapshot from 1.7MB to 688KB and turn a one-line change to a shared query from 373 lines of diff into one. Known limit, worth stating rather than discovering later: it drives everything through planPipeline, so it covers shapes a user can ask for and is blind to builder arguments the planner never produces. A reordering of the anchor-seeded `upstream` branch of boundedTrace passes all seven checks, because the planner always passes 'downstream'. The guarantee is "no reachable shape moved unintentionally", not "no emitted SPARQL moved". --- .github/workflows/checks.yml | 6 + package.json | 1 + scripts/__snapshots__/query-shapes.txt | 3061 ++++++++++++++++++++++++ scripts/check-query-snapshots.mts | 333 +++ 4 files changed, 3401 insertions(+) create mode 100644 scripts/__snapshots__/query-shapes.txt create mode 100644 scripts/check-query-snapshots.mts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c7c38c8..4f21a5a 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -57,6 +57,12 @@ jobs: - name: Query join order and observation joins run: npm run check-query-joins + # Golden-file diff of the SPARQL every shape generates. The one above + # asserts a rule; this one notices when a change moves a shape nobody was + # thinking about, which is the failure mode of a shared query builder. + - name: Query snapshots + run: npm run check-query-snapshots + # Not blocking yet: `npm run lint` reports 15 pre-existing errors, all in # components and none related to the engine. Make this a required step in # the same change that clears them, not before, or the signal is noise diff --git a/package.json b/package.json index 80ec5ce..69af60f 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "check-flowline-scope": "tsx scripts/check-flowline-scope.mts", "check-substance-labels": "tsx scripts/check-substance-labels.mts", "check-query-joins": "tsx scripts/check-query-joins.mts", + "check-query-snapshots": "tsx scripts/check-query-snapshots.mts", "query-matrix": "tsx scripts/query-matrix.mts", "health-check": "tsx scripts/health-check.mts" }, diff --git a/scripts/__snapshots__/query-shapes.txt b/scripts/__snapshots__/query-shapes.txt new file mode 100644 index 0000000..731b554 --- /dev/null +++ b/scripts/__snapshots__/query-shapes.txt @@ -0,0 +1,3061 @@ +# Generated by scripts/check-query-snapshots.mts -- do not hand-edit. +# Re-record with: npm run check-query-snapshots -- --update + +## PREFIXES +SHARED [all] ae03777b4388 + PREFIX rdf: PREFIX rdfs: PREFIX owl: PREFIX xsd: PREFIX skos: PREFIX geo: PREFIX spatial: PREFIX kwg-ont: PREFIX kwgr: PREFIX hyf: PREFIX hyfo: PREFIX coso: PREFIX fio: PREFIX naics: PREFIX qudt: PREFIX comptox: PREFIX me_egad: PREFIX nhdplusv2: PREFIX il_isgs: PREFIX me_mgs: PREFIX gwml2: PREFIX saw_water: PREFIX schema: PREFIX sosa: PREFIX dcterms: +## samples near samples [ME on A] +FIND_TARGET_IRIS [federation] 0be21b7acfd7 +FIND_ANCHOR_IRIS [federation] 672355872582 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near samples [ME on C] +FIND_TARGET_IRIS [federation] bea7dc72f773 +FIND_ANCHOR_IRIS [federation] f80f83193d16 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream samples [ME on A] +FIND_TARGET_IRIS [federation] 886826560be6 +FIND_ANCHOR_IRIS [federation] 25e35a116a7a +GET_FLOWLINE_GEOMETRIES [federation] 9e253e2c142d +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream samples [ME on C] +FIND_TARGET_IRIS [federation] c06847a4af0d +FIND_ANCHOR_IRIS [federation] 5f95683d03c3 +GET_FLOWLINE_GEOMETRIES [federation] 9e253e2c142d +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream samples [ME on A] +FIND_TARGET_IRIS [federation] c06847a4af0d +FIND_ANCHOR_IRIS [federation] 5f95683d03c3 +GET_FLOWLINE_GEOMETRIES [federation] 9e253e2c142d +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream samples [ME on C] +FIND_TARGET_IRIS [federation] 886826560be6 +FIND_ANCHOR_IRIS [federation] 25e35a116a7a +GET_FLOWLINE_GEOMETRIES [federation] 9e253e2c142d +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near facilities [ME on A] +FIND_TARGET_IRIS [federation] 2ece82229dce +FIND_ANCHOR_IRIS [federation] f0c206010b68 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near facilities [ME on C] +FIND_TARGET_IRIS [federation] 5abc07c304ad +FIND_ANCHOR_IRIS [federation] 1506d58ef072 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 714064e8e781 +FIND_ANCHOR_IRIS [federation] 6b0632214d35 +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] e68708fa1d30 +FIND_ANCHOR_IRIS [federation] 1b7a89412729 +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 2a2add9e3c26 +FIND_ANCHOR_IRIS [federation] 7aa05f4cf432 +GET_FLOWLINE_GEOMETRIES [federation] 889f03c020e8 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] faa0a03241cd +FIND_ANCHOR_IRIS [federation] a4e3147c72d7 +GET_FLOWLINE_GEOMETRIES [federation] 889f03c020e8 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 9c73285f224c +FIND_ANCHOR_IRIS [federation] 713a1f7f8ae5 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 73511fbb8c8f +FIND_ANCHOR_IRIS [federation] aec41960948e +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 8e23014aa73f +FIND_ANCHOR_IRIS [federation] d01ac74e4cc0 +GET_FLOWLINE_GEOMETRIES [federation] d7ee9691da5b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 790b26da2a79 +FIND_ANCHOR_IRIS [federation] 832afed999c2 +GET_FLOWLINE_GEOMETRIES [federation] d7ee9691da5b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 151ef1e41632 +FIND_ANCHOR_IRIS [federation] 0cb147205839 +GET_FLOWLINE_GEOMETRIES [federation] 60802b6a7386 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 25554a2d770e +FIND_ANCHOR_IRIS [federation] 70ac417804f8 +GET_FLOWLINE_GEOMETRIES [federation] 60802b6a7386 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near wells [ME on A] +FIND_TARGET_IRIS [federation] b0f01594fdb4 +FIND_ANCHOR_IRIS [federation] ab4e12addc23 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] b948c1dadad5 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near wells [ME on C] +FIND_TARGET_IRIS [federation] 2f7c9d07ed1a +FIND_ANCHOR_IRIS [federation] d271f8200100 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 8db700fbc3ba +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream wells [ME on A] +FIND_TARGET_IRIS [federation] b2a9610b7c52 +FIND_ANCHOR_IRIS [federation] 94d434376702 +GET_FLOWLINE_GEOMETRIES [federation] b6f61e4f4ff3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 081ffe103105 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream wells [ME on C] +FIND_TARGET_IRIS [federation] e6eca666d07e +FIND_ANCHOR_IRIS [federation] b44db2e80018 +GET_FLOWLINE_GEOMETRIES [federation] b6f61e4f4ff3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 631a69b1a6a7 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream wells [ME on A] +FIND_TARGET_IRIS [federation] e6e5f175099a +FIND_ANCHOR_IRIS [federation] 114ec252bd7e +GET_FLOWLINE_GEOMETRIES [federation] 6c90238c34b5 +HYDRATE_TARGET_BY_IRI [federation] 35e5e0379327 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream wells [ME on C] +FIND_TARGET_IRIS [federation] 01ac5b24c08f +FIND_ANCHOR_IRIS [federation] 542cd3bf0080 +GET_FLOWLINE_GEOMETRIES [federation] 6c90238c34b5 +HYDRATE_TARGET_BY_IRI [federation] 6e6e6eba070d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near aquifers [ME on A] +FIND_TARGET_IRIS [federation] 26597fe15d0e +FIND_ANCHOR_IRIS [federation] 192ca0747233 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near aquifers [ME on C] +FIND_TARGET_IRIS [federation] 581c48ae304e +FIND_ANCHOR_IRIS [federation] 454a12d54a4b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 3735b227534b +FIND_ANCHOR_IRIS [federation] d1b9348ef98d +GET_FLOWLINE_GEOMETRIES [federation] 0d7cd31e6182 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] c8b9648ad9ad +FIND_ANCHOR_IRIS [federation] 6b13c5e7d199 +GET_FLOWLINE_GEOMETRIES [federation] 0d7cd31e6182 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] cd1d79f23ba8 +FIND_ANCHOR_IRIS [federation] 907b64185777 +GET_FLOWLINE_GEOMETRIES [federation] ebbacce57f0e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 54b1d508458d +FIND_ANCHOR_IRIS [federation] 7530ba837a17 +GET_FLOWLINE_GEOMETRIES [federation] ebbacce57f0e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near streams [ME on A] +FIND_TARGET_IRIS [federation] d2b20fc4e76d +FIND_ANCHOR_IRIS [federation] 42fba0d6b6e4 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples near streams [ME on C] +FIND_TARGET_IRIS [federation] 950c0e678218 +FIND_ANCHOR_IRIS [federation] 0c695b9c750b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream streams [ME on A] +FIND_TARGET_IRIS [federation] 962a202132fc +FIND_ANCHOR_IRIS [federation] 62aa5619bc67 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream streams [ME on C] +FIND_TARGET_IRIS [federation] e8b95c8c5b5d +FIND_ANCHOR_IRIS [federation] 0d9fd4f4b10a +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream streams [ME on A] +FIND_TARGET_IRIS [federation] b22e14df0511 +FIND_ANCHOR_IRIS [federation] 7dad41fdfd60 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream streams [ME on C] +FIND_TARGET_IRIS [federation] 3bcbbc61caae +FIND_ANCHOR_IRIS [federation] a62588d4bcb9 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near samples [ME on A] +FIND_TARGET_IRIS [federation] 0bb0f6a91db9 +FIND_ANCHOR_IRIS [federation] dd8ee4b54845 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near samples [ME on C] +FIND_TARGET_IRIS [federation] 4ae27f7b3056 +FIND_ANCHOR_IRIS [federation] 08ee3e23c632 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream samples [ME on A] +FIND_TARGET_IRIS [federation] faa0a03241cd +FIND_ANCHOR_IRIS [federation] a4e3147c72d7 +GET_FLOWLINE_GEOMETRIES [federation] 889f03c020e8 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream samples [ME on C] +FIND_TARGET_IRIS [federation] 2a2add9e3c26 +FIND_ANCHOR_IRIS [federation] 7aa05f4cf432 +GET_FLOWLINE_GEOMETRIES [federation] 889f03c020e8 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream samples [ME on A] +FIND_TARGET_IRIS [federation] e68708fa1d30 +FIND_ANCHOR_IRIS [federation] 1b7a89412729 +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream samples [ME on C] +FIND_TARGET_IRIS [federation] 714064e8e781 +FIND_ANCHOR_IRIS [federation] 6b0632214d35 +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near facilities [ME on A] +FIND_TARGET_IRIS [federation] a7b4475fa918 +FIND_ANCHOR_IRIS [federation] c449e2e870bf +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near facilities [ME on C] +FIND_TARGET_IRIS [federation] 2b48a40c896d +FIND_ANCHOR_IRIS [federation] 9039e57855e1 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] b43c08af1964 +FIND_ANCHOR_IRIS [federation] 8a0c2df70ce0 +GET_FLOWLINE_GEOMETRIES [federation] 81641e7d1349 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] b0335b863895 +FIND_ANCHOR_IRIS [federation] 4786e399d0e3 +GET_FLOWLINE_GEOMETRIES [federation] 81641e7d1349 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] b0335b863895 +FIND_ANCHOR_IRIS [federation] 4786e399d0e3 +GET_FLOWLINE_GEOMETRIES [federation] 81641e7d1349 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] b43c08af1964 +FIND_ANCHOR_IRIS [federation] 8a0c2df70ce0 +GET_FLOWLINE_GEOMETRIES [federation] 81641e7d1349 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] dc18ede4eeac +FIND_ANCHOR_IRIS [federation] f2ec010e4080 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 5393441889bb +FIND_ANCHOR_IRIS [federation] 887006d733eb +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 6ddb9c48525a +FIND_ANCHOR_IRIS [federation] f7a2dba8957d +GET_FLOWLINE_GEOMETRIES [federation] cfe6f604cde9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 32f1aa55d0ea +FIND_ANCHOR_IRIS [federation] 294457930c79 +GET_FLOWLINE_GEOMETRIES [federation] cfe6f604cde9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 1084c720a6cc +FIND_ANCHOR_IRIS [federation] 642252450459 +GET_FLOWLINE_GEOMETRIES [federation] 4feabc0eeaca +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] fbcba6bb42a9 +FIND_ANCHOR_IRIS [federation] ea51a457af43 +GET_FLOWLINE_GEOMETRIES [federation] 4feabc0eeaca +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near wells [ME on A] +FIND_TARGET_IRIS [federation] 1bce75dee487 +FIND_ANCHOR_IRIS [federation] 659f6c7fa3f9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 9575a458430b +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near wells [ME on C] +FIND_TARGET_IRIS [federation] c668a2061d6c +FIND_ANCHOR_IRIS [federation] 4cd25d8b0a3e +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] be1b15d1b106 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream wells [ME on A] +FIND_TARGET_IRIS [federation] 50afef424c69 +FIND_ANCHOR_IRIS [federation] cbb05158da0c +GET_FLOWLINE_GEOMETRIES [federation] f015bfcba03e +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 3bce92acebce +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream wells [ME on C] +FIND_TARGET_IRIS [federation] 59b91de5e995 +FIND_ANCHOR_IRIS [federation] 9968e7786c81 +GET_FLOWLINE_GEOMETRIES [federation] f015bfcba03e +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 1084e9f48e96 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream wells [ME on A] +FIND_TARGET_IRIS [federation] f878bab0aeba +FIND_ANCHOR_IRIS [federation] 98d7c72d4aab +GET_FLOWLINE_GEOMETRIES [federation] 62f130505471 +HYDRATE_TARGET_BY_IRI [federation] e45a36c23efe +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream wells [ME on C] +FIND_TARGET_IRIS [federation] 141d81ecb9ec +FIND_ANCHOR_IRIS [federation] 20f966337069 +GET_FLOWLINE_GEOMETRIES [federation] 62f130505471 +HYDRATE_TARGET_BY_IRI [federation] e238ca8606c2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near aquifers [ME on A] +FIND_TARGET_IRIS [federation] cf073b1ce3f0 +FIND_ANCHOR_IRIS [federation] e9b13461268b +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near aquifers [ME on C] +FIND_TARGET_IRIS [federation] 40c7bc3ecc04 +FIND_ANCHOR_IRIS [federation] a99936a88d0b +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 1a0e0369b410 +FIND_ANCHOR_IRIS [federation] 32747a1b563b +GET_FLOWLINE_GEOMETRIES [federation] 5515bd777411 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 2fdb9d27c845 +FIND_ANCHOR_IRIS [federation] b6983d91a529 +GET_FLOWLINE_GEOMETRIES [federation] 5515bd777411 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 35eea760e846 +FIND_ANCHOR_IRIS [federation] 021c99bd21fe +GET_FLOWLINE_GEOMETRIES [federation] 23e64482073d +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 4ca2878d179f +FIND_ANCHOR_IRIS [federation] 21aab4d7bdf7 +GET_FLOWLINE_GEOMETRIES [federation] 23e64482073d +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near streams [ME on A] +FIND_TARGET_IRIS [federation] 25764463de3a +FIND_ANCHOR_IRIS [federation] 5005fd5c331c +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities near streams [ME on C] +FIND_TARGET_IRIS [federation] 935860c79d56 +FIND_ANCHOR_IRIS [federation] 84faebbbe4de +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream streams [ME on A] +FIND_TARGET_IRIS [federation] 88a05eee9640 +FIND_ANCHOR_IRIS [federation] eedde23983a6 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream streams [ME on C] +FIND_TARGET_IRIS [federation] f8ce75f3f7ee +FIND_ANCHOR_IRIS [federation] a7e872d51a0f +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream streams [ME on A] +FIND_TARGET_IRIS [federation] 81325b745fd1 +FIND_ANCHOR_IRIS [federation] 404c3355f3fd +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream streams [ME on C] +FIND_TARGET_IRIS [federation] ba8393ad2e9d +FIND_ANCHOR_IRIS [federation] d2cd8e8cafdf +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near samples [ME on A] +FIND_TARGET_IRIS [federation] 3c4091f51398 +FIND_ANCHOR_IRIS [federation] cf808bb25a1f +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near samples [ME on C] +FIND_TARGET_IRIS [federation] 0d49e383659d +FIND_ANCHOR_IRIS [federation] a735c3a3bff6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream samples [ME on A] +FIND_TARGET_IRIS [federation] 25554a2d770e +FIND_ANCHOR_IRIS [federation] 70ac417804f8 +GET_FLOWLINE_GEOMETRIES [federation] 60802b6a7386 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream samples [ME on C] +FIND_TARGET_IRIS [federation] 151ef1e41632 +FIND_ANCHOR_IRIS [federation] 0cb147205839 +GET_FLOWLINE_GEOMETRIES [federation] 60802b6a7386 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream samples [ME on A] +FIND_TARGET_IRIS [federation] 790b26da2a79 +FIND_ANCHOR_IRIS [federation] 832afed999c2 +GET_FLOWLINE_GEOMETRIES [federation] d7ee9691da5b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream samples [ME on C] +FIND_TARGET_IRIS [federation] 8e23014aa73f +FIND_ANCHOR_IRIS [federation] d01ac74e4cc0 +GET_FLOWLINE_GEOMETRIES [federation] d7ee9691da5b +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near facilities [ME on A] +FIND_TARGET_IRIS [federation] 6203bb98fd9b +FIND_ANCHOR_IRIS [federation] 09c1cecf0048 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near facilities [ME on C] +FIND_TARGET_IRIS [federation] 8abd2faf7bb0 +FIND_ANCHOR_IRIS [federation] 8e369b7deccc +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] fbcba6bb42a9 +FIND_ANCHOR_IRIS [federation] ea51a457af43 +GET_FLOWLINE_GEOMETRIES [federation] 4feabc0eeaca +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 1084c720a6cc +FIND_ANCHOR_IRIS [federation] 642252450459 +GET_FLOWLINE_GEOMETRIES [federation] 4feabc0eeaca +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 32f1aa55d0ea +FIND_ANCHOR_IRIS [federation] 294457930c79 +GET_FLOWLINE_GEOMETRIES [federation] cfe6f604cde9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 6ddb9c48525a +FIND_ANCHOR_IRIS [federation] f7a2dba8957d +GET_FLOWLINE_GEOMETRIES [federation] cfe6f604cde9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 78dcb9fb3928 +FIND_ANCHOR_IRIS [federation] 409740b46fb7 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 09e5950369e5 +FIND_ANCHOR_IRIS [federation] 73934d7aae0d +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 0a29f890a209 +FIND_ANCHOR_IRIS [federation] 3a19b33e3025 +GET_FLOWLINE_GEOMETRIES [federation] c8295f7305c1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 6ff4852b422e +FIND_ANCHOR_IRIS [federation] b2a4e26f4048 +GET_FLOWLINE_GEOMETRIES [federation] c8295f7305c1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 6ff4852b422e +FIND_ANCHOR_IRIS [federation] b2a4e26f4048 +GET_FLOWLINE_GEOMETRIES [federation] c8295f7305c1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 0a29f890a209 +FIND_ANCHOR_IRIS [federation] 3a19b33e3025 +GET_FLOWLINE_GEOMETRIES [federation] c8295f7305c1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near wells [ME on A] +FIND_TARGET_IRIS [federation] 934d8ac6f612 +FIND_ANCHOR_IRIS [federation] f58221d89287 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 6cab754cbe12 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near wells [ME on C] +FIND_TARGET_IRIS [federation] 5ab06945d883 +FIND_ANCHOR_IRIS [federation] 80df1fdbcf14 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 90d0a0452943 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream wells [ME on A] +FIND_TARGET_IRIS [federation] 41ca24011057 +FIND_ANCHOR_IRIS [federation] 66b8cb8fd320 +GET_FLOWLINE_GEOMETRIES [federation] 7b5980388f2c +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ff746e2b17d8 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream wells [ME on C] +FIND_TARGET_IRIS [federation] 6f09d7bbdcc7 +FIND_ANCHOR_IRIS [federation] 1efed1c496e5 +GET_FLOWLINE_GEOMETRIES [federation] 7b5980388f2c +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ce0c65a4578d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream wells [ME on A] +FIND_TARGET_IRIS [federation] 8c6ab3d31bf7 +FIND_ANCHOR_IRIS [federation] 9813a80e0c5a +GET_FLOWLINE_GEOMETRIES [federation] 663f948f7bf0 +HYDRATE_TARGET_BY_IRI [federation] 9f5c1bba715e +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream wells [ME on C] +FIND_TARGET_IRIS [federation] b679bd47f6b1 +FIND_ANCHOR_IRIS [federation] e7e2854c8ae7 +GET_FLOWLINE_GEOMETRIES [federation] 663f948f7bf0 +HYDRATE_TARGET_BY_IRI [federation] 31d0f4e2be6f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near aquifers [ME on A] +FIND_TARGET_IRIS [federation] 223115ac5eb1 +FIND_ANCHOR_IRIS [federation] c547f4e0656f +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near aquifers [ME on C] +FIND_TARGET_IRIS [federation] d913d9d71840 +FIND_ANCHOR_IRIS [federation] 50885dc7a1b9 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 99dd9196dcc8 +FIND_ANCHOR_IRIS [federation] 1beadb689ecd +GET_FLOWLINE_GEOMETRIES [federation] a28356585b79 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 2ecade927c68 +FIND_ANCHOR_IRIS [federation] 48a5326856de +GET_FLOWLINE_GEOMETRIES [federation] a28356585b79 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] ba778257a97f +FIND_ANCHOR_IRIS [federation] 5c6cc33fae88 +GET_FLOWLINE_GEOMETRIES [federation] 137df84ed6d2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 4b6cc3a024ee +FIND_ANCHOR_IRIS [federation] 208b7a3a6317 +GET_FLOWLINE_GEOMETRIES [federation] 137df84ed6d2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near streams [ME on A] +FIND_TARGET_IRIS [federation] ebbb13c13f83 +FIND_ANCHOR_IRIS [federation] e466cf40dd85 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies near streams [ME on C] +FIND_TARGET_IRIS [federation] 2372d3380521 +FIND_ANCHOR_IRIS [federation] 14e83b4e30cd +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream streams [ME on A] +FIND_TARGET_IRIS [federation] d98072521790 +FIND_ANCHOR_IRIS [federation] bba7273cdba4 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream streams [ME on C] +FIND_TARGET_IRIS [federation] 94b023ca04bf +FIND_ANCHOR_IRIS [federation] 39f68d9178a5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream streams [ME on A] +FIND_TARGET_IRIS [federation] 3a5de06aa701 +FIND_ANCHOR_IRIS [federation] 1890d6fd07a7 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream streams [ME on C] +FIND_TARGET_IRIS [federation] eeb6a4be8d87 +FIND_ANCHOR_IRIS [federation] 2bc13625bc04 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near samples [ME on A] +FIND_TARGET_IRIS [federation] 0bf72e236353 +FIND_ANCHOR_IRIS [federation] 6cc73e470a1e +HYDRATE_TARGET_BY_IRI [federation] f2161e75506a +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near samples [ME on C] +FIND_TARGET_IRIS [federation] f8a37eb37178 +FIND_ANCHOR_IRIS [federation] ef35db5ca18b +HYDRATE_TARGET_BY_IRI [federation] 8dfa184e0d2b +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream samples [ME on A] +FIND_TARGET_IRIS [federation] 01ac5b24c08f +FIND_ANCHOR_IRIS [federation] 542cd3bf0080 +GET_FLOWLINE_GEOMETRIES [federation] 6c90238c34b5 +HYDRATE_TARGET_BY_IRI [federation] 6e6e6eba070d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream samples [ME on C] +FIND_TARGET_IRIS [federation] e6e5f175099a +FIND_ANCHOR_IRIS [federation] 114ec252bd7e +GET_FLOWLINE_GEOMETRIES [federation] 6c90238c34b5 +HYDRATE_TARGET_BY_IRI [federation] 35e5e0379327 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream samples [ME on A] +FIND_TARGET_IRIS [federation] e6eca666d07e +FIND_ANCHOR_IRIS [federation] b44db2e80018 +GET_FLOWLINE_GEOMETRIES [federation] b6f61e4f4ff3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 631a69b1a6a7 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream samples [ME on C] +FIND_TARGET_IRIS [federation] b2a9610b7c52 +FIND_ANCHOR_IRIS [federation] 94d434376702 +GET_FLOWLINE_GEOMETRIES [federation] b6f61e4f4ff3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 081ffe103105 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near facilities [ME on A] +FIND_TARGET_IRIS [federation] c0f56f77ba8f +FIND_ANCHOR_IRIS [federation] 153a3a7992c8 +HYDRATE_TARGET_BY_IRI [federation] 73c37175d3a3 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near facilities [ME on C] +FIND_TARGET_IRIS [federation] 6dda347a097f +FIND_ANCHOR_IRIS [federation] 78e1f8a446f0 +HYDRATE_TARGET_BY_IRI [federation] e0f406bc2dd6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 141d81ecb9ec +FIND_ANCHOR_IRIS [federation] 20f966337069 +GET_FLOWLINE_GEOMETRIES [federation] 62f130505471 +HYDRATE_TARGET_BY_IRI [federation] e238ca8606c2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] f878bab0aeba +FIND_ANCHOR_IRIS [federation] 98d7c72d4aab +GET_FLOWLINE_GEOMETRIES [federation] 62f130505471 +HYDRATE_TARGET_BY_IRI [federation] e45a36c23efe +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 59b91de5e995 +FIND_ANCHOR_IRIS [federation] 9968e7786c81 +GET_FLOWLINE_GEOMETRIES [federation] f015bfcba03e +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 1084e9f48e96 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 50afef424c69 +FIND_ANCHOR_IRIS [federation] cbb05158da0c +GET_FLOWLINE_GEOMETRIES [federation] f015bfcba03e +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 3bce92acebce +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] d58893c96966 +FIND_ANCHOR_IRIS [federation] 63fd9d8c7d26 +HYDRATE_TARGET_BY_IRI [federation] 6b18905b32f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 39419051512e +FIND_ANCHOR_IRIS [federation] 30b8f06aa807 +HYDRATE_TARGET_BY_IRI [federation] a7b1fa7dc839 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] b679bd47f6b1 +FIND_ANCHOR_IRIS [federation] e7e2854c8ae7 +GET_FLOWLINE_GEOMETRIES [federation] 663f948f7bf0 +HYDRATE_TARGET_BY_IRI [federation] 31d0f4e2be6f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 8c6ab3d31bf7 +FIND_ANCHOR_IRIS [federation] 9813a80e0c5a +GET_FLOWLINE_GEOMETRIES [federation] 663f948f7bf0 +HYDRATE_TARGET_BY_IRI [federation] 9f5c1bba715e +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 6f09d7bbdcc7 +FIND_ANCHOR_IRIS [federation] 1efed1c496e5 +GET_FLOWLINE_GEOMETRIES [federation] 7b5980388f2c +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ce0c65a4578d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 41ca24011057 +FIND_ANCHOR_IRIS [federation] 66b8cb8fd320 +GET_FLOWLINE_GEOMETRIES [federation] 7b5980388f2c +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ff746e2b17d8 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near wells [ME on A] +FIND_TARGET_IRIS [federation] 920687fc77ed +FIND_ANCHOR_IRIS [federation] 6ede512b148d +HYDRATE_TARGET_BY_IRI [federation] c498321cc486 +HYDRATE_ANCHOR_BY_IRI [federation] 05cd3b39feaf +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near wells [ME on C] +FIND_TARGET_IRIS [federation] 83d77a45d03c +FIND_ANCHOR_IRIS [federation] 187c48927d97 +HYDRATE_TARGET_BY_IRI [federation] 88b94aeb229d +HYDRATE_ANCHOR_BY_IRI [federation] c85fdb421ca6 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream wells [ME on A] +FIND_TARGET_IRIS [federation] ac87cac97a08 +FIND_ANCHOR_IRIS [federation] ee767dadbf6f +GET_FLOWLINE_GEOMETRIES [federation] 4bc79000b146 +HYDRATE_TARGET_BY_IRI [federation] c80d21e0d32d +HYDRATE_ANCHOR_BY_IRI [federation] cb961f64c07f +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream wells [ME on C] +FIND_TARGET_IRIS [federation] 968075df2792 +FIND_ANCHOR_IRIS [federation] fa96bd1b30f8 +GET_FLOWLINE_GEOMETRIES [federation] 4bc79000b146 +HYDRATE_TARGET_BY_IRI [federation] 258e1bb27b55 +HYDRATE_ANCHOR_BY_IRI [federation] 440f71464197 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream wells [ME on A] +FIND_TARGET_IRIS [federation] 968075df2792 +FIND_ANCHOR_IRIS [federation] fa96bd1b30f8 +GET_FLOWLINE_GEOMETRIES [federation] 4bc79000b146 +HYDRATE_TARGET_BY_IRI [federation] 258e1bb27b55 +HYDRATE_ANCHOR_BY_IRI [federation] 440f71464197 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream wells [ME on C] +FIND_TARGET_IRIS [federation] ac87cac97a08 +FIND_ANCHOR_IRIS [federation] ee767dadbf6f +GET_FLOWLINE_GEOMETRIES [federation] 4bc79000b146 +HYDRATE_TARGET_BY_IRI [federation] c80d21e0d32d +HYDRATE_ANCHOR_BY_IRI [federation] cb961f64c07f +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near aquifers [ME on A] +FIND_TARGET_IRIS [federation] 4cf300178a3d +FIND_ANCHOR_IRIS [federation] 17938cd745d9 +HYDRATE_TARGET_BY_IRI [federation] 8a1266fbf3b4 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near aquifers [ME on C] +FIND_TARGET_IRIS [federation] 1c5477f4a20d +FIND_ANCHOR_IRIS [federation] a1a3610cba42 +HYDRATE_TARGET_BY_IRI [federation] f1abbefd32dd +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] b6893ae200af +FIND_ANCHOR_IRIS [federation] b9d0126bda7a +GET_FLOWLINE_GEOMETRIES [federation] 79b82d9e0fe1 +HYDRATE_TARGET_BY_IRI [federation] c35d18356b27 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 26bf05053779 +FIND_ANCHOR_IRIS [federation] ddfaa9f20f19 +GET_FLOWLINE_GEOMETRIES [federation] 79b82d9e0fe1 +HYDRATE_TARGET_BY_IRI [federation] ec935451ecfb +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 22c02f8cd68b +FIND_ANCHOR_IRIS [federation] b9d52f76c5da +GET_FLOWLINE_GEOMETRIES [federation] 9a08433a48e0 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] dc4d5d46d3f1 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] c5ae9f5fc826 +FIND_ANCHOR_IRIS [federation] 4f5453f9e32d +GET_FLOWLINE_GEOMETRIES [federation] 9a08433a48e0 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ca1086992b60 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near streams [ME on A] +FIND_TARGET_IRIS [federation] 8952d69eebf7 +FIND_ANCHOR_IRIS [federation] 827004d998b2 +HYDRATE_TARGET_BY_IRI [federation] d335a3eda455 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells near streams [ME on C] +FIND_TARGET_IRIS [federation] e30770406b41 +FIND_ANCHOR_IRIS [federation] b0f1db6f8073 +HYDRATE_TARGET_BY_IRI [federation] 5e175b050654 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream streams [ME on A] +FIND_TARGET_IRIS [federation] e3bb217bc214 +FIND_ANCHOR_IRIS [federation] 032ea9425e6f +HYDRATE_TARGET_BY_IRI [federation] 32cbf641e1bc +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream streams [ME on C] +FIND_TARGET_IRIS [federation] f56b87fc7251 +FIND_ANCHOR_IRIS [federation] 67b90dec7f24 +HYDRATE_TARGET_BY_IRI [federation] 06c0038fb4ce +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream streams [ME on A] +FIND_TARGET_IRIS [federation] 8b7cd81ea5cf +FIND_ANCHOR_IRIS [federation] e5376ca0aa0a +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] bf6a1a426eb1 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream streams [ME on C] +FIND_TARGET_IRIS [federation] 1da7ac18c1ca +FIND_ANCHOR_IRIS [federation] 592bae86ed3a +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 95fe8b8c33ba +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near samples [ME on A] +FIND_TARGET_IRIS [federation] b45c05b3136a +FIND_ANCHOR_IRIS [federation] 003f0f16f9b1 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near samples [ME on C] +FIND_TARGET_IRIS [federation] 2f9aec17c4e9 +FIND_ANCHOR_IRIS [federation] 56c5b92ab83e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream samples [ME on A] +FIND_TARGET_IRIS [federation] 54b1d508458d +FIND_ANCHOR_IRIS [federation] 7530ba837a17 +GET_FLOWLINE_GEOMETRIES [federation] ebbacce57f0e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream samples [ME on C] +FIND_TARGET_IRIS [federation] cd1d79f23ba8 +FIND_ANCHOR_IRIS [federation] 907b64185777 +GET_FLOWLINE_GEOMETRIES [federation] ebbacce57f0e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream samples [ME on A] +FIND_TARGET_IRIS [federation] c8b9648ad9ad +FIND_ANCHOR_IRIS [federation] 6b13c5e7d199 +GET_FLOWLINE_GEOMETRIES [federation] 0d7cd31e6182 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream samples [ME on C] +FIND_TARGET_IRIS [federation] 3735b227534b +FIND_ANCHOR_IRIS [federation] d1b9348ef98d +GET_FLOWLINE_GEOMETRIES [federation] 0d7cd31e6182 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near facilities [ME on A] +FIND_TARGET_IRIS [federation] 5aedb347a53b +FIND_ANCHOR_IRIS [federation] b6d4297f115e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near facilities [ME on C] +FIND_TARGET_IRIS [federation] 88d952d2a2c5 +FIND_ANCHOR_IRIS [federation] 6316b038687c +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 4ca2878d179f +FIND_ANCHOR_IRIS [federation] 21aab4d7bdf7 +GET_FLOWLINE_GEOMETRIES [federation] 23e64482073d +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 35eea760e846 +FIND_ANCHOR_IRIS [federation] 021c99bd21fe +GET_FLOWLINE_GEOMETRIES [federation] 23e64482073d +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] 2fdb9d27c845 +FIND_ANCHOR_IRIS [federation] b6983d91a529 +GET_FLOWLINE_GEOMETRIES [federation] 5515bd777411 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 1a0e0369b410 +FIND_ANCHOR_IRIS [federation] 32747a1b563b +GET_FLOWLINE_GEOMETRIES [federation] 5515bd777411 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] e2b3d9f8c117 +FIND_ANCHOR_IRIS [federation] 40a495b7a46a +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] e0d3a87dd863 +FIND_ANCHOR_IRIS [federation] 38cb444f42f8 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 4b6cc3a024ee +FIND_ANCHOR_IRIS [federation] 208b7a3a6317 +GET_FLOWLINE_GEOMETRIES [federation] 137df84ed6d2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] ba778257a97f +FIND_ANCHOR_IRIS [federation] 5c6cc33fae88 +GET_FLOWLINE_GEOMETRIES [federation] 137df84ed6d2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 2ecade927c68 +FIND_ANCHOR_IRIS [federation] 48a5326856de +GET_FLOWLINE_GEOMETRIES [federation] a28356585b79 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 99dd9196dcc8 +FIND_ANCHOR_IRIS [federation] 1beadb689ecd +GET_FLOWLINE_GEOMETRIES [federation] a28356585b79 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near wells [ME on A] +FIND_TARGET_IRIS [federation] a408ff1eb89d +FIND_ANCHOR_IRIS [federation] 33e4f401a9db +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 66c78fc2515a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near wells [ME on C] +FIND_TARGET_IRIS [federation] 3e4c26e61ee4 +FIND_ANCHOR_IRIS [federation] cdddd6bdf1d7 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 46bc1db1c4db +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream wells [ME on A] +FIND_TARGET_IRIS [federation] c5ae9f5fc826 +FIND_ANCHOR_IRIS [federation] 4f5453f9e32d +GET_FLOWLINE_GEOMETRIES [federation] 9a08433a48e0 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ca1086992b60 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream wells [ME on C] +FIND_TARGET_IRIS [federation] 22c02f8cd68b +FIND_ANCHOR_IRIS [federation] b9d52f76c5da +GET_FLOWLINE_GEOMETRIES [federation] 9a08433a48e0 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] dc4d5d46d3f1 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream wells [ME on A] +FIND_TARGET_IRIS [federation] 26bf05053779 +FIND_ANCHOR_IRIS [federation] ddfaa9f20f19 +GET_FLOWLINE_GEOMETRIES [federation] 79b82d9e0fe1 +HYDRATE_TARGET_BY_IRI [federation] ec935451ecfb +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream wells [ME on C] +FIND_TARGET_IRIS [federation] b6893ae200af +FIND_ANCHOR_IRIS [federation] b9d0126bda7a +GET_FLOWLINE_GEOMETRIES [federation] 79b82d9e0fe1 +HYDRATE_TARGET_BY_IRI [federation] c35d18356b27 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near aquifers [ME on A] +FIND_TARGET_IRIS [federation] 4eb7e82611af +FIND_ANCHOR_IRIS [federation] 2bec684879ca +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near aquifers [ME on C] +FIND_TARGET_IRIS [federation] 0667c0004f62 +FIND_ANCHOR_IRIS [federation] 8529b7fb6ffa +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] dc584e6cfe79 +FIND_ANCHOR_IRIS [federation] a3823ffd8794 +GET_FLOWLINE_GEOMETRIES [federation] 3cdf1859eeef +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] a963e5be882c +FIND_ANCHOR_IRIS [federation] 58c16900aa65 +GET_FLOWLINE_GEOMETRIES [federation] 3cdf1859eeef +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] a963e5be882c +FIND_ANCHOR_IRIS [federation] 58c16900aa65 +GET_FLOWLINE_GEOMETRIES [federation] 3cdf1859eeef +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] dc584e6cfe79 +FIND_ANCHOR_IRIS [federation] a3823ffd8794 +GET_FLOWLINE_GEOMETRIES [federation] 3cdf1859eeef +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near streams [ME on A] +FIND_TARGET_IRIS [federation] 8f5c7dd5246f +FIND_ANCHOR_IRIS [federation] 07bcc0d2ef5b +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers near streams [ME on C] +FIND_TARGET_IRIS [federation] ef7f4d420285 +FIND_ANCHOR_IRIS [federation] 93c67796bf6d +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream streams [ME on A] +FIND_TARGET_IRIS [federation] e13c4295e7b0 +FIND_ANCHOR_IRIS [federation] bac0c29c4f57 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream streams [ME on C] +FIND_TARGET_IRIS [federation] 98b1603dafe4 +FIND_ANCHOR_IRIS [federation] 481ef65eaf6e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream streams [ME on A] +FIND_TARGET_IRIS [federation] 132f284d8912 +FIND_ANCHOR_IRIS [federation] 629f7809931c +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream streams [ME on C] +FIND_TARGET_IRIS [federation] eb7c41d74f46 +FIND_ANCHOR_IRIS [federation] 2ab8259a58d6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near samples [ME on A] +FIND_TARGET_IRIS [federation] daaf4827bae1 +FIND_ANCHOR_IRIS [federation] bea267f2f762 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near samples [ME on C] +FIND_TARGET_IRIS [federation] 377f854f6cc6 +FIND_ANCHOR_IRIS [federation] 6e59770323b3 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream samples [ME on A] +FIND_TARGET_IRIS [federation] 3bcbbc61caae +FIND_ANCHOR_IRIS [federation] a62588d4bcb9 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream samples [ME on C] +FIND_TARGET_IRIS [federation] b22e14df0511 +FIND_ANCHOR_IRIS [federation] 7dad41fdfd60 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream samples [ME on A] +FIND_TARGET_IRIS [federation] e8b95c8c5b5d +FIND_ANCHOR_IRIS [federation] 0d9fd4f4b10a +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream samples [ME on C] +FIND_TARGET_IRIS [federation] 962a202132fc +FIND_ANCHOR_IRIS [federation] 62aa5619bc67 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near facilities [ME on A] +FIND_TARGET_IRIS [federation] 0d03523e6c23 +FIND_ANCHOR_IRIS [federation] e0f6624fc264 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near facilities [ME on C] +FIND_TARGET_IRIS [federation] 8ef73aad6fa9 +FIND_ANCHOR_IRIS [federation] a3ac25aca5df +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream facilities [ME on A] +FIND_TARGET_IRIS [federation] ba8393ad2e9d +FIND_ANCHOR_IRIS [federation] d2cd8e8cafdf +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 81325b745fd1 +FIND_ANCHOR_IRIS [federation] 404c3355f3fd +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream facilities [ME on A] +FIND_TARGET_IRIS [federation] f8ce75f3f7ee +FIND_ANCHOR_IRIS [federation] a7e872d51a0f +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream facilities [ME on C] +FIND_TARGET_IRIS [federation] 88a05eee9640 +FIND_ANCHOR_IRIS [federation] eedde23983a6 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 6da1ed2de01d +FIND_ANCHOR_IRIS [federation] 320b9d0e5ff8 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near waterBodies [ME on C] +FIND_TARGET_IRIS [federation] ade4600c7066 +FIND_ANCHOR_IRIS [federation] 2e32c0ffbc3c +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] eeb6a4be8d87 +FIND_ANCHOR_IRIS [federation] 2bc13625bc04 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 3a5de06aa701 +FIND_ANCHOR_IRIS [federation] 1890d6fd07a7 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 94b023ca04bf +FIND_ANCHOR_IRIS [federation] 39f68d9178a5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream waterBodies [ME on C] +FIND_TARGET_IRIS [federation] d98072521790 +FIND_ANCHOR_IRIS [federation] bba7273cdba4 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near wells [ME on A] +FIND_TARGET_IRIS [federation] daae4206ce0f +FIND_ANCHOR_IRIS [federation] fb42af7be1f5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] bc5e31538d28 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near wells [ME on C] +FIND_TARGET_IRIS [federation] fcaea4147d56 +FIND_ANCHOR_IRIS [federation] 56ea6a34453b +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 2fe8928c9eac +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream wells [ME on A] +FIND_TARGET_IRIS [federation] 1da7ac18c1ca +FIND_ANCHOR_IRIS [federation] 592bae86ed3a +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 95fe8b8c33ba +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream wells [ME on C] +FIND_TARGET_IRIS [federation] 8b7cd81ea5cf +FIND_ANCHOR_IRIS [federation] e5376ca0aa0a +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] bf6a1a426eb1 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream wells [ME on A] +FIND_TARGET_IRIS [federation] f56b87fc7251 +FIND_ANCHOR_IRIS [federation] 67b90dec7f24 +HYDRATE_TARGET_BY_IRI [federation] 06c0038fb4ce +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream wells [ME on C] +FIND_TARGET_IRIS [federation] e3bb217bc214 +FIND_ANCHOR_IRIS [federation] 032ea9425e6f +HYDRATE_TARGET_BY_IRI [federation] 32cbf641e1bc +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near aquifers [ME on A] +FIND_TARGET_IRIS [federation] 871365cea3c3 +FIND_ANCHOR_IRIS [federation] bd4eab4c6f66 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near aquifers [ME on C] +FIND_TARGET_IRIS [federation] 26ef89af73d7 +FIND_ANCHOR_IRIS [federation] 7c9c4702ede4 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] eb7c41d74f46 +FIND_ANCHOR_IRIS [federation] 2ab8259a58d6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] 132f284d8912 +FIND_ANCHOR_IRIS [federation] 629f7809931c +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream aquifers [ME on A] +FIND_TARGET_IRIS [federation] 98b1603dafe4 +FIND_ANCHOR_IRIS [federation] 481ef65eaf6e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream aquifers [ME on C] +FIND_TARGET_IRIS [federation] e13c4295e7b0 +FIND_ANCHOR_IRIS [federation] bac0c29c4f57 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near streams [ME on A] +FIND_TARGET_IRIS [federation] 7658df86ebfb +FIND_ANCHOR_IRIS [federation] 79e0bd042512 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams near streams [ME on C] +FIND_TARGET_IRIS [federation] 9ba66fec62a1 +FIND_ANCHOR_IRIS [federation] 9e8aee90f1eb +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream streams [ME on A] +FIND_TARGET_IRIS [federation] 24e2d640eb8b +FIND_ANCHOR_IRIS [federation] 14f6bfc3ef2b +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream streams [ME on C] +FIND_TARGET_IRIS [federation] 29735aa2afea +FIND_ANCHOR_IRIS [federation] 56f38a86aec7 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream streams [ME on A] +FIND_TARGET_IRIS [federation] 29735aa2afea +FIND_ANCHOR_IRIS [federation] 56f38a86aec7 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream streams [ME on C] +FIND_TARGET_IRIS [federation] 24e2d640eb8b +FIND_ANCHOR_IRIS [federation] 14f6bfc3ef2b +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] fa1833c58b13 +FIND_ANCHOR_IRIS [federation] 4d08a3f185ec +GET_FLOWLINE_GEOMETRIES [federation] 5a03f4f3aae3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] f0d79c0a39c3 +FIND_ANCHOR_IRIS [federation] ece4d96de601 +GET_FLOWLINE_GEOMETRIES [federation] 5a03f4f3aae3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] f0d79c0a39c3 +FIND_ANCHOR_IRIS [federation] ece4d96de601 +GET_FLOWLINE_GEOMETRIES [federation] 5a03f4f3aae3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] fa1833c58b13 +FIND_ANCHOR_IRIS [federation] 4d08a3f185ec +GET_FLOWLINE_GEOMETRIES [federation] 5a03f4f3aae3 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 3dbb4fd45439 +FIND_ANCHOR_IRIS [federation] c6129be91792 +GET_FLOWLINE_GEOMETRIES [federation] 3c6a4d4ad1b9 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 59aee765110c +FIND_ANCHOR_IRIS [federation] 4a22e1a87031 +GET_FLOWLINE_GEOMETRIES [federation] 3c6a4d4ad1b9 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 7d7f1e7d7c60 +FIND_ANCHOR_IRIS [federation] 6e78232de987 +GET_FLOWLINE_GEOMETRIES [federation] a4f6491c0e2c +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 7604a06153a0 +FIND_ANCHOR_IRIS [federation] 666e8b5700a2 +GET_FLOWLINE_GEOMETRIES [federation] a4f6491c0e2c +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] d4ff9a18f9cf +FIND_ANCHOR_IRIS [federation] 2c9b021c5ece +GET_FLOWLINE_GEOMETRIES [federation] 288129aa4dbe +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 751b01f1248c +FIND_ANCHOR_IRIS [federation] 4e22903dafb8 +GET_FLOWLINE_GEOMETRIES [federation] 288129aa4dbe +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] c36613529a50 +FIND_ANCHOR_IRIS [federation] 1195457ff6d4 +GET_FLOWLINE_GEOMETRIES [federation] 70123c8b61f0 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 436d3320d910 +FIND_ANCHOR_IRIS [federation] 518849e03a5b +GET_FLOWLINE_GEOMETRIES [federation] 70123c8b61f0 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] c5ba856ac5a5 +FIND_ANCHOR_IRIS [federation] 802d35965666 +GET_FLOWLINE_GEOMETRIES [federation] 337d970b0f07 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] da7010fa25fd +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 8a8df61dddeb +FIND_ANCHOR_IRIS [federation] 789f1ded1d8a +GET_FLOWLINE_GEOMETRIES [federation] 337d970b0f07 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 52f8acbda00d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 776babccec7b +FIND_ANCHOR_IRIS [federation] 3484afc2016f +GET_FLOWLINE_GEOMETRIES [federation] 5de1200d2e01 +HYDRATE_TARGET_BY_IRI [federation] c9531cc6fbe2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 5dbe52083d8c +FIND_ANCHOR_IRIS [federation] 18515c96f78d +GET_FLOWLINE_GEOMETRIES [federation] 5de1200d2e01 +HYDRATE_TARGET_BY_IRI [federation] 878b7218cf7c +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] a548c30613f2 +FIND_ANCHOR_IRIS [federation] 123fa7029db0 +GET_FLOWLINE_GEOMETRIES [federation] a7ba4bf786b6 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 66321d87ce37 +FIND_ANCHOR_IRIS [federation] 2bcc64889ee4 +GET_FLOWLINE_GEOMETRIES [federation] a7ba4bf786b6 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] 5109f240a9f0 +FIND_ANCHOR_IRIS [federation] fa5208b4f1f5 +GET_FLOWLINE_GEOMETRIES [federation] 934aca1f2f29 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 296a0d00de9e +FIND_ANCHOR_IRIS [federation] 71f036d9cd02 +GET_FLOWLINE_GEOMETRIES [federation] 934aca1f2f29 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 55f5714d004c +FIND_ANCHOR_IRIS [federation] 27a652bc4a63 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] 614ca43f8807 +FIND_ANCHOR_IRIS [federation] 3ac013fb1120 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] ac7ebc96d761 +FIND_ANCHOR_IRIS [federation] fc48809955c6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## samples upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] b4008588edaf +FIND_ANCHOR_IRIS [federation] 6ac9015a260c +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 7604a06153a0 +FIND_ANCHOR_IRIS [federation] 666e8b5700a2 +GET_FLOWLINE_GEOMETRIES [federation] a4f6491c0e2c +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] 7d7f1e7d7c60 +FIND_ANCHOR_IRIS [federation] 6e78232de987 +GET_FLOWLINE_GEOMETRIES [federation] a4f6491c0e2c +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 59aee765110c +FIND_ANCHOR_IRIS [federation] 4a22e1a87031 +GET_FLOWLINE_GEOMETRIES [federation] 3c6a4d4ad1b9 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] 3dbb4fd45439 +FIND_ANCHOR_IRIS [federation] c6129be91792 +GET_FLOWLINE_GEOMETRIES [federation] 3c6a4d4ad1b9 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] eda7f49eaf9d +FIND_ANCHOR_IRIS [federation] f1e4ac3d1adc +GET_FLOWLINE_GEOMETRIES [federation] bf8ffdfa1ad9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 8758a29be4cd +FIND_ANCHOR_IRIS [federation] 3de8c144de70 +GET_FLOWLINE_GEOMETRIES [federation] bf8ffdfa1ad9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 8758a29be4cd +FIND_ANCHOR_IRIS [federation] 3de8c144de70 +GET_FLOWLINE_GEOMETRIES [federation] bf8ffdfa1ad9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] eda7f49eaf9d +FIND_ANCHOR_IRIS [federation] f1e4ac3d1adc +GET_FLOWLINE_GEOMETRIES [federation] bf8ffdfa1ad9 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 6537d90d135f +FIND_ANCHOR_IRIS [federation] 69f0475ae80a +GET_FLOWLINE_GEOMETRIES [federation] fd28138d5b69 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 8fbe3088c265 +FIND_ANCHOR_IRIS [federation] 060c1e184a76 +GET_FLOWLINE_GEOMETRIES [federation] fd28138d5b69 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 9b750fdb6a09 +FIND_ANCHOR_IRIS [federation] 7ab11f2c9448 +GET_FLOWLINE_GEOMETRIES [federation] 9f955f3f75d5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] f560ebd6282b +FIND_ANCHOR_IRIS [federation] 86a26ec60121 +GET_FLOWLINE_GEOMETRIES [federation] 9f955f3f75d5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 5c5c06fd1d35 +FIND_ANCHOR_IRIS [federation] 1b7220b76dc0 +GET_FLOWLINE_GEOMETRIES [federation] 53706371792a +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 9c03aae08c7b +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] e5836fc46bf4 +FIND_ANCHOR_IRIS [federation] a0d6980914ac +GET_FLOWLINE_GEOMETRIES [federation] 53706371792a +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 5a01b1674751 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] ab7cba78e7a4 +FIND_ANCHOR_IRIS [federation] e710b494417c +GET_FLOWLINE_GEOMETRIES [federation] 8becca5939ec +HYDRATE_TARGET_BY_IRI [federation] 719474b95b24 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 242afddb2669 +FIND_ANCHOR_IRIS [federation] 748a8ca41a32 +GET_FLOWLINE_GEOMETRIES [federation] 8becca5939ec +HYDRATE_TARGET_BY_IRI [federation] af3062364f60 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] be59394dac59 +FIND_ANCHOR_IRIS [federation] da77e9a226ae +GET_FLOWLINE_GEOMETRIES [federation] 5bb2d62da8a0 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] c1505f76d1a2 +FIND_ANCHOR_IRIS [federation] 78d85e00dcd9 +GET_FLOWLINE_GEOMETRIES [federation] 5bb2d62da8a0 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] 7087d0c06d24 +FIND_ANCHOR_IRIS [federation] dfffea098028 +GET_FLOWLINE_GEOMETRIES [federation] e0c43ef101a2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 027492953f58 +FIND_ANCHOR_IRIS [federation] e1ccb826ce9b +GET_FLOWLINE_GEOMETRIES [federation] e0c43ef101a2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 37c324b2fb11 +FIND_ANCHOR_IRIS [federation] dda55e8be700 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] a7c3f2ccff0c +FIND_ANCHOR_IRIS [federation] cc4b39ebe0a2 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] e792abfe6ef8 +FIND_ANCHOR_IRIS [federation] 10dbee777757 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## facilities upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] 1f724fa39386 +FIND_ANCHOR_IRIS [federation] 8138a7e702af +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 436d3320d910 +FIND_ANCHOR_IRIS [federation] 518849e03a5b +GET_FLOWLINE_GEOMETRIES [federation] 70123c8b61f0 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] c36613529a50 +FIND_ANCHOR_IRIS [federation] 1195457ff6d4 +GET_FLOWLINE_GEOMETRIES [federation] 70123c8b61f0 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 751b01f1248c +FIND_ANCHOR_IRIS [federation] 4e22903dafb8 +GET_FLOWLINE_GEOMETRIES [federation] 288129aa4dbe +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] d4ff9a18f9cf +FIND_ANCHOR_IRIS [federation] 2c9b021c5ece +GET_FLOWLINE_GEOMETRIES [federation] 288129aa4dbe +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] f560ebd6282b +FIND_ANCHOR_IRIS [federation] 86a26ec60121 +GET_FLOWLINE_GEOMETRIES [federation] 9f955f3f75d5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 9b750fdb6a09 +FIND_ANCHOR_IRIS [federation] 7ab11f2c9448 +GET_FLOWLINE_GEOMETRIES [federation] 9f955f3f75d5 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 8fbe3088c265 +FIND_ANCHOR_IRIS [federation] 060c1e184a76 +GET_FLOWLINE_GEOMETRIES [federation] fd28138d5b69 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 6537d90d135f +FIND_ANCHOR_IRIS [federation] 69f0475ae80a +GET_FLOWLINE_GEOMETRIES [federation] fd28138d5b69 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 8c90b6016e50 +FIND_ANCHOR_IRIS [federation] 090aa1368fc6 +GET_FLOWLINE_GEOMETRIES [federation] cd57b7a763e6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] b7423f86a11e +FIND_ANCHOR_IRIS [federation] 6ed5aed4968a +GET_FLOWLINE_GEOMETRIES [federation] cd57b7a763e6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] b7423f86a11e +FIND_ANCHOR_IRIS [federation] 6ed5aed4968a +GET_FLOWLINE_GEOMETRIES [federation] cd57b7a763e6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 8c90b6016e50 +FIND_ANCHOR_IRIS [federation] 090aa1368fc6 +GET_FLOWLINE_GEOMETRIES [federation] cd57b7a763e6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 77f682fb65ef +FIND_ANCHOR_IRIS [federation] 13bb3ff18f50 +GET_FLOWLINE_GEOMETRIES [federation] b97f4349ba61 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 1b55c84eb49b +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 8d3c6166926c +FIND_ANCHOR_IRIS [federation] 3a2bb0cd96e0 +GET_FLOWLINE_GEOMETRIES [federation] b97f4349ba61 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 74340ac75507 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] ca528e8925b8 +FIND_ANCHOR_IRIS [federation] 3691010af47d +GET_FLOWLINE_GEOMETRIES [federation] 22b41e20cf91 +HYDRATE_TARGET_BY_IRI [federation] 19c1603fd525 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 07f85ea74c11 +FIND_ANCHOR_IRIS [federation] e93784de47f2 +GET_FLOWLINE_GEOMETRIES [federation] 22b41e20cf91 +HYDRATE_TARGET_BY_IRI [federation] 83a09bfc0c0a +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] ee66561a00f7 +FIND_ANCHOR_IRIS [federation] 02fc7f5ebfab +GET_FLOWLINE_GEOMETRIES [federation] b3c1864cf554 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 96f67a03be24 +FIND_ANCHOR_IRIS [federation] 90d82873e3c0 +GET_FLOWLINE_GEOMETRIES [federation] b3c1864cf554 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] bd10519b155e +FIND_ANCHOR_IRIS [federation] 6ad2a8fa8e74 +GET_FLOWLINE_GEOMETRIES [federation] 1b2c8dc5e4e2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] c1711127344f +FIND_ANCHOR_IRIS [federation] 794a5c139565 +GET_FLOWLINE_GEOMETRIES [federation] 1b2c8dc5e4e2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 970a4ae75376 +FIND_ANCHOR_IRIS [federation] b57ca9e8c32e +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] b6f2102221d1 +FIND_ANCHOR_IRIS [federation] 9a0037a928d9 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 82022c612381 +FIND_ANCHOR_IRIS [federation] 5151a972eede +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## waterBodies upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] c339d1c42d50 +FIND_ANCHOR_IRIS [federation] 423d5033fc48 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 5dbe52083d8c +FIND_ANCHOR_IRIS [federation] 18515c96f78d +GET_FLOWLINE_GEOMETRIES [federation] 5de1200d2e01 +HYDRATE_TARGET_BY_IRI [federation] 878b7218cf7c +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] 776babccec7b +FIND_ANCHOR_IRIS [federation] 3484afc2016f +GET_FLOWLINE_GEOMETRIES [federation] 5de1200d2e01 +HYDRATE_TARGET_BY_IRI [federation] c9531cc6fbe2 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 8a8df61dddeb +FIND_ANCHOR_IRIS [federation] 789f1ded1d8a +GET_FLOWLINE_GEOMETRIES [federation] 337d970b0f07 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] 52f8acbda00d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] c5ba856ac5a5 +FIND_ANCHOR_IRIS [federation] 802d35965666 +GET_FLOWLINE_GEOMETRIES [federation] 337d970b0f07 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] da7010fa25fd +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 242afddb2669 +FIND_ANCHOR_IRIS [federation] 748a8ca41a32 +GET_FLOWLINE_GEOMETRIES [federation] 8becca5939ec +HYDRATE_TARGET_BY_IRI [federation] af3062364f60 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] ab7cba78e7a4 +FIND_ANCHOR_IRIS [federation] e710b494417c +GET_FLOWLINE_GEOMETRIES [federation] 8becca5939ec +HYDRATE_TARGET_BY_IRI [federation] 719474b95b24 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] e5836fc46bf4 +FIND_ANCHOR_IRIS [federation] a0d6980914ac +GET_FLOWLINE_GEOMETRIES [federation] 53706371792a +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 5a01b1674751 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 5c5c06fd1d35 +FIND_ANCHOR_IRIS [federation] 1b7220b76dc0 +GET_FLOWLINE_GEOMETRIES [federation] 53706371792a +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 9c03aae08c7b +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 07f85ea74c11 +FIND_ANCHOR_IRIS [federation] e93784de47f2 +GET_FLOWLINE_GEOMETRIES [federation] 22b41e20cf91 +HYDRATE_TARGET_BY_IRI [federation] 83a09bfc0c0a +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] ca528e8925b8 +FIND_ANCHOR_IRIS [federation] 3691010af47d +GET_FLOWLINE_GEOMETRIES [federation] 22b41e20cf91 +HYDRATE_TARGET_BY_IRI [federation] 19c1603fd525 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 8d3c6166926c +FIND_ANCHOR_IRIS [federation] 3a2bb0cd96e0 +GET_FLOWLINE_GEOMETRIES [federation] b97f4349ba61 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 74340ac75507 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 77f682fb65ef +FIND_ANCHOR_IRIS [federation] 13bb3ff18f50 +GET_FLOWLINE_GEOMETRIES [federation] b97f4349ba61 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [federation] 1b55c84eb49b +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 163001e80cdb +FIND_ANCHOR_IRIS [federation] dcf4ba3a467c +GET_FLOWLINE_GEOMETRIES [federation] f9af91a7570a +HYDRATE_TARGET_BY_IRI [federation] aa5fdb59ec6f +HYDRATE_ANCHOR_BY_IRI [federation] 24b7baa84045 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 7d5fd908795e +FIND_ANCHOR_IRIS [federation] 119afb444b62 +GET_FLOWLINE_GEOMETRIES [federation] f9af91a7570a +HYDRATE_TARGET_BY_IRI [federation] 29547f75bee0 +HYDRATE_ANCHOR_BY_IRI [federation] 977ce19228f3 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 7d5fd908795e +FIND_ANCHOR_IRIS [federation] 119afb444b62 +GET_FLOWLINE_GEOMETRIES [federation] f9af91a7570a +HYDRATE_TARGET_BY_IRI [federation] 29547f75bee0 +HYDRATE_ANCHOR_BY_IRI [federation] 977ce19228f3 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 163001e80cdb +FIND_ANCHOR_IRIS [federation] dcf4ba3a467c +GET_FLOWLINE_GEOMETRIES [federation] f9af91a7570a +HYDRATE_TARGET_BY_IRI [federation] aa5fdb59ec6f +HYDRATE_ANCHOR_BY_IRI [federation] 24b7baa84045 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] f9a94dc1bcc9 +FIND_ANCHOR_IRIS [federation] c90f839ad3a4 +GET_FLOWLINE_GEOMETRIES [federation] 02e163a42cfe +HYDRATE_TARGET_BY_IRI [federation] 000f97199f10 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 93ba832c29d7 +FIND_ANCHOR_IRIS [federation] 8c23d3755445 +GET_FLOWLINE_GEOMETRIES [federation] 02e163a42cfe +HYDRATE_TARGET_BY_IRI [federation] bf2ceb812bdb +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] 50a3fd88e46f +FIND_ANCHOR_IRIS [federation] 50e13b4749a3 +GET_FLOWLINE_GEOMETRIES [federation] e4b7f27cdd3e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 90f83102d132 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 276ce6ba94f0 +FIND_ANCHOR_IRIS [federation] 57420cc1d1e2 +GET_FLOWLINE_GEOMETRIES [federation] e4b7f27cdd3e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 01821ca119a9 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 7cb722edd17a +FIND_ANCHOR_IRIS [federation] be142639d65c +HYDRATE_TARGET_BY_IRI [federation] 251a657c96b2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] ceaa643cf456 +FIND_ANCHOR_IRIS [federation] c1449fc486a8 +HYDRATE_TARGET_BY_IRI [federation] ac1966b9691f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 2fc1e89df154 +FIND_ANCHOR_IRIS [federation] f8efc6828155 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 898bd716c54a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## wells upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] 167778822ddb +FIND_ANCHOR_IRIS [federation] aae1eb735bf1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 0ab0a62dc232 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 296a0d00de9e +FIND_ANCHOR_IRIS [federation] 71f036d9cd02 +GET_FLOWLINE_GEOMETRIES [federation] 934aca1f2f29 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] 5109f240a9f0 +FIND_ANCHOR_IRIS [federation] fa5208b4f1f5 +GET_FLOWLINE_GEOMETRIES [federation] 934aca1f2f29 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 66321d87ce37 +FIND_ANCHOR_IRIS [federation] 2bcc64889ee4 +GET_FLOWLINE_GEOMETRIES [federation] a7ba4bf786b6 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] a548c30613f2 +FIND_ANCHOR_IRIS [federation] 123fa7029db0 +GET_FLOWLINE_GEOMETRIES [federation] a7ba4bf786b6 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 027492953f58 +FIND_ANCHOR_IRIS [federation] e1ccb826ce9b +GET_FLOWLINE_GEOMETRIES [federation] e0c43ef101a2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 7087d0c06d24 +FIND_ANCHOR_IRIS [federation] dfffea098028 +GET_FLOWLINE_GEOMETRIES [federation] e0c43ef101a2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] c1505f76d1a2 +FIND_ANCHOR_IRIS [federation] 78d85e00dcd9 +GET_FLOWLINE_GEOMETRIES [federation] 5bb2d62da8a0 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] be59394dac59 +FIND_ANCHOR_IRIS [federation] da77e9a226ae +GET_FLOWLINE_GEOMETRIES [federation] 5bb2d62da8a0 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] c1711127344f +FIND_ANCHOR_IRIS [federation] 794a5c139565 +GET_FLOWLINE_GEOMETRIES [federation] 1b2c8dc5e4e2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] bd10519b155e +FIND_ANCHOR_IRIS [federation] 6ad2a8fa8e74 +GET_FLOWLINE_GEOMETRIES [federation] 1b2c8dc5e4e2 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] 96f67a03be24 +FIND_ANCHOR_IRIS [federation] 90d82873e3c0 +GET_FLOWLINE_GEOMETRIES [federation] b3c1864cf554 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] ee66561a00f7 +FIND_ANCHOR_IRIS [federation] 02fc7f5ebfab +GET_FLOWLINE_GEOMETRIES [federation] b3c1864cf554 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 276ce6ba94f0 +FIND_ANCHOR_IRIS [federation] 57420cc1d1e2 +GET_FLOWLINE_GEOMETRIES [federation] e4b7f27cdd3e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 01821ca119a9 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 50a3fd88e46f +FIND_ANCHOR_IRIS [federation] 50e13b4749a3 +GET_FLOWLINE_GEOMETRIES [federation] e4b7f27cdd3e +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [federation] 90f83102d132 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 93ba832c29d7 +FIND_ANCHOR_IRIS [federation] 8c23d3755445 +GET_FLOWLINE_GEOMETRIES [federation] 02e163a42cfe +HYDRATE_TARGET_BY_IRI [federation] bf2ceb812bdb +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] f9a94dc1bcc9 +FIND_ANCHOR_IRIS [federation] c90f839ad3a4 +GET_FLOWLINE_GEOMETRIES [federation] 02e163a42cfe +HYDRATE_TARGET_BY_IRI [federation] 000f97199f10 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] d0422a3a1b39 +FIND_ANCHOR_IRIS [federation] 5a98acf98b84 +GET_FLOWLINE_GEOMETRIES [federation] 18a6e65f767f +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] e933a835c975 +FIND_ANCHOR_IRIS [federation] 19a47153e361 +GET_FLOWLINE_GEOMETRIES [federation] 18a6e65f767f +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] e933a835c975 +FIND_ANCHOR_IRIS [federation] 19a47153e361 +GET_FLOWLINE_GEOMETRIES [federation] 18a6e65f767f +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] d0422a3a1b39 +FIND_ANCHOR_IRIS [federation] 5a98acf98b84 +GET_FLOWLINE_GEOMETRIES [federation] 18a6e65f767f +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 5dfec1ecf571 +FIND_ANCHOR_IRIS [federation] 74f6726cb460 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] bba05a0302fc +FIND_ANCHOR_IRIS [federation] 6a8f8b9351bc +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 36f3da58361d +FIND_ANCHOR_IRIS [federation] a79808637aab +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## aquifers upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] 1c7638f408b9 +FIND_ANCHOR_IRIS [federation] b58c8c35f1eb +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] b4008588edaf +FIND_ANCHOR_IRIS [federation] 6ac9015a260c +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] ac7ebc96d761 +FIND_ANCHOR_IRIS [federation] fc48809955c6 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) samples [ME on A] +FIND_TARGET_IRIS [federation] 614ca43f8807 +FIND_ANCHOR_IRIS [federation] 3ac013fb1120 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) samples [ME on C] +FIND_TARGET_IRIS [federation] 55f5714d004c +FIND_ANCHOR_IRIS [federation] 27a652bc4a63 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] 1f724fa39386 +FIND_ANCHOR_IRIS [federation] 8138a7e702af +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] e792abfe6ef8 +FIND_ANCHOR_IRIS [federation] 10dbee777757 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) facilities [ME on A] +FIND_TARGET_IRIS [federation] a7c3f2ccff0c +FIND_ANCHOR_IRIS [federation] cc4b39ebe0a2 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) facilities [ME on C] +FIND_TARGET_IRIS [federation] 37c324b2fb11 +FIND_ANCHOR_IRIS [federation] dda55e8be700 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] c339d1c42d50 +FIND_ANCHOR_IRIS [federation] 423d5033fc48 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 82022c612381 +FIND_ANCHOR_IRIS [federation] 5151a972eede +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 196733917305 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) waterBodies [ME on A] +FIND_TARGET_IRIS [federation] b6f2102221d1 +FIND_ANCHOR_IRIS [federation] 9a0037a928d9 +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) waterBodies [ME on C] +FIND_TARGET_IRIS [federation] 970a4ae75376 +FIND_ANCHOR_IRIS [federation] b57ca9e8c32e +HYDRATE_TARGET_BY_IRI [hydrologykg] 3b88da2bc6f2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] 167778822ddb +FIND_ANCHOR_IRIS [federation] aae1eb735bf1 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 0ab0a62dc232 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 2fc1e89df154 +FIND_ANCHOR_IRIS [federation] f8efc6828155 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [federation] 898bd716c54a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) wells [ME on A] +FIND_TARGET_IRIS [federation] ceaa643cf456 +FIND_ANCHOR_IRIS [federation] c1449fc486a8 +HYDRATE_TARGET_BY_IRI [federation] ac1966b9691f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) wells [ME on C] +FIND_TARGET_IRIS [federation] 7cb722edd17a +FIND_ANCHOR_IRIS [federation] be142639d65c +HYDRATE_TARGET_BY_IRI [federation] 251a657c96b2 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] 1c7638f408b9 +FIND_ANCHOR_IRIS [federation] b58c8c35f1eb +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 36f3da58361d +FIND_ANCHOR_IRIS [federation] a79808637aab +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) aquifers [ME on A] +FIND_TARGET_IRIS [federation] bba05a0302fc +FIND_ANCHOR_IRIS [federation] 6a8f8b9351bc +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) aquifers [ME on C] +FIND_TARGET_IRIS [federation] 5dfec1ecf571 +FIND_ANCHOR_IRIS [federation] 74f6726cb460 +HYDRATE_TARGET_BY_IRI [hydrologykg] eb3b32e6b88d +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] ff4f5433385d +FIND_ANCHOR_IRIS [federation] 8e0f26314aa4 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams downstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] 13b885df21d2 +FIND_ANCHOR_IRIS [federation] 2b58e51b6c3d +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) streams [ME on A] +FIND_TARGET_IRIS [federation] 13b885df21d2 +FIND_ANCHOR_IRIS [federation] 2b58e51b6c3d +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## streams upstream(30km) streams [ME on C] +FIND_TARGET_IRIS [federation] ff4f5433385d +FIND_ANCHOR_IRIS [federation] 8e0f26314aa4 +HYDRATE_TARGET_BY_IRI [hydrologykg] 373c4f087d16 +HYDRATE_ANCHOR_BY_IRI [hydrologykg] aeb350c37047 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: near hops=0 +FIND_TARGET_IRIS [federation] a01b1b84351c +FIND_ANCHOR_IRIS [federation] 5c0972841eb9 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: near hops=2 +FIND_TARGET_IRIS [federation] 396a2519092b +FIND_ANCHOR_IRIS [federation] aadf4d36b6ad +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: near hops=4 +FIND_TARGET_IRIS [federation] c8190383299a +FIND_ANCHOR_IRIS [federation] edaa65a35aac +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: downstream maxDistanceKm=10 +FIND_TARGET_IRIS [federation] 3325fb88c1d7 +FIND_ANCHOR_IRIS [federation] 74c3d0bb8bf8 +GET_FLOWLINE_GEOMETRIES [federation] 91f383f2621e +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: upstream maxDistanceKm=10 +FIND_TARGET_IRIS [federation] 061fd7e20e08 +FIND_ANCHOR_IRIS [federation] 875d5698ab94 +GET_FLOWLINE_GEOMETRIES [federation] d7635cc00d76 +HYDRATE_TARGET_BY_IRI [federation] 7b8a451b6ce6 +HYDRATE_ANCHOR_BY_IRI [federation] 48bc512f5a3a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: PI question: facilities upstream from PFOS samples in York, detections only +FIND_TARGET_IRIS [federation] 8cb4f136fa6e +FIND_ANCHOR_IRIS [federation] aa8204e520fc +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 4ef4712a6813 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: PI question, bounded to 30km of flow +FIND_TARGET_IRIS [federation] 1f6c48b09155 +FIND_ANCHOR_IRIS [federation] f996426f75e0 +GET_FLOWLINE_GEOMETRIES [federation] 3c6a4d4ad1b9 +HYDRATE_TARGET_BY_IRI [federation] 4ef4712a6813 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: samples substance filter only +FIND_TARGET_IRIS [federation] fe93660f9298 +FIND_ANCHOR_IRIS [federation] 9ef048145cc3 +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] abac476ba422 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: samples include-nondetects off only +FIND_TARGET_IRIS [federation] 1d4fff471300 +FIND_ANCHOR_IRIS [federation] 64a08a171f7d +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 18f27c194233 +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: no region either side +FIND_TARGET_IRIS [federation] 129a5d0e306a +FIND_ANCHOR_IRIS [federation] 4dee4c0f482e +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +## VARIANT: county-scoped both sides +FIND_TARGET_IRIS [federation] 8e74bfffca28 +FIND_ANCHOR_IRIS [federation] ea51101cddd0 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: sample filters +FIND_TARGET_IRIS [federation] 7b1c835798e7 +FIND_ANCHOR_IRIS [federation] b4f373f3b10c +GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 +HYDRATE_TARGET_BY_IRI [federation] 225ebb47d1ba +HYDRATE_ANCHOR_BY_IRI [federation] f15a49a11b96 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: facility + water body + well + aquifer filters +FIND_TARGET_IRIS [federation] ff0e8a4e0a65 +FIND_ANCHOR_IRIS [federation] 24db169bc111 +HYDRATE_TARGET_BY_IRI [federation] 9498222e580a +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa +## VARIANT: stream ftype filter as target +FIND_TARGET_IRIS [federation] f484f51fbc63 +FIND_ANCHOR_IRIS [federation] 3b68e8810ae7 +HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f +HYDRATE_ANCHOR_BY_IRI [hydrologykg] 3da8119633c2 +GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa + +# ---- query bodies, one line per distinct query ---- +000f97199f10 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +003f0f16f9b1 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +01821ca119a9 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +01ac5b24c08f SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +021c99bd21fe SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +025d57e51b2a SELECT DISTINCT ?aquifer ?aquiferType WHERE { VALUES ?aquifer { } ?aquifer rdf:type gwml2:GW_Aquifer . OPTIONAL { ?aquifer saw_water:aquiferType ?aquiferType . } } +027492953f58 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +02e163a42cfe SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +02fc7f5ebfab SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +032ea9425e6f SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +05cd3b39feaf SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +060c1e184a76 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +061fd7e20e08 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +0667c0004f62 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +06c0038fb4ce SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +07bcc0d2ef5b SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +07f85ea74c11 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +081ffe103105 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +08ee3e23c632 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +090aa1368fc6 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +09c1cecf0048 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +09e5950369e5 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +0a29f890a209 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +0ab0a62dc232 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +0bb0f6a91db9 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +0be21b7acfd7 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +0bf72e236353 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +0c695b9c750b SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +0cb147205839 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +0d03523e6c23 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +0d49e383659d SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +0d7cd31e6182 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +0d9fd4f4b10a SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +1084c720a6cc SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +1084e9f48e96 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +10a063aa6d84 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +10dbee777757 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +114ec252bd7e SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +1195457ff6d4 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +119afb444b62 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +123fa7029db0 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +129a5d0e306a SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +132f284d8912 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +137df84ed6d2 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +13b885df21d2 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +13bb3ff18f50 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +141d81ecb9ec SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +14e83b4e30cd SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +14f6bfc3ef2b SELECT DISTINCT (?streamA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +1506d58ef072 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +151ef1e41632 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +153a3a7992c8 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +163001e80cdb SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +167778822ddb SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +17938cd745d9 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +18515c96f78d SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +187c48927d97 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +1890d6fd07a7 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +18a6e65f767f SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +18f27c194233 SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) FILTER(BOUND(?numericResult)) } GROUP BY ?sp ?spWKT ?s2cell +192ca0747233 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +196733917305 SELECT DISTINCT ?waterBody ?wbWKT ?wbName ?ftype ?comid ?reachcode ?fcode ?s2cell WHERE { VALUES ?waterBody { } ?s2cell spatial:connectedTo ?waterBody ; rdf:type kwg-ont:S2Cell_Level13 . ?waterBody rdf:type hyf:HY_WaterBody ; geo:hasGeometry/geo:asWKT ?wbWKT . OPTIONAL { ?waterBody schema:name ?wbName . } OPTIONAL { ?waterBody nhdplusv2:hasFTYPE ?ftype . } OPTIONAL { ?waterBody nhdplusv2:hasCOMID ?comid . } OPTIONAL { ?waterBody nhdplusv2:hasReachCode ?reachcode . } OPTIONAL { ?waterBody nhdplusv2:hasFCODE ?fcode . } } +19a47153e361 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +19c1603fd525 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +1a0e0369b410 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +1b2c8dc5e4e2 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +1b55c84eb49b SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +1b7220b76dc0 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +1b7a89412729 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +1bce75dee487 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +1beadb689ecd SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +1c5477f4a20d SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +1c7638f408b9 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +1d4fff471300 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +1da7ac18c1ca SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +1efed1c496e5 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +1f6c48b09155 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +1f724fa39386 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +208b7a3a6317 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +20f966337069 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +21aab4d7bdf7 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +223115ac5eb1 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +225ebb47d1ba SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . ?result coso:measurementUnit ?unit . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) VALUES ?substance { } VALUES ?matType { } BIND(xsd:decimal(?numericResult) as ?numericValue) FILTER(BOUND(?numericValue) && ?unit = && ?numericValue >= 4 && ?numericValue <= 100) } GROUP BY ?sp ?spWKT ?s2cell +22b41e20cf91 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +22c02f8cd68b SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +2372d3380521 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +23e64482073d SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +242afddb2669 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +24b7baa84045 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +24db169bc111 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?aquiferA saw_water:aquiferType ?aqTypeA . VALUES ?aqTypeA { "bedrock" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type me_mgs:MGS-Well . ?wellC me_mgs:hasUse ?wuC . VALUES ?wuC { } } } +24e2d640eb8b SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +251a657c96b2 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +25554a2d770e SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +25764463de3a SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +258e1bb27b55 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +25e35a116a7a SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +26597fe15d0e SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +26bf05053779 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +26ef89af73d7 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +276ce6ba94f0 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +27a652bc4a63 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +288129aa4dbe SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +294457930c79 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +29547f75bee0 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +296a0d00de9e SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +29735aa2afea SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +2a2add9e3c26 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +2ab8259a58d6 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +2b48a40c896d SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +2b58e51b6c3d SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +2bc13625bc04 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +2bcc64889ee4 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +2bec684879ca SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +2c9b021c5ece SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +2e32c0ffbc3c SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +2ecade927c68 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +2ece82229dce SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +2f7c9d07ed1a SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +2f9aec17c4e9 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +2fc1e89df154 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +2fdb9d27c845 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +2fe8928c9eac SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +30b8f06aa807 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +31d0f4e2be6f SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +320b9d0e5ff8 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +32747a1b563b SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +32cbf641e1bc SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +32f1aa55d0ea SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +3325fb88c1d7 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +337d970b0f07 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +33e4f401a9db SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +3484afc2016f SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +35e5e0379327 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +35eea760e846 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +3691010af47d SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +36f3da58361d SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +3735b227534b SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +373c4f087d16 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { VALUES ?flowline { } ?flowline rdf:type hyf:HY_FlowPath ; geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +377f854f6cc6 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +37c324b2fb11 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +38cb444f42f8 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +39419051512e SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +396a2519092b SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor (kwg-ont:sfTouches | owl:sameAs)/(kwg-ont:sfTouches | owl:sameAs) ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +39f68d9178a5 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +3a19b33e3025 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +3a2bb0cd96e0 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +3a5de06aa701 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +3ac013fb1120 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +3b68e8810ae7 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +3b88da2bc6f2 SELECT DISTINCT ?waterBody ?wbWKT ?wbName ?ftype ?comid ?reachcode ?fcode ?s2cell WHERE { VALUES ?waterBody { } ?s2cell spatial:connectedTo ?waterBody ; rdf:type kwg-ont:S2Cell_Level13 . ?waterBody rdf:type hyf:HY_WaterBody ; geo:hasGeometry/geo:asWKT ?wbWKT . OPTIONAL { ?waterBody schema:name ?wbName . } OPTIONAL { ?waterBody nhdplusv2:hasFTYPE ?ftype . } OPTIONAL { ?waterBody nhdplusv2:hasCOMID ?comid . } OPTIONAL { ?waterBody nhdplusv2:hasReachCode ?reachcode . } OPTIONAL { ?waterBody nhdplusv2:hasFCODE ?fcode . } } +3bcbbc61caae SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +3bce92acebce SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +3c4091f51398 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +3c6a4d4ad1b9 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +3cdf1859eeef SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +3da8119633c2 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { VALUES ?flowline { } ?flowline rdf:type hyf:HY_FlowPath ; geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } VALUES ?fl_type { "460" } } +3dbb4fd45439 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +3de8c144de70 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +3e4c26e61ee4 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +404c3355f3fd SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +409740b46fb7 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +40a495b7a46a SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +40c7bc3ecc04 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +41ca24011057 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +423d5033fc48 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +42fba0d6b6e4 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +436d3320d910 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +440f71464197 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +454a12d54a4b SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +46bc1db1c4db SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +4786e399d0e3 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +481ef65eaf6e SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +48a5326856de SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +48bc512f5a3a SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) } GROUP BY ?sp ?spWKT ?s2cell +4a22e1a87031 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +4ae27f7b3056 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +4b6cc3a024ee SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +4bc79000b146 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +4ca2878d179f SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +4cd25d8b0a3e SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +4cf300178a3d SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +4d08a3f185ec SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +4dee4c0f482e SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +4e22903dafb8 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +4eb7e82611af SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +4ef4712a6813 SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) VALUES ?substance { } FILTER(BOUND(?numericResult)) } GROUP BY ?sp ?spWKT ?s2cell +4f5453f9e32d SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +4feabc0eeaca SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +5005fd5c331c SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +50885dc7a1b9 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +50a3fd88e46f SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +50afef424c69 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +50e13b4749a3 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +5109f240a9f0 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +5151a972eede SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +518849e03a5b SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +52f8acbda00d SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +53706371792a SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +5393441889bb SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +542cd3bf0080 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +54b1d508458d SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +5515bd777411 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +55f5714d004c SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +56c5b92ab83e SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +56ea6a34453b SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +56f38a86aec7 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +57420cc1d1e2 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +581c48ae304e SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +58c16900aa65 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +592bae86ed3a SELECT DISTINCT (?wellA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +59aee765110c SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +59b91de5e995 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +5a01b1674751 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +5a03f4f3aae3 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +5a98acf98b84 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +5ab06945d883 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +5abc07c304ad SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +5aedb347a53b SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +5bb2d62da8a0 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +5c0972841eb9 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . BIND(?s2anchor AS ?s2target) ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +5c5c06fd1d35 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +5c6cc33fae88 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +5dbe52083d8c SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +5de1200d2e01 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +5dfec1ecf571 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +5e175b050654 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +5f95683d03c3 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +60802b6a7386 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +614ca43f8807 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +6203bb98fd9b SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +629f7809931c SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +62aa5619bc67 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +62f130505471 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +6316b038687c SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +631a69b1a6a7 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +63fd9d8c7d26 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +642252450459 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +64a08a171f7d SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +6537d90d135f SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +659f6c7fa3f9 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +66321d87ce37 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +663f948f7bf0 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +666e8b5700a2 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +66b8cb8fd320 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +66c78fc2515a SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +672355872582 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +67b90dec7f24 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +69f0475ae80a SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +6a8f8b9351bc SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +6ac9015a260c SELECT DISTINCT (?spA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +6ad2a8fa8e74 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +6b0632214d35 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +6b13c5e7d199 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +6b18905b32f2 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +6c90238c34b5 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +6cab754cbe12 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +6cc73e470a1e SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +6da1ed2de01d SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +6dda347a097f SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +6ddb9c48525a SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +6e59770323b3 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +6e6e6eba070d SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +6e78232de987 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +6ed5aed4968a SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +6ede512b148d SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +6f09d7bbdcc7 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +6ff4852b422e SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +70123c8b61f0 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +7087d0c06d24 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +70ac417804f8 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +713a1f7f8ae5 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +714064e8e781 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +719474b95b24 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +71f036d9cd02 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +73511fbb8c8f SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +73934d7aae0d SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +73c37175d3a3 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +74340ac75507 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +748a8ca41a32 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +74c3d0bb8bf8 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +74f6726cb460 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +751b01f1248c SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +7530ba837a17 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +7604a06153a0 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +7658df86ebfb SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +776babccec7b SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +77f682fb65ef SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +789f1ded1d8a SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +78d85e00dcd9 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +78dcb9fb3928 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +78e1f8a446f0 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +790b26da2a79 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +794a5c139565 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +79b82d9e0fe1 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +79e0bd042512 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +7aa05f4cf432 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +7ab11f2c9448 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +7b1c835798e7 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) } +7b5980388f2c SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +7b8a451b6ce6 SELECT DISTINCT ?facility ?facWKT ?facilityName ?industryCode ?industryName ?s2cell WHERE { VALUES ?facility { } ?s2cell kwg-ont:sfContains ?facility ; rdf:type kwg-ont:S2Cell_Level13 . ?facility fio:ofIndustry ?industryCode ; geo:hasGeometry/geo:asWKT ?facWKT ; rdfs:label ?facilityName . ?industryCode a naics:NAICS-IndustryCode ; rdfs:label ?industryName . } +7c9c4702ede4 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +7cb722edd17a SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +7d5fd908795e SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +7d7f1e7d7c60 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +7dad41fdfd60 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +802d35965666 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +80df1fdbcf14 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +81325b745fd1 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +8138a7e702af SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +81641e7d1349 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +82022c612381 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +827004d998b2 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +832afed999c2 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +83a09bfc0c0a SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +83d77a45d03c SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +84faebbbe4de SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +8529b7fb6ffa SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +86920d0a3b5f SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) } GROUP BY ?sp ?spWKT ?s2cell +86a26ec60121 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +871365cea3c3 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +8758a29be4cd SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +875d5698ab94 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +878b7218cf7c SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +886826560be6 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +887006d733eb SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +889f03c020e8 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +88a05eee9640 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +88b94aeb229d SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +88d952d2a2c5 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +8952d69eebf7 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +898bd716c54a SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +8a0c2df70ce0 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +8a1266fbf3b4 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +8a8df61dddeb SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +8abd2faf7bb0 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +8b7cd81ea5cf SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +8becca5939ec SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +8c23d3755445 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +8c6ab3d31bf7 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +8c90b6016e50 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +8cb4f136fa6e SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +8d3c6166926c SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +8db700fbc3ba SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +8dfa184e0d2b SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +8e0f26314aa4 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +8e23014aa73f SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +8e369b7deccc SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +8e74bfffca28 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . VALUES ?_regionA { kwgr:administrativeRegion.USA.23005 kwgr:administrativeRegion.USA.23019 } ?s2anchor spatial:connectedTo ?_regionA . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23019 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +8ef73aad6fa9 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +8f5c7dd5246f SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +8fbe3088c265 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +9039e57855e1 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +907b64185777 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +90d0a0452943 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +90d82873e3c0 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +90f83102d132 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +91f383f2621e SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +920687fc77ed SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +934aca1f2f29 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +934d8ac6f612 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +935860c79d56 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +93ba832c29d7 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +93c67796bf6d SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +9498222e580a SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?aquiferA saw_water:aquiferType ?aqTypeA . VALUES ?aqTypeA { "bedrock" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type me_mgs:MGS-Well . ?wellC me_mgs:hasUse ?wuC . VALUES ?wuC { } } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +94b023ca04bf SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +94d434376702 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +950c0e678218 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +9575a458430b SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +95fe8b8c33ba SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +962a202132fc SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +968075df2792 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +96f67a03be24 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +970a4ae75376 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +977ce19228f3 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +9813a80e0c5a SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +98b1603dafe4 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +98d7c72d4aab SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +9968e7786c81 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +99dd9196dcc8 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +9a0037a928d9 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +9a08433a48e0 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +9b750fdb6a09 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +9ba66fec62a1 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +9c03aae08c7b SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +9c73285f224c SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +9e253e2c142d SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +9e8aee90f1eb SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +9ef048145cc3 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . VALUES ?substanceC { } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +9f5c1bba715e SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +9f955f3f75d5 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +a01b1b84351c SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . BIND(?s2anchor AS ?s2target) ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +a0d6980914ac SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +a1a3610cba42 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +a28356585b79 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +a3823ffd8794 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +a3ac25aca5df SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +a408ff1eb89d SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +a4e3147c72d7 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +a4f6491c0e2c SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +a548c30613f2 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +a62588d4bcb9 SELECT DISTINCT (?spA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +a735c3a3bff6 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +a79808637aab SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +a7b1fa7dc839 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +a7b4475fa918 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +a7ba4bf786b6 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +a7c3f2ccff0c SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +a7e872d51a0f SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +a963e5be882c SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +a99936a88d0b SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +aa5fdb59ec6f SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +aa8204e520fc SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +aadf4d36b6ad SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor (kwg-ont:sfTouches | owl:sameAs)/(kwg-ont:sfTouches | owl:sameAs) ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +aae1eb735bf1 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +ab4e12addc23 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +ab7cba78e7a4 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +abac476ba422 SELECT (COUNT(DISTINCT ?observation) as ?resultCount) (COUNT(DISTINCT ?sample) as ?sampleCount) (MAX(?numericResult) as ?max) (GROUP_CONCAT(DISTINCT ?substance; separator="; ") as ?substances) (GROUP_CONCAT(DISTINCT ?matTypeLabel; separator="; ") as ?materials) (SAMPLE(?spName) as ?samplePointName) ?sp ?spWKT ?s2cell WHERE { VALUES ?sp { } ?sp spatial:connectedTo ?s2cell ; geo:hasGeometry/geo:asWKT ?spWKT . OPTIONAL { ?sp rdfs:label ?spName } ?s2cell rdf:type kwg-ont:S2Cell_Level13 . ?observation rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?sp ; coso:ofDSSToxSubstance ?substance ; coso:analyzedSample ?sample ; coso:hasResult ?result . ?sample rdfs:label ?sampleLabel ; coso:sampleOfMaterialType ?matType . ?matType rdfs:label ?matTypeLabel . OPTIONAL { ?result qudt:quantityValue/qudt:numericValue ?numericResult } OPTIONAL { ?result qudt:quantityValue ?_qv . ?_qv rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetect) } BIND(COALESCE(STR(?numericResult), IF(BOUND(?nonDetect), "non-detect", "non-quantified")) AS ?result_value) VALUES ?substance { } } GROUP BY ?sp ?spWKT ?s2cell +ac1966b9691f SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +ac7ebc96d761 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +ac87cac97a08 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +ade4600c7066 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +aeb350c37047 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { VALUES ?flowline { } ?flowline rdf:type hyf:HY_FlowPath ; geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +aec41960948e SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +af3062364f60 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +b0335b863895 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +b0f01594fdb4 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +b0f1db6f8073 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +b22e14df0511 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +b2a4e26f4048 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +b2a9610b7c52 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +b3c1864cf554 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +b4008588edaf SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +b43c08af1964 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +b44db2e80018 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +b45c05b3136a SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +b4f373f3b10c SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) } +b57ca9e8c32e SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +b58c8c35f1eb SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +b679bd47f6b1 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +b6893ae200af SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +b6983d91a529 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +b6d4297f115e SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +b6f2102221d1 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +b6f61e4f4ff3 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +b7423f86a11e SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +b948c1dadad5 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +b97f4349ba61 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +b9d0126bda7a SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +b9d52f76c5da SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +ba778257a97f SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +ba8393ad2e9d SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +bac0c29c4f57 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +bba05a0302fc SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +bba7273cdba4 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +bc5e31538d28 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +bd10519b155e SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +bd4eab4c6f66 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +be142639d65c SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +be1b15d1b106 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +be59394dac59 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +bea267f2f762 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +bea7dc72f773 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +bf2ceb812bdb SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +bf6a1a426eb1 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +bf8ffdfa1ad9 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +c06847a4af0d SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +c0f56f77ba8f SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +c1449fc486a8 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +c1505f76d1a2 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +c1711127344f SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +c339d1c42d50 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +c35d18356b27 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +c36613529a50 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +c449e2e870bf SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +c498321cc486 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +c547f4e0656f SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +c5ae9f5fc826 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +c5ba856ac5a5 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +c6129be91792 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +c668a2061d6c SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +c80d21e0d32d SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +c8190383299a SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches/kwg-ont:sfTouches/kwg-ont:sfTouches/kwg-ont:sfTouches ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +c8295f7305c1 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +c85fdb421ca6 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +c8b9648ad9ad SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +c90f839ad3a4 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +c9531cc6fbe2 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +ca1086992b60 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +ca528e8925b8 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +cb961f64c07f SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +cbb05158da0c SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +cc4b39ebe0a2 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +cd1d79f23ba8 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +cd57b7a763e6 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +cdddd6bdf1d7 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +ce0c65a4578d SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +ceaa643cf456 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +cf073b1ce3f0 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +cf808bb25a1f SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +cfe6f604cde9 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +d01ac74e4cc0 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +d0422a3a1b39 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +d1b9348ef98d SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +d271f8200100 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +d2b20fc4e76d SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +d2cd8e8cafdf SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +d335a3eda455 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +d4ff9a18f9cf SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +d52aaecf97fa SELECT ?region (SAMPLE(?_name) AS ?regionName) (SAMPLE(?_wkt) AS ?regionWKT) WHERE { ?region kwg-ont:administrativePartOf kwgr:administrativeRegion.USA.23 ; rdfs:label ?_name ; geo:hasGeometry/geo:asWKT ?_wkt . FILTER(STRSTARTS(STR(?region), STR(kwgr:))) } GROUP BY ?region +d58893c96966 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +d7635cc00d76 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +d7ee9691da5b SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +d913d9d71840 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +d98072521790 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +da7010fa25fd SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +da77e9a226ae SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +daae4206ce0f SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +daaf4827bae1 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +dc18ede4eeac SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +dc4d5d46d3f1 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +dc584e6cfe79 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +dcf4ba3a467c SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +dd8ee4b54845 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +dda55e8be700 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +ddfaa9f20f19 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +dfffea098028 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +e0c43ef101a2 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?facilityA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +e0d3a87dd863 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +e0f406bc2dd6 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +e0f6624fc264 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +e13c4295e7b0 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +e1ccb826ce9b SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +e238ca8606c2 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +e2b3d9f8c117 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +e30770406b41 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +e3bb217bc214 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +e45a36c23efe SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +e466cf40dd85 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +e4b7f27cdd3e SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +e5376ca0aa0a SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } +e5836fc46bf4 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +e68708fa1d30 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +e6e5f175099a SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +e6eca666d07e SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +e710b494417c SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +e792abfe6ef8 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +e7e2854c8ae7 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +e8b95c8c5b5d SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +e933a835c975 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +e93784de47f2 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +e9b13461268b SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +ea51101cddd0 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . VALUES ?_regionA { kwgr:administrativeRegion.USA.23005 kwgr:administrativeRegion.USA.23019 } ?s2anchor spatial:connectedTo ?_regionA . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23019 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +ea51a457af43 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +eb3b32e6b88d SELECT DISTINCT ?aquifer ?aquiferType WHERE { VALUES ?aquifer { } ?aquifer rdf:type gwml2:GW_Aquifer . OPTIONAL { ?aquifer saw_water:aquiferType ?aquiferType . } } +eb7c41d74f46 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +ebbacce57f0e SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?spA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?aquiferC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +ebbb13c13f83 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +ec6ed949be4d SELECT DISTINCT ?facility ?facWKT ?facilityName ?industryCode ?industryName ?s2cell WHERE { VALUES ?facility { } ?s2cell kwg-ont:sfContains ?facility ; rdf:type kwg-ont:S2Cell_Level13 . ?facility fio:ofIndustry ?industryCode ; geo:hasGeometry/geo:asWKT ?facWKT ; rdfs:label ?facilityName . ?industryCode a naics:NAICS-IndustryCode ; rdfs:label ?industryName . } +ec935451ecfb SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +ece4d96de601 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +eda7f49eaf9d SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +edaa65a35aac SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches/kwg-ont:sfTouches/kwg-ont:sfTouches/kwg-ont:sfTouches ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +ee66561a00f7 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +ee767dadbf6f SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } } +eeb6a4be8d87 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +eedde23983a6 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +ef35db5ca18b SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +ef7f4d420285 SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +f015bfcba03e SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +f0c206010b68 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +f0d79c0a39c3 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +f15a49a11b96 SELECT DISTINCT ?facility ?facWKT ?facilityName ?industryCode ?industryName ?s2cell WHERE { VALUES ?facility { } ?s2cell kwg-ont:sfContains ?facility ; rdf:type kwg-ont:S2Cell_Level13 . ?facility fio:ofIndustry ?industryCode ; geo:hasGeometry/geo:asWKT ?facWKT ; rdfs:label ?facilityName . ?industryCode a naics:NAICS-IndustryCode ; rdfs:label ?industryName . VALUES ?selectedIndustry { naics:NAICS-562212 } FILTER(?industryCode = ?selectedIndustry || EXISTS { ?industryCode fio:subcodeOf ?selectedIndustry }) } +f1abbefd32dd SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +f1e4ac3d1adc SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +f2161e75506a SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } +f2ec010e4080 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +f484f51fbc63 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +f560ebd6282b SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +f56b87fc7251 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +f58221d89287 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } +f7a2dba8957d SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } +f80f83193d16 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +f878bab0aeba SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +f8a37eb37178 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +f8ce75f3f7ee SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +f8efc6828155 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +f996426f75e0 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23031 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) VALUES ?substanceC { } FILTER(BOUND(?numericResultC)) ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +f9a94dc1bcc9 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } +f9af91a7570a SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?wellC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +fa1833c58b13 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +fa5208b4f1f5 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } +fa96bd1b30f8 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } +faa0a03241cd SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } +fb42af7be1f5 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +fbcba6bb42a9 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +fc48809955c6 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } BIND(?ds_flowline AS ?streamC) } +fcaea4147d56 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } +fd28138d5b69 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?facilityC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } +fe93660f9298 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . VALUES ?substanceC { } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } +ff0e8a4e0a65 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?aquiferA saw_water:aquiferType ?aqTypeA . VALUES ?aqTypeA { "bedrock" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type me_mgs:MGS-Well . ?wellC me_mgs:hasUse ?wuC . VALUES ?wuC { } } } +ff4f5433385d SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +ff746e2b17d8 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } diff --git a/scripts/check-query-snapshots.mts b/scripts/check-query-snapshots.mts new file mode 100644 index 0000000..c49ac59 --- /dev/null +++ b/scripts/check-query-snapshots.mts @@ -0,0 +1,333 @@ +// Golden-file snapshot of the SPARQL the planner generates, for every shape. +// +// npx tsx scripts/check-query-snapshots.mts # verify +// npx tsx scripts/check-query-snapshots.mts --update # re-record +// +// Why this exists: near and downstream/upstream share one query builder +// (buildFusedWhereBody in src/engine/templates/fusedQueries.ts takes a `mode` +// and differs only in the middle hop). Everything else -- entity binding, +// region clauses, IRI pinning, sample-observation joins -- is common. So a fix +// aimed at a trace bug silently rewrites the `near` queries too, and the only +// thing that noticed until now was a live sweep taking ~30 minutes. +// +// This records the generated SPARQL for every shape and fails on any diff. The +// diff is the point: an intentional change shows exactly which other shapes +// moved with it, then you --update. No network, runs in about a second. +// +// The grid has four axes, and every one of them earned its place by hiding a +// bug that the others could not see: +// +// entity pair (36) one builder serves all of them, so a fix aimed at +// one pair rewrites the rest +// relationship (3) near and the two hydrology directions share +// buildFusedWhereBody +// region placement (2) which block carries the region decides which side is +// "constrained", which decides the join order. An +// earlier version of this grid put the region on block +// A always; for an upstream question that makes the +// anchor the constrained side, so the target-first +// order was never recorded, and neither was the +// question that broke in the app (block A wide open, +// block C scoped to a county). +// flow-distance bound the bounded trace is a different query, not a +// (2, hydrology only) filtered one: it seeds an aggregate. With one bounded +// variant in the grid, the fix that moved every bounded +// shape showed up here as a single moved line. +// +// 6 x 6 x 3 x 2 = 216 unbounded, plus 6 x 6 x 2 x 2 = 144 bounded, plus the +// variants below that reach clauses the grid does not vary. +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync, existsSync } from 'node:fs'; +import { createHash } from 'node:crypto'; +import { planPipeline, type PipelineContext } from '../src/engine/planner'; +import { PREFIXES } from '../src/constants/prefixes'; +import type { AnalysisQuestion, EntityType, SpatialRelationship } from '../src/types/query'; + +const SNAPSHOT = new URL('./__snapshots__/query-shapes.txt', import.meta.url); + +const ENTITY_TYPES: EntityType[] = [ + 'samples', + 'facilities', + 'waterBodies', + 'wells', + 'aquifers', + 'streams', +]; +// 'within' is in the type union but RelationshipSelector never offers it. +const RELATIONSHIPS: SpatialRelationship['type'][] = ['near', 'downstream', 'upstream']; +const HYDROLOGY: SpatialRelationship['type'][] = ['downstream', 'upstream']; +// Which block carries the region. See the header: this is the axis that decides +// the join order, and it is not symmetric between the two relationship +// directions, because the planner maps block A to the anchor for an upstream +// question and to the target for a downstream one. +const REGION_ON = ['A', 'C'] as const; + +// Fixed IRIs so pinValues output is deterministic. Two entries: enough to show +// the VALUES clause and its ordering, short enough to stay readable. +const context = (question: AnalysisQuestion): PipelineContext => ({ + question, + targetIris: ['http://example.org/target/1', 'http://example.org/target/2'], + anchorIris: ['http://example.org/anchor/1', 'http://example.org/anchor/2'], + results: {}, +}); + +// Collapse whitespace: indentation churn is not a behaviour change and would +// bury the diffs that are. +// +// The shared PREFIX preamble is stripped for the same reason, plus one of its +// own: it is byte-identical in every query and was 66% of this file, so it made +// the snapshot three times the size it needs to be and pushed the part that +// varies off the side of every diff. It is recorded once, on its own, so a +// change to the prefix list still shows up as exactly one moved entry instead +// of moving all 360. +const collapse = (q: string) => q.replace(/\s+/g, ' ').trim(); +const PREFIX_BLOCK = collapse(PREFIXES); +const normalise = (q: string) => collapse(q).replace(PREFIX_BLOCK, '').trim(); + +// Query bodies are written once each, in a table at the end, and referenced by +// hash from the shapes above. 375 shapes reference 2,078 step queries but only +// 603 distinct ones — the region-boundary query alone is identical in 373 of +// them — so inlining every body made the file 2.6x larger and turned a one-line +// change to a shared query into 373 lines of diff. +const bodies = new Map(); +const BODIES_MARKER = '# ---- query bodies, one line per distinct query ----'; + +function record(name: string, question: AnalysisQuestion): string[] { + const lines = [`## ${name}`]; + const ctx = context(question); + for (const step of planPipeline(question)) { + const query = normalise(step.buildQuery(ctx)); + assert.ok(query.length > 0, `empty query: ${name} / ${step.type}`); + const hash = createHash('sha256').update(query).digest('hex').slice(0, 12); + bodies.set(hash, query); + lines.push(`${step.type} [${step.endpoint}] ${hash}`); + } + return lines; +} + +const shape = ( + a: EntityType, + rel: SpatialRelationship['type'], + c: EntityType, + relExtra: Partial = {}, + regionOn: (typeof REGION_ON)[number] = 'A', +): AnalysisQuestion => { + const region = { region: { stateCode: '23' } }; + return { + blockA: { type: a, ...(regionOn === 'A' ? region : {}) }, + relationship: { type: rel, ...(rel === 'near' ? { hops: 1 } : {}), ...relExtra }, + blockC: { type: c, ...(regionOn === 'C' ? region : {}) }, + } as AnalysisQuestion; +}; + +const out: string[] = [ + '# Generated by scripts/check-query-snapshots.mts -- do not hand-edit.', + '# Re-record with: npm run check-query-snapshots -- --update', + '', +]; + +// 0. The prefix preamble, recorded once because normalise() strips it. +out.push( + '## PREFIXES', + `SHARED [all] ${createHash('sha256').update(PREFIX_BLOCK).digest('hex').slice(0, 12)}`, + ` ${PREFIX_BLOCK}`, +); + +// 1. Every entity pair x relationship x region placement: 6 x 6 x 3 x 2 = 216. +for (const a of ENTITY_TYPES) { + for (const c of ENTITY_TYPES) { + for (const rel of RELATIONSHIPS) { + for (const on of REGION_ON) { + out.push(...record(`${a} ${rel} ${c} [ME on ${on}]`, shape(a, rel, c, {}, on))); + } + } + } +} + +// 2. The hydrology pairs again with a flow-distance bound: 6 x 6 x 2 x 2 = 144. +// `near` has no flow bound; its distance axis is hops, covered in the variants. +for (const a of ENTITY_TYPES) { + for (const c of ENTITY_TYPES) { + for (const rel of HYDROLOGY) { + for (const on of REGION_ON) { + out.push( + ...record(`${a} ${rel}(30km) ${c} [ME on ${on}]`, shape(a, rel, c, { maxDistanceKm: 30 }, on)), + ); + } + } + } +} + +// 3. The variants that reach clauses the grid above does not vary: hop counts, +// the per-type filter blocks, and the exact questions that have broken in the +// app. A change to any of these is the class of change that crosses +// relationship boundaries. +const PFOS = 'http://w3id.org/DSSTox/v1/DTXSID3031864'; +const YORK = { stateCode: '23', countyCodes: ['23031'] }; +const variants: Array<[string, AnalysisQuestion]> = [ + ['near hops=0', shape('samples', 'near', 'facilities', { hops: 0 })], + ['near hops=2', shape('samples', 'near', 'facilities', { hops: 2 })], + ['near hops=4', shape('samples', 'near', 'facilities', { hops: 4 })], + ['downstream maxDistanceKm=10', shape('samples', 'downstream', 'facilities', { maxDistanceKm: 10 })], + ['upstream maxDistanceKm=10', shape('samples', 'upstream', 'facilities', { maxDistanceKm: 10 })], + // The question behind #55 and #57, in the two states it is asked in. Block A + // carries nothing at all, which is what makes it the expensive shape: the + // trace has to be seeded from block C or it starts from every facility in + // the graph. Recorded bounded and unbounded because those are two different + // queries, not one query with a filter. + [ + 'PI question: facilities upstream from PFOS samples in York, detections only', + { + blockA: { type: 'facilities' }, + relationship: { type: 'upstream' }, + blockC: { + type: 'samples', + region: YORK, + sampleFilters: { substances: [PFOS], includeNondetects: false }, + }, + } as AnalysisQuestion, + ], + [ + 'PI question, bounded to 30km of flow', + { + blockA: { type: 'facilities' }, + relationship: { type: 'upstream', maxDistanceKm: 30 }, + blockC: { + type: 'samples', + region: YORK, + sampleFilters: { substances: [PFOS], includeNondetects: false }, + }, + } as AnalysisQuestion, + ], + // The two sample-filter shapes that decide whether the observation chain is + // joined at all. Substance-only is the common case and is what the + // coso:measurementUnit join silently filtered; non-detects-off is the only + // filter that adds the result clauses without adding the unit join. + [ + 'samples substance filter only', + { + blockA: { type: 'samples', region: { stateCode: '23' }, sampleFilters: { substances: [PFOS] } }, + relationship: { type: 'downstream' }, + blockC: { type: 'facilities' }, + } as AnalysisQuestion, + ], + [ + 'samples include-nondetects off only', + { + blockA: { type: 'samples', region: { stateCode: '23' }, sampleFilters: { includeNondetects: false } }, + relationship: { type: 'downstream' }, + blockC: { type: 'facilities' }, + } as AnalysisQuestion, + ], + [ + 'no region either side', + { + blockA: { type: 'samples' }, + relationship: { type: 'downstream' }, + blockC: { type: 'facilities' }, + } as AnalysisQuestion, + ], + [ + 'county-scoped both sides', + { + blockA: { type: 'samples', region: { stateCode: '23', countyCodes: ['23019'] } }, + relationship: { type: 'near', hops: 1 }, + blockC: { type: 'facilities', region: { stateCode: '23', countyCodes: ['23005', '23019'] } }, + } as AnalysisQuestion, + ], + [ + 'sample filters', + { + blockA: { + type: 'samples', + region: { stateCode: '23' }, + sampleFilters: { + substances: ['http://sawgraph.spatialai.org/v1/pfas#PFHpA'], + materialTypes: ['http://sawgraph.spatialai.org/v1/me-egad-data#Groundwater'], + minConcentration: 4, + maxConcentration: 100, + unit: 'ng/L', + includeNondetects: false, + }, + }, + relationship: { type: 'downstream' }, + blockC: { type: 'facilities', facilityFilters: { industryCodes: ['562212'] } }, + } as AnalysisQuestion, + ], + [ + 'facility + water body + well + aquifer filters', + { + blockA: { type: 'wells', region: { stateCode: '23' }, wellFilters: { wellCategories: ['meUse||http://example.org/use/Domestic'] } }, + relationship: { type: 'near', hops: 1 }, + blockC: { type: 'aquifers', aquiferFilters: { aquiferTypes: ['bedrock'] } }, + } as AnalysisQuestion, + ], + [ + 'stream ftype filter as target', + { + blockA: { type: 'samples', region: { stateCode: '23' } }, + relationship: { type: 'downstream' }, + blockC: { type: 'streams', streamFilters: { ftypes: ['460'] } }, + } as AnalysisQuestion, + ], +]; +for (const [name, question] of variants) out.push(...record(`VARIANT: ${name}`, question)); + +// Every distinct query body, sorted by hash so the table has a stable order and +// a new query lands as one added line rather than reshuffling the file. +out.push('', BODIES_MARKER); +for (const [hash, query] of [...bodies].sort(([a], [b]) => a.localeCompare(b))) { + out.push(`${hash} ${query}`); +} + +const next = out.join('\n') + '\n'; +const update = process.argv.includes('--update'); + +if (update || !existsSync(SNAPSHOT)) { + writeFileSync(SNAPSHOT, next); + console.log(`${update ? 'Re-recorded' : 'Recorded'} ${out.filter((l) => l.startsWith('## ')).length} shapes.`); + process.exit(0); +} + +const prev = readFileSync(SNAPSHOT, 'utf8'); +if (prev === next) { + console.log(`OK: ${out.filter((l) => l.startsWith('## ')).length} shapes match the snapshot.`); + process.exit(0); +} + +// Report which shapes moved, grouped by relationship, so a "downstream fix" +// that also moved 36 near shapes says so in the first line of output. +// Shapes only: the body table at the end is keyed by content hash, so any +// change to a query already moves the hash of every shape that references it. +// Reporting the table as well would add a line of noise to every diff. +const headings = (text: string) => { + const map = new Map(); + let current = ''; + for (const line of text.split('\n')) { + if (line === BODIES_MARKER) break; + if (line.startsWith('## ')) current = line.slice(3); + else if (current) map.set(current, (map.get(current) ?? '') + line + '\n'); + } + return map; +}; +const before = headings(prev); +const after = headings(next); +const moved = [...after.keys()].filter((k) => before.get(k) !== after.get(k)); +const gone = [...before.keys()].filter((k) => !after.has(k)); + +// Bucket by every axis of the grid, not just the relationship: a change that +// moves only the bounded shapes, or only the ones scoped on block C, is saying +// something quite different from one that moves a whole relationship, and the +// first line of output should be enough to tell them apart. +const count = (names: string[], re: RegExp) => names.filter((n) => re.test(n)).length; +console.error(`Generated SPARQL changed for ${moved.length} shape(s)${gone.length ? `, ${gone.length} removed` : ''}:`); +console.error( + ` near ${count(moved, / near /)} downstream ${count(moved, / downstream[( ]/)} upstream ${count(moved, / upstream[( ]/)}` + + ` bounded ${count(moved, /\(30km\)/)} region on A ${count(moved, /\[ME on A\]/)} region on C ${count(moved, /\[ME on C\]/)}` + + ` variants ${count(moved, /^VARIANT/)}`, +); +for (const name of moved.slice(0, 40)) console.error(` - ${name}`); +if (moved.length > 40) console.error(` ... and ${moved.length - 40} more`); +console.error('\nIf every one of those is intended, re-record:'); +console.error(' npm run check-query-snapshots -- --update'); +process.exit(1); From 3de9eb2d3fc8359f61731f5c888615264bc83a20 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 01:11:02 -0400 Subject: [PATCH 62/66] docs(matrix): the warm before-and-after for the bounded seed-side fix Four MD sweeps. The result is 2 shapes fixed, 0 regressed, and it took three extra runs to be able to say that honestly. The first sweep (002e529, committed earlier) was cold, and the sweep taken after the fix was warm, so comparing them credited the fix with three flips. One of those three is `facilities upstream samples [ME on A] step1`, which is unbounded and anchor-constrained: the reorder cannot reach it, and the generated SPARQL is byte-identical at 1,950 characters either side of ec221d9. It times out cold and answers in 15s warm. That row is the cache, not the code. The cold sweep now carries a .note saying so. Re-running the pre-fix engine warm (e84a11f's src, current harness) gives the comparison that means something: pre-fix warm 12/32 pass post-fix warm 14/32 pass, identical in three consecutive runs FIXED facilities upstream(30km) samples [ME on C] step1 oom -> 3213 rows, 17s FIXED samples downstream(30km) facilities [ME on A] step1 oom -> 3213 rows, 15s REGRESSED none row-count drift where both pass none Both fixed rows are exactly the condition the reorder covers: bounded, with the constrained side on the target. All 8 bounded rows whose constrained side is the anchor are unchanged, which is the guard working. Three things the sweep says that the spot-check could not. Run-to-run noise is zero here. Three sweeps at identical code disagree on no row and report row counts identical to the unit, so a single flip in this file is signal, provided both halves are warm. Step 0 of both fixed shapes still fails. The fix lands on step 1 both times. These are statewide Maine with no filters, where the samples projection is the far heavier half; the York County question this started from passes both steps in 20s and 3s. Question size, not the reorder, but it means "bounded upstream questions work now" is false as a general claim. `facilities upstream(30km) streams [ME on C]` did not start passing. It changed failure mode, timeout to out-of-memory on step 0 and to a sort-estimate timeout on step 1. Worth knowing before anyone reads the two fixes as covering the bounded target-constrained case generally. Wells is unchanged on all four bounded combinations, as it was before, for its own reasons (W38 entry 12). --- .../2026-09-20-raw-002e529.csv.note | 7 ++++ docs/query-matrix/2026-09-20-raw-e84a11f.csv | 33 +++++++++++++++++++ docs/query-matrix/2026-09-20-raw-ec221d9.csv | 33 +++++++++++++++++++ docs/query-matrix/README.md | 10 ++++++ 4 files changed, 83 insertions(+) create mode 100644 docs/query-matrix/2026-09-20-raw-002e529.csv.note create mode 100644 docs/query-matrix/2026-09-20-raw-e84a11f.csv create mode 100644 docs/query-matrix/2026-09-20-raw-ec221d9.csv diff --git a/docs/query-matrix/2026-09-20-raw-002e529.csv.note b/docs/query-matrix/2026-09-20-raw-002e529.csv.note new file mode 100644 index 0000000..357b69e --- /dev/null +++ b/docs/query-matrix/2026-09-20-raw-002e529.csv.note @@ -0,0 +1,7 @@ +**Cold. Do not diff this against a later sweep on its own.** This was the first +MD sweep ever run, so every query in it missed the engine's cache, and the three +sweeps taken after it were all warm. One row moves on that difference alone: +`facilities upstream samples [ME on A] step1` times out here and answers in 15s +warm, with the generated SPARQL byte-identical (1,950 chars either side of +`ec221d9`). Read against `2026-09-20-raw-e84a11f.csv`, which re-runs the same +pre-fix engine warm, and is the honest before-half of that comparison. diff --git a/docs/query-matrix/2026-09-20-raw-e84a11f.csv b/docs/query-matrix/2026-09-20-raw-e84a11f.csv new file mode 100644 index 0000000..4867230 --- /dev/null +++ b/docs/query-matrix/2026-09-20-raw-e84a11f.csv @@ -0,0 +1,33 @@ +runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg +2026-09-20T04:57,4454b80,MD,"facilities upstream samples [ME on A] step0",facilities,upstream,,samples,ME on A,"none",FIND_TARGET_IRIS,federation,429,35192,0,111567,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T04:57,4454b80,MD,"facilities upstream samples [ME on A] step1",facilities,upstream,,samples,ME on A,"none",FIND_ANCHOR_IRIS,federation,200,15049,2652,257294,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream samples [ME on C] step0",facilities,upstream,,samples,ME on C,"none",FIND_TARGET_IRIS,federation,429,35304,0,108006,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"facilities upstream samples [ME on C] step1",facilities,upstream,,samples,ME on C,"none",FIND_ANCHOR_IRIS,federation,429,31895,0,107974,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) samples [ME on A] step0",facilities,upstream,,samples,ME on A,"30km",FIND_TARGET_IRIS,federation,200,22272,2399,238993,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) samples [ME on A] step1",facilities,upstream,,samples,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,8737,2523,244781,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) samples [ME on C] step0",facilities,upstream,,samples,ME on C,"30km",FIND_TARGET_IRIS,federation,429,30365,0,479272,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) samples [ME on C] step1",facilities,upstream,,samples,ME on C,"30km",FIND_ANCHOR_IRIS,federation,500,22988,0,479803,engine-oom,"Tried to allocate 2.1 GB, but only 1.2 GB were available" +2026-09-20T04:57,4454b80,MD,"facilities upstream streams [ME on A] step0",facilities,upstream,,streams,ME on A,"none",FIND_TARGET_IRIS,federation,200,15741,9632,749884,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream streams [ME on A] step1",facilities,upstream,,streams,ME on A,"none",FIND_ANCHOR_IRIS,federation,200,1336,2858,277276,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream streams [ME on C] step0",facilities,upstream,,streams,ME on C,"none",FIND_TARGET_IRIS,federation,200,17914,9502,739652,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream streams [ME on C] step1",facilities,upstream,,streams,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,3546,4056,393482,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) streams [ME on A] step0",facilities,upstream,,streams,ME on A,"30km",FIND_TARGET_IRIS,federation,200,11490,9110,709410,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) streams [ME on A] step1",facilities,upstream,,streams,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,1555,2858,277276,ok,"" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) streams [ME on C] step0",facilities,upstream,,streams,ME on C,"30km",FIND_TARGET_IRIS,federation,429,31331,0,479098,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) streams [ME on C] step1",facilities,upstream,,streams,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,31126,0,478929,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T04:57,4454b80,MD,"facilities upstream wells [ME on A] step0",facilities,upstream,,wells,ME on A,"none",FIND_TARGET_IRIS,federation,429,30580,0,117034,timeout-30s,"Operation timed out. Last operation: Join on ?ds_flowline" +2026-09-20T04:57,4454b80,MD,"facilities upstream wells [ME on A] step1",facilities,upstream,,wells,ME on A,"none",FIND_ANCHOR_IRIS,federation,500,18201,0,117149,engine-oom,"Tried to allocate 1.6 GB, but only 911.8 MB were available" +2026-09-20T04:57,4454b80,MD,"facilities upstream wells [ME on C] step0",facilities,upstream,,wells,ME on C,"none",FIND_TARGET_IRIS,federation,429,35003,0,111544,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"facilities upstream wells [ME on C] step1",facilities,upstream,,wells,ME on C,"none",FIND_ANCHOR_IRIS,federation,429,35129,0,111554,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) wells [ME on A] step0",facilities,upstream,,wells,ME on A,"30km",FIND_TARGET_IRIS,federation,429,30727,0,524032,timeout-30s,"Operation timed out. Last operation: GroupBy on ?_flEnd ?upstream_flowline" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) wells [ME on A] step1",facilities,upstream,,wells,ME on A,"30km",FIND_ANCHOR_IRIS,federation,429,30515,0,532240,timeout-30s,"Operation timed out. Last operation: Join on ?upstream_flowline" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) wells [ME on C] step0",facilities,upstream,,wells,ME on C,"30km",FIND_TARGET_IRIS,federation,429,31265,0,521767,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"facilities upstream(30km) wells [ME on C] step1",facilities,upstream,,wells,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,30485,0,526100,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"samples downstream facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"none",FIND_TARGET_IRIS,federation,500,26885,0,108100,engine-oom,"Tried to allocate 2.6 GB, but only 1.5 GB were available" +2026-09-20T04:57,4454b80,MD,"samples downstream facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"none",FIND_ANCHOR_IRIS,federation,429,31087,0,107966,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T04:57,4454b80,MD,"samples downstream facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"none",FIND_TARGET_IRIS,federation,429,33932,0,111521,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T04:57,4454b80,MD,"samples downstream facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,15537,2652,257294,ok,"" +2026-09-20T04:57,4454b80,MD,"samples downstream(30km) facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"30km",FIND_TARGET_IRIS,federation,429,30809,0,478795,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?_flMid" +2026-09-20T04:57,4454b80,MD,"samples downstream(30km) facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"30km",FIND_ANCHOR_IRIS,federation,500,27170,0,479799,engine-oom,"Tried to allocate 2.1 GB, but only 1.2 GB were available" +2026-09-20T04:57,4454b80,MD,"samples downstream(30km) facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"30km",FIND_TARGET_IRIS,federation,200,22030,2399,238993,ok,"" +2026-09-20T04:57,4454b80,MD,"samples downstream(30km) facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"30km",FIND_ANCHOR_IRIS,federation,200,8022,2523,244781,ok,"" diff --git a/docs/query-matrix/2026-09-20-raw-ec221d9.csv b/docs/query-matrix/2026-09-20-raw-ec221d9.csv new file mode 100644 index 0000000..ab2e982 --- /dev/null +++ b/docs/query-matrix/2026-09-20-raw-ec221d9.csv @@ -0,0 +1,33 @@ +runAt,commit,matrix,label,blockA,rel,hops,blockC,region,filters,step,endpoint,status,ms,rows,bytes,errorClass,errorMsg +2026-09-20T03:59,ec221d9,MD,"facilities upstream samples [ME on A] step0",facilities,upstream,,samples,ME on A,"none",FIND_TARGET_IRIS,federation,429,34883,0,111567,timeout-30s,"Operation timed out. Last operation: Sort (internal order) on ?s2anchor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream samples [ME on A] step1",facilities,upstream,,samples,ME on A,"none",FIND_ANCHOR_IRIS,federation,200,15632,2652,257294,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream samples [ME on C] step0",facilities,upstream,,samples,ME on C,"none",FIND_TARGET_IRIS,federation,429,32842,0,108003,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream samples [ME on C] step1",facilities,upstream,,samples,ME on C,"none",FIND_ANCHOR_IRIS,federation,429,33502,0,107965,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) samples [ME on A] step0",facilities,upstream,,samples,ME on A,"30km",FIND_TARGET_IRIS,federation,200,23001,2399,238993,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) samples [ME on A] step1",facilities,upstream,,samples,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,9362,2523,244781,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) samples [ME on C] step0",facilities,upstream,,samples,ME on C,"30km",FIND_TARGET_IRIS,federation,429,30290,0,366814,timeout-30s,"Operation timed out. Last operation: Join on ?s2anchor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) samples [ME on C] step1",facilities,upstream,,samples,ME on C,"30km",FIND_ANCHOR_IRIS,federation,200,17243,3213,311711,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream streams [ME on A] step0",facilities,upstream,,streams,ME on A,"none",FIND_TARGET_IRIS,federation,200,15779,9632,749884,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream streams [ME on A] step1",facilities,upstream,,streams,ME on A,"none",FIND_ANCHOR_IRIS,federation,200,1242,2858,277276,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream streams [ME on C] step0",facilities,upstream,,streams,ME on C,"none",FIND_TARGET_IRIS,federation,200,11135,9502,739652,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream streams [ME on C] step1",facilities,upstream,,streams,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,3565,4056,393482,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) streams [ME on A] step0",facilities,upstream,,streams,ME on A,"30km",FIND_TARGET_IRIS,federation,200,11488,9110,709410,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) streams [ME on A] step1",facilities,upstream,,streams,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,1433,2858,277276,ok,"" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) streams [ME on C] step0",facilities,upstream,,streams,ME on C,"30km",FIND_TARGET_IRIS,federation,500,23847,0,360813,engine-oom,"Tried to allocate 3.9 GB, but only 2.6 GB were available" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) streams [ME on C] step1",facilities,upstream,,streams,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,30612,0,361262,timeout-sort-estimate,"Sort operation was canceled, because time estimate exceeded remaining time by a factor of 3 Last operation: Sort (internal order) on ?_flEnd ?ds_flowline" +2026-09-20T03:59,ec221d9,MD,"facilities upstream wells [ME on A] step0",facilities,upstream,,wells,ME on A,"none",FIND_TARGET_IRIS,federation,429,30551,0,117000,timeout-30s,"Operation timed out. Last operation: Join on ?ds_flowline" +2026-09-20T03:59,ec221d9,MD,"facilities upstream wells [ME on A] step1",facilities,upstream,,wells,ME on A,"none",FIND_ANCHOR_IRIS,federation,500,17749,0,117117,engine-oom,"Tried to allocate 1.6 GB, but only 911.8 MB were available" +2026-09-20T03:59,ec221d9,MD,"facilities upstream wells [ME on C] step0",facilities,upstream,,wells,ME on C,"none",FIND_TARGET_IRIS,federation,429,34370,0,111544,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream wells [ME on C] step1",facilities,upstream,,wells,ME on C,"none",FIND_ANCHOR_IRIS,federation,429,34232,0,111553,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) wells [ME on A] step0",facilities,upstream,,wells,ME on A,"30km",FIND_TARGET_IRIS,federation,429,30417,0,532214,timeout-30s,"Operation timed out. Last operation: Join on ?upstream_flowline" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) wells [ME on A] step1",facilities,upstream,,wells,ME on A,"30km",FIND_ANCHOR_IRIS,federation,429,31453,0,532547,timeout-30s,"Operation timed out. Last operation: Join on ?s2anchor" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) wells [ME on C] step0",facilities,upstream,,wells,ME on C,"30km",FIND_TARGET_IRIS,federation,429,30844,0,415612,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T03:59,ec221d9,MD,"facilities upstream(30km) wells [ME on C] step1",facilities,upstream,,wells,ME on C,"30km",FIND_ANCHOR_IRIS,federation,429,30814,0,415634,timeout-30s,"Operation timed out. Last operation: Join on ?_flMid" +2026-09-20T03:59,ec221d9,MD,"samples downstream facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"none",FIND_TARGET_IRIS,federation,429,31277,0,108000,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"samples downstream facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"none",FIND_ANCHOR_IRIS,federation,429,31232,0,107964,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"samples downstream facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"none",FIND_TARGET_IRIS,federation,429,30242,0,111522,timeout-30s,"Operation timed out. Last operation: Join on ?s2anchor" +2026-09-20T03:59,ec221d9,MD,"samples downstream facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"none",FIND_ANCHOR_IRIS,federation,200,3934,2652,257294,ok,"" +2026-09-20T03:59,ec221d9,MD,"samples downstream(30km) facilities [ME on A] step0",samples,downstream,,facilities,ME on A,"30km",FIND_TARGET_IRIS,federation,429,30332,0,368309,timeout-30s,"Operation timed out. Last operation: Join on ?s2neighbor" +2026-09-20T03:59,ec221d9,MD,"samples downstream(30km) facilities [ME on A] step1",samples,downstream,,facilities,ME on A,"30km",FIND_ANCHOR_IRIS,federation,200,15649,3213,311711,ok,"" +2026-09-20T03:59,ec221d9,MD,"samples downstream(30km) facilities [ME on C] step0",samples,downstream,,facilities,ME on C,"30km",FIND_TARGET_IRIS,federation,200,19627,2399,238993,ok,"" +2026-09-20T03:59,ec221d9,MD,"samples downstream(30km) facilities [ME on C] step1",samples,downstream,,facilities,ME on C,"30km",FIND_ANCHOR_IRIS,federation,200,8464,2523,244781,ok,"" diff --git a/docs/query-matrix/README.md b/docs/query-matrix/README.md index f8b28ec..427f9e2 100644 --- a/docs/query-matrix/README.md +++ b/docs/query-matrix/README.md @@ -16,6 +16,8 @@ engine change. The two are not comparable row for row. | Sweep | Mode | Commit | Shapes | Pass | Fail | Since the previous sweep | | --- | --- | --- | ---: | ---: | ---: | --- | +| [`2026-09-20`](./2026-09-20-raw-e84a11f.csv) | raw | `e84a11f` | 32 | 12 | 20 | **2 broke** (facilities upstream(30km) samples [ME on C] step1, samples downstream(30km) facilities [ME on A] step1) | +| [`2026-09-20`](./2026-09-20-raw-ec221d9.csv) | raw | `ec221d9` | 32 | 14 | 18 | 3 fixed | | [`2026-09-20`](./2026-09-20-raw-002e529.csv) | raw | `002e529` | 32 | 11 | 21 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-raw-baseline.csv) | raw-baseline | `unrecorded` | 124 | 87 | 37 | _first sweep in this mode_ | | [`2026-09-14`](./2026-09-14-engine.csv) | engine | `unrecorded` | 124 | 112 | 9 | _first sweep in this mode_ | @@ -23,6 +25,14 @@ engine change. The two are not comparable row for row. ## Notes +**[`2026-09-20-raw-002e529.csv`](./2026-09-20-raw-002e529.csv)** — **Cold. Do not diff this against a later sweep on its own.** This was the first +MD sweep ever run, so every query in it missed the engine's cache, and the three +sweeps taken after it were all warm. One row moves on that difference alone: +`facilities upstream samples [ME on A] step1` times out here and answers in 15s +warm, with the generated SPARQL byte-identical (1,950 chars either side of +`ec221d9`). Read against `2026-09-20-raw-e84a11f.csv`, which re-runs the same +pre-fix engine warm, and is the honest before-half of that comparison. + **[`2026-09-14-engine.csv`](./2026-09-14-engine.csv)** — **The 25 `upstream` rows measured the wrong question.** Every upstream shape traced the relation backwards until 2026-09-16 (`docs/DEBUGGING.md`, 2026-09-16), so their status, timing and row counts describe the mirror From 0abdc49931a3dcb3fa2a242aa5faeb492d0f702c Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 01:13:38 -0400 Subject: [PATCH 63/66] docs: the seed-side fix, the sweep that could not see it, and two traps QUERY-MATRIX.md gains Part 10: what the flow-distance bound was doing, the one-variable isolation (block A wide open gives a 4.3 GB allocation failure, block A scoped to York County gives 1,429 rows in 4s), the warm-against-warm before and after, and what the fix does not do. DEBUGGING.md gains a 2026-09-20 entry with the root cause, the reachability tripwire that replaced a string blacklist a correct query now trips, and the two measurement traps this cost: comparing a cold sweep against a warm one, and measuring an endpoint while your own pipeline run is hammering it. W38 entries 15 and 16. Entry 15 states the limits in the entry rather than leaving them to be found: step 0 of the statewide shapes still fails, both rescued rows are step 1, the streams shape changed failure mode rather than passing, and wells is untouched. --- docs/DEBUGGING.md | 83 ++++++++++++++++++++++++++++++++++++ docs/QUERY-MATRIX.md | 86 ++++++++++++++++++++++++++++++++++++++ docs/changelog/2026-W38.md | 26 ++++++++++++ 3 files changed, 195 insertions(+) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 7597e78..cc84b92 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -648,3 +648,86 @@ already led with. It is now one exported `blockIsFiltered`. - **"Stop at the cutoff" and "stop where it stops mattering" are different bounds.** A distance cap looked like it should have prevented this and did not, because the wrong basin was well within range. + +## 2026-09-20: A distance bound failed whenever block A was left open (FIXED) + +Picking any "within N km of flow" on "what facilities are upstream from PFOS +samples in York County" returned nothing. Every option, 5, 10 and 30 km, both +projections, six queries, six identical failures: HTTP 429 carrying +`Operation timed out. Last operation: Query planning`. Note *planning*, not +execution. The engine could not even build a plan inside its 30s budget. + +**The bound was not the problem; the side it seeded from was.** The +constrained-side-first reorder that landed on 2026-09-17 deliberately skipped +bounded queries, with a comment recording that the shape had not been measured +either way. It has now. `boundedTrace` duplicates its seed block inside an +aggregate that sums `nhdplusv2:hasFlowPathLength` across two +`hyf:downstreamFlowPathTC` hops, so seeding the unconstrained side sums path +lengths over the national flowline graph. With block A left as plain Facilities +that seed is 1,506,326 facilities. + +Isolated by varying one thing. Same 30 km bound, same target type, only the +block A scope differing: + +| Block A | Result | +| --- | --- | +| wide open | 500, tried to allocate 4.3 GB | +| scoped to York County | 1,429 rows in 4s | + +And the control that proves bounded queries were fine in general: the Cook +County dashboard question, whose block A carries both a county and a NAICS +filter, answers in 28s and 6s throughout. + +**The fix** gives `boundedTrace` a seed side and drops one clause from the +guard, so a bounded trace is reordered by the same rule as everything else. The +trace, the `GROUP BY` and the `+1` fringe all follow the seed. The fringe still +extends away from the seed, which means the physical end that receives the extra +segment follows the seed side; on a question where both forms run, the result +sets were identical, so nothing observable turns on it. + +Measured before trusting the speed: + +- where both forms run, identical IRI sets on both projections +- against the unbounded answer, the bounded one is a strict subset, 918 of 1,494 + facilities, 0 added +- across 5, 10, 30 and 50 km the answers nest, each bound's set inside the next +- the York question answers in 20s and 3s, 132 samples and 918 facilities, + against two 429s before + +**What it did not fix.** Step 0 of the statewide MD shapes still fails; both +rescued rows are step 1. `facilities upstream(30km) streams [ME on C]` changed +failure mode rather than passing. Wells remains unchanged on all four bounded +combinations. Details in `docs/QUERY-MATRIX.md` Part 10. + +### The tripwire this nearly disarmed + +`check-trace-direction.mts` kept `?_flEnd hyf:downstreamFlowPathTC ?_flMid` on a +blacklist of reversed traces. A block seeded from the target writes that exact +triple while tracing correctly, so the string cannot decide it any more. Deleting +the entry would have quietly removed the only guard against the 2026-09-16 +direction bug. + +Queries that name both ends are now checked by reachability instead: build the +directed edges from `hyf:downstreamFlowPathTC` and `hyf:downstreamFlowPath?`, +where `?a ?b` always means a flows into b, and assert a path from +`?upstream_flowline` to `?ds_flowline`. That is the property the string was +standing in for, and it admits both seed sides. Verified by mutation: +reintroducing the 2026-09-16 bug still fails it, and a half-applied reorder that +moves the query text while leaving the aggregate seeded from the anchor fails +the new `seedsFrom` assertion in `check-query-joins.mts`. + +### Two measurement traps worth not repeating + +**Cold against warm.** The first MD sweep was the phase's first ever run, so it +was entirely cold, and the post-fix sweep was warm. Compared directly it credits +the fix with three flips instead of two; the extra row is unbounded and +anchor-constrained, its SPARQL byte-identical at 1,950 characters either side, +timing out cold and answering in 15s warm. Re-run the old engine warm before +quoting a delta. Run-to-run noise, once both halves are warm, is zero: three +consecutive sweeps at identical code agreed on every row. + +**Your own load.** Three bounded queries were measured failing with +out-of-memory, one reporting only 2.9 MB available, while a full pipeline run of +mine was hammering the same endpoint. Re-run alone, they failed differently, as +planning timeouts. The header of `query-matrix.mts` warns about this; it applies +to ad-hoc curl measurements just as much. diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 7ade3fc..1445292 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -821,3 +821,89 @@ comid/1001 -> comid/1005 a_end == b_start: true a_start == b_end: false So `A TC B` means B is downstream of A, as the predicate name says, and as Part 8 already concluded by a different route. This is the cheaper check to repeat if it is ever in doubt again. + +## Part 10: Flow-distance bounds and the seed side (2026-09-20) + +Until this date the harness never swept the flow-distance bound at all. +`maxDistanceKm` appeared zero times in `scripts/query-matrix.mts`, `mk()` had no +distance parameter, and M4, which the header called a distance sweep, sweeps the +`near` relationship's hop distance in miles instead. The only bounded shape the +matrix ever ran was one dashboard prebuilt inside M5. + +There was a second gap behind that one. `mk()` attached the region to block A +unconditionally, and for an upstream question the planner maps block A to the +anchor, so the anchor was always the constrained side. The join order that only +fires when the *target* is narrowed was unreachable from this harness, and so +was every bounded question that leaves block A wide open, which is the shape +users build. + +Phase MD closes both: four shapes, each bounded and unbounded, with the region +on block A and on block C, on both discovery steps. 32 rows. + +### 10.1 What the bound was doing + +Every bounded shape whose constrained side was the target failed, and the bound +was the thing breaking it. `boundedTrace` embeds its seed inside an aggregate +that sums path lengths across two closure hops, so seeding the wide-open side +sums them over the national flowline graph, all 1,506,326 facilities. The +failure is a 30s timeout in *query planning*, before execution starts, or a 4.3 +GB allocation failure. + +The isolating measurement, same bound, same target type, only the block A scope +differing: + +| Block A | Result | +| --- | --- | +| wide open | 500, tried to allocate 4.3 GB | +| scoped to York County | 1,429 rows in 4s | + +### 10.2 Before and after, warm against warm + +`ec221d9` seeds the bounded block from whichever side is constrained, the same +rule the unbounded path already followed. + +| | pre-fix warm | post-fix warm | +| --- | ---: | ---: | +| MD rows passing | 12/32 | **14/32** | + +| Row | Before | After | +| --- | --- | --- | +| `facilities upstream(30km) samples [ME on C] step1` | out of memory | **3,213 rows, 17s** | +| `samples downstream(30km) facilities [ME on A] step1` | out of memory | **3,213 rows, 15s** | +| all 8 bounded rows constrained on the anchor | unchanged | unchanged | + +0 regressed, and no row-count drift on any row that passed both times. Three +consecutive post-fix sweeps agree on every row, so run-to-run noise on this +phase is zero. + +### 10.3 Three things this phase says that a spot check did not + +**Step 0 of both fixed shapes still fails.** The fix lands on step 1 both times. +MD runs statewide Maine with no filters, where the samples projection is the +heavier half; the York County question that prompted the work passes both steps +in 20s and 3s. So "bounded upstream questions work now" is false as a general +claim, and the honest one is that the bound no longer fails *because* block A is +open. + +**`facilities upstream(30km) streams [ME on C]` did not start passing.** It +changed failure mode, from a timeout to an out-of-memory on step 0 and to a +sort-estimate timeout on step 1. + +**Wells is unchanged on all four bounded combinations**, as it was before, for +the reasons in Part 9 and W38 entry 12. + +### 10.4 The cold-cache trap, which cost three extra sweeps + +The first MD sweep was the first ever run of the phase, so every query in it +missed the engine's cache, and the sweep taken after the fix was warm. Compared +directly, that credits the fix with three flips instead of two. The extra one is +`facilities upstream samples [ME on A] step1`, which is unbounded and +anchor-constrained: the reorder cannot reach it, and its generated SPARQL is +byte-identical at 1,950 characters either side of the fix. It times out cold and +answers in 15s warm. + +The header of `query-matrix.mts` has always said results are cache-sensitive. +This is what ignoring it looks like in practice: a plausible number, in the +right direction, that attributes a cache effect to a code change. The pre-fix +engine was re-run warm into `2026-09-20-raw-e84a11f.csv`, and that file, not the +cold one, is the before-half of 10.2. The cold sweep carries a `.note` saying so. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 0849b12..4cef85e 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -151,3 +151,29 @@ `scripts/check-flowline-scope.mts` asserts both ends of the closure are bound for all 100 shapes that draw the layer (400 checks), bounded and unbounded, and runs in CI. *Files:* `src/engine/templates/fusedQueries.ts`, `src/engine/planner.ts`, `src/engine/scope.ts`, `scripts/check-flowline-scope.mts` (new), `.github/workflows/checks.yml`, `package.json`, `docs/DEBUGGING.md`, `docs/ARCHITECTURE.md`, `docs/wiki/Samples Non Detects.md` (new), `docs/wiki/_Sidebar.md`, `docs/wiki/Home.md`, `docs/wiki/Dropdowns.md`, `docs/plans/drafts/2026-09-19-symmetric-cell-widening.md` (new) + +15. **Fixed: The Distance Dropdown Did Nothing on the Most Common Question Shape** (2026-09-20) + Reported while verifying the York County map with the PI's question: picking any "within N km of flow" on "what facilities are upstream from PFOS samples" returned nothing at all. Every option, 5, 10 and 30 km, both projections, six queries and six identical failures, each a 30s timeout in *query planning* rather than execution. + + The bound was not the problem. The constrained-side-first reorder from entry 13 deliberately skipped bounded queries, with a comment recording that the shape had never been measured either way. `boundedTrace` duplicates its seed inside an aggregate that sums flow-path lengths across two closure hops, so seeding the unconstrained side sums them over the national flowline graph: with block A left as plain Facilities, 1,506,326 facilities. One variable isolates it. Same bound, same target, block A wide open gives a 4.3 GB allocation failure; block A scoped to York County gives **1,429 rows in 4 seconds**. + + A bounded trace is now seeded from whichever side is constrained, the same rule everything else follows. The York question answers in **20s and 3s, 132 samples and 918 facilities**, against two timeouts before. Correctness was checked before speed: where both forms run they return identical IRI sets on both projections, the bounded answer is a strict subset of the unbounded one (918 of 1,494 facilities, 0 added), and across 5, 10, 30 and 50 km the answers nest. + + **The measurement cost more than the fix.** Three things had to be redone. Three bounded queries were first measured failing with out-of-memory while a pipeline run of ours was hammering the same endpoint. The before-and-after was first taken cold against warm, which credited the fix with three flips instead of two: the extra row is unbounded and anchor-constrained, with SPARQL byte-identical at 1,950 characters either side, timing out cold and answering in 15s warm. Re-run warm against warm, the honest number is **2 rows fixed, 0 regressed, 0 row-count drift**, identical across three consecutive sweeps. + + **Stated rather than buried:** step 0 of the statewide sweep shapes still fails, both rescued rows are step 1, and "bounded upstream questions work now" would be false. What is true is that the bound no longer fails *because* block A is open. `facilities upstream(30km) streams` changed failure mode rather than passing, and wells is unchanged on all four bounded combinations. + + Two guards were rebuilt rather than relaxed. `check-query-joins` asserted that bounded traces keep the anchor-first order, which was the defect; it now asserts the constrained-side rule and, separately, that the aggregate seeds from that side, since a query can read target-first while the cost stays where it was. `check-trace-direction` kept a string on a blacklist of reversed traces that a correctly target-seeded block also writes, so deleting it would have disarmed the only guard against the 2026-09-16 direction bug; queries naming both ends are now checked by reachability through the flow graph. Both verified by mutation. + + *Files:* `src/engine/templates/fusedQueries.ts`, `scripts/check-query-joins.mts`, `scripts/check-trace-direction.mts`, `scripts/query-matrix.mts`, `docs/query-matrix/*` (4 sweeps + a note), `docs/QUERY-MATRIX.md` (Part 10), `docs/DEBUGGING.md` + +16. **The Sweep That Could Not See the Bug, and a Snapshot Test That Was Never Committed** (2026-09-20) + Entry 15 could not be measured when it was found, because nothing in the harness could express the failing shape. `maxDistanceKm` appeared **zero times** in `scripts/query-matrix.mts`; M4, labelled a distance sweep in the header, sweeps the `near` relationship's hop distance in miles. The only bounded shape the matrix ever ran was one dashboard prebuilt. Behind that sat a second gap: `mk()` attached the region to block A unconditionally, and since the planner maps block A to the anchor for an upstream question, the anchor was always the constrained side, so the target-first join order and every question that leaves block A wide open were both unreachable. Phase MD adds the two axes, 32 rows, and measures both discovery steps rather than only the first, because at 30 km the samples projection answered while the facilities projection ran out of memory. + + Separately, `scripts/check-query-snapshots.mts` turned out to already exist, written on 2026-09-17, **untracked**, with `package.json` on another branch registering a command against a file nobody else had. It is committed here with its grid extended, because it was blind in the same two places: region placement and the flow bound. Measured on entry 15's fix, the old grid reports **1** moved shape; the extended grid reports **74**, bucketed by axis. 375 shapes now, and it is blocking in CI. + + Two things keep that snapshot readable rather than enormous. The PREFIX preamble is byte-identical in every query and was 66% of the file, so it is stripped and recorded once. Query bodies are written once each in a hash-keyed table: 375 shapes reference 2,078 step queries but only 603 distinct ones, the region-boundary query alone being identical in 373 of them. Together, 1.7MB down to 688KB, and a one-line change to a shared query stops being 373 lines of diff. + + **Known limit, recorded so it is not discovered later:** the snapshot drives everything through `planPipeline`, so it covers shapes a user can ask for and is blind to builder arguments the planner never produces. A reordering of the anchor-seeded `upstream` branch of `boundedTrace` passes all seven checks. The guarantee is "no reachable shape moved unintentionally", not "no emitted SPARQL moved". + + *Files:* `scripts/query-matrix.mts`, `scripts/check-query-snapshots.mts` (new), `scripts/__snapshots__/query-shapes.txt` (new), `package.json`, `.github/workflows/checks.yml` From abca208b22c768576e3f07019b571d87f815eabe Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 02:28:05 -0400 Subject: [PATCH 64/66] fix(engine): rank how narrow a side is, instead of asking whether it is Adding an industry filter to block A turned a working question into a failing one. "What facilities are within 5 km upstream from PFOS samples in York County" answers in 3s with block A empty; add NAICS 221320 to it and both projections time out in query planning at 30s. `sideIsConstrained` was a boolean: region, filter or IRI pin, any of them means constrained. An industry filter set it to true, the reorder stopped firing, and the query went back to seeding from block A, which now meant every sewage treatment facility in the country rather than the 118 sample points in one county. The comment two lines above it already said "narrowed is not small"; the predicate did not act on its own warning. It now returns a rank, and the body leads with the higher one: 3 an IRI pin. The executor chose this slice. 2 a region. Bounded by geography, and the graph is indexed for it. 1 an entity filter only. Selective in kind, unbounded in extent. 0 nothing. Ties keep the anchor-first order, so this only changes cases where both sides are constrained at different levels. Everything where one side was constrained and the other was not keeps the plan it had, which the snapshot confirms: of 375 shapes, 2 move, both variants with a region on one side and a bare filter on the other. Measured on the live endpoint, all with block A carrying no region: 1 code, unbounded 429 planning timeout -> 35 facilities, 16s 1 code, 5 km 429 planning timeout -> 22 facilities, 8s 8 codes, 5 km 429 planning timeout -> 88 facilities, 3s 8 codes, unbounded 429 planning timeout -> 192 facilities, 15s 21 codes still fails. That is a different cost, the `|| EXISTS { ?ic fio:subcodeOf ?sel }` clause evaluated per selected code and duplicated inside the bounded aggregate, and it is not addressed here. One shipped dashboard question changes plan. `samples-downstream-waste-indiana` has samples scoped to Indiana and NAICS 5622 with no region, so its anchor is nationwide and its target is one state. Both orders were run: identical answers, 136 samples and 415 facilities either way, reordered no slower at 13s and 2s against 16s and 3s. `check-query-joins` asserted that no prebuilt may reorder, which described the old predicate rather than a rule; it now expects this one to and says why. 30 new assertions pin the ranking in both directions, and a mutation reverting it to the boolean fails them. --- scripts/__snapshots__/query-shapes.txt | 16 +++--- scripts/check-query-joins.mts | 67 ++++++++++++++++++++++++-- src/engine/templates/fusedQueries.ts | 26 ++++++++-- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/scripts/__snapshots__/query-shapes.txt b/scripts/__snapshots__/query-shapes.txt index 731b554..69cae52 100644 --- a/scripts/__snapshots__/query-shapes.txt +++ b/scripts/__snapshots__/query-shapes.txt @@ -2437,8 +2437,8 @@ HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f HYDRATE_ANCHOR_BY_IRI [federation] ec6ed949be4d GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa ## VARIANT: sample filters -FIND_TARGET_IRIS [federation] 7b1c835798e7 -FIND_ANCHOR_IRIS [federation] b4f373f3b10c +FIND_TARGET_IRIS [federation] 3ae8e5cca3a7 +FIND_ANCHOR_IRIS [federation] d9a6c533c502 GET_FLOWLINE_GEOMETRIES [federation] 10a063aa6d84 HYDRATE_TARGET_BY_IRI [federation] 225ebb47d1ba HYDRATE_ANCHOR_BY_IRI [federation] f15a49a11b96 @@ -2450,8 +2450,8 @@ HYDRATE_TARGET_BY_IRI [federation] 9498222e580a HYDRATE_ANCHOR_BY_IRI [hydrologykg] 025d57e51b2a GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa ## VARIANT: stream ftype filter as target -FIND_TARGET_IRIS [federation] f484f51fbc63 -FIND_ANCHOR_IRIS [federation] 3b68e8810ae7 +FIND_TARGET_IRIS [federation] a8825c1ad3c8 +FIND_ANCHOR_IRIS [federation] 744604955bf5 HYDRATE_TARGET_BY_IRI [federation] 86920d0a3b5f HYDRATE_ANCHOR_BY_IRI [hydrologykg] 3da8119633c2 GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa @@ -2605,7 +2605,7 @@ GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa 3a2bb0cd96e0 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } 3a5de06aa701 SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . BIND(?ds_flowline AS ?streamC) } 3ac013fb1120 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } -3b68e8810ae7 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } +3ae8e5cca3a7 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) } 3b88da2bc6f2 SELECT DISTINCT ?waterBody ?wbWKT ?wbName ?ftype ?comid ?reachcode ?fcode ?s2cell WHERE { VALUES ?waterBody { } ?s2cell spatial:connectedTo ?waterBody ; rdf:type kwg-ont:S2Cell_Level13 . ?waterBody rdf:type hyf:HY_WaterBody ; geo:hasGeometry/geo:asWKT ?wbWKT . OPTIONAL { ?waterBody schema:name ?wbName . } OPTIONAL { ?waterBody nhdplusv2:hasFTYPE ?ftype . } OPTIONAL { ?waterBody nhdplusv2:hasCOMID ?comid . } OPTIONAL { ?waterBody nhdplusv2:hasReachCode ?reachcode . } OPTIONAL { ?waterBody nhdplusv2:hasFCODE ?fcode . } } 3bcbbc61caae SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . } 3bce92acebce SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } @@ -2735,6 +2735,7 @@ GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa 73934d7aae0d SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } 73c37175d3a3 SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } 74340ac75507 SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } +744604955bf5 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } } 748a8ca41a32 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } 74c3d0bb8bf8 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(10)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } 74f6726cb460 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } @@ -2754,7 +2755,6 @@ GET_REGION_BOUNDARIES [spatialkg] d52aaecf97fa 79e0bd042512 SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } 7aa05f4cf432 SELECT DISTINCT (?spA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } 7ab11f2c9448 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } -7b1c835798e7 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) } 7b5980388f2c SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?wellA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?waterBodyC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?s2celltarget spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } 7b8a451b6ce6 SELECT DISTINCT ?facility ?facWKT ?facilityName ?industryCode ?industryName ?s2cell WHERE { VALUES ?facility { } ?s2cell kwg-ont:sfContains ?facility ; rdf:type kwg-ont:S2Cell_Level13 . ?facility fio:ofIndustry ?industryCode ; geo:hasGeometry/geo:asWKT ?facWKT ; rdfs:label ?facilityName . ?industryCode a naics:NAICS-IndustryCode ; rdfs:label ?industryName . } 7c9c4702ede4 SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } @@ -2865,6 +2865,7 @@ a7b4475fa918 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg a7ba4bf786b6 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_length WHERE { { SELECT ?flowline (MIN(?_ptotal) AS ?path_length) WHERE { { SELECT ?_flSeed ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?_flSeed ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?_flSeed WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?aquiferA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?_flSeed rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus . } } ?_flSeed hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?_flSeed ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_endLen . ?_flEnd hyf:downstreamFlowPath? ?flowline . BIND(IF(?flowline = ?_flEnd, 0.0, ?_endLen) AS ?_extra) BIND(xsd:float(?_plen) + xsd:float(?_extra) AS ?_ptotal) } GROUP BY ?flowline } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } a7c3f2ccff0c SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?upstream_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?upstream_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?upstream_flowline WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . } } ?upstream_flowline hyf:downstreamFlowPathTC ?_flMid . ?_flMid hyf:downstreamFlowPathTC ?_flEnd . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?upstream_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?_flEnd hyf:downstreamFlowPath? ?ds_flowline . } } ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } a7e872d51a0f SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } +a8825c1ad3c8 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } } a963e5be882c SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } a99936a88d0b SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } aa5fdb59ec6f SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } @@ -2892,7 +2893,6 @@ b4008588edaf SELECT DISTINCT (?streamC AS ?iri) WHERE { ?ds_flowline rdf:type hy b43c08af1964 SELECT DISTINCT (?facilityC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } b44db2e80018 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } b45c05b3136a SELECT DISTINCT (?aquiferC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?aquiferC . ?aquiferC rdf:type gwml2:GW_Aquifer . } -b4f373f3b10c SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) } b57ca9e8c32e SELECT DISTINCT (?streamA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } b58c8c35f1eb SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?ds_flowline rdf:type hyf:HY_FlowPath . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . BIND(?ds_flowline AS ?streamC) } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } b679bd47f6b1 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . } @@ -2971,6 +2971,7 @@ d7635cc00d76 SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName ?path_l d7ee9691da5b SELECT DISTINCT ?flowline ?flowlineWKT ?fl_type ?streamName WHERE { { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2cellus WHERE { VALUES ?waterBodyA { } ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2cellus . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2cellus ; hyf:downstreamFlowPathTC ?flowline . } } { SELECT DISTINCT ?flowline WHERE { { SELECT DISTINCT ?s2celltarget WHERE { VALUES ?spC { } ?s2celltarget rdf:type kwg-ont:S2Cell_Level13 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2celltarget . } } ?_flTarget spatial:connectedTo ?s2celltarget . ?flowline hyf:downstreamFlowPathTC ?_flTarget . } } ?flowline geo:hasGeometry/geo:asWKT ?flowlineWKT ; nhdplusv2:hasFTYPE ?fl_type . OPTIONAL { ?flowline rdfs:label ?streamName } } d913d9d71840 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } d98072521790 SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . } +d9a6c533c502 SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC coso:observedAtSamplePoint ?spC . ?observationC coso:ofDSSToxSubstance ?substanceC . ?observationC coso:analyzedSample ?sampleC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?observationC coso:hasResult ?resultC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?resultC coso:measurementUnit ?unitC . VALUES ?substanceC { } VALUES ?matTypeC { } BIND(xsd:decimal(?numericResultC) as ?numericValueC) FILTER(BOUND(?numericValueC) && ?unitC = && ?numericValueC >= 4 && ?numericValueC <= 100) ?s2target spatial:connectedTo ?ds_flowline . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . VALUES ?selectedIndustryA { naics:NAICS-562212 } FILTER(?industryCodeA = ?selectedIndustryA || EXISTS { ?industryCodeA fio:subcodeOf ?selectedIndustryA }) } da7010fa25fd SELECT DISTINCT (?wellA AS ?well) ?wellWKT (?s2anchor AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . ?observationC rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spC ; coso:ofDSSToxSubstance ?substanceC ; coso:analyzedSample ?sampleC ; coso:hasResult ?resultC . ?sampleC coso:sampleOfMaterialType ?matTypeC . ?matTypeC rdfs:label ?matTypeLabelC . ?resultC coso:measurementUnit ?unitC . OPTIONAL { ?resultC qudt:quantityValue/qudt:numericValue ?numericResultC } OPTIONAL { ?resultC qudt:quantityValue ?_qvC . ?_qvC rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectC) } BIND(COALESCE(STR(?numericResultC), IF(BOUND(?nonDetectC), "non-detect", "non-quantified")) AS ?result_valueC) ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?wellA geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellA rdfs:label ?wellName . } OPTIONAL { ?wellA me_mgs:hasUse ?meUse . } OPTIONAL { ?wellA me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellA me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellA me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellA il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellA il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellA il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellA il_isgs:wellYield/qudt:numericValue ?ilYield . } } da77e9a226ae SELECT DISTINCT (?aquiferA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?aquiferA . ?aquiferA rdf:type gwml2:GW_Aquifer . } daae4206ce0f SELECT DISTINCT (?streamC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?streamC . ?streamC rdf:type hyf:HY_FlowPath . } @@ -3033,7 +3034,6 @@ f1abbefd32dd SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ? f1e4ac3d1adc SELECT DISTINCT (?facilityA AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } f2161e75506a SELECT DISTINCT (?wellC AS ?well) ?wellWKT (?s2target AS ?s2cell) ?wellName ?meUse ?meWellType ?meDepth ?meOverburden ?ilOwner ?ilDepth ?ilPurpose ?ilYield WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?spA rdf:type coso:SamplePoint ; spatial:connectedTo ?s2anchor . ?observationA rdf:type coso:ContaminantObservation ; coso:observedAtSamplePoint ?spA ; coso:ofDSSToxSubstance ?substanceA ; coso:analyzedSample ?sampleA ; coso:hasResult ?resultA . ?sampleA coso:sampleOfMaterialType ?matTypeA . ?matTypeA rdfs:label ?matTypeLabelA . ?resultA coso:measurementUnit ?unitA . OPTIONAL { ?resultA qudt:quantityValue/qudt:numericValue ?numericResultA } OPTIONAL { ?resultA qudt:quantityValue ?_qvA . ?_qvA rdf:type coso:NonDetectQuantityValue . BIND(true AS ?nonDetectA) } BIND(COALESCE(STR(?numericResultA), IF(BOUND(?nonDetectA), "non-detect", "non-quantified")) AS ?result_valueA) ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } ?wellC geo:hasGeometry/geo:asWKT ?wellWKT . OPTIONAL { ?wellC rdfs:label ?wellName . } OPTIONAL { ?wellC me_mgs:hasUse ?meUse . } OPTIONAL { ?wellC me_mgs:ofWellType ?meWellType . } OPTIONAL { ?wellC me_mgs:wellDepth/qudt:numericValue ?meDepth . } OPTIONAL { ?wellC me_mgs:wellOverburden/qudt:numericValue ?meOverburden . } OPTIONAL { ?wellC il_isgs:hasOwner ?ilOwner . } OPTIONAL { ?wellC il_isgs:wellDepth/qudt:numericValue ?ilDepth . } OPTIONAL { ?wellC il_isgs:wellPurpose ?ilPurpose . } OPTIONAL { ?wellC il_isgs:wellYield/qudt:numericValue ?ilYield . } } f2ec010e4080 SELECT DISTINCT (?waterBodyA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?waterBodyA . ?waterBodyA rdf:type hyf:HY_WaterBody . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target kwg-ont:sfContains ?facilityC . ?facilityC fio:ofIndustry ?industryCodeC . ?industryCodeC a naics:NAICS-IndustryCode . } -f484f51fbc63 SELECT DISTINCT (?spC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?streamA nhdplusv2:hasFTYPE ?flFtypeA . VALUES ?flFtypeA { "460" } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?spC rdf:type coso:SamplePoint ; spatial:connectedTo ?s2target . } f560ebd6282b SELECT DISTINCT (?waterBodyC AS ?iri) WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . { SELECT DISTINCT ?upstream_flowline ?ds_flowline WHERE { { SELECT ?ds_flowline ?_flEnd (SUM(?_flLen) AS ?_plen) WHERE { { SELECT ?ds_flowline ?_flMid ?_flEnd WHERE { { SELECT DISTINCT ?ds_flowline WHERE { ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . ?s2target spatial:connectedTo ?ds_flowline . } } ?_flMid hyf:downstreamFlowPathTC ?ds_flowline . ?_flEnd hyf:downstreamFlowPathTC ?_flMid . } } ?_flMid nhdplusv2:hasFlowPathLength/qudt:quantityValue/qudt:numericValue ?_flLen . } GROUP BY ?ds_flowline ?_flEnd } FILTER (xsd:float(?_plen) < xsd:float(30)) ?upstream_flowline hyf:downstreamFlowPath? ?_flEnd . } } ?upstream_flowline rdf:type hyf:HY_FlowPath ; spatial:connectedTo ?s2neighbor . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor kwg-ont:sfContains ?facilityA . ?facilityA fio:ofIndustry ?industryCodeA . ?industryCodeA a naics:NAICS-IndustryCode . } f56b87fc7251 SELECT DISTINCT (?wellC AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2anchor spatial:connectedTo ?streamA . ?streamA rdf:type hyf:HY_FlowPath . ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2neighbor . ?s2neighbor spatial:connectedTo ?upstream_flowline . ?upstream_flowline rdf:type hyf:HY_FlowPath . ?upstream_flowline hyf:downstreamFlowPathTC ?ds_flowline . ?s2target spatial:connectedTo ?ds_flowline ; rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo ?wellC . { ?wellC rdf:type il_isgs:ISGS-Well } UNION { ?wellC rdf:type me_mgs:MGS-Well } } f58221d89287 SELECT DISTINCT (?wellA AS ?iri) WHERE { ?s2anchor rdf:type kwg-ont:S2Cell_Level13 . ?s2anchor spatial:connectedTo ?wellA . { ?wellA rdf:type il_isgs:ISGS-Well } UNION { ?wellA rdf:type me_mgs:MGS-Well } ?s2anchor kwg-ont:sfTouches | owl:sameAs ?s2target . ?s2target rdf:type kwg-ont:S2Cell_Level13 . ?s2target spatial:connectedTo kwgr:administrativeRegion.USA.23 . ?s2target spatial:connectedTo ?waterBodyC . ?waterBodyC rdf:type hyf:HY_WaterBody . } diff --git a/scripts/check-query-joins.mts b/scripts/check-query-joins.mts index d491807..1d659c6 100644 --- a/scripts/check-query-joins.mts +++ b/scripts/check-query-joins.mts @@ -252,7 +252,67 @@ for (const c of joinCases) { } } -// --- 3. The prebuilt dashboard questions must not change plan. +// --- 2b. Narrowness is a ranking, not a boolean. A region beats a bare entity +// filter, because a filter with no region is selective in kind and unbounded in +// extent: "all sewage treatment facilities" is a nationwide set. Getting this +// wrong is not a slow query, it is no query at all. Adding an industry filter +// to block A of "facilities upstream from PFOS samples in York" used to turn a +// 3s answer into a 30s timeout in query planning, because the filter alone +// counted as constrained and switched the reorder off. +for (const targetType of ENTITY_TYPES) { + for (const maxDistanceKm of [undefined, 30]) { + const base = { project: 'target' as const, direction: 'downstream' as const, ...(maxDistanceKm ? { maxDistanceKm } : {}) }; + const label = `${targetType} <- facilities${maxDistanceKm ? `, bounded ${maxDistanceKm}km` : ''}`; + + // Anchor filtered but unscoped, target scoped: the region wins. + const filteredAnchor = buildFusedHydrologyQuery({ + ...base, + anchor: { type: 'facilities', ...filtersFor('facilities') }, + target: { type: targetType, ...filtersFor(targetType) }, + targetRegion: ['23005'], + }); + check( + leadsWith(filteredAnchor) === 'target', + `${label}: a bare industry filter must not outrank a region, or the seed is nationwide`, + ); + if (maxDistanceKm) { + check( + seedsFrom(filteredAnchor) === 'target', + `${label}: the bounded aggregate must seed from the region-scoped side`, + ); + } + + // The mirror: anchor scoped, target only filtered. The anchor keeps it. + const filteredTarget = buildFusedHydrologyQuery({ + ...base, + anchor: { type: 'facilities' }, + target: { type: targetType, ...filtersFor(targetType) }, + anchorRegion: ['23005'], + }); + check( + leadsWith(filteredTarget) === 'anchor', + `${label}: a region on the anchor outranks a bare filter on the target`, + ); + } +} + +// --- 3. The prebuilt dashboard questions lead with their narrower side. +// +// This used to assert that no prebuilt reorders, on the grounds that every one +// of them has a constrained anchor. That was a description of the old boolean +// predicate rather than a rule, and it stopped being true when "constrained" +// became a ranking: an industry filter with no region is constrained but not +// narrow. One prebuilt legitimately reorders under the ranking. +// +// `samples-downstream-waste-indiana` has samples scoped to Indiana on block A +// and NAICS 5622 with no region on block C, so the anchor is every waste +// treatment facility in the country and the target is one state. Both orders +// were measured on the live endpoint: identical answers, 136 samples and 415 +// facilities either way, with the reordered form no slower (13s and 2s against +// 16s and 3s). It reorders because the rule says the state-scoped side is the +// narrower one, and the measurement agrees. +const EXPECTED_REORDER = new Set(['samples-downstream-waste-indiana']); + for (const prebuilt of PREBUILT_QUERIES) { const question: AnalysisQuestion = prebuilt.question; if (question.relationship.type === 'near') continue; @@ -261,9 +321,10 @@ for (const prebuilt of PREBUILT_QUERIES) { { question, targetIris: [], anchorIris: [], results: {} } as never, undefined, ); + const expected = EXPECTED_REORDER.has(prebuilt.id) ? 'target' : 'anchor'; check( - leadsWith(query) === 'anchor', - `${prebuilt.id}: every prebuilt has a constrained anchor, so none of them may reorder`, + leadsWith(query) === expected, + `${prebuilt.id}: expected the body to lead with the ${expected}, the narrower of its two sides`, ); } diff --git a/src/engine/templates/fusedQueries.ts b/src/engine/templates/fusedQueries.ts index 481b853..5789d5c 100644 --- a/src/engine/templates/fusedQueries.ts +++ b/src/engine/templates/fusedQueries.ts @@ -408,7 +408,7 @@ function buildFusedWhereBody(opts: FusedBodyOpts): string { // shape whose constrained side was the target failed before this (MD in // docs/query-matrix): timeouts in query planning, or 4.3 GB allocation // failures. Reordered, the same three shapes answer in seconds. - if (sideIsConstrained(opts, 'target') && !sideIsConstrained(opts, 'anchor')) { + if (sideNarrowness(opts, 'target') > sideNarrowness(opts, 'anchor')) { // The target's own entity and filters come first, then the hop onto the // river network. A streams target *is* the flowline, so it needs no hop. const targetHead = @@ -473,11 +473,31 @@ export function blockIsFiltered(block: EntityBlock): boolean { // A side is constrained when the question already narrows it: a region, any // entity filter, or an IRI pin from chunking. Unconstrained means "every // facility in the graph", which is the side that must not lead the query. -function sideIsConstrained(opts: FusedBodyOpts, side: 'anchor' | 'target'): boolean { +// How narrow a side is, not whether it is narrowed at all. The seed walks +// outward from whichever side leads, so the question is always which of the two +// is *smaller*, and a boolean cannot answer it: an industry filter with no +// region says "constrained" while meaning every sewage plant in the country. +// Answering the boolean is what made "facilities upstream from PFOS samples in +// York" fail the moment an industry filter was added to block A, after the same +// question had just been fixed without one. +// +// 3 an IRI pin. The executor chose this slice; re-seeding from the other +// side would throw the slice away. +// 2 a region. Bounded by geography at any level, and the graph is indexed +// for it. +// 1 an entity filter only. Selective in kind, unbounded in extent. +// 0 nothing. +// +// Ties keep the anchor-first order, so this only ever changes cases where both +// sides are constrained at different levels. Every shape where one side was +// constrained and the other was not keeps the order it had. +function sideNarrowness(opts: FusedBodyOpts, side: 'anchor' | 'target'): 0 | 1 | 2 | 3 { const block = side === 'anchor' ? opts.anchor : opts.target; const region = side === 'anchor' ? opts.anchorRegion : opts.targetRegion; const pins = side === 'anchor' ? opts.anchorIris : opts.targetIris; - return Boolean(pins?.length || region?.length) || blockIsFiltered(block); + if (pins?.length) return 3; + if (region?.length) return 2; + return blockIsFiltered(block) ? 1 : 0; } export interface FusedBaseOpts { From d00d893ff1fb61f100d6d51e257d1c102a3b8310 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 02:30:20 -0400 Subject: [PATCH 65/66] docs: narrowing a question by industry used to break it QUERY-MATRIX.md Part 11: what the boolean predicate cost, the rank that replaced it, the measured before and after with block A unscoped, and the two things it does not fix. DEBUGGING.md gains a second 2026-09-20 entry, with the one-variable isolation table showing that block A had to be small rather than merely filtered, and the note that a long industry selection fails for a different reason. W38 entry 17. Written to be read next to entry 15, since this is the same class of bug one level up and was found by doing the obvious next thing with the map entry 15 fixed. --- docs/DEBUGGING.md | 41 ++++++++++++++++++++++++++++ docs/QUERY-MATRIX.md | 56 ++++++++++++++++++++++++++++++++++++++ docs/changelog/2026-W38.md | 13 +++++++++ 3 files changed, 110 insertions(+) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index cc84b92..a97fa97 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -731,3 +731,44 @@ out-of-memory, one reporting only 2.9 MB available, while a full pipeline run of mine was hammering the same endpoint. Re-run alone, they failed differently, as planning timeouts. The header of `query-matrix.mts` warns about this; it applies to ad-hoc curl measurements just as much. + +## 2026-09-20: Adding an industry filter broke a question that worked (FIXED) + +Found while answering "what does this result really mean" about the York County +map. The unfiltered question, facilities within 5 km upstream from PFOS +detections, returns 418 facilities in 3s. It also returns dentists and schools, +because block A carries no industry filter and "facility" means anything with a +NAICS code. The obvious next step is to filter block A to PFAS source +categories. Doing that returned nothing: 429, `Operation timed out. Last +operation: Query planning`, on both projections. + +**Root cause, one level up from the 2026-09-20 seed-side entry above.** +`sideIsConstrained` treated a region, an entity filter and an IRI pin as the +same thing. An industry filter made the anchor count as constrained, so the +reorder stopped firing, so the query seeded from block A, which with a filter +and no region means every facility in that industry across the country. + +Isolated by varying one thing at a time, all at 5 km, York, detections only: + +| Block A | Result | +| --- | --- | +| no filter, no region | works, 418 facilities, 3s | +| 1 code, no region | 429, query planning | +| 21 codes, region Maine | 429 Cartesian Product, then 500 at 728 MB | +| 21 codes, region York | 500 at 728 MB | +| 1 code, region York | works, 21 facilities, 13s | + +The pattern is that block A had to be *small*, not merely filtered, and only a +region made it small. + +**The fix** replaces the boolean with a rank: IRI pin 3, region 2, entity filter +1, nothing 0, lead with the higher, ties keep anchor-first. Only questions with +both sides constrained at different levels change plan. See +`docs/QUERY-MATRIX.md` Part 11 for the measurements. + +**Not fixed: long industry selections.** 21 codes still fails where 8 answers in +3s. The `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })` clause is +evaluated per selected code against every candidate facility and appears twice +in a bounded query, once in the body and once inside the aggregate's duplicated +seed. Keep selections under about ten codes, or rework the clause into a VALUES +join over the closure of `fio:subcodeOf`. diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 1445292..0c2c774 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -907,3 +907,59 @@ This is what ignoring it looks like in practice: a plausible number, in the right direction, that attributes a cache effect to a code change. The pre-fix engine was re-run warm into `2026-09-20-raw-e84a11f.csv`, and that file, not the cold one, is the before-half of 10.2. The cold sweep carries a `.note` saying so. + +## Part 11: Narrowness is a ranking, not a boolean (2026-09-20) + +Part 10 made the distance bound work when block A is left open. Putting an +industry filter on block A broke it again, and for a reason one level up from +the seed side. + +`sideIsConstrained` answered yes for a region, a filter or an IRI pin alike. An +industry filter therefore made the anchor "constrained", the reorder stopped +firing, and the query seeded from block A again. Only now block A meant every +facility in that industry nationwide rather than every facility in the graph, +which is smaller and still far too large to seed an aggregate from. + +### 11.1 What it cost + +"What facilities are within 5 km upstream from PFOS samples", York County, +detections only, block A carrying no region: + +| Block A | Before | After | +| --- | --- | --- | +| no filter | 418 facilities, 3s | unchanged | +| 1 code, unbounded | 429, query planning | 35 facilities, 16s | +| 1 code, 5 km | 429, query planning | 22 facilities, 8s | +| 8 codes, 5 km | 429, query planning | **88 facilities, 3s** | +| 8 codes, unbounded | 429, query planning | 192 facilities, 15s | + +Adding a filter to a working question made it fail. That is the shape of the +report: a user narrowing a result set that was too broad, and getting nothing. + +### 11.2 The rank + + 3 an IRI pin. The executor chose this slice; re-seeding discards it. + 2 a region. Bounded by geography at any level, and indexed for. + 1 an entity filter only. Selective in kind, unbounded in extent. + 0 nothing. + +The body leads with the higher rank, and ties keep the anchor-first order. So +this only changes questions where both sides are constrained at *different* +levels; everything where one side was constrained and the other was not keeps +the plan it had. Of the 375 shapes in `scripts/__snapshots__/query-shapes.txt`, +2 move, both variants with a region on one side and a bare filter on the other. + +### 11.3 What it does not fix + +**Long industry selections still fail.** 21 codes times out where 8 answers in +3s. The cost is the `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })` +clause, evaluated per selected code against every candidate facility, and +duplicated a second time inside the bounded aggregate. Keep selections under +about ten codes until that clause is reworked. + +**One dashboard question changes plan.** `samples-downstream-waste-indiana` +scopes samples to Indiana and filters block C to NAICS 5622 with no region, so +its anchor is nationwide and its target is one state. Both orders were measured +before accepting the change: identical answers, 136 samples and 415 facilities +either way, and the reordered form is no slower at 13s and 2s against 16s and +3s. diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 4cef85e..8f5c46b 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -177,3 +177,16 @@ **Known limit, recorded so it is not discovered later:** the snapshot drives everything through `planPipeline`, so it covers shapes a user can ask for and is blind to builder arguments the planner never produces. A reordering of the anchor-seeded `upstream` branch of `boundedTrace` passes all seven checks. The guarantee is "no reachable shape moved unintentionally", not "no emitted SPARQL moved". *Files:* `scripts/query-matrix.mts`, `scripts/check-query-snapshots.mts` (new), `scripts/__snapshots__/query-shapes.txt` (new), `package.json`, `.github/workflows/checks.yml` + +17. **Fixed: Narrowing a Question by Industry Made It Fail** (2026-09-20) + Found immediately after entry 15, by doing the obvious next thing with the map it fixed. "What facilities are within 5 km upstream from PFOS samples in York County" answers in 3s and returns 418 facilities, of which 261 distinct industries include dentists, schools and hospitals, because block A carries no industry filter and "facility" means anything with a NAICS code. Filtering block A to PFAS source categories returned nothing at all: a 30s timeout in query planning, on both projections. + + The cause sits one level above entry 15. `sideIsConstrained` answered yes for a region, an entity filter or an IRI pin alike, so an industry filter made the anchor count as constrained, the reorder stopped firing, and the query seeded from block A again. With a filter and no region that means every facility in that industry nationwide. The comment two lines above the predicate already read "narrowed is not small"; the predicate did not act on its own warning. + + It now returns a rank instead: an IRI pin 3, a region 2, an entity filter 1, nothing 0. The body leads with the higher, and ties keep the anchor-first order, so only questions with both sides constrained at *different* levels change plan. Of the 375 shapes in the query snapshot, 2 move. + + Measured with block A carrying no region: one code goes from a planning timeout to **35 facilities in 16s** unbounded and **22 in 8s** at 5 km; eight codes go from a planning timeout to **88 facilities in 3s** at 5 km. The filtered map is the useful one, 88 candidates rather than 418, with the dentists gone and sewage treatment, dry cleaners, boatyards, airports and petroleum terminals at the top. + + **Two limits, stated rather than left to be found.** Selections longer than about ten codes still fail: 21 codes times out where 8 answers in 3s, because the `|| EXISTS { ?ic fio:subcodeOf ?sel }` clause is evaluated per selected code and appears twice in a bounded query. And one dashboard question changes plan, `samples-downstream-waste-indiana`, whose anchor is NAICS 5622 with no region against samples scoped to Indiana. Both orders were run before accepting it: identical answers, 136 samples and 415 facilities either way, reordered no slower. + + *Files:* `src/engine/templates/fusedQueries.ts`, `scripts/check-query-joins.mts` (30 new assertions), `scripts/__snapshots__/query-shapes.txt`, `docs/QUERY-MATRIX.md` (Part 11), `docs/DEBUGGING.md` From e73d84c610cb45b0a1f40cbd856e9a815ab674a8 Mon Sep 17 00:00:00 2001 From: Prayas Lashkari Date: Sun, 20 Sep 2026 02:35:32 -0400 Subject: [PATCH 66/66] docs: correct the industry-code limit, and clear the clause blamed for it Yesterday's entries said industry selections beyond about ten codes fail, and blamed the `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })` clause. Both halves were wrong, and both were written from a measurement taken before the narrowness ranking landed. 21 codes answers fine at 5 km: 101 facilities in 13s, 84 samples in 23s. It fails only unbounded, at 430 MB. Code count is a cost on the closure, and a distance bound already caps it, so a long selection is a reason to set a distance rather than to shorten the list. codes 5 km unbounded 1 22 facilities, 8s 35 facilities, 16s 8 88 facilities, 3s 192 facilities, 15s 21 101 facilities, 13s 500, out of memory at 430 MB The clause is cleared as well, by trying the fix rather than reasoning about it. `fio:subcodeOf` is materialised transitively (325110 is a direct subcode of 32, 325 and 3251), so `?ic fio:subcodeOf? ?sel` is an exact rewrite of the FILTER. Measured on the 21-code bounded query: 13s with the FILTER, query-planning timeout with the path. The FILTER is the fast form. Recorded as a rejected design so nobody optimises it again. --- docs/DEBUGGING.md | 17 +++++++++++------ docs/QUERY-MATRIX.md | 28 +++++++++++++++++++++++----- docs/changelog/2026-W38.md | 2 +- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index a97fa97..c2c1fc7 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -766,9 +766,14 @@ region made it small. both sides constrained at different levels change plan. See `docs/QUERY-MATRIX.md` Part 11 for the measurements. -**Not fixed: long industry selections.** 21 codes still fails where 8 answers in -3s. The `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })` clause is -evaluated per selected code against every candidate facility and appears twice -in a bounded query, once in the body and once inside the aggregate's duplicated -seed. Keep selections under about ten codes, or rework the clause into a VALUES -join over the closure of `fio:subcodeOf`. +**Long selections: measure before blaming the clause.** The first version of +this entry said selections beyond about ten codes still fail. Re-measured after +the ranking landed, that is wrong. 21 codes answers at 5 km (101 facilities, +13s; 84 samples, 23s) and only fails unbounded (500, 430 MB). Code count is a +cost on the closure, which a distance bound already caps. + +The suspected culprit was cleared too. `fio:subcodeOf` is materialised +transitively, so `?ic fio:subcodeOf? ?sel` is an exact rewrite of +`FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })`. Measured: 13s with +the FILTER, query-planning timeout with the path. The FILTER is the fast form +here; do not "optimise" it. diff --git a/docs/QUERY-MATRIX.md b/docs/QUERY-MATRIX.md index 0c2c774..d69deb5 100644 --- a/docs/QUERY-MATRIX.md +++ b/docs/QUERY-MATRIX.md @@ -951,11 +951,29 @@ the plan it had. Of the 375 shapes in `scripts/__snapshots__/query-shapes.txt`, ### 11.3 What it does not fix -**Long industry selections still fail.** 21 codes times out where 8 answers in -3s. The cost is the `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })` -clause, evaluated per selected code against every candidate facility, and -duplicated a second time inside the bounded aggregate. Keep selections under -about ten codes until that clause is reworked. +**Long industry selections fail only without a bound.** An earlier draft of +this part said 21 codes fails outright. Re-measured after the ranking landed, +that is wrong: the code count only matters when the trace is unbounded. + +| Codes | 5 km | Unbounded | +| ---: | --- | --- | +| 1 | 22 facilities, 8s | 35 facilities, 16s | +| 8 | 88 facilities, 3s | 192 facilities, 15s | +| 21 | 101 facilities, 13s | 500, out of memory at 430 MB | + +Which is what a bound is for: the unbounded form walks the whole closure from +every matched facility, so more codes means more seeds and more work, while the +bounded form caps it. A long selection is a reason to set a distance, not a +reason to shorten the list. + +**A rewrite of the industry clause was tried and rejected.** The obvious suspect +was `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })`, evaluated per +selected code and duplicated inside the bounded aggregate. `fio:subcodeOf` is +materialised transitively (`325110` is a direct subcode of `32`, `325` and +`3251`), so `?ic fio:subcodeOf? ?sel` says exactly the same thing as a +zero-or-one path. It is slower, not faster: the 21-code bounded query answers in +13s with the FILTER and times out in query planning with the path. Leave the +clause alone. **One dashboard question changes plan.** `samples-downstream-waste-indiana` scopes samples to Indiana and filters block C to NAICS 5622 with no region, so diff --git a/docs/changelog/2026-W38.md b/docs/changelog/2026-W38.md index 8f5c46b..0383502 100644 --- a/docs/changelog/2026-W38.md +++ b/docs/changelog/2026-W38.md @@ -187,6 +187,6 @@ Measured with block A carrying no region: one code goes from a planning timeout to **35 facilities in 16s** unbounded and **22 in 8s** at 5 km; eight codes go from a planning timeout to **88 facilities in 3s** at 5 km. The filtered map is the useful one, 88 candidates rather than 418, with the dentists gone and sewage treatment, dry cleaners, boatyards, airports and petroleum terminals at the top. - **Two limits, stated rather than left to be found.** Selections longer than about ten codes still fail: 21 codes times out where 8 answers in 3s, because the `|| EXISTS { ?ic fio:subcodeOf ?sel }` clause is evaluated per selected code and appears twice in a bounded query. And one dashboard question changes plan, `samples-downstream-waste-indiana`, whose anchor is NAICS 5622 with no region against samples scoped to Indiana. Both orders were run before accepting it: identical answers, 136 samples and 415 facilities either way, reordered no slower. + **One limit, and one that turned out not to exist.** A long industry selection fails only without a distance bound: 21 codes answers at 5 km (101 facilities, 13s) and runs out of memory unbounded, because the unbounded form walks the whole closure from every matched facility. That is a reason to set a distance, not to shorten the list. The clause first blamed for it, `FILTER(?ic = ?sel || EXISTS { ?ic fio:subcodeOf ?sel })`, was cleared by measurement: `fio:subcodeOf` is materialised transitively, so a zero-or-one path is an exact rewrite, and it is slower, 13s against a planning timeout. And one dashboard question changes plan, `samples-downstream-waste-indiana`, whose anchor is NAICS 5622 with no region against samples scoped to Indiana. Both orders were run before accepting it: identical answers, 136 samples and 415 facilities either way, reordered no slower. *Files:* `src/engine/templates/fusedQueries.ts`, `scripts/check-query-joins.mts` (30 new assertions), `scripts/__snapshots__/query-shapes.txt`, `docs/QUERY-MATRIX.md` (Part 11), `docs/DEBUGGING.md`
Facility - - {props.name || 'Facility'}{registryId ? ` (${registryId})` : ''} - - {registryId && ( - <> · EPA FRS + {registryId ? ( + + {label} + + ) : ( + label )}
Industry - - {props.industryName || 'Industry'} (NAICS {String(props.industryCode).split('-').pop()}) - + {props.industryName || 'Industry'} (NAICS{' '} + {String(props.industryCode).split('-').pop()})