Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5b78189
Remove old Intersection module
jorgenherje Mar 26, 2025
810ae91
New Intersection Module - WIP
jorgenherje Apr 28, 2025
371bfa3
WIP - and fix after rebase
jorgenherje Apr 29, 2025
e1d0962
Fix prev settings/storedData issue in provider
jorgenherje Apr 30, 2025
3f24ebd
Adjust color scales and utilize value ranges for grid and seismic
jorgenherje Apr 30, 2025
6e2f68b
Adjust viewport code, and remove duplicate layerMaker-code
jorgenherje Apr 30, 2025
11016c8
Fix linting/formatting issues
jorgenherje May 2, 2025
a1c3243
Adjust calc of boundingBox, bounds and viewport
jorgenherje May 2, 2025
fecf69e
Minor adjustment of maker functions - utilise isLoading
jorgenherje May 2, 2025
e4f461b
Fix WebGL context issue
jorgenherje May 2, 2025
cad7f06
Adjust filename and import order
jorgenherje May 2, 2025
9bd1cad
Adjust boundingBox methods for layers
jorgenherje May 2, 2025
d3c0803
Rename module from IntersectionNew to Intersection
jorgenherje May 2, 2025
2421d32
Fix typing of utility functions
jorgenherje May 2, 2025
55b800f
Ensure invalid/error for fetch if polyline has less than two points
jorgenherje May 2, 2025
b1ac2a5
Sort available settings alphabetically and adjust time/interval setting
jorgenherje May 5, 2025
635ba0c
Ensure valid viewport and bounds values
jorgenherje May 7, 2025
76bce44
Rename IntersectionExtensionLength -> WellboreExtensionLength
jorgenherje May 7, 2025
aea27cd
Adjust seismic colorScale to be symmetric around 0
jorgenherje May 7, 2025
dcdc748
Adjust after rebase
jorgenherje May 12, 2025
ea580c3
Merge branch 'main' into 880-intersection-module-layer-framework-NEW
jorgenherje May 16, 2025
d4034da
Adjust after merge
jorgenherje May 16, 2025
ef2d02d
Adjust viewport and make arrays readonly
jorgenherje May 9, 2025
0b5ba34
Control enable state for view setting
jorgenherje May 13, 2025
99d3009
Add validation and fixup for DrilledWellborePicksSetting
jorgenherje May 13, 2025
cc89018
Add default color scale for seismic
jorgenherje May 13, 2025
84c5dc6
Add color opacity setting for grid and seismic layer
jorgenherje May 13, 2025
f8d2da3
Adjust wellbore dependency code for providers
jorgenherje May 14, 2025
d4336ad
Add IntersectionView by default for a new module
jorgenherje May 14, 2025
3c98f26
Fix EnsembleSetting bug: use EnsembleIdent.equals() for comparison
jorgenherje May 14, 2025
c06201b
Adjust shared settings options and add date as shared setting
jorgenherje May 15, 2025
7ef7335
adjust moved allowed logic
jorgenherje May 15, 2025
a822a67
Handle valid extension length for selected intersection type
jorgenherje May 15, 2025
925e833
Improve IntersectionSetting
jorgenherje May 16, 2025
13607c6
Remove ?. notation for already guarded null
jorgenherje May 16, 2025
1c3e504
Fix import path after merge
jorgenherje May 16, 2025
1a49bda
Revert incorrect formatting in package and package-lock files
jorgenherje May 16, 2025
5af705f
Make SeismicLayer generate image async in `onRescale` handler
jorgenherje May 19, 2025
30573e2
Fix incorrect folder name for utils
jorgenherje May 19, 2025
9db75a2
Add boundingbox for surfaces uncertainties
jorgenherje May 19, 2025
c96f321
Review feedback: Filter surface names on selected attribute
jorgenherje May 19, 2025
1608617
Added observation number to well pick endpoints
Anders2303 May 20, 2025
12126a8
Generate api after update of end-point
jorgenherje May 20, 2025
6a18dbd
First step of fixes based on review
jorgenherje May 20, 2025
eaba538
Second step of fixes based on review
jorgenherje May 21, 2025
1c417ed
Merge remote-tracking branch 'equinor/main' into 880-intersection-mod…
jorgenherje May 22, 2025
bf4f0a9
Use new useVisualizationAssemblerProduct hook
jorgenherje May 21, 2025
734627e
Handle verticalScale in handleFitInViewClick function
jorgenherje May 21, 2025
9429e93
Fixes based on review
jorgenherje May 22, 2025
32fdc43
Update viewport when changing intersection and extension length
jorgenherje May 22, 2025
143ad1b
Merge remote-tracking branch 'equinor/main' into 880-intersection-mod…
jorgenherje May 26, 2025
5d1fca8
Improve viewport and fit in view functionality
jorgenherje May 27, 2025
9ff4a6d
Move ColorLegends into viewportwrapper
jorgenherje May 27, 2025
ff9f87d
Adjust according to review
jorgenherje May 28, 2025
847108d
Make correct bounding box for surfaces and surfaces uncertainty
jorgenherje Jun 2, 2025
d8a4292
Remove unused code
jorgenherje Jun 2, 2025
a94abe8
Remove mismatching comment, improve error message
jorgenherje Jun 3, 2025
300f260
Control min width and visibility of input in SliderNumberSetting
jorgenherje Jun 3, 2025
d2bdc16
Focus on reference system if no layers are visible
jorgenherje Jun 3, 2025
610948d
Merge remote-tracking branch 'equinor/main' into 880-intersection-mod…
jorgenherje Jun 3, 2025
1c80b00
Merge branch 'main' into 880-intersection-module-layer-framework-NEW
jorgenherje Jun 4, 2025
dd7b7cb
Adjust request refocus and focus bounds logic
jorgenherje Jun 4, 2025
4fe047c
Adjust enum naming
jorgenherje Jun 4, 2025
cd2e20f
Correct extraction of number of providers to visualize
jorgenherje Jun 4, 2025
d6bf3c5
Minor adjustment
rubenthoms Jun 4, 2025
0c24288
fix: Add missing group properties
rubenthoms Jun 4, 2025
09b07f8
Merge branch 'dpf-add-missing-group-props' into 880-intersection-modu…
rubenthoms Jun 4, 2025
0379710
Format import
jorgenherje Jun 4, 2025
a43feca
Merge remote-tracking branch 'equinor/main' into 880-intersection-mod…
jorgenherje Jun 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/src/api/autogen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,7 @@ export type WellborePick_api = {
depthReferencePoint: string;
mdUnit: string;
interpreter: string | null;
obsNo: number;
};

export type WellboreTrajectory_api = {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/components/ToggleButton/toggleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ export type ToggleButtonProps = ButtonUnstyledProps & {
function ToggleButtonComponent(props: ToggleButtonProps, ref: React.ForwardedRef<HTMLDivElement>) {
const { active, onToggle, ...other } = props;
const [isActive, setIsActive] = React.useState<boolean>(active);
const [prevIsActive, setPrevIsActive] = React.useState<boolean>(active);

const buttonRef = React.useRef<HTMLButtonElement>(null);
React.useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(
props.buttonRef,
() => buttonRef.current,
);

if (active !== prevIsActive) {
setIsActive(active);
setPrevIsActive(isActive);
}

const handleClick = React.useCallback(() => {
setIsActive(!isActive);
onToggle(!active);
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/lib/utils/assertNonNull.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function assertNonNull<T>(value: T | null | undefined, message?: string): T {
if (value === null || value === undefined) {
message = message || "Value cannot be null or undefined";
throw new Error(message);
}
return value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function makeGridBoundingBox({
// Ensure consistency between fetched data and requested polyline
if (polylineIntersectionData.fenceMeshSections.length !== polylineActualSectionLengths.length) {
throw new Error(
`Number of fence mesh sections (${polylineIntersectionData.fenceMeshSections.length}) does not match number of actual section
`Number of fence mesh sections (${polylineIntersectionData.fenceMeshSections.length}) does not match number of actual section
lengths (${polylineActualSectionLengths.length}) for requested polyline`,
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BBox } from "@lib/utils/bbox";
import { fromNumArray, type BBox } from "@lib/utils/bbox";
import type {
IntersectionRealizationSeismicData,
IntersectionRealizationSeismicSettings,
Expand Down Expand Up @@ -42,16 +42,5 @@ export function makeSeismicBoundingBox({
const minY = data.min_fence_depth;
const maxY = data.max_fence_depth;

return {
min: {
x: minX,
y: minY,
z: 0.0,
},
max: {
x: maxX,
y: maxY,
z: 0.0,
},
};
return fromNumArray([minX, minY, 0, maxX, maxY, 0]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,32 @@ export function makeSurfacesBoundingBox({
const minX = -extensionLength;
const maxX = polylineActualSectionLengths.reduce((sum, length) => sum + length, -extensionLength);

// If no surfaces, return a bounding box with only the x-coordinates
// If no surfaces are selected
if (data.length === 0) {
return fromNumArray([minX, 0, 0, maxX, 0, 0]);
return null;
}

let minY = Number.MAX_VALUE;
let maxY = -Number.MAX_VALUE;
for (const surface of data) {
minY = Math.min(minY, ...surface.z_points);
maxY = Math.max(maxY, ...surface.z_points);
// Find valid min and max values for the surface
const { min: surfaceMin, max: surfaceMax } = surface.z_points.reduce(
(acc, z) => {
if (z === null) {
return acc;
}

return {
min: Math.min(acc.min, z),
max: Math.max(acc.max, z),
};
},
{ min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
);

// Update the overall min and max values
minY = Math.min(minY, surfaceMin);
maxY = Math.max(maxY, surfaceMax);
}

return fromNumArray([minX, minY, 0, maxX, maxY, 0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { filter, groupBy, isEqual, keys } from "lodash";
import { groupBy, isEqual, keys } from "lodash";

import { type WellborePick_api, getWellborePicksInStratColumnOptions } from "@api";
import { IntersectionType } from "@framework/types/intersection";
Expand Down Expand Up @@ -101,13 +101,17 @@ export class EnsembleWellborePicksProvider

availableSettingsUpdater(Setting.WELLBORE_PICKS, ({ getLocalSetting, getHelperDependency }) => {
const wellborePicks = getHelperDependency(wellborePicksDep);
const interpreter = getLocalSetting(Setting.WELLBORE_PICK_IDENTIFIER);
const selectedInterpreter = getLocalSetting(Setting.WELLBORE_PICK_IDENTIFIER);

if (!wellborePicks || !interpreter) {
if (!wellborePicks || !selectedInterpreter) {
return [];
}

return filter(wellborePicks, ["interpreter", interpreter]).sort();
return wellborePicks
.filter((elm) => elm.interpreter === selectedInterpreter)
.sort((a, b) => {
return a.pickIdentifier.localeCompare(b.pickIdentifier);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
postGetSurfaceIntersectionOptions,
} from "@api";
import { IntersectionType } from "@framework/types/intersection";
import { assertNonNull } from "@lib/utils/assertNonNull";
import {
createIntersectionPolylineWithSectionLengthsForField,
fetchWellboreHeaders,
Expand Down Expand Up @@ -71,7 +72,16 @@ export class RealizationSurfacesProvider
}

doSettingsChangesRequireDataRefetch(prevSettings: SettingsWithTypes, newSettings: SettingsWithTypes): boolean {
return !isEqual(prevSettings, newSettings);
return (
!prevSettings ||
!isEqual(prevSettings.intersection, newSettings.intersection) ||
!isEqual(prevSettings.wellboreExtensionLength, newSettings.wellboreExtensionLength) ||
!isEqual(prevSettings.ensemble, newSettings.ensemble) ||
!isEqual(prevSettings.realization, newSettings.realization) ||
!isEqual(prevSettings.attribute, newSettings.attribute) ||
!isEqual(prevSettings.surfaceNames, newSettings.surfaceNames) ||
!isEqual(prevSettings.sampleResolutionInMeters, newSettings.sampleResolutionInMeters)
);
}

areCurrentSettingsValid({
Expand Down Expand Up @@ -233,24 +243,23 @@ export class RealizationSurfacesProvider
RealizationSurfacesData,
RealizationSurfacesStoredData
>): Promise<RealizationSurfacesData> {
const ensembleIdent = getSetting(Setting.ENSEMBLE);
const realization = getSetting(Setting.REALIZATION);
const attribute = getSetting(Setting.ATTRIBUTE);
const surfaceNames = getSetting(Setting.SURFACE_NAMES);
const sampleResolutionInMeters = getSetting(Setting.SAMPLE_RESOLUTION_IN_METERS) ?? 1;
const ensembleIdent = assertNonNull(getSetting(Setting.ENSEMBLE), "No ensemble selected");
const realization = assertNonNull(getSetting(Setting.REALIZATION), "No realization number selected");
const attribute = assertNonNull(getSetting(Setting.ATTRIBUTE), "No attribute selected");
const surfaceNames = assertNonNull(getSetting(Setting.SURFACE_NAMES), "No surface names selected");
const sampleResolutionInMeters = assertNonNull(
getSetting(Setting.SAMPLE_RESOLUTION_IN_METERS),
"No sample resolution selected",
);
const polylineWithSectionLengths = assertNonNull(
getStoredData("polylineWithSectionLengths"),
"No polyline and actual section lengths found in stored data",
);
const extensionLength = createValidExtensionLength(
getSetting(Setting.INTERSECTION),
getSetting(Setting.WELLBORE_EXTENSION_LENGTH),
);

if (sampleResolutionInMeters === null || !surfaceNames || !attribute) {
throw new Error("Invalid settings: Sample resolution, surface names or attribute are not set");
}

const polylineWithSectionLengths = getStoredData("polylineWithSectionLengths");
if (!polylineWithSectionLengths) {
throw new Error("No polyline and actual section lengths found in stored data");
}
if (polylineWithSectionLengths.polylineUtmXy.length < 4) {
throw new Error("Invalid polyline in stored data. Must contain at least two (x,y)-points");
}
Expand All @@ -267,11 +276,11 @@ export class RealizationSurfacesProvider
surfaceNames.map((surfaceName) => {
const queryOptions = postGetSurfaceIntersectionOptions({
query: {
case_uuid: ensembleIdent?.getCaseUuid() ?? "",
ensemble_name: ensembleIdent?.getEnsembleName() ?? "",
realization_num: realization ?? 0,
case_uuid: ensembleIdent.getCaseUuid(),
ensemble_name: ensembleIdent.getEnsembleName(),
realization_num: realization,
name: surfaceName,
attribute: attribute ?? "",
attribute: attribute,
},
body: {
cumulative_length_polyline: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
postGetSampleSurfaceInPointsOptions,
} from "@api";
import { IntersectionType } from "@framework/types/intersection";
import { assertNonNull } from "@lib/utils/assertNonNull";
import {
createIntersectionPolylineWithSectionLengthsForField,
fetchWellboreHeaders,
Expand Down Expand Up @@ -75,7 +76,16 @@ export class SurfacesPerRealizationValuesProvider
}

doSettingsChangesRequireDataRefetch(prevSettings: SettingsWithTypes, newSettings: SettingsWithTypes): boolean {
return !isEqual(prevSettings, newSettings);
return (
!prevSettings ||
!isEqual(prevSettings.intersection, newSettings.intersection) ||
!isEqual(prevSettings.wellboreExtensionLength, newSettings.wellboreExtensionLength) ||
!isEqual(prevSettings.ensemble, newSettings.ensemble) ||
!isEqual(prevSettings.realizations, newSettings.realizations) ||
!isEqual(prevSettings.attribute, newSettings.attribute) ||
!isEqual(prevSettings.surfaceNames, newSettings.surfaceNames) ||
!isEqual(prevSettings.sampleResolutionInMeters, newSettings.sampleResolutionInMeters)
);
}

areCurrentSettingsValid({
Expand Down Expand Up @@ -256,47 +266,29 @@ export class SurfacesPerRealizationValuesProvider
SurfacesPerRealizationValuesData,
SurfacesPerRealizationValuesStoredData
>): Promise<SurfacesPerRealizationValuesData> {
const ensembleIdent = getSetting(Setting.ENSEMBLE);
const ensembleIdent = assertNonNull(getSetting(Setting.ENSEMBLE), "No ensemble selected");
const realizations = getSetting(Setting.REALIZATIONS);
const attribute = getSetting(Setting.ATTRIBUTE);
const surfaceNames = getSetting(Setting.SURFACE_NAMES);

if (!surfaceNames || !attribute) {
throw new Error("Invalid settings: Sample resolution, surface names or attribute are not set");
}
const attribute = assertNonNull(getSetting(Setting.ATTRIBUTE), "No attribute selected");
const surfaceNames = assertNonNull(getSetting(Setting.SURFACE_NAMES), "No surface names selected");
const requestedPolylineWithCumulatedLengths = assertNonNull(
getStoredData("requestedPolylineWithCumulatedLengths"),
"No polyline and cumulated lengths found in stored data",
);

const requestedPolylineWithCumulatedLengths = getStoredData("requestedPolylineWithCumulatedLengths");
if (!requestedPolylineWithCumulatedLengths) {
throw new Error("No polyline and cumulated lengths found in stored data");
}
if (requestedPolylineWithCumulatedLengths.xUtmPoints.length < 2) {
throw new Error(
"Invalid polyline in stored data. Must contain at least two (x,y)-points, and cumulated length per polyline section",
);
}
if (
requestedPolylineWithCumulatedLengths.xUtmPoints.length !==
requestedPolylineWithCumulatedLengths.yUtmPoints.length
) {
throw new Error("Invalid polyline points in stored data. Must have same number of X and Y points");
}
if (
requestedPolylineWithCumulatedLengths.xUtmPoints.length !==
requestedPolylineWithCumulatedLengths.cumulatedHorizontalPolylineLengthArr.length
) {
throw new Error(
"Invalid polyline in stored data. Number of cumulated lengths must be equal to number of polyline points",
);
}

// Create list of surface name and its fetch promise
const surfaceNameAndFetchList = surfaceNames.map((surfaceName) => {
const queryOptions = postGetSampleSurfaceInPointsOptions({
query: {
case_uuid: ensembleIdent?.getCaseUuid() ?? "",
ensemble_name: ensembleIdent?.getEnsembleName() ?? "",
case_uuid: ensembleIdent.getCaseUuid(),
ensemble_name: ensembleIdent.getEnsembleName(),
surface_name: surfaceName,
surface_attribute: attribute ?? "",
surface_attribute: attribute,
realization_nums: realizations ?? [],
},
body: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import type { Vec2 } from "@lib/utils/vec2";
import { normalizeVec2, point2Distance } from "@lib/utils/vec2";

/**
* Validate that the xPoints, yPoints, and cumulatedHorizontalPolylineLengthArr arrays have the same length.
*/
function validatePolylinePointsAndCumulatedLengthArray(
xPoints: readonly number[],
yPoints: readonly number[],
cumulatedHorizontalPolylineLengthArr: readonly number[],
): void {
if (xPoints.length !== yPoints.length) {
throw new Error("Invalid polyline: xPoints and yPoints arrays must have the same length");
}
if (xPoints.length !== cumulatedHorizontalPolylineLengthArr.length) {
throw new Error("Number of cumulated lengths must be equal to number of polyline points");
}
}

/**
* Create resampled polyline and provide the cumulated horizontal length per point in resampled polyline.
*
Expand Down Expand Up @@ -54,6 +70,9 @@ export function createResampledPolylinePointsAndCumulatedLengthArray(
cumulatedHorizontalPolylineLengthArr.push(cumulatedPolylineLength);
}

// Validate output
validatePolylinePointsAndCumulatedLengthArray(xPoints, yPoints, cumulatedHorizontalPolylineLengthArr);

return {
xPoints,
yPoints,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { IntersectionReferenceSystem } from "@equinor/esv-intersection";

import { LayerType } from "@modules/_shared/components/EsvIntersection";
import type {
IntersectionRealizationGridData,
Expand Down Expand Up @@ -54,7 +52,7 @@ export function createGridLayerItemsMaker({

if (intersectionData.fenceMeshSections.length !== sourcePolylineWithSectionLengths.actualSectionLengths.length) {
throw new Error(
`Number of fence mesh sections (${intersectionData.fenceMeshSections.length}) does not match number of actual section
`Number of fence mesh sections (${intersectionData.fenceMeshSections.length}) does not match number of actual section
lengths (${sourcePolylineWithSectionLengths.actualSectionLengths.length}) for requested polyline`,
);
}
Expand All @@ -71,8 +69,7 @@ export function createGridLayerItemsMaker({
}

const gridIntersectionLayerItemsMaker: EsvLayerItemsMaker = {
makeLayerItems: (intersectionReferenceSystem: IntersectionReferenceSystem | null) => {
void intersectionReferenceSystem; // Not used for this layer
makeLayerItems: () => {
return [
{
id: `${id}-grid-layer`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { IntersectionReferenceSystem } from "@equinor/esv-intersection";

import { LayerType } from "@modules/_shared/components/EsvIntersection";
import type {
IntersectionRealizationSeismicData,
Expand Down Expand Up @@ -98,9 +96,7 @@ export function createSeismicLayerItemsMaker({

// The layer has to be created inside EsvIntersection, so we need to return a LayerItem
const intersectionSeismicLayerItemsMaker: EsvLayerItemsMaker = {
makeLayerItems: (intersectionReferenceSystem: IntersectionReferenceSystem | null) => {
void intersectionReferenceSystem; // Not used for this layer

makeLayerItems: () => {
return [
{
id: `${id}-seismic-layer`,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/modules/Intersection/registerModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ModuleRegistry.registerModule<Interfaces>({
defaultTitle: "Intersection",
category: ModuleCategory.MAIN,
devState: ModuleDevState.DEV,
description: "Generic intersection viewer for co-visualization of intersection data from various sources.",
description: "Generic intersection viewer for co-visualization of data from various sources.",
preview,
dataTagIds: [
ModuleDataTagId.GRID3D,
Expand Down
Loading
Loading