@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
JavaScript
"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