@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
JavaScript
"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);
}