REFAC: replace in-memory Python–C bindings with grt CLI workflow - #287
Merged
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… API Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR changes the main Python computation path from “ctypes / in-memory C bindings” to “assemble arguments → run the
grtexecutable → read/write SAC / NetCDF results”. The goal is to let Python and the command-line interface share one computation entry point, and to reduce the cost of future maintenance and feature work.Commits included:
REFAC: route Python API through grt CLI instead of in-memory bindingsTEST: update comparison and smoke tests for CLI-based Python workflowDOC: sync tutorials, examples and install guide with CLI-based Python APIMotivation
Previously, Python loaded
libgrt.sothroughctypesand relied on a parallel set of in-memory wrappers (for examplec_structures,pygrn, and a large memory-oriented C API) for Green’s functions, synthesis, and tensor calculations. That design had several drawbacks:grtCLI module and as a nearly parallel Python–C memory interface, which was costly and easy to drift.After routing Python through
grt:grtfirst.What changed
1. New CLI helper layer
Added
pygrt/cli.py:find_grt(): prefer the bundledpygrt/C_extension/bin/grt, then fall back toPATHrun_grt(...): rungrtviasubprocess; whenprint_log=True, stream logs live; whenFalse, capture output and attach it to errors on failureformat_float/format_range: normalize numeric CLI formatting2. Refactored public Python API
pygrt/pymod.pyandpygrt/utils.pynow assemble CLI arguments and callrun_grt:compute_grn/compute_static_grncompute_syn/compute_static_syncompute_strain/compute_rotation/compute_stressTypical workflow:
PyModel1D(modelpath)set_dynamic_grn_path(...)/set_static_grn_path(...)compute_*to run the correspondinggrtmodule and write filesread_static_nc, or passreturn_result=True3. Removed the old in-memory path
Removed wrappers and exports that are no longer needed, including:
pygrt/pygrn.pypygrt/c_structures.pyc_interfaces.py/__init__.pyA few capabilities that still fit library calls remain on the ctypes path (for example travel times, time functions, and the Lamb problem), but main computations no longer depend on in-memory bindings.
4. Tests and docs updated
test_cli_args.py)install.rst/intro.rstto the “callgrt+ write files + read back” modelFinal user-facing form
Users still work through high-level APIs such as
PyModel1D, but the semantics are now:Prebuilt packages ship a platform-specific
grt. For Python-only use,find_grt()locates the bundled executable automatically, so no extraPATHsetup is required. ConfigurePATHonly if you also want to invokegrt ...directly in a terminal.When reading dynamic tensor results back, distinguish them by filename prefix:
strain_*.sacrotation_*.sacstress_*.sacSAC headers do not record whether a file is strain / rotation / stress; channel names only carry component labels such as
ZZorNE.Before / After
Architecture
ctypescalls intolibgrt.so/ memory APIssubprocessruns thegrtexecutablegrt <module> [options]return_result=Trueprint_logcontrols whether intermediategrtoutput is showngrt; prebuilt packages work after installgrtmodules; Python mainly forwards argumentsDynamic Green’s functions (illustrative)
pymod = PyModel1D("milrow")pymod = PyModel1D("milrow")pymod.set_dynamic_grn_path("GRN")st_list = pymod.compute_grn(...)(in-memory return)pymod.compute_grn(...)(writes underGRN/...)from obspy import readst = read("GRN/*/*.sac")grt greenfn ...commandgrt greenfn ...internallySynthesis / tensors (illustrative)
pymod.compute_syn(..., output_path="syn_dc", ...)read("syn_dc/?.sac"), orreturn_result=Truepygrt.utils.compute_strain("syn_dc", return_result=True)strain_*.sac/rotation_*.sac/stress_*.sacModule cleanup
pygrt.clifind_grt/run_grt, etc.pygrt.pygrnpygrt.c_structureslibgrt.soBreaking changes / migration notes
This is a breaking change. Old “in-memory binding / list-of-Stream GF return” code must be migrated.
Suggested migration steps:
set_dynamic_grn_path/set_static_grn_pathbefore computationreturn_result=Trueread("*.sac")pygrt/C_extension/bin/grtexists after install (included in prebuilt packages)Minimal example: