Changelog#
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
v1.1.0 - 2026-10-12#
Feature release: phase-resolved wave modes, per-receiver free surface and receiver projection, synthetic geometry builders, a documentation site in HTML and PDF, and branding.
Added#
phase-resolved wave modes:
wave_modeaccepts'P','SV','SH','S'and'PS', where'S'is a composite mode keeping the more detectable of the SV and SH branchesroot-mean-square radiation-pattern magnitudes per phase,
R_P = sqrt(4/15) ~ 0.52,R_SV = sqrt(7/30) ~ 0.48andR_SH = sqrt(1/6) ~ 0.41, averaged over the focal sphere of a double-couple source after Boore and Boatwright (1984) and Hallo and Eisner (2013), exposed throughphase_radiation_patternrad_pattern_p,rad_pattern_sandrad_patternsoverrides onmag_sensitivity_grid, so that results computed with another convention stay reproducible; passrad_pattern_s=0.63to use the combined S-wave valuereceiver projection from the arriving polarization vectors, through
get_phase_station_directionality, which is correct for inclined and curved cables rather than only for a vertical oneprojection of single vertical-component stations onto the vertical axis, driven by a
Componentscolumn; three-component stations record the full vector and are unaffectedper-station free surface amplification through
compute_free_surface_coefficients, withfs_mode,fs_levelandfs_deviationparameters and an optionalSurfacecolumn carrying per-station weightshelpers
normalize_wave_mode,wave_mode_phases,wave_mode_has_p,wave_mode_has_s,wave_mode_s_phases,resolve_radiation_pattern,check_min_stationsandgeometry_requires_receiver_projectionpynetdesign.modelling.geometry, a module of synthetic geometry builders:generate_geometrydispatches togenerate_borehole_geometryfor vertical, inclined and deviated boreholes, togenerate_surface_geometryfor line, zigzag, L, square and double-line layouts, and togenerate_darkfiber_geometryfor a continuous dark-fibre path with turns. Each returns geometry text lines thatread_geometrycan read back, including a depth-dependent noise profile for boreholessave_geometry, writing either generated text lines or a geometry DataFrame back to theread_geometryformat, withZrestored to an elevation so that a round trip is losslessdecimate_geometry, keeping every n-th channel while preserving the metadata, for studying the effect of channel spacing on a dense arrayread_geometryreads the optionalSurfaceandComponentscolumns, so the per-station free surface weights and the single vertical component stations introduced above can be described in a geometry fileread_geometryrecords the path it read inattrs['file_path']test modules covering wave modes and radiation patterns, receiver projection, the free surface correction, network detectability, and phase-resolved sensitivity end to end
test_magnitude_consistency.py, which builds the forward displacement spectrum independently of the package and checks thatcalculate_M0inverts it exactly, that the spectral conversionS(f)is applied once and not twice acrossretrieve_min_ampsandcalculate_M0, and that an event at the threshold magnitude records exactly the requested signal-to-noise ratio for each of the five amplitude types, gauge-length bridge includedSphinx documentation under
docs/, published to GitHub Pages at <https://danikiev.github.io/PyNetDesign/>, with an overview whose quick-link panels lead to every section and to the PDF edition, a getting-started guide covering installation and the input file formats, a methodology chapter, an example gallery and a generated API referencemethodology.rstdocumenting the theory actually implemented: spectral conventions, the attenuation operator, the peak frequency, the detection threshold and its conversion coefficients, the free surface correction, receiver projection and DAS directionality, the radiation pattern with the full root-mean-square derivation, the homogeneous seismic moment relation with a standalone derivation from the far-field point source, and the network detectability criteriondocs/source/references.bibwith the seven works cited from the docstrings and the methodology, so the:cite:roles added earlier now resolveciting,contributingandcreditsdocumentation pages, plus a changelog page that is generated fromCHANGELOG.mdwhen the documentation is built, so the changelog has a single source and the generated page is not committed. On that page each version links to its changes on GitHub. These pages follow the main chapters in the order Citing, Contributing, Changelog, Creditsdocs.ymlworkflow building the documentation on every push and deploying it to GitHub Pages frommain, including a check that the built version matches the tag and, after each deployment, a check that the live site shows the deployed versionpush-tag.ymlworkflow, so that pushing avX.Y.Ztag validates it and starts adocs.ymlrun onmainthat publishes the documentation of that tag. The run is onmainbecause GitHub Pages ignores a deployment made from a tag whenmainhas already deployed the same commit (actions/deploy-pages#383)build-docs.batandbuild-docs.shfor building the documentation, andserve-docs.batandserve-docs.shfor viewing it locally.serve-docsrebuilds incrementally before serving, so only the pages that changed are regenerated, and accepts--portand--no-build. Both acceptSPHINXOPTS, and neither needsmake: they callpython -m sphinx -Mdirectly. Both also take--pdf, which builds the PDF edition and places it where the documentation links to ita PDF edition of the documentation, produced from the same sources through lualatex and linked from the site header and the front page, so the whole manual can be read offline as one file. Each web page keeps its own reference list, while the PDF lists the cited works once, in a bibliography at its end that its citations link to.
docs.ymlbuilds it on every run, publishes it with the site and keeps a copy as a workflow artifactinstall.shanduninstall.sh, the Linux and macOS counterparts of the existing Windows scripts.install.shtakes--devor--no-devto answer the development-tools question in advance, anduninstall.shtakes--yesbranding from the PyNetDesign brand package: the logo in the documentation header and the README, and the full browser icon set, comprising
favicon.ico, a scalablefavicon.svg, an Apple touch icon and a web app manifest. Both themes serve the same transparent logo, the one the README uses, so the mark keeps its own clear space and is never filtered or recoloured by the theme, because the brand gray is fixed and must not be inverted. Hovering the header logo swaps in the brand’s own orange-only lockup, which carries the same geometry at the same viewBox and differs only in colour, so the mark neither moves nor resizes and no filter is involvedbrand colours in the documentation stylesheet. Signal Orange reaches only 2.87:1 against white, so link text in light mode is darkened to
#B84806, which measures 4.81:1 against the light page surface, while the unmodified orange is used on the dark surfaces where it measures 5.17:1
Changed#
S-wave results differ from 1.0.x. The S branch now uses the phase-resolved radiation patterns instead of the combined value 0.63, which raises S-wave thresholds by
2/3*log10(0.63/sqrt(7/30)), about 0.077 magnitude units. Passrad_pattern_s=0.63to recover the previous behaviourthe free surface correction is applied per receiver. In 1.0.x
free_surface=Trueamplified every receiver irrespective of its depth; it now applies only to receivers at the free surface, so geometries mixing surface and downhole receivers are treated correctly. The default mode is'auto', which derives the indicator from the receiver depths or from theSurfacecolumn when presentDetectionParameterstakesfs_mode,fs_levelandfs_deviation; thefree_surfaceflag is deprecated but still accepted, mapping tofs_mode='on'or'off'mag_detectableaccepts the phase-resolved wave modesexample 7 is now the 1-km DAS array benchmark. It models a 1-km-long vertical fibre with 1 m channel spacing, so 1000 channels, a constant strain-rate noise level of 1.95e-9 1/s and a 10 m gauge length, in a homogeneous medium with Vp = 2370 m/s, Vp/Vs = 2, Qp = Qs = 100 and rho = 2500 kg/m^3, requiring detection on at least 60 channels. It shows the three features that follow from a fibre recording only the strain along itself: the threshold magnitude grows with offset, P-wave sensitivity is worst at the array mid-depth once the offset exceeds half the array length, and S-wave sensitivity vanishes on the cable axis and degrades below the array
the methodology and credits pages close with a
Referencessection rather than a rubric, so the bibliography is reachable from the table of contentsthe credits page acknowledges the works the implementation rests on individually, adding Aki and Richards (2002) for the far-field point source, the radiation-pattern convention and the free surface, and Cerveny (2001) for the ray-theoretical global absorption factor
receiver projection is decided from the geometry itself, so
use_station_directionalityis only needed to force tangent projection for a station geometrya single environment file.
environment.ymlnow pins only the interpreter, and every dependency is declared inpyproject.toml, as runtimedependenciesor in thedevanddocsoptional groups. Install withconda env create -f environment.yml -n pndfollowed bypip install -e .orpip install -e ".[dev,docs]". This removes the duplicated dependency lists, which had drifted: they advertisedscipyandplotly, neither of which is imported, and omittedcmcrameri, which is requiredpyproject.tomldeclaresrequires-python = ">=3.9,<3.13", the MIT license and its file, project URLs, and a fuller set of keywords and classifiers; Python 3.8 is no longer advertised, since it is not tested and the package needs 3.9install.batcreates one environment,pnd, from the single file and asks whether to add the development tools, rather than choosing between two conda files and two environment namesthe README documents the documentation site and the PDF download, corrects the Python range and the dependency list, and fixes the case of the clone URL
Removed#
environment-dev.yml, superseded by thedevanddocsoptional dependency groupsthe empty
__init__.pyat the repository root, which made the repository root look like an importable package and confused setuptools flat-layout discoverythe
rays_pandrays_sarguments ofget_ray_station_directionality, which could never be populated because the homogeneous package has no ray tracer. The function is deprecated in favour ofget_phase_station_directionalityand now emits aDeprecationWarning
Fixed#
the
.. only:: htmlblocks on the front page held their content at the wrong indentation, so the directive guarded nothing and the LaTeX build was asked to typeset icon cards it cannot renderexamples/README.txtpromised a raytracing example that this package does not ship, and carried a stale product namea grid point that coincides with a receiver no longer emits a spurious divide-by-zero warning. Such a point gives
r = 0, hencet* = 0and an infinite peak frequency, which the corner-frequency clamp already turned into the right answer; only the warning was wrong. Coincidence is ordinary with a dense DAS cable, where every channel sits on a grid linepytest.ininamedtestsas a directory to avoid, which does not exist here, and never named the directory that does. It now setstestpaths = pytests, soexamplesanddataare not searched for teststest_read_geometry.pyresolved its sample geometry files relative to the working directory, so it only passed when pytest was started from the repository root. The paths are now anchored to the test filethe station-count guard in
mag_detectablecompared against the grid axis instead of the station axis, so a request for more receivers than the geometry has was not reported clearlythe default dark-fibre turn distances are now fractions of the cable length, at one quarter, one half and three quarters, so that
generate_geometry(mode='darkfiber')works for any cable. The previous fixed distances of 6, 12 and 18 km exceeded the default cable length and made the default call fail; for a 24 km cable the layout is unchangeduninstall.batcould never remove an environment.ENV_NAMEandCONFIRMwere assigned and read inside the sameforblock, socmdsubstituted their pre-loop empty values: the script printed an empty environment name and always took the skip branch regardless of the answer. It now uses delayed expansion, and matches environment names anchored to the start of the line so that an unrelated environment cannot be matched through its path
v1.0.1 - 2026-09-10#
Bugfix release correcting the seismic moment calculation.
Fixed#
the seismic moment is no longer underestimated by a factor of
2*pi*f(#3).calculate_M0applied the amplitude-to-displacement spectral conversion a second time, afterretrieve_min_ampshad already applied it throughget_scaling_displacement. Minimum detectable moment magnitudes reported by v1.0.0 were therefore too low bydMw = (2/3)*log10(2*pi*f_r), which is 1.20 at a representative frequency of 10 Hz and 1.87 at 100 Hz. Because the representative frequencyf_r = min(v*Q/(pi*r), f_c)depends on the source-receiver distance, the correction varies across the grid and changes the shape of the sensitivity maps, not only their colour scalepynetdesign.visualizationcan be imported on Python 3.9 again;plot_sensitivity_sliceused amatchstatement, which is syntax available only from Python 3.10 onwards
Changed#
calculate_M0now documents the seismic moment relation it evaluates and states that the amplitudes it takes are the displacement amplitude spectrum, with units given for the remaining arguments
Removed#
loc_uncertainty_grid, which calledcalculate_pdfandget_uncertainty_from_pdf. Neither function has ever been part of the package, so every call raisedNameError. Location uncertainty will be reintroduced later together with the functions it depends on
Added#
pytests/test_magnitude.py, covering the seismic moment relation, the moment magnitude conversion and its inverse, the amplitude-type scaling coefficients, the peak frequency and its corner-frequency clamp, and the DAS strain and strain-rate detection thresholds. The closed-form checks fail on the v1.0.0 formula and so guard against a recurrence of #3
v1.0.0 - 2025-04-01#
Initial public release, archived on Zenodo as 10.5281/zenodo.14945917. This changelog was added retroactively so that the release is documented alongside its archived record; the code itself is unchanged from the deposited version.
Added#
magnitude sensitivity modelling for a 3D elastic homogeneous medium with attenuation: the minimum moment magnitude of a microseismic event that is theoretically detectable on a given network, evaluated on a 3D grid of potential source locations
get_mag_sensitivityandget_mag_sensitivity_localhigh-level drivers, dispatching on the velocity model type and handling combined geometriesmag_sensitivity_gridvectorized homogeneous-medium engine computing per-station minimum detectable moment magnitudesseismic moment to moment magnitude conversion after Kanamori (1977), and its inverse
peak frequency estimation after Eisner et al. (2013), limited by a corner frequency defaulting to 100 Hz
conversion of station noise levels to minimum detectable amplitudes for displacement, particle velocity, particle acceleration, strain, and strain-rate inputs, scaled by the required signal-to-noise ratio
distributed acoustic sensing (DAS) support: gauge length parsing from the geometry header with unit conversion, strain and strain-rate noise types, and a directionality correction accounting for sensitivity along the cable axis
support for station networks, DAS cables, and combined geometries evaluated together
free surface amplification correction for receivers recording at the daily surface
network detectability criterion based on the minimum number of stations required for P-wave, S-wave, or joint P- and S-wave detection
ASCII readers for network geometry in local and global (WGS84) coordinates, with conversion of geographic to local Cartesian coordinates
ASCII reader for homogeneous velocity models
DetectionParameterscontainer with validation for signal-to-noise ratios, station counts, and frequenciesstation geometry visualization in map and side views, colour-coded by noise level
magnitude sensitivity slice visualization with contour and image rendering
ten worked examples covering surface station networks, vertical, inclined and twice-inclined borehole DAS, depth-varying DAS noise profiles, and combined station plus DAS networks
conda environment files for user and development installations, and Windows installation scripts
MIT license