Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libs/seiscomp/seismology/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SET(SEISMOLOGY_SOURCES
depthlookup.cpp
firstmotion.cpp
locatorinterface.cpp
mb.cpp
Expand All @@ -9,6 +10,7 @@ SET(SEISMOLOGY_SOURCES
)

SET(SEISMOLOGY_HEADERS
depthlookup.h
firstmotion.h
ttt.h
regions.h
Expand Down
194 changes: 194 additions & 0 deletions libs/seiscomp/seismology/depthlookup.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/***************************************************************************
* 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 <seiscomp/seismology/depthlookup.h>
#include <seiscomp/core/interfacefactory.ipp>
#include <seiscomp/geo/feature.h>
#include <seiscomp/geo/featureset.h>
#include <seiscomp/core/strings.h>
#include <seiscomp/logging/log.h>

#include <algorithm>
#include <optional>
#include <string>
#include <vector>


IMPLEMENT_INTERFACE_FACTORY(Seiscomp::Seismology::DepthLookup, SC_SYSTEM_CORE_API);


namespace Seiscomp {
namespace Seismology {


// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

namespace {

std::optional<double> 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 &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 fetch(double, double) const override {
return _value;
}

double fetchMaxDepth(double, double) const override {
return _value;
}

private:
double _value{10.0};
};

REGISTER_DEPTH_LOOKUP(DepthLookupConstant, "Constant");


// ---------------------------------------------------------------------------
// DepthLookupPolygon
// ---------------------------------------------------------------------------

/**
* Queries named polygon features from SeisComP's global GeoFeatureSet.
*
* 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<std::string> names;
try {
names = config.getStrings("depths.polygon.regions");
}
catch ( ... ) {}

if ( names.empty() ) {
SEISCOMP_WARNING("DepthLookup/Polygon: no regions configured "
"under depths.polygon.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 fetch(double lat, double lon) const override {
for ( const auto &e : _entries ) {
if ( e.feature->contains({lat, lon}) ) {
return e.defaultDepth;
}
}
return _fallback;
}

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 _fallback;
}

private:
struct Entry {
const Geo::GeoFeature *feature{nullptr};
double defaultDepth{0.0};
std::optional<double> maxDepth;
};

double _fallback{10.0};
std::vector<Entry> _entries;
};

REGISTER_DEPTH_LOOKUP(DepthLookupPolygon, "Polygon");


} // namespace Seismology
} // namespace Seiscomp
103 changes: 103 additions & 0 deletions libs/seiscomp/seismology/depthlookup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/***************************************************************************
* 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 <string>

#include <seiscomp/config/config.h>
#include <seiscomp/core/baseobject.h>
#include <seiscomp/core/interfacefactory.h>
#include <seiscomp/core.h>


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 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:
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).
*
* Always returns a finite value; the implementation supplies its
* own configured fallback when no region/slab matches.
*/
virtual double fetch(double lat, double lon) const = 0;

/**
* @brief Return the maximum acceptable depth (km) at (@p lat, @p lon).
*
* Always returns a finite value; the implementation supplies its
* own configured fallback when no region/slab matches.
*/
virtual double fetchMaxDepth(double lat, double lon) const = 0;
};


DEFINE_INTERFACE_FACTORY(DepthLookup);


} // namespace Seismology
} // namespace Seiscomp


#define REGISTER_DEPTH_LOOKUP(Class, Service) \
Seiscomp::Core::Generic::InterfaceFactory<Seiscomp::Seismology::DepthLookup, Class> \
__##Class##InterfaceFactory__(Service)


#endif // SEISCOMP_SEISMOLOGY_DEPTHLOOKUP_H