154 lines
8.5 KiB
Java
154 lines
8.5 KiB
Java
package com.oiusa.las.service;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
|
|
import com.oiusa.las.model.Curve;
|
|
import com.oiusa.las.model.ResolvedRole;
|
|
|
|
/**
|
|
* Maps the raw LAS channel mnemonics to standard drilling "roles" (ROP, WOB, total gas, stick-slip,
|
|
* …) so the UI can build a proper multi-track log plot instead of a wall of numbers.
|
|
*
|
|
* <p>Resolution is by exact mnemonic first (Pason names are stable), then a description-keyword
|
|
* fallback for robustness across exports. Whatever auto-resolves is just the default — the UI lets
|
|
* the engineer reassign any track to any of the file's curves.
|
|
*/
|
|
public final class ChannelRoles {
|
|
|
|
public record RoleDef(String key, String label, String group, String unit,
|
|
double defMin, double defMax, List<String> aliases) {}
|
|
|
|
/** group keys, in display order */
|
|
public static final List<String> GROUPS = List.of("index", "mechanics", "hydraulics", "gas", "directional");
|
|
|
|
// The role table. unit is expected unit (resolved curve's own unit wins for display); defMin/defMax
|
|
// are sensible physical scales so a single garbage spike can't flatten the real trace.
|
|
public static final List<RoleDef> ROLES = List.of(
|
|
// ---- index / state ----
|
|
new RoleDef("holeDepth", "Hole Depth", "index", "ft", 0, 25000, List.of("DEPT")),
|
|
new RoleDef("bitDepth", "Bit Depth", "index", "ft", 0, 25000, List.of("BDEP")),
|
|
new RoleDef("time", "Time", "index", "s", 0, 0, List.of("TIME")),
|
|
new RoleDef("tvd", "TVD", "index", "ft", 0, 15000, List.of("TVDHD", "TVDBD")),
|
|
new RoleDef("onBottom", "On Bottom", "index", "", 0, 1, List.of("ONBTM")),
|
|
|
|
// ---- drilling mechanics ----
|
|
new RoleDef("rop", "ROP", "mechanics", "ft/hr", 0, 300, List.of("ROP", "IROP", "OBR", "OROP")),
|
|
new RoleDef("wob", "WOB", "mechanics", "klbs", 0, 80, List.of("WOB", "ADWOB")),
|
|
new RoleDef("rpm", "Rotary RPM", "mechanics", "RPM", 0, 250, List.of("RPM", "TDROT")),
|
|
new RoleDef("bitRpm", "Bit RPM", "mechanics", "RPM", 0, 300, List.of("BR", "MTRPM")),
|
|
new RoleDef("torque", "Torque", "mechanics", "kft-lbf", 0, 50, List.of("TDTOR", "TOR", "BITOR")),
|
|
new RoleDef("mse", "MSE", "mechanics", "kpsi", 0, 60, List.of("MSED")),
|
|
new RoleDef("hookload", "Hook Load", "mechanics", "klbs", 0, 500, List.of("HL", "CSW", "STRWT")),
|
|
new RoleDef("blockHeight", "Block Height", "mechanics", "ft", 0, 140, List.of("BHT", "ADBLP")),
|
|
new RoleDef("diffPress", "Diff Press", "mechanics", "psi", 0, 2000, List.of("DIFP")),
|
|
new RoleDef("doc", "Depth of Cut", "mechanics", "in", 0, 1, List.of("DOC")),
|
|
new RoleDef("overpull", "Over Pull", "mechanics", "klbs", 0, 100, List.of("OVRP")),
|
|
|
|
// ---- hydraulics / well control ----
|
|
new RoleDef("spp", "Standpipe Press", "hydraulics", "psi", 0, 5000, List.of("SPP", "UFSPP")),
|
|
new RoleDef("flow", "Flow", "hydraulics", "%", 0, 100, List.of("FLOW", "FEST")),
|
|
new RoleDef("spm1", "Pump 1 SPM", "hydraulics", "SPM", 0, 150, List.of("SPM1")),
|
|
new RoleDef("spm2", "Pump 2 SPM", "hydraulics", "SPM", 0, 150, List.of("SPM2")),
|
|
new RoleDef("spmTotal", "Total SPM", "hydraulics", "SPM", 0, 400, List.of("SKTtl")),
|
|
new RoleDef("pumpOutput", "Pump Output", "hydraulics", "gpm", 0, 1200, List.of("TPO")),
|
|
new RoleDef("casingPress", "Casing Press", "hydraulics", "psi", 0, 3000, List.of("PCAS")),
|
|
new RoleDef("mudVolume", "Total Mud Vol", "hydraulics", "bbl", 0, 1500, List.of("MV", "SIMUD")),
|
|
new RoleDef("gainLoss", "Pit Gain/Loss", "hydraulics", "bbl", -50, 50, List.of("VTGL", "GLA1")),
|
|
new RoleDef("tripTank", "Trip Tank", "hydraulics", "bbl", 0, 200, List.of("MVTT", "MVTT1", "TTACC")),
|
|
|
|
// ---- mud gas / formation ----
|
|
new RoleDef("totalGas", "Total Gas", "gas", "%", 0, 100, List.of("PGAS", "3GAS", "WGASP")),
|
|
new RoleDef("c1", "C1 Methane", "gas", "ppm", 0, 50000, List.of("C1M")),
|
|
new RoleDef("c2", "C2 Ethane", "gas", "ppm", 0, 10000, List.of("C2M")),
|
|
new RoleDef("c3", "C3 Propane", "gas", "ppm", 0, 5000, List.of("C3M")),
|
|
new RoleDef("ic4", "iC4", "gas", "ppm", 0, 2000, List.of("IC4")),
|
|
new RoleDef("nc4", "nC4", "gas", "ppm", 0, 2000, List.of("NC4")),
|
|
new RoleDef("ic5", "iC5", "gas", "ppm", 0, 1000, List.of("IC5")),
|
|
new RoleDef("nc5", "nC5", "gas", "ppm", 0, 1000, List.of("NC5")),
|
|
new RoleDef("gamma", "Gamma", "gas", "gAPI", 0, 150, List.of("GAM", "GAMB")),
|
|
new RoleDef("h2s", "H2S", "gas", "ppm", 0, 100, List.of("H2S")),
|
|
|
|
// ---- directional & drilling dynamics ----
|
|
new RoleDef("incl", "Inclination", "directional", "deg", 0, 110, List.of("INCL", "DYNIN")),
|
|
new RoleDef("azi", "Azimuth", "directional", "deg", 0, 360, List.of("AZ", "DYNAZ")),
|
|
new RoleDef("toolface", "Tool Face", "directional", "deg", 0, 360, List.of("TF", "GTF", "MTF", "ATFAV")),
|
|
new RoleDef("stickSlip", "Stick-Slip", "directional", "%", 0, 100, List.of("SSSI", "DTSEA")),
|
|
new RoleDef("vibeAxial", "Axial Vibe", "directional", "g", 0, 10, List.of("DAVAM")),
|
|
new RoleDef("vibeLateral", "Lateral Vibe", "directional", "g", 0, 10, List.of("DAVLM")),
|
|
new RoleDef("vibeHfto", "HFTO Vibe", "directional", "g", 0, 10, List.of("DAVHM")),
|
|
new RoleDef("slideRotate", "Slide/Rotate", "directional", "", 0, 1, List.of("ASR"))
|
|
);
|
|
|
|
/** Physical default [min,max] display scale for a role key (0,0 if unknown / index role). */
|
|
public static double[] defaultScale(String key) {
|
|
for (RoleDef r : ROLES) if (r.key().equals(key)) return new double[]{ r.defMin(), r.defMax() };
|
|
return new double[]{ 0, 0 };
|
|
}
|
|
|
|
private ChannelRoles() {}
|
|
|
|
/** Resolve every role against the file's curves; missing roles are simply omitted. */
|
|
public static Map<String, ResolvedRole> resolve(List<Curve> curves) {
|
|
// index curves by upper mnemonic
|
|
Map<String, Curve> byMnem = new LinkedHashMap<>();
|
|
for (Curve c : curves) byMnem.put(c.mnemonic().toUpperCase(Locale.ROOT), c);
|
|
|
|
Map<String, ResolvedRole> out = new LinkedHashMap<>();
|
|
for (RoleDef r : ROLES) {
|
|
Curve hit = null;
|
|
for (String alias : r.aliases()) {
|
|
Curve c = byMnem.get(alias.toUpperCase(Locale.ROOT));
|
|
if (c != null) { hit = c; break; }
|
|
}
|
|
if (hit == null) hit = byDescription(curves, r);
|
|
if (hit != null) {
|
|
out.put(r.key(), new ResolvedRole(r.key(), r.label(), r.group(),
|
|
hit.mnemonic(), hit.unit(), hit.description(), hit.column()));
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
private static Curve byDescription(List<Curve> curves, RoleDef r) {
|
|
// very light keyword fallback derived from the role label
|
|
String kw = r.label().toLowerCase(Locale.ROOT);
|
|
for (Curve c : curves) {
|
|
String d = c.description() == null ? "" : c.description().toLowerCase(Locale.ROOT);
|
|
if (!d.isEmpty() && d.contains(kw)) return c;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Distinct data columns that a set of resolved roles needs (sorted ascending). */
|
|
public static int[] neededColumns(Map<String, ResolvedRole> roles, int... extra) {
|
|
java.util.TreeSet<Integer> set = new java.util.TreeSet<>();
|
|
for (ResolvedRole r : roles.values()) if (r.column() >= 0) set.add(r.column());
|
|
for (int e : extra) if (e >= 0) set.add(e);
|
|
int[] cols = new int[set.size()];
|
|
int i = 0;
|
|
for (int v : set) cols[i++] = v;
|
|
return cols;
|
|
}
|
|
|
|
/** Default track layout (ordered) used by the UI as the starting point. */
|
|
public static List<List<String>> defaultTracks() {
|
|
List<List<String>> t = new ArrayList<>();
|
|
t.add(List.of("gamma"));
|
|
t.add(List.of("rop"));
|
|
t.add(List.of("wob", "rpm"));
|
|
t.add(List.of("torque", "mse"));
|
|
t.add(List.of("spp", "flow"));
|
|
t.add(List.of("spmTotal", "pumpOutput"));
|
|
t.add(List.of("totalGas", "c1", "c2", "c3"));
|
|
t.add(List.of("gainLoss", "tripTank"));
|
|
t.add(List.of("incl", "azi"));
|
|
t.add(List.of("toolface"));
|
|
t.add(List.of("stickSlip", "vibeLateral", "vibeAxial"));
|
|
return t;
|
|
}
|
|
}
|