Conversation
HASH-style (Hardebeck & Shearer 2002) grid search inversion for P-wave
first motion polarities in the scolv focal mechanism plot.
Features:
- Grid search over strike/dip/rake with perturbation stability trials
- Auto button ("A") and context menu entry on FM plot
- Quality assessment: HASH letter grades (A/B/C/D), misfit, STDR,
azimuthal gap, misfitting station identification
- Populates FocalMechanism fields (stationPolarityCount, misfit,
stationDistributionRatio, azimuthalGap) on commit
- Comprehensive SEISCOMP_DEBUG/INFO logging for --debug diagnostics
- Azimuthal gap warning when > 180 degrees
Minimum 6 polarity observations with valid takeoff angles required.
|
Thank you, we will be looking into it. What I can tell you from the first glance is that the code is looking pretty good and aligned with our coding style, well done! I will continue to comment in the code. |
0fa1cc6 to
55d74f1
Compare
gempa-stephan
left a comment
There was a problem hiding this comment.
Thanks for your efforts. SeisComP code may now be written for the C++17 coding standard. These are some Clang-Tidy remarks. I flagged each recommendation type only once.
55d74f1 to
e52c49c
Compare
|
Bugs are now fixed. |
Fix three bugs in the first motion polarity inversion: 1. Fix double deg-to-rad conversion on np2nd input: np2nd() expects degrees and converts internally, but we were converting to radians before calling it. This caused all radiation pattern vectors to be computed from near-zero angles, making every mechanism appear equivalent (4.7M accepted mechanisms instead of thousands). 2. Fix double rad-to-deg conversion on nd2dc output: nd2dc() returns degrees (calls np2deg internally), but we applied rad2deg() again, producing garbage NP2 values (e.g. 5335.8/5156.6/-5204.1). 3. Fix MECH_AVG sign alignment reference: use a fixed reference (first mechanism) for sign alignment following HASH MECH_AVG (uncert_subs.f), instead of the running sum. The running sum becomes dominated by np2nd's hemisphere convention (n.z always <= 0), systematically collapsing the averaged solution to a degenerate near-horizontal dip. Also improve MECH_PROB outlier removal performance: use batch removal (discard all mechanisms beyond cutoff, recompute average, repeat until stable) instead of one-at-a-time removal. This reduces complexity from O(n^2) to O(n*k) where k is typically 2-6 iterations, fixing a hang with large numbers of accepted mechanisms.
e52c49c to
d135752
Compare
|
We have tested the code with an example event and the solution did not quite match our expectation. We can add an example if you would like to take a look, but can you provide some test results from your end? There is currently no option to configure the inversion apart from modifying the source code. Do you have any ideas in that regard? |
|
Yeah, test results would be great. |
|
The FM seems to be inverted ... |
|
You are right.
When playing with the same data, maybe this could be more preferable
<img width="1958" height="1155" alt="image" src="https://github.com/user-attachments/assets/34e48ca8-f99e-43d9-8bf8-87351107e7c7" />
…On Fri, 13 Feb 2026 at 20:43, Jan Becker ***@***.***> wrote:
*gempa-jabe* left a comment (SeisComP/common#176)
<#176 (comment)>
The FM seems to be inverted ...
—
Reply to this email directly, view it on GitHub
<#176 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACB5ZSHXC6JZOVH4QFAKJKL4LWMFVAVCNFSM6AAAAACU3YKN76VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQOJWGA4DONZRGI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
Kind regards
Mustafa
|
|
Exactly, this is much better. So there seems to be a rotation somewhere? @gempa-lukas reported that the original SKHASH code produces similar issues. |
|
Yes, thank you for the confirmation for SKHASH. Also correct there is an issue with the rotation. I am looking into it. |
|
Last year I wrote a python script that can be used as external script in scolv. It simply dumps the origins (which include the takeoffangles, which is still a hack) and starts the SKHASH python script. The results seemed to be fitting quite good. One thing I recently struggled with is the SKHASH parameter: This must be true for SC. |
- Implement full HASH MECH_ROT algorithm (Hardebeck & Shearer 2002) for mechanism rotation, replacing simplified average-of-angles approach - Fix takeoff angle convention: rz=cos(ih) for NED z-Down coordinate system (was incorrectly using -cos from HASH z-UP convention) - Add 21 unit tests covering mechanismRotation, predictPolarity, azimuthal gap, quality grading, and full inversion recovery - Add FM inversion configuration parameters to OriginLocatorView: gridSpacing, numTrials, takeoffUncertainty, azimuthUncertainty, maxBadFraction - Make mechanismRotation() part of the public API
|
I made some improvement, I believe. Would you mind testing the one you shared earlier? |
|
Yes, we will do. Thanks. |
|
Thanks for testing. As far as I know, the first motion method is not reliable for distant events at all. we would rather use Moment Tensor. |
np2nd() returns normal and slip vectors in Aki & Richards convention (z-UP), identical to HASH's TO_CAR subroutine. The ray direction must use the same coordinate system: rz = -cos(ih), not +cos(ih). The previous change to rz=cos(ih) mixed z-DOWN rays with z-UP mechanism vectors, producing wrong polarities for ~50% of non-vertical mechanisms. This caused the inversion to converge to the same mechanism regardless of input data (only strike changed, dip/rake were always ~65/170). Add polarity tests with oblique (strike=45/dip=60/rake=30) and normal fault mechanisms that verify against hand-computed HASH TO_CAR radiation patterns. These tests fail with the wrong rz sign.
|
I will add TX network as well. let me test. There is a new version already. would you mind testing with a local or regional event |
|
Yes, first motions might not be that reliable for teleseismic events. Still if the polarities have been picked, the algorithm should be able to match the FM accordingly to the polarities/takeoffangle/azimuth etc.. That behavior should be independent of the type of EQ. Nevertheless, I testet the newest version. Now it reverted back to the previous state, where the mechanism seemed to be flipped. And most of the times one nodal plane has a steep dip (>80°). |
|
Closing this PR. After extensive testing and debugging, the C++ HASH reimplementation still has persistent issues with coordinate system conventions (takeoff angle / ray direction vs. np2nd's Aki & Richards z-UP system), leading to unreliable results on real data — specifically flipped mechanisms and a systematic bias toward steep dip (>80°), as @gempa-lukas pointed out. Given that the SKHASH Python wrapper already exists and produces correct results, it makes more sense to use that for now. I may revisit this with a simpler, custom approach later. The original goal was to provide a native C++ solution accessible to the broader SeisComP community without external dependencies. |






Summary
What's included
seiscomp/seismology/firstmotion.h/.cpp-- standalone inversion with no GUI dependenciesSEISCOMP_DEBUG/INFOlogging for--debugdiagnosticsImplementation notes
References