UNPKG

@seismo/core

Version:

This is the package for the core library of Seismo, a JavaScript library for seismic data processing and visualization. It provides utilities for handling seismic data, including FDSN web services, waveform processing, and event handling. The library is d

1,270 lines 68.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseUtil = exports.CreationInfo = exports.Comment = exports.Quantity = exports.WaveformID = exports.DataUsed = exports.SourceTimeFunction = exports.Tensor = exports.MomentTensor = exports.Axis = exports.PrincipalAxes = exports.NodalPlane = exports.NodalPlanes = exports.FocalMechanism = exports.Pick = exports.Arrival = exports.StationMagnitudeContribution = exports.Magnitude = exports.OriginQuality = exports.ConfidenceEllipsoid = exports.OriginUncertainty = exports.CompositeTime = exports.Origin = exports.TimeWindow = exports.StationMagnitude = exports.Amplitude = exports.EventDescription = exports.Quake = exports.EventParameters = exports.QUAKE_CLICK_EVENT = exports.FAKE_EMPTY_XML = exports.FAKE_ORIGIN_TIME = exports.UNKNOWN_PUBLIC_ID = exports.UNKNOWN_MAG_TYPE = exports.USGS_HOST = exports.ANSS_CATALOG_NS = exports.ANSS_NS = exports.IRIS_NS = exports.BED_NS = exports.QML_NS = void 0; exports.createQuakeClickEvent = createQuakeClickEvent; exports.parseQuakeML = parseQuakeML; exports.createQuakeFromValues = createQuakeFromValues; exports.fetchQuakeML = fetchQuakeML; const utils_1 = require("../utils"); const text_format_1 = require("./text-format"); const luxon_1 = require("luxon"); exports.QML_NS = "http://quakeml.org/xmlns/quakeml/1.2"; exports.BED_NS = "http://quakeml.org/xmlns/bed/1.2"; exports.IRIS_NS = "http://service.iris.edu/fdsnws/event/1/"; exports.ANSS_NS = "http://anss.org/xmlns/event/0.1"; exports.ANSS_CATALOG_NS = "http://anss.org/xmlns/catalog/0.1"; exports.USGS_HOST = "earthquake.usgs.gov"; exports.UNKNOWN_MAG_TYPE = "unknown"; exports.UNKNOWN_PUBLIC_ID = "unknownId"; exports.FAKE_ORIGIN_TIME = luxon_1.DateTime.fromISO("1900-01-01T00:00:00Z"); exports.FAKE_EMPTY_XML = '<?xml version="1.0"?><q:quakeml xmlns="http://quakeml.org/xmlns/bed/1.2" xmlns:q="http://quakeml.org/xmlns/quakeml/1.2"><eventParameters publicID="quakeml:fake/empty"></eventParameters></q:quakeml>'; exports.QUAKE_CLICK_EVENT = "quakeclick"; /** * Utility function to create CustomEvent for clicking on a Quake, for example * in a map or table. * * @param q Quake clicked on * @param mouseclick original mouse click Event * @returns CustomEvent populated with quake field in detail. */ function createQuakeClickEvent(q, mouseclick) { const detail = { mouseevent: mouseclick, quake: q, }; return new CustomEvent(exports.QUAKE_CLICK_EVENT, { detail: detail }); } // QuakeML classes class BaseElement { publicId = exports.UNKNOWN_PUBLIC_ID; comments = []; creationInfo; populate(qml) { const pid = _grabAttribute(qml, "publicID"); if (!(0, utils_1.isNonEmptyStringArg)(pid)) { throw new Error("missing publicID"); } this.publicId = pid; this.comments = _grabAllElComment(qml, "comment"); this.creationInfo = _grabFirstElCreationInfo(qml, "creationInfo"); } } /** * Represent a QuakeML EventParameters. */ class EventParameters extends BaseElement { eventList = []; description; /** * Parses a QuakeML event parameters xml element into an EventParameters object. * * @param eventParametersQML the event parameters xml Element * @param host optional source of the xml, helpful for parsing the eventid * @returns EventParameters instance */ static createFromXml(eventParametersQML, host) { if (eventParametersQML.localName !== "eventParameters") { throw new Error(`Cannot extract, not a QuakeML event parameters: ${eventParametersQML.localName}`); } const eventEls = Array.from(eventParametersQML.getElementsByTagNameNS(exports.BED_NS, "event")); const events = eventEls.map((e) => Quake.createFromXml(e, host)); const description = _grabFirstElText(eventParametersQML, "description"); const out = new EventParameters(); out.populate(eventParametersQML); out.eventList = events; out.description = description; return out; } } exports.EventParameters = EventParameters; /** * Represent a QuakeML Event. Renamed to Quake as Event conflicts with * other uses in javascript. */ class Quake extends BaseElement { eventId; descriptionList = []; amplitudeList = []; stationMagnitudeList = []; magnitudeList = []; originList = []; pickList = []; focalMechanismList = []; preferredOrigin; preferredMagnitude; preferredFocalMechanism; type; typeCertainty; /** * Parses a QuakeML event xml element into a Quake object. Pass in * host=seisplotjs.fdsnevent.USGS_HOST for xml from the USGS service * in order to parse the eventid, otherwise this can be left out * * @param qml the event xml Element * @param host optional source of the xml, helpful for parsing the eventid * @returns QuakeML Quake(Event) object */ static createFromXml(qml, host) { if (qml.localName !== "event") { throw new Error(`Cannot extract, not a QuakeML Event: ${qml.localName}`); } const out = new Quake(); out.populate(qml); const descriptionEls = Array.from(qml.children).filter((e) => e.tagName === "description"); out.descriptionList = descriptionEls.map((d) => EventDescription.createFromXml(d)); //need picks before can do origins const allPickEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "pick")); const allPicks = []; for (const pickEl of allPickEls) { allPicks.push(Pick.createFromXml(pickEl)); } const allAmplitudeEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "amplitude")); const allAmplitudes = []; for (const amplitudeEl of allAmplitudeEls) { allAmplitudes.push(Amplitude.createFromXml(amplitudeEl, allPicks)); } const allOriginEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "origin")); const allOrigins = []; for (const originEl of allOriginEls) { allOrigins.push(Origin.createFromXml(originEl, allPicks)); } const allStationMagEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "stationMagnitude")); const allStationMags = []; for (const stationMagEl of allStationMagEls) { allStationMags.push(StationMagnitude.createFromXml(stationMagEl, allOrigins, allAmplitudes)); } const allMagEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "magnitude")); const allMags = []; for (const magEl of allMagEls) { allMags.push(Magnitude.createFromXml(magEl, allOrigins, allStationMags)); } const allFocalMechEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "focalMechanism")); const allFocalMechs = []; for (const focalMechEl of allFocalMechEls) { allFocalMechs.push(FocalMechanism.createFromXml(focalMechEl, allOrigins, allMags)); } out.originList = allOrigins; out.magnitudeList = allMags; out.pickList = allPicks; out.amplitudeList = allAmplitudes; out.stationMagnitudeList = allStationMags; out.focalMechanismList = allFocalMechs; out.eventId = Quake.extractEventId(qml, host); const preferredOriginId = _grabFirstElText(qml, "preferredOriginID"); const preferredMagnitudeId = _grabFirstElText(qml, "preferredMagnitudeID"); const preferredFocalMechId = _grabFirstElText(qml, "preferredFocalMechanismID"); if ((0, utils_1.isNonEmptyStringArg)(preferredOriginId)) { out.preferredOrigin = allOrigins.find((o) => o.publicId === preferredOriginId); if (!out.preferredOrigin) { throw new Error(`no preferredOriginId match: ${preferredOriginId}`); } } if ((0, utils_1.isNonEmptyStringArg)(preferredMagnitudeId)) { out.preferredMagnitude = allMags.find((m) => m.publicId === preferredMagnitudeId); if (!out.preferredMagnitude) { throw new Error(`no match: ${preferredMagnitudeId}`); } } if ((0, utils_1.isNonEmptyStringArg)(preferredFocalMechId)) { out.preferredFocalMechanism = allFocalMechs.find((m) => m.publicId === preferredFocalMechId); if (!out.preferredFocalMechanism) { throw new Error(`no match: ${preferredFocalMechId}`); } } out.type = _grabFirstElText(qml, "type"); out.typeCertainty = _grabFirstElText(qml, "typeCertainty"); return out; } /** * Extracts the EventId from a QuakeML element, guessing from one of several * incompatible (grumble grumble) formats. * * @param qml Quake(Event) to extract from * @param host optional source of the xml to help determine the event id style * @returns Extracted Id, or "unknownEventId" if we can't figure it out */ static extractEventId(qml, host) { const eventId = _grabAttributeNS(qml, exports.ANSS_CATALOG_NS, "eventid"); const catalogEventSource = _grabAttributeNS(qml, exports.ANSS_CATALOG_NS, "eventsource"); if ((0, utils_1.isNonEmptyStringArg)(eventId)) { if (host === exports.USGS_HOST && (0, utils_1.isNonEmptyStringArg)(catalogEventSource)) { // USGS, NCEDC and SCEDC use concat of eventsource and eventId as eventid, sigh... return catalogEventSource + eventId; } else { return eventId; } } const publicid = _grabAttribute(qml, "publicID"); if ((0, utils_1.isNonEmptyStringArg)(publicid)) { let re = /eventid=([\w\d]+)/; let parsed = re.exec(publicid); if (parsed) { return parsed[1]; } re = /evid=([\w\d]+)/; parsed = re.exec(publicid); if (parsed) { return parsed[1]; } } return exports.UNKNOWN_PUBLIC_ID; } hasPreferredOrigin() { return (0, utils_1.isDef)(this.preferredOrigin); } hasOrigin() { return (0, utils_1.isDef)(this.preferredOrigin) || this.originList.length > 1; } get origin() { if ((0, utils_1.isDef)(this.preferredOrigin)) { return this.preferredOrigin; } else if (this.originList.length > 0) { return this.originList[0]; } else { throw new Error("No origins in quake"); } } hasPreferredMagnitude() { return (0, utils_1.isDef)(this.preferredMagnitude); } hasMagnitude() { return (0, utils_1.isDef)(this.preferredMagnitude) || this.magnitudeList.length > 1; } get magnitude() { if ((0, utils_1.isDef)(this.preferredMagnitude)) { return this.preferredMagnitude; } else if (this.magnitudeList.length > 0) { return this.magnitudeList[0]; } else { throw new Error("No magnitudes in quake"); } } get time() { return this.origin.time; } get latitude() { return this.origin.latitude; } get longitude() { return this.origin.longitude; } get depth() { return this.origin.depth; } get depthKm() { return this.depth / 1000; } get description() { return this.descriptionList.length > 0 ? this.descriptionList[0].text : ""; } get arrivals() { return this.origin.arrivalList; } get picks() { return this.pickList; } toString() { if (this.hasOrigin()) { const magStr = this.hasMagnitude() ? this.magnitude.toString() : ""; const latlon = `(${text_format_1.latlonFormat.format(this.latitude)}/${text_format_1.latlonFormat.format(this.longitude)})`; const depth = text_format_1.depthFormat.format(this.depth / 1000); return `${this.time.toISO()} ${latlon} ${depth} ${magStr}`; } else if (this.eventId != null) { return `Event: ${this.eventId}`; } else { return `Event: unknown`; } } } exports.Quake = Quake; /** Represents a QuakeML EventDescription. */ class EventDescription { text; type; constructor(text) { this.text = text; } /** * Parses a QuakeML description xml element into a EventDescription object. * * @param descriptionQML the description xml Element * @returns EventDescription instance */ static createFromXml(descriptionQML) { if (descriptionQML.localName !== "description") { throw new Error(`Cannot extract, not a QuakeML description ID: ${descriptionQML.localName}`); } const text = _grabFirstElText(descriptionQML, "text"); if (!(0, utils_1.isNonEmptyStringArg)(text)) { throw new Error("description missing text"); } const out = new EventDescription(text); out.type = _grabFirstElText(descriptionQML, "type"); return out; } toString() { return this.text; } } exports.EventDescription = EventDescription; /** Represents a QuakeML Amplitude. */ class Amplitude extends BaseElement { genericAmplitude; type; category; unit; methodID; period; snr; timeWindow; pick; waveformID; filterID; scalingTime; magnitudeHint; evaluationMode; evaluationStatus; constructor(genericAmplitude) { super(); this.genericAmplitude = genericAmplitude; } /** * Parses a QuakeML amplitude xml element into an Amplitude object. * * @param amplitudeQML the amplitude xml Element * @param allPicks picks already extracted from the xml for linking arrivals with picks * @returns Amplitude instance */ static createFromXml(amplitudeQML, allPicks) { if (amplitudeQML.localName !== "amplitude") { throw new Error(`Cannot extract, not a QuakeML amplitude: ${amplitudeQML.localName}`); } const genericAmplitude = _grabFirstElRealQuantity(amplitudeQML, "genericAmplitude"); if (!(0, utils_1.isDef)(genericAmplitude)) { throw new Error("amplitude missing genericAmplitude"); } const out = new Amplitude(genericAmplitude); out.populate(amplitudeQML); out.type = _grabFirstElText(amplitudeQML, "type"); out.category = _grabFirstElText(amplitudeQML, "category"); out.unit = _grabFirstElText(amplitudeQML, "unit"); out.methodID = _grabFirstElText(amplitudeQML, "methodID"); out.period = _grabFirstElRealQuantity(amplitudeQML, "period"); out.snr = _grabFirstElFloat(amplitudeQML, "snr"); out.timeWindow = _grabFirstElType(TimeWindow.createFromXml.bind(TimeWindow))(amplitudeQML, "timeWindow"); const pickID = _grabFirstElText(amplitudeQML, "pickID"); out.pick = allPicks.find((p) => p.publicId === pickID); if (pickID && !out.pick) { throw new Error("No pick with ID " + pickID); } out.waveformID = _grabFirstElType(WaveformID.createFromXml.bind(WaveformID))(amplitudeQML, "waveformID"); out.filterID = _grabFirstElText(amplitudeQML, "filterID"); out.scalingTime = _grabFirstElTimeQuantity(amplitudeQML, "scalingTime"); out.magnitudeHint = _grabFirstElText(amplitudeQML, "magnitudeHint"); out.evaluationMode = _grabFirstElText(amplitudeQML, "evaluationMode"); out.evaluationStatus = _grabFirstElText(amplitudeQML, "evaluationStatus"); return out; } } exports.Amplitude = Amplitude; /** Represents a QuakeML StationMagnitude. */ class StationMagnitude extends BaseElement { origin; mag; type; amplitude; methodID; waveformID; constructor(origin, mag) { super(); this.origin = origin; this.mag = mag; } /** * Parses a QuakeML station magnitude xml element into a StationMagnitude object. * * @param stationMagnitudeQML the station magnitude xml Element * @param allOrigins origins already extracted from the xml for linking station magnitudes with origins * @param allAmplitudes amplitudes already extracted from the xml for linking station magnitudes with amplitudes * @returns StationMagnitude instance */ static createFromXml(stationMagnitudeQML, allOrigins, allAmplitudes) { if (stationMagnitudeQML.localName !== "stationMagnitude") { throw new Error(`Cannot extract, not a QuakeML station magnitude: ${stationMagnitudeQML.localName}`); } const originID = _grabFirstElText(stationMagnitudeQML, "originID"); if (!(0, utils_1.isNonEmptyStringArg)(originID)) { throw new Error("stationMagnitude missing origin ID"); } const origin = allOrigins.find((o) => o.publicId === originID); if (!(0, utils_1.isDef)(origin)) { throw new Error("No origin with ID " + originID); } const mag = _grabFirstElRealQuantity(stationMagnitudeQML, "mag"); if (!(0, utils_1.isDef)(mag)) { throw new Error("stationMagnitude missing mag"); } const out = new StationMagnitude(origin, mag); out.populate(stationMagnitudeQML); out.type = _grabFirstElText(stationMagnitudeQML, "type"); const amplitudeID = _grabFirstElText(stationMagnitudeQML, "amplitudeID"); out.amplitude = allAmplitudes.find((a) => a.publicId === amplitudeID); if (amplitudeID && !out.amplitude) { throw new Error("No amplitude with ID " + amplitudeID); } out.methodID = _grabFirstElText(stationMagnitudeQML, "methodID"); out.waveformID = _grabFirstElType(WaveformID.createFromXml.bind(WaveformID))(stationMagnitudeQML, "waveformID"); return out; } } exports.StationMagnitude = StationMagnitude; /** Represents a QuakeML TimeWindow. */ class TimeWindow { begin; end; reference; constructor(begin, end, reference) { this.begin = begin; this.end = end; this.reference = reference; } /** * Parses a QuakeML time window xml element into a TimeWindow object. * * @param timeWindowQML the time window xml Element * @returns TimeWindow instance */ static createFromXml(timeWindowQML) { if (timeWindowQML.localName !== "timeWindow") { throw new Error(`Cannot extract, not a QuakeML time window: ${timeWindowQML.localName}`); } const begin = _grabFirstElFloat(timeWindowQML, "begin"); if (!(0, utils_1.isDef)(begin)) { throw new Error("timeWindow missing begin"); } const end = _grabFirstElFloat(timeWindowQML, "end"); if (!(0, utils_1.isDef)(end)) { throw new Error("timeWindow missing end"); } const reference = _grabFirstElDateTime(timeWindowQML, "reference"); if (!(0, utils_1.isDef)(reference)) { throw new Error("timeWindow missing reference"); } const out = new TimeWindow(begin, end, reference); return out; } } exports.TimeWindow = TimeWindow; /** Represents a QuakeML Origin. */ class Origin extends BaseElement { compositeTimes; originUncertainty; arrivalList; timeQuantity; latitudeQuantity; longitudeQuantity; depthQuantity; depthType; timeFixed; epicenterFixed; referenceSystemID; methodID; earthModelID; quality; type; region; evaluationMode; evaluationStatus; constructor(time, latitude, longitude) { super(); this.compositeTimes = []; this.arrivalList = []; if (time instanceof luxon_1.DateTime) { this.timeQuantity = new Quantity(time); } else { this.timeQuantity = time; } if (typeof latitude == "number") { this.latitudeQuantity = new Quantity(latitude); } else { this.latitudeQuantity = latitude; } if (typeof longitude == "number") { this.longitudeQuantity = new Quantity(longitude); } else { this.longitudeQuantity = longitude; } } /** * Parses a QuakeML origin xml element into a Origin object. * * @param qml the origin xml Element * @param allPicks picks already extracted from the xml for linking arrivals with picks * @returns Origin instance */ static createFromXml(qml, allPicks) { if (qml.localName !== "origin") { throw new Error(`Cannot extract, not a QuakeML Origin: ${qml.localName}`); } const time = _grabFirstElTimeQuantity(qml, "time"); if (!(0, utils_1.isObject)(time)) { throw new Error("origin missing time"); } const lat = _grabFirstElRealQuantity(qml, "latitude"); if (!(0, utils_1.isObject)(lat)) { throw new Error("origin missing latitude"); } const lon = _grabFirstElRealQuantity(qml, "longitude"); if (!(0, utils_1.isObject)(lon)) { throw new Error("origin missing longitude"); } const out = new Origin(time, lat, lon); out.populate(qml); out.originUncertainty = _grabFirstElType(OriginUncertainty.createFromXml.bind(OriginUncertainty))(qml, "originUncertainty"); const allArrivalEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "arrival")); out.arrivalList = allArrivalEls.map((arrivalEl) => Arrival.createFromXml(arrivalEl, allPicks)); out.depthQuantity = _grabFirstElRealQuantity(qml, "depth"); out.depthType = _grabFirstElText(qml, "depthType"); out.timeFixed = _grabFirstElBool(qml, "timeFixed"); out.epicenterFixed = _grabFirstElBool(qml, "epicenterFixed"); out.referenceSystemID = _grabFirstElText(qml, "referenceSystemID"); out.methodID = _grabFirstElText(qml, "methodID"); out.earthModelID = _grabFirstElText(qml, "earthModelID"); out.quality = _grabFirstElType(OriginQuality.createFromXml.bind(OriginQuality))(qml, "quality"); out.type = _grabFirstElText(qml, "type"); out.region = _grabFirstElText(qml, "region"); out.evaluationMode = _grabFirstElText(qml, "evaluationMode"); out.evaluationStatus = _grabFirstElText(qml, "evaluationStatus"); return out; } toString() { const latlon = `(${text_format_1.latlonFormat.format(this.latitude)}/${text_format_1.latlonFormat.format(this.longitude)})`; const depth = text_format_1.depthFormat.format(this.depth / 1000); return `${this.time.toISO()} ${latlon} ${depth} km`; } get time() { return this.timeQuantity.value; } set time(t) { if (t instanceof luxon_1.DateTime) { this.timeQuantity.value = t; } else { this.timeQuantity = t; } } get latitude() { return this.latitudeQuantity.value; } set latitude(lat) { if (typeof lat == "number") { this.latitudeQuantity.value = lat; } else { this.latitudeQuantity = lat; } } get longitude() { return this.longitudeQuantity.value; } set longitude(lon) { if (typeof lon == "number") { this.longitudeQuantity.value = lon; } else { this.longitudeQuantity = lon; } } get depthKm() { return this.depth / 1000; } get depth() { return this.depthQuantity?.value ?? NaN; } set depth(depth) { if (typeof depth == "number") { if (!this.depthQuantity) { this.depthQuantity = new Quantity(depth); } else { this.depthQuantity.value = depth; } } else { this.depthQuantity = depth; } } get arrivals() { return this.arrivalList; } } exports.Origin = Origin; /** Represents a QuakeML CompositeTime. */ class CompositeTime { year; month; day; hour; minute; second; /** * Parses a QuakeML composite time xml element into an CompositeTime object. * * @param qml the composite time xml Element * @returns CompositeTime instance */ static createFromXml(qml) { if (qml.localName !== "compositeTime") { throw new Error(`Cannot extract, not a QuakeML Composite Time: ${qml.localName}`); } const out = new CompositeTime(); out.year = _grabFirstElIntegerQuantity(qml, "year"); out.month = _grabFirstElIntegerQuantity(qml, "month"); out.day = _grabFirstElIntegerQuantity(qml, "day"); out.hour = _grabFirstElIntegerQuantity(qml, "hour"); out.minute = _grabFirstElIntegerQuantity(qml, "minute"); out.second = _grabFirstElIntegerQuantity(qml, "second"); return out; } } exports.CompositeTime = CompositeTime; /** Represents a QuakeML OriginUncertainty. */ class OriginUncertainty { horizontalUncertainty; minHorizontalUncertainty; maxHorizontalUncertainty; azimuthMaxHorizontalUncertainty; confidenceEllipsoid; preferredDescription; confidenceLevel; /** * Parses a QuakeML origin uncertainty xml element into an OriginUncertainty object. * * @param qml the origin uncertainty xml Element * @returns OriginUncertainty instance */ static createFromXml(qml) { if (qml.localName !== "originUncertainty") { throw new Error(`Cannot extract, not a QuakeML Origin Uncertainty: ${qml.localName}`); } const out = new OriginUncertainty(); out.horizontalUncertainty = _grabFirstElFloat(qml, "horizontalUncertainty"); out.minHorizontalUncertainty = _grabFirstElFloat(qml, "minHorizontalUncertainty"); out.maxHorizontalUncertainty = _grabFirstElFloat(qml, "maxHorizontalUncertainty"); out.azimuthMaxHorizontalUncertainty = _grabFirstElFloat(qml, "azimuthMaxHorizontalUncertainty"); out.confidenceEllipsoid = _grabFirstElType(ConfidenceEllipsoid.createFromXml.bind(ConfidenceEllipsoid))(qml, "confidenceEllipsoid"); out.preferredDescription = _grabFirstElText(qml, "preferredDescription"); out.confidenceLevel = _grabFirstElFloat(qml, "confidenceLevel"); return out; } } exports.OriginUncertainty = OriginUncertainty; /** Represents a QuakeML ConfidenceEllipsoid. */ class ConfidenceEllipsoid { semiMajorAxisLength; semiMinorAxisLength; semiIntermediateAxisLength; majorAxisPlunge; majorAxisAzimuth; majorAxisRotation; constructor(semiMajorAxisLength, semiMinorAxisLength, semiIntermediateAxisLength, majorAxisPlunge, majorAxisAzimuth, majorAxisRotation) { this.semiMajorAxisLength = semiMajorAxisLength; this.semiMinorAxisLength = semiMinorAxisLength; this.semiIntermediateAxisLength = semiIntermediateAxisLength; this.majorAxisPlunge = majorAxisPlunge; this.majorAxisAzimuth = majorAxisAzimuth; this.majorAxisRotation = majorAxisRotation; } /** * Parses a QuakeML confidence ellipsoid xml element into an ConfidenceEllipsoid object. * * @param qml the confidence ellipsoid xml Element * @returns ConfidenceEllipsoid instance */ static createFromXml(qml) { if (qml.localName !== "confidenceEllipsoid") { throw new Error(`Cannot extract, not a QuakeML Confidence Ellipsoid: ${qml.localName}`); } const semiMajorAxisLength = _grabFirstElFloat(qml, "semiMajorAxisLength"); if (semiMajorAxisLength === undefined) { throw new Error("confidenceEllipsoid missing semiMajorAxisLength"); } const semiMinorAxisLength = _grabFirstElFloat(qml, "semiMinorAxisLength"); if (semiMinorAxisLength === undefined) { throw new Error("confidenceEllipsoid missing semiMinorAxisLength"); } const semiIntermediateAxisLength = _grabFirstElFloat(qml, "semiIntermediateAxisLength"); if (semiIntermediateAxisLength === undefined) { throw new Error("confidenceEllipsoid missing semiIntermediateAxisLength"); } const majorAxisPlunge = _grabFirstElFloat(qml, "majorAxisPlunge"); if (majorAxisPlunge === undefined) { throw new Error("confidenceEllipsoid missing majorAxisPlunge"); } const majorAxisAzimuth = _grabFirstElFloat(qml, "majorAxisAzimuth"); if (majorAxisAzimuth === undefined) { throw new Error("confidenceEllipsoid missing majorAxisAzimuth"); } const majorAxisRotation = _grabFirstElFloat(qml, "majorAxisRotation"); if (majorAxisRotation === undefined) { throw new Error("confidenceEllipsoid missing majorAxisRotation"); } const out = new ConfidenceEllipsoid(semiMajorAxisLength, semiMinorAxisLength, semiIntermediateAxisLength, majorAxisPlunge, majorAxisAzimuth, majorAxisRotation); return out; } } exports.ConfidenceEllipsoid = ConfidenceEllipsoid; /** Represents a QuakeML OriginQuality. */ class OriginQuality { associatedPhaseCount; usedPhaseCount; associatedStationCount; usedStationCount; depthPhaseCount; standardError; azimuthalGap; secondaryAzimuthalGap; groundTruthLevel; maximumDistance; minimumDistance; medianDistance; /** * Parses a QuakeML origin quality xml element into an OriginQuality object. * * @param qml the origin quality xml Element * @returns OriginQuality instance */ static createFromXml(qml) { if (qml.localName !== "quality") { throw new Error(`Cannot extract, not a QuakeML Origin Quality: ${qml.localName}`); } const out = new OriginQuality(); out.associatedPhaseCount = _grabFirstElInt(qml, "associatedPhaseCount"); out.usedPhaseCount = _grabFirstElInt(qml, "usedPhaseCount"); out.associatedStationCount = _grabFirstElInt(qml, "associatedStationCount"); out.usedStationCount = _grabFirstElInt(qml, "usedStationCount"); out.standardError = _grabFirstElFloat(qml, "standardError"); out.azimuthalGap = _grabFirstElFloat(qml, "azimuthalGap"); out.secondaryAzimuthalGap = _grabFirstElFloat(qml, "secondaryAzimuthalGap"); out.groundTruthLevel = _grabFirstElText(qml, "groundTruthLevel"); out.maximumDistance = _grabFirstElFloat(qml, "maximumDistance"); out.minimumDistance = _grabFirstElFloat(qml, "minimumDistance"); out.medianDistance = _grabFirstElFloat(qml, "medianDistance"); return out; } } exports.OriginQuality = OriginQuality; /** Represents a QuakeML Magnitude. */ class Magnitude extends BaseElement { stationMagnitudeContributions = []; magQuantity; type; origin; methodID; stationCount; azimuthalGap; evaluationMode; evaluationStatus; constructor(mag, type) { super(); if (typeof mag === "number") { this.magQuantity = new Quantity(mag); } else { this.magQuantity = mag; } if (type) { this.type = type; } } /** * Parses a QuakeML magnitude xml element into a Magnitude object. * * @param qml the magnitude xml Element * @param allOrigins origins already extracted from the xml for linking magnitudes with origins * @param allStationMagnitudes station magnitudes already extracted from the xml * @returns Magnitude instance */ static createFromXml(qml, allOrigins, allStationMagnitudes) { if (qml.localName !== "magnitude") { throw new Error(`Cannot extract, not a QuakeML Magnitude: ${qml.localName}`); } const mag = _grabFirstElRealQuantity(qml, "mag"); if (!mag) { throw new Error("magnitude missing mag"); } const out = new Magnitude(mag); out.populate(qml); const stationMagnitudeContributionEls = Array.from(qml.getElementsByTagNameNS(exports.BED_NS, "stationMagnitudeContribution")); out.stationMagnitudeContributions = stationMagnitudeContributionEls.map((smc) => StationMagnitudeContribution.createFromXml(smc, allStationMagnitudes)); out.type = _grabFirstElText(qml, "type"); const originID = _grabFirstElText(qml, "originID"); out.origin = allOrigins.find((o) => o.publicId === originID); if (originID && !out.origin) { throw new Error("No origin with ID " + originID); } out.methodID = _grabFirstElText(qml, "methodID"); out.stationCount = _grabFirstElInt(qml, "stationCount"); out.azimuthalGap = _grabFirstElFloat(qml, "azimuthalGap"); out.evaluationMode = _grabFirstElText(qml, "evaluationMode"); out.evaluationStatus = _grabFirstElText(qml, "evaluationStatus"); return out; } toString() { return `${text_format_1.magFormat.format(this.mag)} ${this.type ? this.type : ""}`; } get mag() { return this.magQuantity.value; } set mag(value) { if (typeof value === "number") { this.magQuantity.value = value; } else { this.magQuantity = value; } } } exports.Magnitude = Magnitude; /** Represents a QuakeML StationMagnitudeContribution. */ class StationMagnitudeContribution { stationMagnitude; residual; weight; constructor(stationMagnitude) { this.stationMagnitude = stationMagnitude; } /** * Parses a QuakeML station magnitude contribution xml element into a StationMagnitudeContribution object. * * @param qml the station magnitude contribution xml Element * @param allStationMagnitudes station magnitudes already extracted from the xml for linking station magnitudes with station magnitude contributions * @returns StationMagnitudeContribution instance */ static createFromXml(qml, allStationMagnitudes) { if (qml.localName !== "stationMagnitudeContribution") { throw new Error(`Cannot extract, not a QuakeML StationMagnitudeContribution: ${qml.localName}`); } const stationMagnitudeID = _grabFirstElText(qml, "stationMagnitudeID"); if (!(0, utils_1.isNonEmptyStringArg)(stationMagnitudeID)) { throw new Error("stationMagnitudeContribution missing stationMagnitude"); } const stationMagnitude = allStationMagnitudes.find((sm) => sm.publicId === stationMagnitudeID); if (!(0, utils_1.isDef)(stationMagnitude)) { throw new Error("No stationMagnitude with ID " + stationMagnitudeID); } const out = new StationMagnitudeContribution(stationMagnitude); out.residual = _grabFirstElFloat(qml, "residual"); out.weight = _grabFirstElFloat(qml, "weight"); return out; } } exports.StationMagnitudeContribution = StationMagnitudeContribution; /** Represents a QuakeML Arrival, a combination of a Pick with a phase name. */ class Arrival extends BaseElement { phase; pick; timeCorrection; azimuth; distance; takeoffAngle; timeResidual; horizontalSlownessResidual; backazimuthResidual; timeWeight; horizontalSlownessWeight; backazimuthWeight; earthModelID; constructor(phase, pick) { super(); this.phase = phase; this.pick = pick; } /** * Parses a QuakeML arrival xml element into a Arrival object. * * @param arrivalQML the arrival xml Element * @param allPicks picks already extracted from the xml for linking arrivals with picks * @returns Arrival instance */ static createFromXml(arrivalQML, allPicks) { if (arrivalQML.localName !== "arrival") { throw new Error(`Cannot extract, not a QuakeML Arrival: ${arrivalQML.localName}`); } const pickId = _grabFirstElText(arrivalQML, "pickID"); const phase = _grabFirstElText(arrivalQML, "phase"); if ((0, utils_1.isNonEmptyStringArg)(phase) && (0, utils_1.isNonEmptyStringArg)(pickId)) { const myPick = allPicks.find(function (p) { return p.publicId === pickId; }); if (!myPick) { throw new Error("Can't find pick with Id=" + pickId + " for Arrival"); } const out = new Arrival(phase, myPick); out.populate(arrivalQML); out.timeCorrection = _grabFirstElFloat(arrivalQML, "timeCorrection"); out.azimuth = _grabFirstElFloat(arrivalQML, "azimuth"); out.distance = _grabFirstElFloat(arrivalQML, "distance"); out.takeoffAngle = _grabFirstElRealQuantity(arrivalQML, "takeoffAngle"); out.timeResidual = _grabFirstElFloat(arrivalQML, "timeResidual"); out.horizontalSlownessResidual = _grabFirstElFloat(arrivalQML, "horizontalSlownessResidual"); out.backazimuthResidual = _grabFirstElFloat(arrivalQML, "backazimuthResidual"); out.timeWeight = _grabFirstElFloat(arrivalQML, "timeWeight"); out.horizontalSlownessWeight = _grabFirstElFloat(arrivalQML, "horizontalSlownessWeight"); out.backazimuthWeight = _grabFirstElFloat(arrivalQML, "backazimuthWeight"); out.earthModelID = _grabFirstElText(arrivalQML, "earthModelID"); return out; } else { throw new Error("Arrival does not have phase or pickId: " + (0, utils_1.stringify)(phase) + " " + (0, utils_1.stringify)(pickId)); } } } exports.Arrival = Arrival; /** Represents a QuakeML Pick. */ class Pick extends BaseElement { timeQuantity; waveformID; filterID; methodID; horizontalSlowness; backazimuth; slownessMethodID; onset; phaseHint; polarity; evaluationMode; evaluationStatus; constructor(time, waveformID) { super(); if (time instanceof luxon_1.DateTime) { this.timeQuantity = new Quantity(time); } else { this.timeQuantity = time; } this.waveformID = waveformID; } get time() { return this.timeQuantity.value; } set time(t) { if (t instanceof luxon_1.DateTime) { this.timeQuantity.value = t; } else { this.timeQuantity = t; } } /** * Parses a QuakeML pick xml element into a Pick object. * * @param pickQML the pick xml Element * @returns Pick instance */ static createFromXml(pickQML) { if (pickQML.localName !== "pick") { throw new Error(`Cannot extract, not a QuakeML Pick: ${pickQML.localName}`); } const time = _grabFirstElTimeQuantity(pickQML, "time"); if (!(0, utils_1.isDef)(time)) { throw new Error("Missing time"); } const waveformId = _grabFirstElType(WaveformID.createFromXml.bind(WaveformID))(pickQML, "waveformID"); if (!(0, utils_1.isObject)(waveformId)) { throw new Error("pick missing waveformID"); } const out = new Pick(time, waveformId); out.populate(pickQML); out.filterID = _grabFirstElText(pickQML, "filterID"); out.methodID = _grabFirstElText(pickQML, "methodID"); out.horizontalSlowness = _grabFirstElRealQuantity(pickQML, "horizontalSlowness"); out.backazimuth = _grabFirstElRealQuantity(pickQML, "backazimuth"); out.slownessMethodID = _grabFirstElText(pickQML, "slownessMethodID"); out.onset = _grabFirstElText(pickQML, "onset"); out.phaseHint = _grabFirstElText(pickQML, "phaseHint"); out.polarity = _grabFirstElText(pickQML, "polarity"); out.evaluationMode = _grabFirstElText(pickQML, "evaluationMode"); out.evaluationStatus = _grabFirstElText(pickQML, "evaluationStatus"); return out; } get networkCode() { return this.waveformID.networkCode; } get stationCode() { return this.waveformID.stationCode; } get locationCode() { return this.waveformID.locationCode || "--"; } get channelCode() { return this.waveformID.channelCode || "---"; } isAtStation(station) { return (this.networkCode === station.networkCode && this.stationCode === station.stationCode); } isOnChannel(channel) { return (this.networkCode === channel.station.networkCode && this.stationCode === channel.station.stationCode && this.locationCode === channel.locationCode && this.channelCode === channel.channelCode); } toString() { return ((0, utils_1.stringify)(this.time) + ` ${this.networkCode}.${this.stationCode}.${this.locationCode}.${this.channelCode}`); } } exports.Pick = Pick; /** Represents a QuakeML Focal Mechanism. */ class FocalMechanism extends BaseElement { waveformIDList = []; momentTensorList = []; triggeringOrigin; nodalPlanes; principalAxes; azimuthalGap; stationPolarityCount; misfit; stationDistributionRatio; methodID; evaluationMode; evaluationStatus; /** * Parses a QuakeML focal mechanism xml element into a FocalMechanism object. * * @param focalMechQML the focal mechanism xml Element * @param allOrigins origins already extracted from the xml for linking focal mechanisms with origins * @param allMagnitudes magnitudes already extracted from the xml for linking moment tensors with magnitudes * @returns FocalMechanism instance */ static createFromXml(focalMechQML, allOrigins, allMagnitudes) { if (focalMechQML.localName !== "focalMechanism") { throw new Error(`Cannot extract, not a QuakeML focalMechanism: ${focalMechQML.localName}`); } const out = new FocalMechanism(); out.populate(focalMechQML); const waveformIDEls = Array.from(focalMechQML.getElementsByTagNameNS(exports.BED_NS, "waveformID")); out.waveformIDList = waveformIDEls.map((wid) => WaveformID.createFromXml(wid)); const momentTensorEls = Array.from(focalMechQML.getElementsByTagNameNS(exports.BED_NS, "momentTensor")); out.momentTensorList = momentTensorEls.map((mt) => MomentTensor.createFromXml(mt, allOrigins, allMagnitudes)); const triggeringOriginID = _grabFirstElText(focalMechQML, "triggeringOriginID"); out.triggeringOrigin = allOrigins.find((o) => o.publicId === triggeringOriginID); if (triggeringOriginID && !out.triggeringOrigin) { throw new Error("No origin with ID " + triggeringOriginID); } out.nodalPlanes = _grabFirstElType(NodalPlanes.createFromXml.bind(NodalPlanes))(focalMechQML, "nodalPlanes"); out.principalAxes = _grabFirstElType(PrincipalAxes.createFromXml.bind(PrincipalAxes))(focalMechQML, "principalAxes"); out.azimuthalGap = _grabFirstElFloat(focalMechQML, "azimuthalGap"); out.stationPolarityCount = _grabFirstElInt(focalMechQML, "stationPolarityCount"); out.misfit = _grabFirstElFloat(focalMechQML, "misfit"); out.stationDistributionRatio = _grabFirstElFloat(focalMechQML, "stationDistributionRatio"); out.methodID = _grabFirstElText(focalMechQML, "methodID"); out.evaluationMode = _grabFirstElText(focalMechQML, "evaluationMode"); out.evaluationStatus = _grabFirstElText(focalMechQML, "evaluationStatus"); return out; } } exports.FocalMechanism = FocalMechanism; /** Represents a QuakeML NodalPlanes. */ class NodalPlanes { nodalPlane1; nodalPlane2; preferredPlane; /** * Parses a QuakeML nodal planes xml element into a NodalPlanes object. * * @param nodalPlanesQML the nodal planes xml Element * @returns NodalPlanes instance */ static createFromXml(nodalPlanesQML) { const out = new NodalPlanes(); out.nodalPlane1 = _grabFirstElType(NodalPlane.createFromXml.bind(NodalPlane))(nodalPlanesQML, "nodalPlane1"); out.nodalPlane2 = _grabFirstElType(NodalPlane.createFromXml.bind(NodalPlane))(nodalPlanesQML, "nodalPlane2"); const preferredPlaneString = _grabAttribute(nodalPlanesQML, "preferredPlane"); out.preferredPlane = (0, utils_1.isNonEmptyStringArg)(preferredPlaneString) ? parseInt(preferredPlaneString) : undefined; return out; } } exports.NodalPlanes = NodalPlanes; /** Represents a QuakeML NodalPlane. */ class NodalPlane { strike; dip; rake; constructor(strike, dip, rake) { this.strike = strike; this.dip = dip; this.rake = rake; } /** * Parses a QuakeML nodal plane xml element into a NodalPlane object. * * @param nodalPlaneQML the nodal plane xml Element * @returns NodalPlane instance */ static createFromXml(nodalPlaneQML) { const strike = _grabFirstElRealQuantity(nodalPlaneQML, "strike"); if (!(0, utils_1.isObject)(strike)) { throw new Error("nodal plane missing strike"); } const dip = _grabFirstElRealQuantity(nodalPlaneQML, "dip"); if (!(0, utils_1.isObject)(dip)) { throw new Error("nodal plane missing dip"); } const rake = _grabFirstElRealQuantity(nodalPlaneQML, "rake"); if (!(0, utils_1.isObject)(rake)) { throw new Error("nodal plane missing rake"); } const out = new NodalPlane(strike, dip, rake); return out; } } exports.NodalPlane = NodalPlane; /** Represents a QuakeML PrincipalAxes. */ class PrincipalAxes { tAxis; pAxis; nAxis; constructor(tAxis, pAxis) { this.tAxis = tAxis; this.pAxis = pAxis; } /** * Parses a QuakeML princpalAxes element into a PrincipalAxes object. * * @param princpalAxesQML the princpalAxes xml Element * @returns PrincipalAxes instance */ static createFromXml(princpalAxesQML) { if (princpalAxesQML.localName !== "principalAxes") { throw new Error(`Cannot extract, not a QuakeML princpalAxes: ${princpalAxesQML.localName}`); } const tAxis = _grabFirstElType(Axis.createFromXml.bind(Axis))(princpalAxesQML, "tAxis"); if (!(0, utils_1.isObject)(tAxis)) { throw new Error("nodal plane missing tAxis"); } const pAxis = _grabFirstElType(Axis.createFromXml.bind(Axis))(princpalAxesQML, "pAxis"); if (!(0, utils_1.isObject)(pAxis)) { throw new Error("nodal plane missing pAxis"); } const out = new PrincipalAxes(tAxis, pAxis); out.nAxis = _grabFirstElType(Axis.createFromXml.bind(Axis))(princpalAxesQML, "nAxis"); return out; } } exports.PrincipalAxes = PrincipalAxes; /** Represents a QuakeML Axis. */ class Axis { azimuth; plunge; length; constructor(azimuth, plunge, length) { this.azimuth = azimuth; this.plunge = plunge; this.length = length; } /** * Parses a QuakeML axis xml element into a Axis object. * * @param axisQML the axis xml Element * @returns Axis instance */ static createFromXml(axisQML) { const azimuth = _grabFirstElRealQuantity(axisQML, "azimuth"); if (!(0, utils_1.isObject)(azimuth)) { throw new Error("nodal plane missing azimuth"); } const plunge = _grabFirstElRealQuantity(axisQML, "plunge"); if (!(0, utils_1.isObject)(plunge)) { throw new Error("nodal plane missing plunge"); } const length = _grabFirstElRealQuantity(axisQML, "length"); if (!(0, utils_1.isObject)(length)) { throw new Error("nodal plane missing length"); } const out = new Axis(azimuth, plunge, length); return out; } } exports.Axis = Axis; /** Represents a QuakeML MomentTensor. */ class MomentTensor extends BaseElement { dataUsedList = []; derivedOrigin; momentMagnitude; scalarMoment; tensor; variance; varianceReduction; doubleCouple; clvd; iso; greensFunctionID; filterID; sourceTimeFunction; methodID; category; inversionType; constructor(derivedOrigin) { super(); this.derivedOrigin = derivedOrigin; } /** * Parses a QuakeML momentTensor xml element into a MomentTensor object. * * @param momentTensorQML the momentTensor xml Element * @param allOrigins origins already extracted from the xml for linking moment tensors with origins * @param allMagnitudes magnitudes already extracted from the xml for linking moment tensors with magnitudes * @returns MomentTensor instance */ static createFromXml(momentTensorQML, allOrigins, allMagnitudes) { if (momentTensorQML.localName !== "momentTensor") { throw new Error(`Cannot extract, not a QuakeML momentTensor: ${momentTensorQML.localName}`); } const derivedOriginID = _grabFirstElText(momentTensorQML, "derivedOriginID"); if (!(0, utils_1.isNonEmptyStringArg)(derivedOriginID)) { throw new Error("momentTensor missing derivedOriginID"); } const derivedOrigin = allOrigins.find((o) => o.publicId === derivedOriginID); if (!(0, utils_1.isDef)(derivedOrigin)) { throw new Error("No origin with ID " + derivedOriginID); } const