Changelog#
v0.5.0 - 2026-10-12#
Added#
ordered
InteractionandRayItineraryobjects for prescribed direct, reflected, transmitted, converted, and multiple phase pathsopt-in per-ray
SolveDiagnosticswith accepted solve route, iteration counts, transformed and physical ray parameters, independently recomputed endpoint residual, conditioning, and criticality marginsparse fixed-topology analytic derivatives of traveltime and physical ray parameter with respect to layer
Vp/Vs, interface depths, and source and receiver coordinatesreusable linearized-ray, point-cloud anchor-selection, and topology-safe dense traveltime approximation APIs
opt-in second-order endpoint traveltime prediction, including the zero-offset curvature limit and exact direct same-layer paths
a visual sensitivity example showing scaled traveltime and ray-parameter effects, local model prediction, dense endpoint prediction, and a vertical-well microseismic traveltime table approximated from sparse source anchors
optional
complex_coefficient_productoutput alongside the established real coefficient-magnitude productLayTracer logo and branding assets, including full, medium, icon, circular icon, and PDF-compatible logo variants (#12)
deterministic logo generation script under
branding/logo/with vendored Poppins font assets and staleness checking (#12)logo integration in the repository README, HTML documentation overview, Sphinx header, favicon, and LaTeX/PDF title page (#12)
branding documentation describing the logo design concept, color palette, generated outputs, usage locations, and regeneration commands (#12)
a Contributing page in the documentation, covering issue reports, the development setup, branches and releases, tests, the documentation build, and the changelog; it replaces the short contributing note in Credits
a section in the README and in Getting Started on limiting NumPy’s BLAS threads with
OPENBLAS_NUM_THREADS, because on Windows some OpenBLAS builds commit a buffer for every thread when NumPy is imported (#15)
Changed#
the transformed-parameter solver now uses a checked bracketed fallback and accepts a result only after independently verifying the endpoint offset
density and quality-factor columns are validated only when a requested output depends on them
legacy
reflectionandrefractiontuples compile through the same fixed-itinerary representation;refractioncontinues to mean prescribed transmission or mode conversion rather than a head wavenew scientific outputs remain additive and opt-in; the 0.4 public
trace_raysargument order, result flattening, phase dispatch, and default allocations are unchangedexact-endpoint anchor fitting and per-pair prediction bookkeeping are streamlined for dense traveltime tables
rays_per_chunknow caps the rays per parallel task rather than per chunk. Left asNone, the task size follows from the number of rays and workers and from the output size per ray, measured on a probe of up to 64 rays;trace_raysissues aRuntimeWarningwhen the estimated output exceeds available memory (#15)n_jobs=1abovesequential_limituses the same bounded-memory path, in-process (#15)verbose tracing prints the task plan and the estimated output size, then progress in 10% steps, instead of one line per chunk (#15)
joblib>=1.4is required, for results streamed back as tasks finish (#15)loky workers trace with one BLAS/OpenMP thread each (joblib’s
inner_max_num_threads=1), because tracing makes no BLAS calls. On Windows, OpenBLAS commits a buffer for every thread when NumPy is imported, about 135 MB per thread with conda-forge builds, so the default of CPUs divided by workers could cost a worker over 1 GB (#15)LayTracer requires NumPy 2 (
numpy>=2) and Python 3.9 or newer, without the previous upper bound of 3.13; continuous integration tests Python 3.9 to 3.14dependencies are declared only in
pyproject.toml, as in PyNetDesign: a newdevextra adds pytest and setuptools_scm next to the existingdocsextra, andinstall.batandinstall.shinstall".[dev]". Installs therefore take NumPy from its PyPI wheels, which bundle OpenBLASthe documentation’s project pages follow the main chapters in the order Citing, Contributing, Changelog, Credits, as do the panels on the overview, where the PDF download now spans the full width
chapters of the PDF start on the next page rather than the next right-hand one, so the PDF has no blank pages
the documentation workflow builds with Python 3.12, which Sphinx 9.1 requires
the changelog page shows version headings without brackets, each followed by a link to its changes on GitHub, taken from the link definitions now at the end of
CHANGELOG.md; code written between double backticks there renders as code instead of showing stray backticks
Removed#
support for Python 3.8 and for NumPy 1
the automatic
rays_per_chunkvalue, 50% of available RAM divided by the number of workers at an assumed 64 bytes per ray, and itsAuto-detected rays_per_chunkmessage. No parameter was removed:rays_per_chunkremains and now caps the rays per task, sized as described under Changed (#15)the package list in
environment.yml, which now provides only Python andpip; the runtime, test and documentation packages are installed frompyproject.tomlthe
release.ymlworkflow that published packages when a tag was pushed; packages are now published only from a published GitHub Release, after the tag and the Zenodo metadata are validated
Fixed#
parallel
trace_raysno longer runs out of memory on large grids, where it failed withMemoryErrorin a loky worker sending its results back. Tasks now return NumPy columns that are copied into the output as soon as each task finishes, instead of one Python tuple per ray held for a whole chunk, first in the workers and then in the main process. For travel times of two phases the 0.4 chunk size assumed 64 bytes per ray, while the tuples, their pickling and the indices needed close to 1 kB per ray; memory use is now the output plus a few tasks per worker (#15)reflected and multiple-ray spreading now uses the actual source- and receiver-side phase velocities (#13)
coefficient products retain complex sign and phase when explicitly requested while
trans_productremains a real, nonnegative magnitude for existing workflows2-D ray plotting uses the public pyplot colormap accessor and remains compatible with Matplotlib 3.11, where
matplotlib.cm.get_cmapwas removedthe PDF builds with the June 2026 LaTeX release, where tables in the default
colorrowsstyle of Sphinx 9.1.0 exhausted the TeX input stack (sphinx-doc/sphinx#14465)citations in the PDF link to its bibliography; they pointed at the reference lists that only the HTML pages contain
build-docs.batdetects failed steps inside its blocks, and both build scripts stop at a LaTeX error instead of waiting at the TeX promptmake cleanallremoves the generated example gallery indocs/source/examplesa push to
devno longer cancels a running documentation build ofmainor of a release tag, and with it the Pages deployment
v0.4.0 - 2026-05-02#
Added#
trace_rays(..., source_phase=...)now accepts a list of phases, for example["P", "SH", "SV"], and returns adict[str, TraceResult]for multi-phase requests (#7)explicit SH-wave ray tracing support, including SH-SH reflection/transmission coefficients for welded isotropic interfaces (#7)
TraceResult.source_phaseto record the canonical traced phase (#7)regression tests for multi-phase API behavior, S/SV aliasing, SV/SH shared kinematics, SH energy conservation, SH post-critical behavior, and upward-path SV/SH equality for
tstarand spreading (#7)coefficient-panel styling for complex-valued coefficient segments and truly evanescent outgoing branches, with regression tests for the plot helper and SH reflected-coefficient null
optional
layer_colorsandray_linewidtharguments forlaytracer.plot.rays_2d(), with regression tests for custom layer palettes, ray widths, and unpadded x limits
Changed#
canonicalized phase handling so legacy
Smaps toSV, whileP,SV, andSHare available as explicit source phases (#7)multi-phase tracing reuses kinematic solves across phases when possible; SV and SH share ray paths, travel times, ray parameters,
tstar, and geometrical spreading, while retaining phase-specific transmission/reflection products (#7)example 03 now includes SH reflection/transmission cases, distinguishes complex coefficient phase shifts from evanescent outgoing branches, and annotates the SH oblique impedance-match null (#7)
clarified the methodology narrative for SH in 3-D layered media, distinguishing 2-D incidence-plane ray geometry from transverse SH polarization (#7)
expanded example 04 with an SV/SH comparison showing shared S-wave kinematics and phase-specific interface coefficient products (#7)
example 03 ray-path diagrams now use a seven-color ColorBrewer Accent palette, explicit incident-ray paths, solid ray lines, and clearer layer/ray contrast
cleaned up and refactored example 03
API and methodology documentation now describe SH support, multi-phase tracing, and the decoupled SH behavior in isotropic 1-D media (#7)
Fixed#
Removed unnecessary
plt.show()call from 3D ray plot in example 01 to enable 3D plot in docs pages
v0.3.1 - 2026-04-20#
Added#
critical_angle()andfind_critical_angles()helpers inlaytracer.amplitudefor reusable critical-angle detectionlaytracer.plot.coefficient_panels()for reusable multi-panel plotting of reflection/transmission coefficient curvesnew regression tests for the critical-angle helpers and coefficient-panel plotting helper
citing docs section with updated DOI and citation info
credits docs section with author and contributor acknowledgements and library credits
Changed#
refactored example 3 to use the new critical-angle and coefficient-panel helpers instead of open-coded calculations and repeated subplot logic
updated the API reference to include the new amplitude and plotting helpers
docs index page revised
v0.3.0 - 2026-03-14#
Added#
add explicit
requested={...}output selection totrace_rays()andsolve(), replacing the coarse amplitude switch (#3)
Changed#
only build and return ray paths, ray parameters, and path-dependent scalar outputs when explicitly requested (#3)
Fixed#
fix degenerate direct-ray amplitude outputs for zero-offset vertical rays and exact same-point rays (#2)
make amplitude result packing robust to mixed
Noneand finite values (#2)add regression tests for degenerate direct-ray amplitude cases (#2)
v0.2.1 - 2026-03-07#
Added#
normalize_rt_coefficient()function inamplitude.pyimplementing Červený (2001) Eq. 5.3.10 energy-flux normalization of R/T coefficients (#1)transcoef_method="normalized"option intrace_raysandsolvefor energy-flux-normalized transmission coefficient products (#1)new tests:
test_transmission_normalized,test_normalized_vertical_ray(#1)methodology docs: section on energy-flux-normalized coefficients (#1)
Changed#
transcoef_methodvalues renamed:"angle"→"standard","angle_normalized"→"normalized"(#1)default
transcoef_methodis now"standard"(was"angle") (#1)updated documentation to reflect new method names and default (#1)
updated example 5 to use new method names and default (#1)
updated example 4 to compare standard vs normalized transmission coefficients (#1)
updated example 3 to show comparison of standard vs normalized transmission and reflection coefficients (#1)
Removed#
"normal"(impedance-only) transmission coefficient method — only"standard"and"normalized"are supported (#1)normal-incidence section removed from methodology docs (#1)
v0.2.0 - 2026-03-04#
Added#
ModelArraysdataclass for pre-extracted NumPy arrays, avoiding repeated DataFrame column extraction during parallel tracingfast path in
_trace_onefor direct waves (no reflections/refractions)memory-aware
rays_per_chunkauto-sizing and progress reporting with ETA intrace_rays
Changed#
build_layer_stacknow accepts bothpd.DataFrameandModelArrays(unified from the formerbuild_layer_stack/build_layer_stack_fastpair)batched parallel dispatch: rays are grouped into ~n_workers batches with lightweight NumPy-only serialisation instead of per-ray DataFrame pickling
updated documentation index page
Removed#
dead first-pass loop in
_trace_onethat built unused variables
Fixed#
handle degenerate case in
_trace_onefunction to return minimal resultfix NaN results for same-depth source–receiver rays (e.g. stations and grid points both at z = 0): zero-thickness layer stack is now handled as a horizontal straight-line ray with correct travel time, geometrical spreading, attenuation t*, and transmission product instead of returning NaN
v0.1.0 - 2026-03-03#
Added#
Files for initial release
This changelog
GitHub Actions CI for pytest, docs build, and release automation