From 744ed1040efc82b8fadd0694cd3d22d2d443a5fe Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Thu, 21 May 2026 07:46:04 +1000 Subject: [PATCH 1/2] [seismology] Add DepthLookup abstract interface Adds an extensible depth-lookup interface used by scautoloc and other processing modules to select region- or slab-specific default and maximum depths instead of a single global value. Two built-in implementations: "Constant" (passthrough) and "Polygon" (named GeoFeatureSet regions with defaultDepth/maxDepth attributes). Third-party backends register via REGISTER_DEPTH_LOOKUP in a plugin. --- libs/seiscomp/seismology/CMakeLists.txt | 2 + libs/seiscomp/seismology/depthlookup.cpp | 173 +++++++++++++++++++++++ libs/seiscomp/seismology/depthlookup.h | 97 +++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 libs/seiscomp/seismology/depthlookup.cpp create mode 100644 libs/seiscomp/seismology/depthlookup.h diff --git a/libs/seiscomp/seismology/CMakeLists.txt b/libs/seiscomp/seismology/CMakeLists.txt index 361c88540..8d3f8f71f 100644 --- a/libs/seiscomp/seismology/CMakeLists.txt +++ b/libs/seiscomp/seismology/CMakeLists.txt @@ -1,4 +1,5 @@ SET(SEISMOLOGY_SOURCES + depthlookup.cpp firstmotion.cpp locatorinterface.cpp mb.cpp @@ -9,6 +10,7 @@ SET(SEISMOLOGY_SOURCES ) SET(SEISMOLOGY_HEADERS + depthlookup.h firstmotion.h ttt.h regions.h diff --git a/libs/seiscomp/seismology/depthlookup.cpp b/libs/seiscomp/seismology/depthlookup.cpp new file mode 100644 index 000000000..117db7ee3 --- /dev/null +++ b/libs/seiscomp/seismology/depthlookup.cpp @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (C) gempa GmbH * + * All rights reserved. * + * Contact: gempa GmbH (seiscomp-dev@gempa.de) * + * * + * GNU Affero General Public License Usage * + * This file may be used under the terms of the GNU Affero * + * Public License version 3.0 as published by the Free Software Foundation * + * and appearing in the file LICENSE included in the packaging of this * + * file. Please review the following information to ensure the GNU Affero * + * Public License version 3.0 requirements will be met: * + * https://www.gnu.org/licenses/agpl-3.0.html. * + * * + * Other Usage * + * Alternatively, this file may be used in accordance with the terms and * + * conditions contained in a signed written agreement between you and * + * gempa GmbH. * + ***************************************************************************/ + + +#define SEISCOMP_COMPONENT DepthLookup + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +IMPLEMENT_INTERFACE_FACTORY(Seiscomp::Seismology::DepthLookup, SC_SYSTEM_CORE_API); + + +namespace Seiscomp { +namespace Seismology { + + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +namespace { + +std::optional parseAttr(const Geo::GeoFeature *f, + const std::string &key) { + const auto &attrs = f->attributes(); + auto it = attrs.find(key); + if ( it == attrs.end() || it->second.empty() ) { + return std::nullopt; + } + double v; + if ( !Core::fromString(v, it->second) ) { + return std::nullopt; + } + return v; +} + +} // anonymous namespace + + +// --------------------------------------------------------------------------- +// DepthLookupConstant +// --------------------------------------------------------------------------- + +class DepthLookupConstant : public DepthLookup { + public: + bool init(const Config::Config &) override { return true; } + + double getDefaultDepth(double, double, double fallback) const override { + return fallback; + } + + double getMaxDepth(double, double, double fallback) const override { + return fallback; + } +}; + +REGISTER_DEPTH_LOOKUP(DepthLookupConstant, "Constant"); + + +// --------------------------------------------------------------------------- +// DepthLookupPolygon +// --------------------------------------------------------------------------- + +/** + * Queries named polygon features from SeisComP's global GeoFeatureSet. + * + * Config key: autoloc.regionDepth.regions (list of feature names) + */ +class DepthLookupPolygon : public DepthLookup { + public: + bool init(const Config::Config &config) override { + std::vector names; + try { + names = config.getStrings("autoloc.regionDepth.regions"); + } + catch ( ... ) {} + + if ( names.empty() ) { + SEISCOMP_WARNING("DepthLookup/Polygon: no regions configured " + "under autoloc.regionDepth.regions"); + return true; + } + + const Geo::GeoFeatureSet &fs = + Geo::GeoFeatureSetSingleton::getInstance(); + + for ( const auto *f : fs.features() ) { + if ( !f->closedPolygon() ) { + continue; + } + if ( std::find(names.begin(), names.end(), f->name()) == names.end() ) { + continue; + } + + auto dd = parseAttr(f, "defaultDepth"); + if ( !dd ) { + SEISCOMP_WARNING("DepthLookup/Polygon: feature '%s' has " + "no defaultDepth attribute — skipped", + f->name().c_str()); + continue; + } + + _entries.push_back({f, *dd, parseAttr(f, "maxDepth")}); + SEISCOMP_DEBUG("DepthLookup/Polygon: loaded region '%s' " + "defaultDepth=%.0f", f->name().c_str(), *dd); + } + + SEISCOMP_INFO("DepthLookup/Polygon: %zu region(s) loaded", + _entries.size()); + return true; + } + + double getDefaultDepth(double lat, double lon, + double fallback) const override { + for ( const auto &e : _entries ) { + if ( e.feature->contains({lat, lon}) ) { + return e.defaultDepth; + } + } + return fallback; + } + + double getMaxDepth(double lat, double lon, + double fallback) const override { + for ( const auto &e : _entries ) { + if ( e.feature->contains({lat, lon}) ) { + return e.maxDepth.value_or(fallback); + } + } + return fallback; + } + + private: + struct Entry { + const Geo::GeoFeature *feature{nullptr}; + double defaultDepth{0.0}; + std::optional maxDepth; + }; + + std::vector _entries; +}; + +REGISTER_DEPTH_LOOKUP(DepthLookupPolygon, "Polygon"); + + +} // namespace Seismology +} // namespace Seiscomp diff --git a/libs/seiscomp/seismology/depthlookup.h b/libs/seiscomp/seismology/depthlookup.h new file mode 100644 index 000000000..d447545cf --- /dev/null +++ b/libs/seiscomp/seismology/depthlookup.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) gempa GmbH * + * All rights reserved. * + * Contact: gempa GmbH (seiscomp-dev@gempa.de) * + * * + * GNU Affero General Public License Usage * + * This file may be used under the terms of the GNU Affero * + * Public License version 3.0 as published by the Free Software Foundation * + * and appearing in the file LICENSE included in the packaging of this * + * file. Please review the following information to ensure the GNU Affero * + * Public License version 3.0 requirements will be met: * + * https://www.gnu.org/licenses/agpl-3.0.html. * + * * + * Other Usage * + * Alternatively, this file may be used in accordance with the terms and * + * conditions contained in a signed written agreement between you and * + * gempa GmbH. * + ***************************************************************************/ + + +#ifndef SEISCOMP_SEISMOLOGY_DEPTHLOOKUP_H +#define SEISCOMP_SEISMOLOGY_DEPTHLOOKUP_H + + +#include + +#include +#include +#include +#include + + +namespace Seiscomp { +namespace Seismology { + + +DEFINE_SMARTPOINTER(DepthLookup); + +/** + * @brief Abstract interface for region- and slab-based default/maximum depth + * lookup, used by scautoloc and other SeisComP processing modules. + * + * Concrete implementations are registered via the REGISTER_DEPTH_LOOKUP macro + * and instantiated at runtime through DepthLookupFactory::Create(). + * + * Two implementations ship with the library: + * - "Constant" Returns the caller-supplied fallback (no-op default). + * - "Polygon" Queries named polygon features from SeisComP's global + * GeoFeatureSet; each polygon must carry a @c defaultDepth + * attribute (km, required) and may carry @c maxDepth (km). + * + * A separate @c dlslab2 plugin (seiscomp/main) provides depth lookup from + * USGS Slab2.0 depth-footprint contours. + */ +class SC_SYSTEM_CORE_API DepthLookup : public Core::BaseObject { + public: + virtual ~DepthLookup() = default; + + /** + * @brief Initialise the implementation. + * + * Called once after construction. Each implementation reads its + * own settings from @p config. + * + * @return True on success. + */ + virtual bool init(const Config::Config &config) = 0; + + /** + * @brief Return the default depth (km) at (@p lat, @p lon). + * @param fallback Returned when no region/slab matches. + */ + virtual double getDefaultDepth(double lat, double lon, + double fallback) const = 0; + + /** + * @brief Return the maximum acceptable depth (km) at (@p lat, @p lon). + * @param fallback Returned when no region/slab matches. + */ + virtual double getMaxDepth(double lat, double lon, + double fallback) const = 0; +}; + + +DEFINE_INTERFACE_FACTORY(DepthLookup); + + +} // namespace Seismology +} // namespace Seiscomp + + +#define REGISTER_DEPTH_LOOKUP(Class, Service) \ +Seiscomp::Core::Generic::InterfaceFactory \ +__##Class##InterfaceFactory__(Service) + + +#endif // SEISCOMP_SEISMOLOGY_DEPTHLOOKUP_H From a886635f48cc2966732bd18d3ea047503a7b3c20 Mon Sep 17 00:00:00 2001 From: Mustafa Comoglu Date: Thu, 21 May 2026 20:47:39 +1000 Subject: [PATCH 2/2] [seismology] DepthLookup: fetch/fetchMaxDepth API, backends own config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename getDefaultDepth/getMaxDepth → fetch/fetchMaxDepth; remove caller-supplied fallback parameter. Each backend now owns its full depth knowledge including fallback via its own config namespace: depths.constant.value, depths.polygon.regions, depths.polygon.fallback. --- libs/seiscomp/seismology/depthlookup.cpp | 51 +++++++++++++++++------- libs/seiscomp/seismology/depthlookup.h | 20 ++++++---- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/libs/seiscomp/seismology/depthlookup.cpp b/libs/seiscomp/seismology/depthlookup.cpp index 117db7ee3..be186f11e 100644 --- a/libs/seiscomp/seismology/depthlookup.cpp +++ b/libs/seiscomp/seismology/depthlookup.cpp @@ -69,15 +69,27 @@ std::optional parseAttr(const Geo::GeoFeature *f, class DepthLookupConstant : public DepthLookup { public: - bool init(const Config::Config &) override { return true; } + bool init(const Config::Config &config) override { + try { + _value = config.getDouble("depths.constant.value"); + } + catch ( ... ) { + SEISCOMP_INFO("DepthLookup/Constant: depths.constant.value not set, " + "using default %.0f km", _value); + } + return true; + } - double getDefaultDepth(double, double, double fallback) const override { - return fallback; + double fetch(double, double) const override { + return _value; } - double getMaxDepth(double, double, double fallback) const override { - return fallback; + double fetchMaxDepth(double, double) const override { + return _value; } + + private: + double _value{10.0}; }; REGISTER_DEPTH_LOOKUP(DepthLookupConstant, "Constant"); @@ -90,20 +102,30 @@ REGISTER_DEPTH_LOOKUP(DepthLookupConstant, "Constant"); /** * Queries named polygon features from SeisComP's global GeoFeatureSet. * - * Config key: autoloc.regionDepth.regions (list of feature names) + * Config keys: + * depths.polygon.regions — ordered list of feature names + * depths.polygon.fallback — depth returned when no polygon matches (km) */ class DepthLookupPolygon : public DepthLookup { public: bool init(const Config::Config &config) override { + try { + _fallback = config.getDouble("depths.polygon.fallback"); + } + catch ( ... ) { + SEISCOMP_INFO("DepthLookup/Polygon: depths.polygon.fallback not set, " + "using default %.0f km", _fallback); + } + std::vector names; try { - names = config.getStrings("autoloc.regionDepth.regions"); + names = config.getStrings("depths.polygon.regions"); } catch ( ... ) {} if ( names.empty() ) { SEISCOMP_WARNING("DepthLookup/Polygon: no regions configured " - "under autoloc.regionDepth.regions"); + "under depths.polygon.regions"); return true; } @@ -136,24 +158,22 @@ class DepthLookupPolygon : public DepthLookup { return true; } - double getDefaultDepth(double lat, double lon, - double fallback) const override { + double fetch(double lat, double lon) const override { for ( const auto &e : _entries ) { if ( e.feature->contains({lat, lon}) ) { return e.defaultDepth; } } - return fallback; + return _fallback; } - double getMaxDepth(double lat, double lon, - double fallback) const override { + double fetchMaxDepth(double lat, double lon) const override { for ( const auto &e : _entries ) { if ( e.feature->contains({lat, lon}) ) { - return e.maxDepth.value_or(fallback); + return e.maxDepth.value_or(_fallback); } } - return fallback; + return _fallback; } private: @@ -163,6 +183,7 @@ class DepthLookupPolygon : public DepthLookup { std::optional maxDepth; }; + double _fallback{10.0}; std::vector _entries; }; diff --git a/libs/seiscomp/seismology/depthlookup.h b/libs/seiscomp/seismology/depthlookup.h index d447545cf..6406a4d74 100644 --- a/libs/seiscomp/seismology/depthlookup.h +++ b/libs/seiscomp/seismology/depthlookup.h @@ -44,13 +44,17 @@ DEFINE_SMARTPOINTER(DepthLookup); * and instantiated at runtime through DepthLookupFactory::Create(). * * Two implementations ship with the library: - * - "Constant" Returns the caller-supplied fallback (no-op default). + * - "Constant" Returns a fixed depth read from @c depths.constant.value. * - "Polygon" Queries named polygon features from SeisComP's global * GeoFeatureSet; each polygon must carry a @c defaultDepth * attribute (km, required) and may carry @c maxDepth (km). + * Fallback is read from @c depths.polygon.fallback. * * A separate @c dlslab2 plugin (seiscomp/main) provides depth lookup from * USGS Slab2.0 depth-footprint contours. + * + * Each implementation owns all depth knowledge including its fallback value; + * callers pass no fallback. */ class SC_SYSTEM_CORE_API DepthLookup : public Core::BaseObject { public: @@ -68,17 +72,19 @@ class SC_SYSTEM_CORE_API DepthLookup : public Core::BaseObject { /** * @brief Return the default depth (km) at (@p lat, @p lon). - * @param fallback Returned when no region/slab matches. + * + * Always returns a finite value; the implementation supplies its + * own configured fallback when no region/slab matches. */ - virtual double getDefaultDepth(double lat, double lon, - double fallback) const = 0; + virtual double fetch(double lat, double lon) const = 0; /** * @brief Return the maximum acceptable depth (km) at (@p lat, @p lon). - * @param fallback Returned when no region/slab matches. + * + * Always returns a finite value; the implementation supplies its + * own configured fallback when no region/slab matches. */ - virtual double getMaxDepth(double lat, double lon, - double fallback) const = 0; + virtual double fetchMaxDepth(double lat, double lon) const = 0; };