Initial commit: establish deterministic rod-string solver stack.

Set up the C solver core, Node API orchestration, TS GUI workflow, and engineering documentation with cleaned repo hygiene for private Git hosting.

Made-with: Cursor
This commit is contained in:
2026-04-16 21:59:42 -06:00
commit 725a72a773
83 changed files with 14687 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import type { CaseState } from "./caseModel";
import { computeDoglegSeverityDegPer100 } from "./trajectoryMetrics";
export const PUMP_ROD_MISMATCH_M = 15;
export const DLS_BAD_SECTION_THRESHOLD = 15;
export type EngineeringIssue = {
severity: "warning" | "error";
code: string;
message: string;
};
export type EngineeringChecks = {
issues: EngineeringIssue[];
hasBlockingError: boolean;
};
export function runEngineeringChecks(state: CaseState): EngineeringChecks {
const issues: EngineeringIssue[] = [];
const activeTaper = state.taper.filter((t) => Number.isFinite(t.length) && t.length > 0);
const rodTotal = activeTaper.reduce((acc, t) => acc + t.length, 0);
const pumpDepth = state.pumpDepth;
if (rodTotal > 0 && pumpDepth > 0) {
const diff = Math.abs(pumpDepth - rodTotal);
if (diff > PUMP_ROD_MISMATCH_M) {
issues.push({
severity: "error",
code: "PUMP_ROD_MISMATCH_15M",
message: `Pump depth (${pumpDepth.toFixed(1)}) and total rod length (${rodTotal.toFixed(
1
)}) differ by ${diff.toFixed(1)} m (> ${PUMP_ROD_MISMATCH_M} m limit).`
});
}
}
if (state.survey.length < 2) {
issues.push({
severity: "error",
code: "SURVEY_TOO_SHORT",
message: "Trajectory needs at least 2 survey stations."
});
} else {
let nonMonotonic = false;
let maxDls = 0;
for (let i = 1; i < state.survey.length; i += 1) {
if (state.survey[i].md <= state.survey[i - 1].md) nonMonotonic = true;
maxDls = Math.max(maxDls, computeDoglegSeverityDegPer100(state.survey[i - 1], state.survey[i]));
}
if (nonMonotonic) {
issues.push({
severity: "error",
code: "SURVEY_MD_NON_MONOTONIC",
message: "Measured depth must strictly increase between survey stations."
});
}
if (maxDls > DLS_BAD_SECTION_THRESHOLD) {
issues.push({
severity: "warning",
code: "DLS_HIGH",
message: `High dogleg severity detected (max ${maxDls.toFixed(
2
)} deg/100 > ${DLS_BAD_SECTION_THRESHOLD} deg/100 bad-section threshold).`
});
}
const maxMd = state.survey[state.survey.length - 1].md;
if (pumpDepth > 0 && maxMd > 0 && maxMd < pumpDepth - 10) {
issues.push({
severity: "warning",
code: "SURVEY_BELOW_PUMP_MISSING",
message: `Trajectory ends at MD ${maxMd.toFixed(
1
)}, shallower than pump depth ${pumpDepth.toFixed(1)}.`
});
}
}
return {
issues,
hasBlockingError: issues.some((issue) => issue.severity === "error")
};
}