Repository navigation
Conversation
…ons 1.0.0 and 1.0.1
…rface Ports the medium-independent parts of the reference implementation that the homogeneous public package was missing, so that published DAS sensitivity results are reproducible here. Verified against the reference on the manuscript homogeneous case (1 km vertical DAS with 1 m channel spacing, and the 51-geophone comparison array): P, S and PS agree bit-exactly over all 4860 grid points, with identical NaN masks, for both fs_mode='off' and the default fs_mode='auto'. Previously S differed by 0.077 magnitude units and the geophone array by up to 0.152. Wave modes and radiation patterns: - wave_mode accepts 'P', 'SV', 'SH', 'S' and 'PS'; 'S' is composite and keeps the more detectable of the SV and SH branches through np.fmin - each phase carries its root-mean-square radiation-pattern magnitude over the focal sphere of a double couple: sqrt(4/15) for P, sqrt(7/30) for SV and sqrt(1/6) for SH. The value 0.63 used previously is the combined S-wave magnitude, since <R_SV^2> + <R_SH^2> = 2/5, and does not apply to SV alone - rad_pattern_p, rad_pattern_s and rad_patterns override the defaults, so earlier conventions stay reproducible; rad_pattern_s=0.63 recovers 1.0.x Receiver projection: - get_phase_station_directionality projects the arriving polarization vectors onto the local cable tangent, replacing the 1/|cos| and 1/|sin| shortcut that was only valid for a vertical cable - stations with Components == 'Z' project onto the vertical axis; 3C stations record the full vector and are unaffected - get_ray_station_directionality is kept as a deprecated wrapper. Its rays_p and rays_s arguments are removed because nothing in the homogeneous package could ever populate them Free surface: - compute_free_surface_coefficients applies the factor of two per receiver, gated on depth or on an optional Surface column of weights, instead of amplifying every receiver in the geometry - DetectionParameters gains fs_mode, fs_level and fs_deviation; the deprecated free_surface flag maps onto fs_mode and validation stays idempotent Also fixes the station-count guard in mag_detectable, which compared against the grid axis rather than the station axis. Adds 105 tests across five modules covering wave-mode expansion, the radiation constants and their combination to sqrt(2/5), polarization projection against closed forms for a vertical cable, SH being unobservable on a vertical cable, the free-surface modes and weights, network detectability, and the end-to-end phase behaviour. All ten examples still run.
Ports the geometry tooling from the reference implementation, so that the layouts used in the examples can be produced from code instead of shipped as hand-written tables, and so that the Surface and Components columns the modelling code already understands can actually be expressed in a file. Geometry builders, in the new pynetdesign.modelling.geometry module: - generate_geometry dispatches on mode to generate_borehole_geometry for vertical, inclined and deviated boreholes, generate_surface_geometry for line, zigzag, L, square and double-line layouts, and generate_darkfiber_geometry for a continuous path with prescribed turns - each returns geometry text lines that read_geometry accepts, with an optional depth-dependent noise profile for boreholes - generated output is byte-identical to the reference across all nine layout cases, checked by diffing 2234 lines of generated geometry Geometry I/O: - save_geometry writes either generated lines or a geometry DataFrame back in the read_geometry format, restoring Z to an elevation so the round trip is lossless - decimate_geometry keeps every n-th channel while preserving attrs, which is how channel spacing studies thin a dense array - read_geometry reads the optional Surface and Components columns and validates them: Surface must be a weight in [0, 1], Components must be '3C' or 'Z', and Components is rejected on a DAS geometry - read_geometry records the path it read in attrs['file_path'] Fixes the default dark-fibre turn distances, which were fixed at 6, 12 and 18 km and therefore exceeded the default 5 km cable, making the default call raise. They are now one quarter, one half and three quarters of the cable, so the default works at any length and is unchanged for a 24 km cable. Adds 39 tests covering the builders, the borehole geometry against closed forms for vertical and inclined cables, save and read round trips, the optional columns and their validation, decimation, and a generated array driving a sensitivity computation end to end. The reference parity established for the magnitude core is unaffected, and all ten examples still run.
…vironment Gives the package a published documentation site and consolidates the dependency declaration, so that the environment file pins only the interpreter and everything else is a module declared in pyproject.toml. Single environment: - environment.yml keeps only python and pip; runtime dependencies move to pyproject.toml and the tooling into the dev and docs optional groups. Install with conda env create -f environment.yml -n pnd followed by pip install -e . or pip install -e ".[dev,docs]" - environment-dev.yml is removed. The two files duplicated the dependency list and had drifted: both advertised scipy and plotly, neither of which the package imports, while cmcrameri, which it does import, was missing - pyproject.toml gains requires-python >=3.9,<3.13, the MIT license and its file, project URLs, and fuller keywords and classifiers. Python 3.8 is no longer advertised because it is untested and the package needs 3.9. The build requirement moves to setuptools >= 77 so the PEP 639 license form can be used, which the installed setuptools resolves to License-Expression: MIT - install.bat creates one environment, pnd, from the single file and asks whether to add the development tools, instead of choosing between two conda files and two environment names. Dry-run checked for yes, no and a bare Enter, which defaults to the runtime install, and the resulting pip command was checked with pip install --dry-run in a clean environment. The variable holding the install specification is deliberately not named PIP_something, because pip reads PIP_<OPTION> from the environment and would otherwise interpret the extras as its --target directory - uninstall.bat could never remove an environment: ENV_NAME and CONFIRM were assigned and read inside the same for block, so cmd substituted their pre-loop empty values, printing an empty name and always taking the skip branch whatever the answer. It now uses delayed expansion, and matches environment names anchored to the start of the line so an unrelated environment cannot be matched through its path. Its in-block :: comments are also converted to rem: :: is a degenerate label, and cmd can fail to parse a label inside a parenthesised for or if block Documentation: - docs/ holds a Sphinx project with an overview, a getting-started guide covering installation and the geometry and velocity file formats, a methodology chapter, the example gallery and a generated API reference covering every public function - methodology.rst documents only what is implemented: spectral conventions, the attenuation operator, the peak frequency, the detection threshold with its conversion coefficients, the free surface correction, receiver projection and DAS directionality, the radiation pattern with the full root-mean-square derivation, and the homogeneous seismic moment relation. The homogeneous derivation is written to stand on its own, starting from the far-field point source, rather than as a reduction of a layered result the package does not implement - references.bib carries the seven works cited from the docstrings and the methodology, so the :cite: roles added earlier resolve - changelog.rst is generated from CHANGELOG.md by docs/source/_ext/changelog.py when the documentation is built, and is gitignored, so the changelog has a single source and the rendered page is never committed - citing, contributing and credits pages are added. The credits page names the author with links to the ORCID record and to the GitHub profile, the latter behind a Fontawesome mark, and design.fa-build is suppressed because those glyphs are an HTML embellishment: every icon in these sources sits beside the link text that carries the meaning, so the PDF loses nothing by dropping them, and rendering them would need fontawesome5.sty from texlive-fonts-extra - the credits page acknowledges each work the implementation rests on, including 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. The methodology and credits pages close with a References section rather than a rubric, so the bibliography is reachable from the table of contents - examples/README.txt is rewritten. It promised a raytracing example that this package does not ship and carried a stale product name - the README links to the site and to the PDF, corrects the Python range and the dependency list, and fixes the case of the clone URL - helper scripts for both platforms: build-docs.bat / build-docs.sh build the documentation, serve-docs.bat / serve-docs.sh view it locally. serve-docs rebuilds incrementally before serving, so only the pages that changed are regenerated, and takes --port and --no-build. Both honour SPHINXOPTS and neither requires make: they call python -m sphinx -M directly, which also means they work in a Git Bash shell where make is absent. Both also take --pdf (-pdf on Windows), which generates the LaTeX sources, runs latexmk on them and copies the result to where the site links it, after checking that lualatex and latexmk are on PATH - install.sh and uninstall.sh, the Linux and macOS counterparts of the Windows scripts, with --dev/--no-dev and --yes to skip the prompts All four scripts were exercised: the help and argument validation paths, a clean build, an incremental build, and serving, with HTTP 200 confirmed for index.html, methodology.html and examples/index.html on both platforms' script variants. PDF edition: - the documentation is also produced as a single PDF from the same sources, through lualatex, and is linked from the site header and the front page, so the whole manual can be read offline. conf.py adds the title page, the bibliography style and an end page carrying a QR code back to the site, and docs.yml installs the LaTeX packages, builds it, publishes it inside the site under _static and keeps a copy as a workflow artifact - the latexmk call is left to the latexmkrc that Sphinx writes beside the .tex, which binds the engine to lualatex and the index style to python.ist, so -pdf resolves to lualatex and the index is styled as Sphinx intends - the front page had its .. only:: html content at the wrong indentation, an inherited defect, so the directive guarded nothing and the LaTeX build was asked to typeset the Fontawesome icon cards it cannot render. Fixing the indentation removed all seven such warnings and made the LaTeX generation warning-free The PDF could not be compiled locally. lualatex aborts with TeX capacity exceeded, input stack size, inside sphinxmidrule; the same failure reproduces with no custom preamble at all, and an unrelated project's documentation fails identically in this MiKTeX installation while its published PDF downloads fine. It is a local toolchain defect, so the PDF is first exercised by docs.yml in CI, as the gallery figures are. Branding, from the PyNetDesign brand package: - the logo appears in the documentation header and at the top of the README. Both themes serve the same transparent mark, the one the README uses, so it 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 - the full browser icon set is wired up: favicon.ico through html_favicon, and a scalable favicon.svg, an Apple touch icon and a web app manifest through a layout template, with the theme colour set to the brand gray - the stylesheet carries the brand palette. Signal Orange measures only 2.87:1 against white, so it is used for accents and link text in light mode is darkened to #B84806, which measures 4.81:1 against the light page surface; on the dark surfaces the unmodified orange measures 5.17:1 and is used as is. The contrast ratios were computed rather than estimated Workflows: - docs.yml builds the documentation on every push and deploys to GitHub Pages from main and from release tags, asserting that the built version matches the tag - push-tag.yml validates a pushed vX.Y.Z tag and publishes versioned docs Verified: both the HTML and the LaTeX builds succeed under -W --keep-going, so neither emits a single warning; the HTML build produces 84 pages, including all ten gallery pages, and the 181 tests still pass. The built site carries no reference to any non-public variant of the package, and neither do the tracked files. Example figures could not be rendered locally: matplotlib in the development environment aborts with Windows fatal exception 0xc06d007f inside the Agg backend on any savefig, for PNG and SVG alike and for a one-line plot with no PyNetDesign involved, so it is a delay-loaded DLL problem in that environment rather than a defect here. The gallery figures are therefore first exercised by docs.yml in CI.
- Added a hover state for the header logo that swaps in the brand's orange-only lockup, maintaining the same geometry and viewBox. - Updated the documentation to reflect the new branding elements, including the addition of the orange logo SVG. - Improved accessibility by including appropriate titles and descriptions in the SVG file.
Example 7 becomes the homogeneous DAS benchmark of the downhole monitoring study, and the remaining items from the 1.1.0 plan are finished: the test port, the root package marker and the test configuration. Example 7: - a 1-km-long vertical fibre with 1 m channel spacing, so 1000 channels between 1 and 1000 m depth, 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. Detection requires at least 60 channels above a signal-to-noise ratio of 2, and the section is computed for P, for S and for both, the three panels of the published figure - the source frequency is deliberately left unset so that the representative frequency is the peak frequency of each arrival clamped at the corner frequency of 100 Hz, which is the relation the study states. The free surface correction is switched off, since every channel is downhole, and that also matches what 1.0.1 did by default when the figures were produced - data/homo/test_07 carries the new model and geometry. The reference data for this case is the 5 m spacing variant, so the 1 m geometry is generated rather than copied - the four features the study describes all reproduce: the threshold magnitude grows with offset, from -1.34 at 100 m to +0.25 at 2000 m at 400 m source depth; the values over 100 to 500 m offset, -1.34 to -0.68, sit in the stated band; P-wave sensitivity is worst at the array mid-depth and only once the offset exceeds half the array length, +0.041 at 500 m depth against -0.044 at the array ends for an offset of 1500 m, and nothing measurable at 300 m; and S-wave sensitivity vanishes on the cable axis, where the polarization is perpendicular to the fibre, and degrades below the array - examples/README.txt describes the new case Tests: - test_magnitude_consistency.py builds the forward displacement spectrum independently of the package, from the relation stated in the methodology, and checks that calculate_M0 inverts it exactly over a range of moments, distances and frequencies. It then pins the part that went wrong before 1.0.1 from the other side: the spectral conversion S(f) has to be applied once across retrieve_min_amps and calculate_M0, never twice, so an event at the threshold magnitude must record exactly the requested signal-to-noise ratio. That is asserted for all five amplitude types, including the gauge-length bridge that strain and strain rate need - the reference's read_geometry tests were reviewed rather than copied. Its MinSigmaP and MinSigmaS cases describe location uncertainty, which this package does not carry, and its overlap case needs a function that does not exist here. Of its Components cases, four were already covered by test_geometry_io.py; the fifth is added, in the form that tests the contract rather than the internals: combining a station geometry that declares Components with a DAS geometry leaves the column empty on the DAS rows, and the recovered DAS geometry has to write back without it and read again as the geometry it started as. It does, so no change to recover() is warranted, even though the reference drops the column earlier - test_read_geometry.py resolved its sample files against the working directory, so it passed only when pytest was started from the repository root. The paths are anchored to the test file, confirmed by running it from another drive root - pytest.ini named tests as a directory to avoid, which does not exist here, and never named the one that does. It now sets testpaths = pytests 238 tests pass, up from 181. Fixed: - a grid point that coincides with a receiver no longer emits a spurious divide-by-zero warning. Such a point gives r = 0, hence t* = 0 and an infinite peak frequency, which the corner-frequency clamp already turned into the intended answer; only the warning was wrong. Coincidence is ordinary with a dense DAS cable, where every channel sits on a grid line, so the new example hits it on every run. The values are unchanged, checked against the same run before the guard, and the case is covered by a test that raises on any floating-point error Removed: - the empty __init__.py at the repository root, which made the root look like an importable package and confused setuptools flat-layout discovery
… loading in conf.py
…nd improving heading conversion
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.
No description provided.