Skip to contents

gmsp 0.4.6

New exported functions

  • TSL2PS(.x, xi = 0.05, Tn = NULL, output = "PSL", D50 = FALSE, D100 = FALSE, nTheta = 180L) is the explicit response-spectrum helper for canonical TSL tables produced by AT2TS(), VT2TS(), and DT2TS(). It does not expose BY, COL.s, COL.t, or COL.ID; grouping metadata is derived from the TSL schema. Projects that currently call TS2PS(TSL, COL.s = "s", COL.t = "t", COL.ID = "ID", Output = "PSL") for canonical TSL input should migrate to TSL2PS(TSL, output = "PSL").
  • D50 and D100 are part of the canonical TSL2PS() contract. D50 migration: TSL2PS(TSL, output = "PSL", D50 = TRUE, nTheta = 12L) replaces TS2PS(..., D50 = TRUE, n.theta = 12L). This is a breaking 0.4.6 migration note; other projects should read this changelog before updating.
  • Canonical table-shape helpers are now exported for downstream pipelines: TSL2TSW(), TSW2TSL(), TSL2IM(), IML2IMW(), PSL2PSW(), and PSW2PSL(). These replace local project helpers that manually cast TSL, IML, and PSL tables with repeated dcast() / melt() code.

Table contract helpers

  • TSL2TSW(.x, by = "auto", ids = c("AT", "VT", "DT")) converts canonical long time-series tables (t, s, ID, OCID) to wide TSW columns such as AT.H1, VT.H1, and DT.H1. TSW2TSL() reverses the projection and accepts either t or legacy constructor ts as the time column.

  • TSL2IM(.x, units.source, units.target = "mm", output = c("IML", "IMW")) is the primary intensity API. getIntensity() remains as a compatibility wrapper and keeps the long IML default. Use output = "IMW" or IML2IMW() when a downstream table needs one row per metadata and OCID.

  • PSL2PSW() and PSW2PSL() expose the canonical spectra long/wide conversion. After PSW2PSL(), D50 and D100 are ordinary OCID values, so scripts can filter OCID %in% c("D50", "D100") instead of parsing column-name suffixes.

  • TSL2PS() now accepts vector xi. A scalar xi preserves the previous schema with no xi column. A vector xi adds xi as metadata:

    TSL2PS(TSL, xi = c(0.02, 0.05, 0.10), output = "PSW",
           D50 = TRUE, D100 = TRUE)

    Downstream scripts that currently loop over damping ratios can call TSL2PS() once and group or filter by xi.

D100 spectra extension

  • TSL2PS() now adds D100 horizontal response spectra beside the existing D50 path:

    TSL2PS(TSL, output = "PSW", D50 = TRUE, D100 = TRUE, nTheta = 180L)

    output = "PSL" adds rows with OCID = "D100". output = "PSW" adds PSA.D100, PSV.D100, and SD.D100. Scripts that already consume PSA.D50, PSV.D50, or SD.D50 should explicitly include the matching D100 columns when they opt in.

  • Downstream configs/scripts that currently enumerate D50, such as spectra.D50, DIR_TARGET = "D50", or plot/export direction lists, should add D100 explicitly only for runs that request D100 = TRUE.

  • D100 uses the same rotation grid as D50. It is the maximum over rotated horizontal spectra for each period and spectral ID; the maximizing angle can vary by Tn and by PSA / PSV / SD. The implementation returns spectra only, not the D100 angle. When D50 = TRUE and D100 = TRUE, both derived components are computed from one rotated response matrix.

  • The downstream contract stays canonical TSL2PS(). Do not migrate scripts to TS2PS(), TS2PSA(), RotD50, or RotD100 names. The implementation plan is recorded in dev/SoT/PLAN-TSL2PS-D100.md.

API cleanup

  • getND() has been moved out of the exported package surface to dev/legacy/get_ND.R. Its public signature mixed raw heterogeneous units, target units, and Newmark episode controls in a way that needs a separate design before returning to the package.

  • mapOCIDtoDir() has been moved out of the exported package surface to dev/legacy/mapOCIDtoDir.R. mapComponents() now owns component classification, and extractRecord() calls mapComponents(..., rotate = FALSE) before alignment. The new SoT compares classification against the old helper and verifies byte-identical raw CSV/JSON outputs for fixture extraction.

  • mapComponents() now accepts output = c("long", "wide") and can consume either long t, OCID, s input or wide t, <OCID1>, <OCID2>, <OCID3> input. The default "long" shape remains the compatible output; output = "wide" returns data.table(t, H1, H2, UP). Both outputs preserve componentMap and rotate attributes; rotated outputs also preserve theta.

  • filterIMF() has been moved out of the exported package surface to dev/legacy/filterIMF.R. No current callers were detected in gmsp, AR-S2J2J, or AR-SABP0.R; users should compose filtering workflows directly from canonical TSL, TS2IMF(), and TSL2PS().

  • The 0.4.x spectra path is closed around canonical TSL consumption: spectra code should call TSL2PS(), not TS2PS() with BY, COL.s, COL.t, and COL.ID.

  • TS2PS() has been removed from the exported package surface. It mixed generic long-table dispatch, grouping autodetection, column-name arguments, and D50 behavior. Use TSL2PS() with canonical TSL input.

  • TS2IMF() is now a single-series worker over canonical columns t and s. It no longer exposes BY, COL.s, COL.t, or Output; use output. Grouped callers should use data.table grouping, for example TSL[ID == "AT", TS2IMF(.SD, output = "TSL"), by = .(RecordID, OCID), .SDcols = c("t", "s")].

  • normalizeTS() now consumes canonical TSL input directly: normalizeTS(TSL, norm = "PGA"). It no longer exposes COL.s, COL.ID, COL.OCID, or BY; grouping is derived from metadata columns plus OCID.

  • readTS(), readAT(), readVT(), and readDT() now use .x for the selection table and path for the records root. This is a named-argument breaking change:

    # before
    readTS(SEL = SEL, recordsDir = RecordsDir, kind = "VT")
    readAT(SEL, recordsDir = RecordsDir)
    
    # after
    readTS(.x = SEL, path = RecordsDir, kind = "VT")
    readAT(.x = SEL, path = RecordsDir)

    Positional calls with both arguments, such as readAT(SEL, RecordsDir), remain valid. The same .x / path rule applies to readVT() and readDT(); do not update callers to keep recordsDir =.

  • buildMaster() now uses path for the index root:

    # before
    buildMaster(indexDir = IndexDir, owners = Owner)
    
    # after
    buildMaster(path = IndexDir, owners = Owner)

    Positional calls such as buildMaster(IndexDir, owners = Owner) remain valid. Named callers must not keep indexDir =.

  • buildRawFileTable() now uses path.records for the records root and path.index for the index root:

    # before
    buildRawFileTable(recordsDir = RecordsDir, indexDir = IndexDir,
                      owners = Owner)
    
    # after
    buildRawFileTable(path.records = RecordsDir, path.index = IndexDir,
                      owners = Owner)

    Positional calls with both paths remain valid. Named callers must not keep recordsDir = or indexDir =.

  • buildRawRecordTable() and buildRawIntensityTable() now use the same path argument contract as buildRawFileTable():

    # before
    buildRawRecordTable(recordsDir = RecordsDir, indexDir = IndexDir,
                        owners = Owner)
    buildRawIntensityTable(recordsDir = RecordsDir, indexDir = IndexDir,
                           owners = Owner)
    
    # after
    buildRawRecordTable(path.records = RecordsDir, path.index = IndexDir,
                        owners = Owner)
    buildRawIntensityTable(path.records = RecordsDir, path.index = IndexDir,
                           owners = Owner)

    Named callers must not keep recordsDir = or indexDir =.

  • Single-path raw/archive helpers now use path:

    archiveRawOwner(path = StationDir)
    getRawIntensities(path = StationDir)
    writeSelection(DT, name = "subset", path = SelectionDir)

    Named callers must not keep stationDir = or selectionDir =.

  • parseRecord() and extractRecord() now use .x for the one-record master subset and path for the records root:

    # before
    parseRecord(masterRows = Rows, recordsDir = RecordsDir)
    extractRecord(masterRows = Rows, recordsDir = RecordsDir)
    
    # after
    parseRecord(.x = Rows, path = RecordsDir)
    extractRecord(.x = Rows, path = RecordsDir)

    Positional calls with both arguments, such as extractRecord(Rows, RecordsDir), remain valid. Named callers must not keep masterRows = or recordsDir =.

  • auditParsers() now uses .x for the master table, owner for one OwnerID, and path for the records root:

    # before
    auditParsers(OwnerID = Owner, master = Master, recordsDir = RecordsDir)
    
    # after
    auditParsers(.x = Master, owner = Owner, path = RecordsDir)

    Named callers must not keep OwnerID =, master =, or recordsDir =. Positional calls must use the new order auditParsers(Master, Owner, RecordsDir).

  • AT2TS(), VT2TS(), and DT2TS() now expose time as an input-column selector and always return canonical TSL columns t, s, ID, and OCID. The old COL.t and COL.s arguments are removed. time is not an output-column name; it is only the name of the time column in the input table. Scripts should migrate as follows:

    # before
    AT2TS(Wide, Units = "mm", COL.t = "time", COL.s = "signal",
          Output = "TSL")
    
    # after
    AT2TS(Wide, units.source = "mm", time = "time", output = "TSL")

    Downstream code must consume the returned TSL as t and s. For example, .SDcols = c("time", "signal") should become .SDcols = c("t", "s"). Calls that already used a column named t and did not pass COL.t/COL.s do not need a script change.

  • The constructor family also normalizes the approved public argument names: Units -> units.source, TargetUnits -> units.target, Output -> output, Verbose -> verbose, Audit -> audit, isRawData -> isRaw, Resample -> resample, FlatZeros -> flatZeros, TrimZeros -> trimZeros, Detrend -> detrend, and Regularize -> regularize. VT2TS() and DT2TS() additionally use Derivate -> derivate and LowPass -> lowPass.

  • regularize() is no longer public API. Time-grid regularization is handled inside AT2TS(), VT2TS(), DT2TS(), TS2IMF(), and TSL2PS() via the internal helper .regularize(). External scripts should pass time = "..." to the constructor when the input time column is not named t; they should not call regularize() directly.

  • setSTFT() is no longer public API. STFT strategy selection is now the internal helper .setSTFT() used by AT2TS(), VT2TS(), DT2TS(), and auditSTFT(). External scripts should configure the public constructors instead of calling the STFT strategy helper directly.

gmsp 0.4.5

New exported functions

  • mapComponents(DT, rotate = TRUE) maps one long (t, OCID, s) record to canonical processed directions. Provider channels remain in OCID, returned DIR values are H1 / H2 / UP, and attr(out, "componentMap") records the OCID to DIR mapping. With rotate = TRUE, horizontal samples are rotated to principal axes and attr(out, "theta") stores the rotation angle.

Compatibility

  • mapOCIDtoDir() remained exported and unchanged in 0.4.5. It was removed from the exported package surface in 0.4.6.
  • extractRecord() and raw CSV/JSON writer contracts are unchanged; raw products continue to preserve provider OCID values.

gmsp 0.4.4

Breaking changes — units contract

  • AT2TS(), VT2TS(), DT2TS(), getIntensity() now require canonical base values for Units and TargetUnits:

    • length basis: "mm", "cm", "m" — valid for AT, VT, DT.
    • acceleration aliases: "g", "gal" — valid for AT2TS() only.
    • VT2TS() and DT2TS() reject "g"/"gal" (an acceleration unit passed to a velocity/displacement function is a category error).
    • getIntensity() accepts length-base only ("mm"/"cm"/"m") for Units and TargetUnits; the same scale factor applies to AT, VT, and DT rows of a long TSL, so only a length base is well-defined.
    • Verbose forms like "mm/s", "mm/s2", "m/s2", "cm/s" are rejected with a clear error pointing to the canonical base.

    KIND (acceleration / velocity / displacement) is determined by the function called, not by a suffix of the Units string. Provider string parsers .parseUnits() and .parseKind() continue to accept heterogeneous raw strings (e.g. "cm/sec2", "G", "GALS") — those operate at the ingestion layer and pre-normalize to canonical before flowing into the public API.

    Migration: callers passing Units = "mm/s" switch to Units = "mm"; same for displacement. Callers passing Units = "g" to VT2TS()/DT2TS() must move to AT2TS().

    Validated by a Ship-of-Theseus harness (inst/dev/sot/compare_units_contract.R): Stage A 42/42 (canonical inputs byte-identical to prior gmsp via identical()), Stage A-bis 3/3 (current verbose ≡ canonical, documents migration), Stage C-bis 9/9 (illegal inputs error correctly). Verify mode (post-swap-in, in-place edit vs captured baseline) 51/51 PASS.

New exported functions

  • readTS(SEL, recordsDir, kind) — canonical KIND-parameterised sidecar reader. The previous readAT() is now a one-line wrapper (kind = "AT"); the two new wrappers readVT() and readDT() cover velocity and displacement.
  • readVT(), readDT() — thin wrappers around readTS().

Blasting / velocity-record support

  • readISEE() — Micromate ISEE blasting-seismograph parser (velocity, mm/s). Auto-detects v10 / .TXT and v11 / .CSV firmware variants from the file content.
  • extractRecord() — KIND is routed through the sidecar filename prefix (AT / VT / DT). The JSON peak field is named accordingly: PGA / PGV / PGD. An explicit kind = "VT" override is accepted for records whose Units cannot be parsed by .parseKind().
  • buildRawRecordTable() — scans raw/(AT|VT|DT).*.json (no KIND change to the canonical schema).

Bug fixes

  • extractRecord() — full numeric precision preserved in the sidecar JSON (no digits truncation).
  • extractRecord() / getRawIntensities() — raw CSV columns now consistently remain provider OCID values while the JSON sidecar carries the explicit DIR (H1/H2/UP) to OCID mapping used by raw intensity indexing.
  • TS2PS() — rejects user-supplied Tn grids containing 0; the function already prepends the Tn = 0 peak-value anchor internally.
  • TS2PS(COL.ID = ...) — structured long input now treats source time-series ID and spectral ID as distinct contracts: AT -> PSA, VT -> PSV, and DT -> SD.
  • TS2PS(Output = "PSW") — multi-OCID long input now produces wide OCID-labelled spectral columns such as PSA.H1, PSV.H1, and SD.H1 instead of source-ID-labelled spectral columns. Grouped PSW assembly no longer uses rbindlist(fill = TRUE).
  • TS2PS(D50 = TRUE) — structured long input can now add OCID = "D50" as the fourth horizontal spectral component. PSA.D50, PSV.D50, and SD.D50 are computed independently from rotated AT, VT, and DT respectively. TS2PS(D50 = TRUE) is the public D50 path.
  • TS2IMF() — numeric imf.remove now treats positive indices as IMFs counted from the start and negative indices as IMFs counted from the end, then removes the union. For example, c(1L, -1L, -2L) removes IMF1 plus the last two IMFs. This replaces the previous positive-include / negative-protect behavior, which made mixed selections such as c(1L, -1L) remove nothing. Zero, non-finite, and out-of-range numeric values are ignored.
  • TS2IMF() grouped output no longer pads inconsistent per-group schemas with NA. Groups must produce the same output columns, or the bind fails with a schema diagnostic instead of using rbindlist(fill = TRUE).
  • AT2TS(), VT2TS(), and DT2TS() no longer use blind na.omit() for time-step extraction or TSL packing. Non-finite time and signal samples now fail with explicit diagnostics instead of being hidden by regularization or row dropping; finite regular and irregular inputs are unchanged.
  • getIntensity() no longer uses rbindlist(fill = TRUE) for the final acceleration/velocity/displacement IM bind. Internal IM schemas must match before binding.
  • buildRawIntensityTable() no longer uses fill = TRUE when binding new per-station intensity tables or when merging an incremental cache. Raw intensity tables are canonicalized and schema-checked before binding.
  • buildRawFileTable() no longer uses rbindlist(fill = TRUE). Provider records are canonicalized to the documented RawFileTable schema before binding; absent canonical provider fields are emitted as typed NA columns.
  • buildMaster() no longer uses rbindlist(fill = TRUE) across owner outputs. Per-owner master tables must share the same schema before binding.
  • wideTrunc() was removed. It had no internal callers and no detected callers in the checked consumer projects (AR-S2J2J, AR-SABP0.R).
  • Local-only style cleanup renamed STFT/audit temporaries in AT2TS(), VT2TS(), DT2TS(), auditSTFT(), and .ffilter() without changing public interfaces. The internal source file R/build_FFT.R is now R/buildFFT.R.
  • .setSTFT() is tracked separately under Tier 2 SoT. The approved passes remove a dotted boolean local, canonicalize the candidate-logging guard, and inline a short-lived downsample scalar. A later narrow local cleanup removes one-use k.grid, inlines the one-use NP.required threshold, and resolves NW.max / NWmax without changing candidate/frequency locals. These changes do not alter the STFT strategy or public interfaces.

Documentation

gmsp 0.4.0

First CRAN submission. Consolidates the standalone gmdb package (provider-format parsers and per-record indexing) into gmsp so the full strong-motion record pipeline — from raw provider file to processed AT / VT / DT time series — lives in one place.

New exported functions (merged from gmdb)

Breaking changes

  • The retired gmdb package is no longer maintained. Code that previously called gmdb::extractRecord(...) should now call gmsp::extractRecord(...).

  • Required paths. parseRecord(), extractRecord(), buildRawFileTable(), buildRawRecordTable(), buildRawIntensityTable(), buildMaster(), auditParsers(), writeSelection() and readAT() no longer carry hard-coded ~/kashimaDB/... defaults for their path arguments (recordsDir / indexDir / selectionDir). The path is now a required argument; the function fails fast with a clear “argument … is missing” error if not supplied, rather than silently reading from a developer-specific location.

    Validated end-to-end by a Ship-of-Theseus harness: Stage A (explicit-path identity) 16/16 across 4 real provider fixtures (IGP, NGAW, NWZ, UCR); Stage A-bis (no-arg corner-case errors) 10/10. Pipeline regression 22/22 against the Phase 1 baseline.

  • readAT() signature. Now readAT(SEL, recordsDir); previously read from the unexported package constant RECORDS, which has been removed.

  • Removed fossil parameters. Two parameters that were exposed in the public signature but never reached the function body are dropped:

    • AT2TS(..., Derivate = "time") — the source marked it (future use); no caller used a non-default value and the body never branched on it.
    • TS2IMF(..., TrimZeros = FALSE) — the worker’s if (TrimZeros) block was an explicit no-op placeholder.

    Callers that passed either argument explicitly (none observed in the gmsp ecosystem) will now get unused argument. The default behaviour is unchanged.

  • License. Changed from file LICENSE (all-rights-reserved) to MIT + file LICENSE. LICENSE is the CRAN-form two-line declaration; LICENSE.md ships the full MIT text.

Documentation

  • Six vignettes ship with the package, replacing the previous Jekyll-only docs/ site: gmsp-quickstart (5-minute runnable hello world), signal-processing, imfs, spectra, intensity-measures (math references with LaTeX), and database (indexing-layer pipeline and file-layout contract).
  • _pkgdown.yml reorganised: navbar lists all six vignettes; reference grouped by signal-processing core, indexing helpers, selection / IO, and audit.
  • README.md covers both layers (signal-processing + optional indexing) and includes CRAN status / downloads badges, a citation bibentry, and links to all six vignettes.

Internal

  • R/local.R and R/global.R consolidated into R/gmsp-package.R with a single utils::globalVariables() block and a single TARGET_UNITS declaration.
  • Dropped gmsp:: self-prefix on the call to getIntensity() in getRawIntensities.R.
  • @param LowPass added to DT2TS() and VT2TS() (was undocumented).
  • R CMD check --as-cran: 0 errors, 0 warnings, 0 notes.

gmsp 0.3.0

Final pre-merge release of the standalone signal-processing package. Public API: AT2TS(), VT2TS(), DT2TS(), TS2IMF(), getIntensity(), getND(), regularize().