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

346 lines (345 loc) 12.1 kB
"use strict"; /* * Philip Crotwell * University of South Carolina, 2022 * https://www.seis.sc.edu */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NslcId = exports.EMPTY_LOC_CODE = exports.LocationSourceId = exports.StationSourceId = exports.NetworkSourceId = exports.FDSNSourceId = exports.SEP = exports.FDSN_PREFIX = void 0; exports.bandCodeForRate = bandCodeForRate; exports.parseSourceId = parseSourceId; exports.SourceIdSorter = SourceIdSorter; exports.FDSN_PREFIX = "FDSN:"; exports.SEP = "_"; class FDSNSourceId { networkCode; stationCode; locationCode; bandCode; sourceCode; subsourceCode; constructor(networkCode, stationCode, locationCode, bandCode, sourceCode, subsourceCode) { this.networkCode = networkCode; this.stationCode = stationCode; this.locationCode = locationCode; this.bandCode = bandCode; this.sourceCode = sourceCode; this.subsourceCode = subsourceCode; } static createUnknown(sampRate, source, subsource) { const s = source ? source : "Y"; const ss = subsource ? subsource : "X"; return new FDSNSourceId("XX", "ABC", "", bandCodeForRate(sampRate), s, ss); } static parse(id) { if (!id.startsWith(exports.FDSN_PREFIX)) { throw new Error(`sourceid must start with ${exports.FDSN_PREFIX}: ${id}`); } const items = id.slice(exports.FDSN_PREFIX.length).split(exports.SEP); if (items.length === 6) { return new FDSNSourceId(items[0], items[1], items[2], items[3], items[4], items[5]); } else { throw new Error(`FDSN sourceid must have 6 items for channel; separated by '${exports.SEP}': ${id}`); } } static fromNslc(net, sta, loc, channelCode) { let band; let source; let subsource; if (channelCode.length === 3) { band = channelCode.charAt(0); source = channelCode.charAt(1); subsource = channelCode.charAt(2); } else { const b_s_ss = /(\w)_(\w+)_(\w+)/; const match = b_s_ss.exec(channelCode); if (match) { band = match[1]; source = match[2]; subsource = match[3]; } else { throw new Error(`channel code must be length 3 or have 3 items separated by '${exports.SEP}': ${channelCode}`); } } return new FDSNSourceId(net, sta, loc, band, source, subsource); } static fromNslcId(nslcId) { return FDSNSourceId.fromNslc(nslcId.networkCode, nslcId.stationCode, nslcId.locationCode, nslcId.channelCode); } static parseNslc(nslc, sep = ".") { const items = nslc.split(sep); if (items.length < 4) { throw new Error(`channel nslc must have 4 items separated by '${sep}': ${nslc}`); } return FDSNSourceId.fromNslc(items[0], items[1], items[2], items[3]); } stationSourceId() { return new StationSourceId(this.networkCode, this.stationCode); } networkSourceId() { return new NetworkSourceId(this.networkCode); } asNslc() { let chanCode; if (this.bandCode.length === 1 && this.sourceCode.length === 1 && this.subsourceCode.length === 1) { chanCode = `${this.bandCode}${this.sourceCode}${this.subsourceCode}`; } else { chanCode = `${this.bandCode}${exports.SEP}${this.sourceCode}${exports.SEP}${this.subsourceCode}`; } return new NslcId(this.networkCode, this.stationCode, this.locationCode, chanCode); } /** * returns a channel code. If this is an old style NSLC, it will be 3 chars, * but if either source or subsouce is more than one char, it will be * three fields delimited by underscores. * * @returns the channel code part of the id */ formChannelCode() { return this.asNslc().channelCode; } toString() { return `${exports.FDSN_PREFIX}${this.networkCode}${exports.SEP}${this.stationCode}${exports.SEP}${this.locationCode}${exports.SEP}${this.bandCode}${exports.SEP}${this.sourceCode}${exports.SEP}${this.subsourceCode}`; } toStringNoPrefix() { return `${this.networkCode}${exports.SEP}${this.stationCode}${exports.SEP}${this.locationCode}${exports.SEP}${this.bandCode}${exports.SEP}${this.sourceCode}${exports.SEP}${this.subsourceCode}`; } equals(other) { if (!other) { // useful to be able to check equals to null return false; } return this.toString() === other.toString(); } clone() { return new FDSNSourceId(this.networkCode, this.stationCode, this.locationCode, this.bandCode, this.sourceCode, this.subsourceCode); } } exports.FDSNSourceId = FDSNSourceId; class NetworkSourceId { networkCode; constructor(networkCode) { this.networkCode = networkCode; } static parse(id) { if (!id.startsWith(exports.FDSN_PREFIX)) { throw new Error(`sourceid must start with ${exports.FDSN_PREFIX}: ${id}`); } const items = id.slice(exports.FDSN_PREFIX.length).split(exports.SEP); if (items.length === 1) { return new NetworkSourceId(items[0]); } else { throw new Error(`FDSN network sourceid must have 1 items; separated by '${exports.SEP}': ${id}`); } return new NetworkSourceId(items[0]); } toString() { return `${exports.FDSN_PREFIX}${this.networkCode}`; } equals(other) { return this.toString() === other.toString(); } } exports.NetworkSourceId = NetworkSourceId; class StationSourceId { networkCode; stationCode; constructor(networkCode, stationCode) { this.networkCode = networkCode; this.stationCode = stationCode; } static parse(id) { if (!id.startsWith(exports.FDSN_PREFIX)) { throw new Error(`station sourceid must start with ${exports.FDSN_PREFIX}: ${id}`); } const items = id.slice(exports.FDSN_PREFIX.length).split(exports.SEP); if (items.length === 2) { return new StationSourceId(items[0], items[1]); } else { throw new Error(`FDSN station sourceid must have 2 items; separated by '${exports.SEP}': ${id}`); } return new StationSourceId(items[0], items[1]); } toString() { return `${exports.FDSN_PREFIX}${this.networkCode}${exports.SEP}${this.stationCode}`; } networkSourceId() { return new NetworkSourceId(this.networkCode); } equals(other) { return this.toString() === other.toString(); } } exports.StationSourceId = StationSourceId; class LocationSourceId { networkCode; stationCode; locationCode; constructor(networkCode, stationCode, locationCode) { this.networkCode = networkCode; this.stationCode = stationCode; this.locationCode = locationCode; } toString() { return `${exports.FDSN_PREFIX}${this.networkCode}${exports.SEP}${this.stationCode}${exports.SEP}${this.locationCode}`; } equals(other) { return this.toString() === other.toString(); } } exports.LocationSourceId = LocationSourceId; /** * Generates the best band code for a channel based on the sample rate and * optionally the response lower bound period, which is mostly useful for * separating broadband from short period seismometers. * * @param sampRate sample rate in samples per second * @param resp_lb response long period bound in seconds * @returns single character band code */ function bandCodeForRate(sampRate, resp_lb) { if (!sampRate) { return "I"; } if (sampRate >= 5000) { return "J"; } else if (sampRate >= 1000 && sampRate < 5000) { if (resp_lb && resp_lb < 0.1) { return "F"; } return "G"; } else if (sampRate >= 250 && sampRate < 1000) { if (resp_lb && resp_lb < 0.1) { return "C"; } return "D"; } else if (sampRate >= 80 && sampRate < 250) { if (resp_lb && resp_lb < 0.1) { return "H"; } return "E"; } else if (sampRate >= 10 && sampRate < 80) { if (resp_lb && resp_lb < 0.1) { return "B"; } return "S"; } else if (sampRate > 1.05 && sampRate < 10) { return "M"; } else if (sampRate >= 0.95 && sampRate <= 1.05) { // spec not clear about how far from 1 is L, guess 5% return "L"; } else if (sampRate >= 0.1 && sampRate < 1) { return "V"; } else if (sampRate >= 0.01 && sampRate < 0.1) { return "U"; } else if (sampRate >= 0.001 && sampRate < 0.01) { return "W"; } else if (sampRate >= 0.0001 && sampRate < 0.001) { return "R"; } else if (sampRate >= 0.00001 && sampRate < 0.0001) { return "P"; } else if (sampRate >= 0.000001 && sampRate < 0.00001) { return "T"; } else if (sampRate < 0.000001) { return "Q"; } else { throw new Error(`Unable to calc band code for: ${sampRate} ${resp_lb}`); } } exports.EMPTY_LOC_CODE = "--"; class NslcId { networkCode; stationCode; locationCode; channelCode; constructor(net, sta, loc, chan) { this.networkCode = net; this.stationCode = sta; this.locationCode = loc; this.channelCode = chan; } static parse(nslc, sep = ".") { const items = nslc.split(exports.SEP); if (items.length !== 4) { throw new Error(`NSLC id must have 4 items; separated by '${sep}': ${nslc}`); } return new NslcId(items[0], items[1], items[2], items[3]); } toString() { return `${this.networkCode}_${this.stationCode}_${this.locationCode}_${this.channelCode}`; } equals(other) { if (this.networkCode !== other.networkCode) { return false; } if (this.stationCode !== other.stationCode) { return false; } const myLoc = this.locationCode === exports.EMPTY_LOC_CODE ? "" : this.locationCode; const otherLoc = other.locationCode === exports.EMPTY_LOC_CODE ? "" : other.locationCode; if (myLoc !== otherLoc) { return false; } if (this.channelCode !== other.channelCode) { return false; } return true; } } exports.NslcId = NslcId; function parseSourceId(id) { if (!id.startsWith(exports.FDSN_PREFIX)) { throw new Error(`sourceid must start with ${exports.FDSN_PREFIX}: ${id}`); } const items = id.slice(exports.FDSN_PREFIX.length).split(exports.SEP); if (items.length === 1) { return new NetworkSourceId(items[0]); } else if (items.length === 2) { return new StationSourceId(items[0], items[1]); } else if (items.length !== 6) { throw new Error(`FDSN sourceid must have 6 items for channel, 2 for station or 1 for network; separated by '${exports.SEP}': ${id}`); } return new FDSNSourceId(items[0], items[1], items[2], items[3], items[4], items[5]); } function SourceIdSorter(aSid, bSid) { if (aSid.networkCode !== bSid.networkCode) { return aSid.networkCode.localeCompare(bSid.networkCode); } if (aSid.stationCode !== bSid.stationCode) { return aSid.stationCode.localeCompare(bSid.stationCode); } if (aSid.locationCode !== bSid.locationCode) { return aSid.locationCode.localeCompare(bSid.locationCode); } if (aSid.bandCode !== bSid.bandCode) { return aSid.bandCode.localeCompare(bSid.bandCode); } if (aSid.sourceCode !== bSid.sourceCode) { return aSid.sourceCode.localeCompare(bSid.sourceCode); } return aSid.subsourceCode.localeCompare(bSid.subsourceCode); }