From 1bb786375ac7edc2172db8f5a2621579e22cd3d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 03:44:50 +0000 Subject: [PATCH 1/5] chore: start XYZTS support implementation Agent-Logs-Url: https://github.com/ucgmsim/qcore/sessions/6829334f-dcbc-47d2-9f97-d63ebff1bb3a Co-authored-by: lispandfound <12835929+lispandfound@users.noreply.github.com> --- qcore_utils.egg-info/PKG-INFO | 38 ++++++++++ qcore_utils.egg-info/SOURCES.txt | 88 +++++++++++++++++++++++ qcore_utils.egg-info/dependency_links.txt | 1 + qcore_utils.egg-info/requires.txt | 18 +++++ qcore_utils.egg-info/top_level.txt | 1 + 5 files changed, 146 insertions(+) create mode 100644 qcore_utils.egg-info/PKG-INFO create mode 100644 qcore_utils.egg-info/SOURCES.txt create mode 100644 qcore_utils.egg-info/dependency_links.txt create mode 100644 qcore_utils.egg-info/requires.txt create mode 100644 qcore_utils.egg-info/top_level.txt diff --git a/qcore_utils.egg-info/PKG-INFO b/qcore_utils.egg-info/PKG-INFO new file mode 100644 index 00000000..42280cdb --- /dev/null +++ b/qcore_utils.egg-info/PKG-INFO @@ -0,0 +1,38 @@ +Metadata-Version: 2.4 +Name: qcore-utils +Version: 2025.12.3.dev1+g93313e926 +Summary: Utils Library +Author: ucgmsim +Requires-Python: >=3.11 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: pandas +Requires-Dist: pyfftw +Requires-Dist: pytest +Requires-Dist: pytest-black +Requires-Dist: alphashape +Requires-Dist: descartes +Requires-Dist: filelock +Requires-Dist: pyproj +Requires-Dist: pooch +Requires-Dist: requests +Requires-Dist: shapely +Requires-Dist: numpy +Requires-Dist: numba +Requires-Dist: hypothesis[numpy] +Requires-Dist: typer +Requires-Dist: docstring_parser +Requires-Dist: xarray +Requires-Dist: pyyaml +Dynamic: license-file + +[![Build Status](https://quakecoresoft.canterbury.ac.nz/jenkins/job/qcore/badge/icon?build=last:${params.ghprbActualCommit=master)](https://quakecoresoft.canterbury.ac.nz/jenkins/job/qcore) + +## Installation: + +To install run `pip install -e .` from the root directory of this repository + +### Downloading data after install + +After installing, if you intend to use GMT for plotting you will need to run "download_data.py" (Located in qcore.data) to download and +unpack the data used for these scripts diff --git a/qcore_utils.egg-info/SOURCES.txt b/qcore_utils.egg-info/SOURCES.txt new file mode 100644 index 00000000..a3b6ae05 --- /dev/null +++ b/qcore_utils.egg-info/SOURCES.txt @@ -0,0 +1,88 @@ +.gitignore +CHANGELOG.md +Jenkinsfile +LICENSE +MANIFEST.in +README.md +pyproject.toml +requirements.txt +.github/workflows/git-extension.yml +.github/workflows/publish-PyPi.yml +.github/workflows/wiki.yml +qcore/__init__.py +qcore/archive_structure.py +qcore/cli.py +qcore/constants.py +qcore/coordinates.py +qcore/formats.py +qcore/geo.py +qcore/grid.py +qcore/nhm.py +qcore/point_in_polygon.py +qcore/shared.py +qcore/simulation_structure.py +qcore/siteamp_models.py +qcore/src_site_dist.py +qcore/timeseries.py +qcore/utils.py +qcore/xyts.py +qcore/siteamp_coefs_files/Bayless_ModelCoefs.csv +qcore/test/__init__.py +qcore/test/runscript.sh +qcore/test/test_cli/test_cli.py +qcore/test/test_coordinates/test_coordinates.py +qcore/test/test_geo/__init__.py +qcore/test/test_geo/test_geo.py +qcore/test/test_geo/sample1/README.md +qcore/test/test_grid/__init__.py +qcore/test/test_grid/test_grid.py +qcore/test/test_siteamp/amp_bandpass_benchmark.pkl +qcore/test/test_siteamp/cb_2014_test.csv +qcore/test/test_siteamp/interpolate_benchmark.pkl +qcore/test/test_siteamp/test_siteamp.py +qcore/test/test_source_site_dist/__init__.py +qcore/test/test_source_site_dist/test_src_site_dist_calc.py +qcore/test/test_source_site_dist/sample0/input/calc_rrup_rjb_locations.npy +qcore/test/test_source_site_dist/sample0/input/calc_rrup_rjb_srf_points.npy +qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_locations.npy +qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_srf_header.P +qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_srf_points.npy +qcore/test/test_source_site_dist/sample0/output/calc_rrup_rjb_rjb.npy +qcore/test/test_source_site_dist/sample0/output/calc_rrup_rjb_rrup.npy +qcore/test/test_source_site_dist/sample0/output/calc_rx_ry_rx.npy +qcore/test/test_source_site_dist/sample0/output/calc_rx_ry_ry.npy +qcore/test/test_timeseries/R01_seis-00041.e3d +qcore/test/test_timeseries/test_timeseries.py +qcore/test/test_xyts/__init__.py +qcore/test/test_xyts/test_xyts.py +qcore/test/test_xyts/sample1/output/out_tslice-1 +qcore/test/test_xyts/sample1/output/out_tslice0 +qcore/test/test_xyts/sample1/output/out_tslice1 +qcore/test/test_xyts/sample1/output/out_tslice2 +qcore/test/test_xyts/sample1/output/sample_mmiout +qcore/test/test_xyts/sample1/output/sample_pgvout +qcore/test/tool/__init__.py +qcore/test/tool/create_binaryfile.py +qcore/test/tool/utils.py +qcore/uncertainties/__init__.py +qcore/uncertainties/distributions.py +qcore_utils.egg-info/PKG-INFO +qcore_utils.egg-info/SOURCES.txt +qcore_utils.egg-info/dependency_links.txt +qcore_utils.egg-info/requires.txt +qcore_utils.egg-info/top_level.txt +wiki/Bounding-Box.md +wiki/Home.md +wiki/images/alphashape.png +wiki/images/axis_aligned_minimum.png +wiki/images/better_domain.png +wiki/images/bounding_box.png +wiki/images/bounding_box_circle.png +wiki/images/convex_hull.png +wiki/images/domain_bad.png +wiki/images/example_problem.png +wiki/images/point_cluster.png +wiki/images/point_cluster_with_bounding_box.png +wiki/images/point_cluster_with_hull.png +wiki/images/rotated_convex_hull.png +wiki/images/rotated_minimum_boxes.png \ No newline at end of file diff --git a/qcore_utils.egg-info/dependency_links.txt b/qcore_utils.egg-info/dependency_links.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/qcore_utils.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/qcore_utils.egg-info/requires.txt b/qcore_utils.egg-info/requires.txt new file mode 100644 index 00000000..c5441e1d --- /dev/null +++ b/qcore_utils.egg-info/requires.txt @@ -0,0 +1,18 @@ +pandas +pyfftw +pytest +pytest-black +alphashape +descartes +filelock +pyproj +pooch +requests +shapely +numpy +numba +hypothesis[numpy] +typer +docstring_parser +xarray +pyyaml diff --git a/qcore_utils.egg-info/top_level.txt b/qcore_utils.egg-info/top_level.txt new file mode 100644 index 00000000..4e4eba80 --- /dev/null +++ b/qcore_utils.egg-info/top_level.txt @@ -0,0 +1 @@ +qcore From 692f8c95ef6b071b2d337c973efe98b6ed024143 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 03:48:42 +0000 Subject: [PATCH 2/5] feat: add native XYZTS (tsheader_procP3) support with auto-detection Agent-Logs-Url: https://github.com/ucgmsim/qcore/sessions/6829334f-dcbc-47d2-9f97-d63ebff1bb3a Co-authored-by: lispandfound <12835929+lispandfound@users.noreply.github.com> --- qcore/test/test_xyts/test_xyts.py | 270 ++++++++++++++++++++++++++++++ qcore/xyts.py | 217 ++++++++++++++++++++---- 2 files changed, 457 insertions(+), 30 deletions(-) diff --git a/qcore/test/test_xyts/test_xyts.py b/qcore/test/test_xyts/test_xyts.py index 08ac3d4e..a76c34b7 100644 --- a/qcore/test/test_xyts/test_xyts.py +++ b/qcore/test/test_xyts/test_xyts.py @@ -1,5 +1,6 @@ """Test module for XYTS file processing using pytest fixtures.""" +import struct from pathlib import Path from urllib import request @@ -9,6 +10,92 @@ from qcore import xyts +# --------------------------------------------------------------------------- +# Helpers for constructing synthetic binary timeslice files +# --------------------------------------------------------------------------- + +def _write_standard_xyts_header( + buf: bytearray, + endian: str, + x0: int, + y0: int, + z0: int, + t0: int, + nx: int, + ny: int, + nz: int, + nt: int, + dx: float, + dy: float, + hh: float, + dt: float, + mrot: float, + mlat: float, + mlon: float, +) -> None: + """Write a 60-byte standard XYTS header into *buf*.""" + fmt = f"{endian}4i4i7f" + data = struct.pack( + fmt.replace("4i", "iiii").replace("7f", "fffffff"), + x0, y0, z0, t0, + nx, ny, nz, nt, + dx, dy, hh, dt, mrot, mlat, mlon, + ) + buf[:60] = data + + +def _make_proc_local_header( + endian: str, + x0: int, y0: int, z0: int, t0: int, + local_nx: int, local_ny: int, local_nz: int, + nx: int, ny: int, nz: int, nt: int, + dx: float, dy: float, hh: float, dt: float, + mrot: float, mlat: float, mlon: float, +) -> bytes: + """Return a 72-byte proc-local (tsheader_procP3) header as bytes.""" + pfx = ">" if endian == ">" else "<" + ints = struct.pack( + f"{pfx}11i", + x0, y0, z0, t0, + local_nx, local_ny, local_nz, + nx, ny, nz, nt, + ) + floats = struct.pack( + f"{pfx}7f", + dx, dy, hh, dt, mrot, mlat, mlon, + ) + return ints + floats # 44 + 28 = 72 bytes + + +def _make_xyzts_file( + path: Path, + endian: str, + local_nx: int, + local_ny: int, + local_nz: int, + nx: int, + ny: int, + nt: int, + ncomp: int, + rng: np.random.Generator, +) -> np.ndarray: + """Create a synthetic XYZTS proc-local file and return the payload array.""" + header = _make_proc_local_header( + endian, + x0=0, y0=0, z0=0, t0=0, + local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, + nx=nx, ny=ny, nz=local_nz, nt=nt, + dx=0.4, dy=0.4, hh=0.1, dt=0.02, + mrot=0.0, mlat=-43.5, mlon=172.0, + ) + payload = rng.random( + (nt, ncomp, local_nz, local_ny, local_nx), dtype=np.float32 + ) + dtype = f"{endian}f4" + path.write_bytes(header + payload.astype(dtype).tobytes()) + return payload + + @pytest.fixture(scope="session") def xyts_file() -> xyts.XYTSFile: """Provide path to the XYTS test file.""" @@ -192,3 +279,186 @@ def test_tslice_get( test_output = xyts_file.tslice_get(step, comp=comp) sample_array = np.fromfile(sample_file, dtype="3 np.random.Generator: + """Fixed-seed random number generator for reproducible tests.""" + return np.random.default_rng(42) + + +@pytest.mark.parametrize("endian,ncomp", [ + (">", 3), + ("<", 3), + ("<", 6), + ("<", 9), +]) +def test_xyzts_auto_detection( + tmp_path: Path, + rng: np.random.Generator, + endian: str, + ncomp: int, +) -> None: + """XYTSFile should auto-detect an XYZTS file without proc_local_file flag.""" + fpath = tmp_path / f"test_xyzts-{endian[0]}_ncomp{ncomp}" + _make_xyzts_file( + fpath, + endian=endian, + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=ncomp, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath) + + assert int(xf.local_nz) == _LOCAL_NZ + assert int(xf.local_ny) == _LOCAL_NY + assert int(xf.local_nx) == _LOCAL_NX + assert xf.ncomp == ncomp + assert int(xf.nt) == _NT + + +@pytest.mark.parametrize("endian", [">", "<"]) +def test_xyzts_data_shape( + tmp_path: Path, + rng: np.random.Generator, + endian: str, +) -> None: + """Data memmap for XYZTS should be 5-D (nt, ncomp, nz, ny, nx).""" + ncomp = 3 + fpath = tmp_path / f"shape_xyzts-{endian[0]}" + _make_xyzts_file( + fpath, + endian=endian, + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=ncomp, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath) + + assert xf.data is not None + assert xf.data.ndim == 5 + assert xf.data.shape == (_NT, ncomp, _LOCAL_NZ, _LOCAL_NY, _LOCAL_NX) + + +def test_xyzts_payload_values( + tmp_path: Path, + rng: np.random.Generator, +) -> None: + """Values read from the XYZTS memmap match the written payload.""" + endian = "<" + ncomp = 6 + fpath = tmp_path / "values_xyzts-0" + payload = _make_xyzts_file( + fpath, + endian=endian, + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=ncomp, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath) + + assert xf.data == pytest.approx(payload) + + +def test_xyzts_tslice_get_raises( + tmp_path: Path, + rng: np.random.Generator, +) -> None: + """tslice_get should raise ValueError for volumetric XYZTS files.""" + fpath = tmp_path / "tslice_xyzts-0" + _make_xyzts_file( + fpath, + endian="<", + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=3, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath) + + with pytest.raises(ValueError, match="tslice_get"): + xf.tslice_get(0) + + +def test_xyzts_pgv_raises( + tmp_path: Path, + rng: np.random.Generator, +) -> None: + """pgv() should raise ValueError for volumetric XYZTS files.""" + fpath = tmp_path / "pgv_xyzts-0" + _make_xyzts_file( + fpath, + endian="<", + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=3, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath) + + with pytest.raises(ValueError, match="pgv"): + xf.pgv() + + +def test_xyzts_meta_only( + tmp_path: Path, + rng: np.random.Generator, +) -> None: + """meta_only=True should work for XYZTS files and leave data=None.""" + fpath = tmp_path / "meta_xyzts-0" + _make_xyzts_file( + fpath, + endian="<", + local_nx=_LOCAL_NX, + local_ny=_LOCAL_NY, + local_nz=_LOCAL_NZ, + nx=_GLOBAL_NX, + ny=_GLOBAL_NY, + nt=_NT, + ncomp=3, + rng=rng, + ) + + xf = xyts.XYTSFile(fpath, meta_only=True) + + assert xf.data is None + assert int(xf.local_nz) == _LOCAL_NZ + assert xf.ncomp == 3 diff --git a/qcore/xyts.py b/qcore/xyts.py index dbd3d17a..f8d0b6d4 100644 --- a/qcore/xyts.py +++ b/qcore/xyts.py @@ -1,15 +1,40 @@ """ -This module provides functionality to read xyts files. +This module provides functionality to read xyts and xyzts files. Extended Summary ---------------- -This module includes the XYTSFile class, which represents an XYTS file. It -allows users to load metadata, retrieve data, and calculate PGV (Peak Ground -Velocity) and MMI (Modified Mercalli Intensity) values from the XYTS file. +This module includes the XYTSFile class, which represents an XYTS or XYZTS +file. It allows users to load metadata, retrieve data, and calculate PGV +(Peak Ground Velocity) and MMI (Modified Mercalli Intensity) values from the +XYTS file. + +Two file layouts are supported: + +1. **Standard XYTS** (60-byte ``tsheader`` header, ``nz=1``): + Surface XY-plane timeslices with exactly 3 velocity components. + Data shape: ``(nt, 3, ny, nx)``. + +2. **Proc-local timeslice** (72-byte ``tsheader_procP`` / ``tsheader_procP3`` + header): + Written per MPI rank. Two sub-variants are auto-detected from the header: + + a. **Proc-local XYTS** – ``local_nz == 1``, ``ncomp == 3``. + Data shape: ``(nt, 3, local_ny, local_nx)``. + Requires ``proc_local_file=True`` (backwards-compatible flag). + + b. **Proc-local XYZTS** (EMOD3D ≥ v3.0.13, ``ts_xyz`` output) – + ``local_nz > 1``, ``ncomp ∈ {3, 6, 9}``. + Detected automatically without any user flag. + Data shape: ``(nt, ncomp, local_nz, local_ny, local_nx)``. + Filenames typically follow the ``*_xyzts-*`` pattern. + +For proc-local files ``ncomp`` is derived from the file size so that no +explicit ``ncomp`` field is required in the header. Classes ---------------- -- XYTSFile: Represents an XYTS file and provides methods to interact with it. +- XYTSFile: Represents an XYTS / XYZTS file and provides methods to interact + with it. Notes ----- @@ -25,8 +50,14 @@ Examples -------- -# Load an XYTS file -xyts_file = XYTSFile("example.x3d") +# Load a standard XYTS file +xyts_file = XYTSFile("example.e3d") + +# Load a proc-local XYTS file (backwards-compatible flag) +xyts_file = XYTSFile("example_xyts-000000", proc_local_file=True) + +# Load a volumetric XYZTS file (auto-detected – no flag needed) +xyzts_file = XYTSFile("example_xyzts-000000") # Retrieve corners of the simulation domain corners = xyts_file.corners() @@ -39,13 +70,13 @@ """ import dataclasses +from enum import Enum from math import cos, radians, sin from pathlib import Path import numpy as np from qcore import geo -from enum import Enum class Component(Enum): @@ -60,9 +91,9 @@ class Component(Enum): @dataclasses.dataclass class XYTSFile: """ - Represents an XYTS file containing time slices on the X-Y plane (z = 1, top level). - This class provides methods to read metadata, retrieve data, and calculate - PGV (Peak Ground Velocity) and MMI (Modified Mercalli Intensity) values. + Represents an XYTS or XYZTS file. + + Supports three file layouts – see module docstring for details. Assumptions: - dip = 0: Simulation domain is flat. @@ -73,9 +104,9 @@ class XYTSFile: y0: Starting y-coordinate. z0: Starting z-coordinate. t0: Starting time. - local_nx: Number of local x-coordinates (for proc-local files only). - local_ny: Number of local y-coordinates (for proc-local files only). - local_nz: Number of local z-coordinates (for proc-local files only). + local_nx: Number of local x-coordinates (proc-local files only). + local_ny: Number of local y-coordinates (proc-local files only). + local_nz: Number of local z-coordinates (proc-local files only). nx: Total number of x-coordinates. ny: Total number of y-coordinates. nz: Total number of z-coordinates. @@ -87,6 +118,9 @@ class XYTSFile: mrot: Rotation angle for model origin. mlat: Latitude of the model origin. mlon: Longitude of the model origin. + ncomp: Number of components per grid point. Always 3 for standard + XYTS and proc-local XYTS files. For XYZTS files this is 3, 6, + or 9 as set by ``ts_xyz_ncomp`` in the EMOD3D configuration. dxts: Original simulation grid spacing in the x-direction. dyts: Original simulation grid spacing in the y-direction. nx_sim: Original simulation size in the x-direction. @@ -99,6 +133,9 @@ class XYTSFile: sinP: Sine of the dip angle. rot_matrix: Rotation matrix for components. data: Memory-mapped array containing the data. + Shape is ``(nt, ncomp, ny, nx)`` for standard XYTS, + ``(nt, ncomp, local_ny, local_nx)`` for proc-local XYTS, and + ``(nt, ncomp, local_nz, local_ny, local_nx)`` for XYZTS. ll_map: Longitude-latitude map for data. Methods: @@ -113,10 +150,11 @@ class XYTSFile: Returns the simulation region as a tuple (x_min, x_max, y_min, y_max). tslice_get(step, comp=-1, outfile=None): - Retrieves timeslice data. + Retrieves timeslice data (standard and proc-local XYTS only). pgv(mmi=False, pgvout=None, mmiout=None): - Retrieves PGV map and optionally calculates MMI. + Retrieves PGV map and optionally calculates MMI (standard XYTS + only). """ # Header values @@ -137,6 +175,7 @@ class XYTSFile: mlat: float mlon: float # Derived values + ncomp: int dxts: int dyts: int nx_sim: int @@ -171,12 +210,16 @@ def __init__( Parameters ---------- xyts_path : Path | str - Path to the xyts file. + Path to the xyts / xyzts file. meta_only : bool If True, only loads metadata and doesn't prepare gridpoint datum locations (slower). proc_local_file : bool - If True, indicates a proc-local file. + If True, forces reading with a 72-byte proc-local header. This + is still required for proc-local XYTS files whose ``local_nz`` + equals 1, because those cannot be distinguished from standard XYTS + files by header inspection alone. XYZTS files (``local_nz > 1``) + are detected automatically and do not need this flag. round_dt : bool If True, round the dt value to 4dp (present only for backwards compatibility). @@ -184,29 +227,74 @@ def __init__( Raises ------ ValueError - ValueError: If the file is not an XY timeslice file. + If the file layout cannot be determined from the header bytes. """ xytf = open(xyts_path, "rb") self.xyts_path = xyts_path - # determine endianness, an x-y timeslice has 1 z value - nz = np.fromfile(xytf, dtype=">i4", count=7)[-1] - if nz == 0x00000001: + # --------------------------------------------------------------- + # Step 1 – determine endianness and whether this is a proc-local + # (72-byte header) file. + # + # Layout of the first 7 32-bit integers: + # Standard XYTS (60-byte header): + # [x0, y0, z0, t0, nx, ny, nz] → nz == 1 + # Proc-local XYTS / XYZTS (72-byte header): + # [x0, y0, z0, t0, local_nx, local_ny, local_nz] + # + # For standard XYTS the 7th word is nz=1, giving a reliable + # endianness probe. For XYZTS files local_nz > 1, so the probe + # fails and we fall through to the proc-local branch below. + # --------------------------------------------------------------- + raw7_be = np.fromfile(xytf, dtype=">i4", count=7) + seventh_be = int(raw7_be[-1]) + + if seventh_be == 0x00000001: endian = ">" - elif nz == 0x01000000: + proc_local = proc_local_file + elif seventh_be == 0x01000000: endian = "<" + proc_local = proc_local_file else: - xytf.close() - raise ValueError("File is not an XY timeslice file: %s" % (xyts_path)) + # The 7th word is neither 1 nor byte-swapped 1. The only + # known cause is a proc-local XYZTS file where local_nz > 1. + # Determine endianness from local_nx (5th word, index 4): + # small-positive big-endian reads are implausible as + # little-endian because byte-swapping maps e.g. 100 → 1677721600. + local_nx_be = int(raw7_be[4]) + raw7_le = np.frombuffer(raw7_be.tobytes(), dtype=" 1) : (nt, ncomp, local_nz, local_ny, local_nx) + # --------------------------------------------------------------- + if proc_local: + if int(self.local_nz) > 1: + # Volumetric XYZTS: 5-D tensor + shape: tuple[int, ...] = ( + int(self.nt), + self.ncomp, + int(self.local_nz), + int(self.local_ny), + int(self.local_nx), + ) + else: + # Surface proc-local XYTS: 4-D tensor (backwards-compatible) + shape = ( + int(self.nt), + self.ncomp, + int(self.local_ny), + int(self.local_nx), + ) self.data = np.memmap( xyts_path, dtype="%sf4" % (endian), mode="r", offset=72, - shape=(self.nt, len(self.comps), self.local_ny, self.local_nx), + shape=shape, ) else: # memory map for data section @@ -270,7 +400,7 @@ def __init__( dtype="%sf4" % (endian), mode="r", offset=60, - shape=(self.nt, len(self.comps), self.ny, self.nx), + shape=(int(self.nt), self.ncomp, int(self.ny), int(self.nx)), ) # create longitude, latitude map for data @@ -360,6 +490,10 @@ def tslice_get( ) -> np.ndarray: """Retrieves timeslice data. + This method operates on the surface XY plane and is intended for + standard XYTS and proc-local XYTS files (``local_nz == 1``). For + volumetric XYZTS files access ``self.data`` directly. + Parameters ---------- step : int @@ -371,7 +505,17 @@ def tslice_get( ------- np.ndarray Retrieved timeslice data. + + Raises + ------ + ValueError + If called on a volumetric XYZTS file (``local_nz > 1``). """ + if self.local_nz is not None and int(self.local_nz) > 1: + raise ValueError( + "tslice_get() is not supported for volumetric XYZTS files " + "(local_nz > 1). Access self.data directly." + ) match comp: case Component.MAGNITUDE: return np.linalg.norm(self.data[step, :3, :, :], axis=0) @@ -396,6 +540,9 @@ def pgv( ) -> None | np.ndarray | tuple[np.ndarray, np.ndarray]: """Retrieves PGV and/or MMI map. + This method is intended for standard XYTS files. It is not applicable + to volumetric XYZTS files. + Parameters ---------- mmi : bool @@ -410,7 +557,17 @@ def pgv( None | np.ndarray | Tuple[np.ndarray, np.ndarray] PGV map or tuple of (PGV map, MMI map) or None (if both are written to a file). + + Raises + ------ + ValueError + If called on a volumetric XYZTS file (``local_nz > 1``). """ + if self.local_nz is not None and int(self.local_nz) > 1: + raise ValueError( + "pgv() is not supported for volumetric XYZTS files " + "(local_nz > 1)." + ) # PGV as timeslices reduced to maximum value at each point pgv = np.zeros(self.nx * self.ny) for ts in range(self.t0, self.nt): From 9ce1d57c7c2343f6bdf616ed35e92d5a05c9a96a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 03:50:39 +0000 Subject: [PATCH 3/5] refactor: address code-review feedback (constant, ncomp validation, cleanup) Agent-Logs-Url: https://github.com/ucgmsim/qcore/sessions/6829334f-dcbc-47d2-9f97-d63ebff1bb3a Co-authored-by: lispandfound <12835929+lispandfound@users.noreply.github.com> --- qcore/test/test_xyts/test_xyts.py | 30 ------------------------------ qcore/xyts.py | 28 +++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/qcore/test/test_xyts/test_xyts.py b/qcore/test/test_xyts/test_xyts.py index a76c34b7..1545611b 100644 --- a/qcore/test/test_xyts/test_xyts.py +++ b/qcore/test/test_xyts/test_xyts.py @@ -14,36 +14,6 @@ # Helpers for constructing synthetic binary timeslice files # --------------------------------------------------------------------------- -def _write_standard_xyts_header( - buf: bytearray, - endian: str, - x0: int, - y0: int, - z0: int, - t0: int, - nx: int, - ny: int, - nz: int, - nt: int, - dx: float, - dy: float, - hh: float, - dt: float, - mrot: float, - mlat: float, - mlon: float, -) -> None: - """Write a 60-byte standard XYTS header into *buf*.""" - fmt = f"{endian}4i4i7f" - data = struct.pack( - fmt.replace("4i", "iiii").replace("7f", "fffffff"), - x0, y0, z0, t0, - nx, ny, nz, nt, - dx, dy, hh, dt, mrot, mlat, mlon, - ) - buf[:60] = data - - def _make_proc_local_header( endian: str, x0: int, y0: int, z0: int, t0: int, diff --git a/qcore/xyts.py b/qcore/xyts.py index f8d0b6d4..313eaabd 100644 --- a/qcore/xyts.py +++ b/qcore/xyts.py @@ -78,6 +78,12 @@ from qcore import geo +# Maximum plausible grid dimension. Values up to this threshold are treated +# as valid local_nx / local_ny during endianness detection; byte-swapped +# representations of small integers exceed this bound by several orders of +# magnitude (e.g. 100 byte-swapped → 1 677 721 600). +_MAX_GRID_DIM = 0xFFFF + class Component(Enum): """Timestep component.""" @@ -267,16 +273,16 @@ def __init__( raw7_le = np.frombuffer(raw7_be.tobytes(), dtype=" Date: Mon, 25 May 2026 03:51:39 +0000 Subject: [PATCH 4/5] fix: explicit both-plausible check in endianness tiebreaker Agent-Logs-Url: https://github.com/ucgmsim/qcore/sessions/6829334f-dcbc-47d2-9f97-d63ebff1bb3a Co-authored-by: lispandfound <12835929+lispandfound@users.noreply.github.com> --- qcore/xyts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcore/xyts.py b/qcore/xyts.py index 313eaabd..7d2b3468 100644 --- a/qcore/xyts.py +++ b/qcore/xyts.py @@ -277,7 +277,7 @@ def __init__( endian = ">" elif 1 <= local_nx_le <= _MAX_GRID_DIM and not (1 <= local_nx_be <= _MAX_GRID_DIM): endian = "<" - elif 1 <= local_nx_be <= _MAX_GRID_DIM: + elif (1 <= local_nx_be <= _MAX_GRID_DIM) and (1 <= local_nx_le <= _MAX_GRID_DIM): # Both readings look plausible; use the big-endian # interpretation of local_ny as a tiebreaker. local_ny_be = int(raw7_be[5]) From 2da41e0158e61c624d7e36509e78be9d767618eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 04:01:52 +0000 Subject: [PATCH 5/5] refactor: replace rng/parametrize XYZTS tests with hypothesis, clean xyts.py comments, remove egg-info Agent-Logs-Url: https://github.com/ucgmsim/qcore/sessions/83689858-8f50-44f9-83e1-452c23694707 Co-authored-by: lispandfound <12835929+lispandfound@users.noreply.github.com> --- .gitignore | 1 + qcore/test/test_xyts/test_xyts.py | 311 ++++++++-------------- qcore/xyts.py | 54 ++-- qcore_utils.egg-info/PKG-INFO | 38 --- qcore_utils.egg-info/SOURCES.txt | 88 ------ qcore_utils.egg-info/dependency_links.txt | 1 - qcore_utils.egg-info/requires.txt | 18 -- qcore_utils.egg-info/top_level.txt | 1 - 8 files changed, 134 insertions(+), 378 deletions(-) delete mode 100644 qcore_utils.egg-info/PKG-INFO delete mode 100644 qcore_utils.egg-info/SOURCES.txt delete mode 100644 qcore_utils.egg-info/dependency_links.txt delete mode 100644 qcore_utils.egg-info/requires.txt delete mode 100644 qcore_utils.egg-info/top_level.txt diff --git a/.gitignore b/.gitignore index 557aca80..c905252b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ build/ dist/ qcore.egg-info +qcore_utils.egg-info **/*.pyc **/*.coverage .cache/ diff --git a/qcore/test/test_xyts/test_xyts.py b/qcore/test/test_xyts/test_xyts.py index 1545611b..1a87eb95 100644 --- a/qcore/test/test_xyts/test_xyts.py +++ b/qcore/test/test_xyts/test_xyts.py @@ -1,19 +1,19 @@ """Test module for XYTS file processing using pytest fixtures.""" import struct +import tempfile from pathlib import Path from urllib import request import numpy as np import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st +from hypothesis.extra.numpy import arrays from qcore import xyts -# --------------------------------------------------------------------------- -# Helpers for constructing synthetic binary timeslice files -# --------------------------------------------------------------------------- - def _make_proc_local_header( endian: str, x0: int, y0: int, z0: int, t0: int, @@ -37,33 +37,33 @@ def _make_proc_local_header( return ints + floats # 44 + 28 = 72 bytes -def _make_xyzts_file( - path: Path, - endian: str, - local_nx: int, - local_ny: int, - local_nz: int, - nx: int, - ny: int, - nt: int, - ncomp: int, - rng: np.random.Generator, -) -> np.ndarray: - """Create a synthetic XYZTS proc-local file and return the payload array.""" - header = _make_proc_local_header( - endian, - x0=0, y0=0, z0=0, t0=0, - local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, - nx=nx, ny=ny, nz=local_nz, nt=nt, - dx=0.4, dy=0.4, hh=0.1, dt=0.02, - mrot=0.0, mlat=-43.5, mlon=172.0, - ) - payload = rng.random( - (nt, ncomp, local_nz, local_ny, local_nx), dtype=np.float32 +@st.composite +def xyzts_file_data(draw: st.DrawFn) -> tuple: + """Hypothesis composite strategy generating valid XYZTS file parameters and payload. + + Returns + ------- + tuple + (endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload) + where payload has shape (nt, ncomp, local_nz, local_ny, local_nx). + """ + endian = draw(st.sampled_from([">", "<"])) + ncomp = draw(st.sampled_from([3, 6, 9])) + local_nx = draw(st.integers(min_value=1, max_value=8)) + local_ny = draw(st.integers(min_value=1, max_value=8)) + # local_nz > 1 distinguishes XYZTS from surface proc-local XYTS + local_nz = draw(st.integers(min_value=2, max_value=4)) + nx = draw(st.integers(min_value=local_nx, max_value=20)) + ny = draw(st.integers(min_value=local_ny, max_value=20)) + nt = draw(st.integers(min_value=1, max_value=4)) + payload = draw( + arrays( + dtype=np.float32, + shape=(nt, ncomp, local_nz, local_ny, local_nx), + elements=st.floats(allow_nan=False, allow_infinity=False, width=32), + ) ) - dtype = f"{endian}f4" - path.write_bytes(header + payload.astype(dtype).tobytes()) - return payload + return endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload @pytest.fixture(scope="session") @@ -251,184 +251,97 @@ def test_tslice_get( assert test_output == pytest.approx(sample_array[:, -1].reshape(test_output.shape)) -# --------------------------------------------------------------------------- -# XYZTS-specific tests (use synthetic data; no network required) -# --------------------------------------------------------------------------- - -# Common dimensions used across XYZTS tests -_LOCAL_NX, _LOCAL_NY, _LOCAL_NZ = 4, 5, 3 -_GLOBAL_NX, _GLOBAL_NY = 20, 20 -_NT = 6 - - -@pytest.fixture(scope="module") -def rng() -> np.random.Generator: - """Fixed-seed random number generator for reproducible tests.""" - return np.random.default_rng(42) - - -@pytest.mark.parametrize("endian,ncomp", [ - (">", 3), - ("<", 3), - ("<", 6), - ("<", 9), -]) -def test_xyzts_auto_detection( - tmp_path: Path, - rng: np.random.Generator, - endian: str, - ncomp: int, -) -> None: - """XYTSFile should auto-detect an XYZTS file without proc_local_file flag.""" - fpath = tmp_path / f"test_xyzts-{endian[0]}_ncomp{ncomp}" - _make_xyzts_file( - fpath, - endian=endian, - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=ncomp, - rng=rng, - ) +@given(data=xyzts_file_data()) +def test_xyzts_roundtrip(data: tuple) -> None: + """XYTSFile correctly detects and parses a synthetic XYZTS file (round-trip). - xf = xyts.XYTSFile(fpath) - - assert int(xf.local_nz) == _LOCAL_NZ - assert int(xf.local_ny) == _LOCAL_NY - assert int(xf.local_nx) == _LOCAL_NX - assert xf.ncomp == ncomp - assert int(xf.nt) == _NT - - -@pytest.mark.parametrize("endian", [">", "<"]) -def test_xyzts_data_shape( - tmp_path: Path, - rng: np.random.Generator, - endian: str, -) -> None: - """Data memmap for XYZTS should be 5-D (nt, ncomp, nz, ny, nx).""" - ncomp = 3 - fpath = tmp_path / f"shape_xyzts-{endian[0]}" - _make_xyzts_file( - fpath, - endian=endian, - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=ncomp, - rng=rng, - ) - - xf = xyts.XYTSFile(fpath) - - assert xf.data is not None - assert xf.data.ndim == 5 - assert xf.data.shape == (_NT, ncomp, _LOCAL_NZ, _LOCAL_NY, _LOCAL_NX) - - -def test_xyzts_payload_values( - tmp_path: Path, - rng: np.random.Generator, -) -> None: - """Values read from the XYZTS memmap match the written payload.""" - endian = "<" - ncomp = 6 - fpath = tmp_path / "values_xyzts-0" - payload = _make_xyzts_file( - fpath, - endian=endian, - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=ncomp, - rng=rng, + Checks auto-detection, header field parsing, 5-D data shape, and payload + value fidelity across all valid ncomp values and both endiannesses. + """ + endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload = data + header = _make_proc_local_header( + endian, + x0=0, y0=0, z0=0, t0=0, + local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, + nx=nx, ny=ny, nz=local_nz, nt=nt, + dx=0.4, dy=0.4, hh=0.1, dt=0.02, + mrot=0.0, mlat=-43.5, mlon=172.0, ) - - xf = xyts.XYTSFile(fpath) - - assert xf.data == pytest.approx(payload) - - -def test_xyzts_tslice_get_raises( - tmp_path: Path, - rng: np.random.Generator, -) -> None: + file_bytes = header + payload.astype(f"{endian}f4").tobytes() + with tempfile.TemporaryDirectory() as tmpdir: + fpath = Path(tmpdir) / "test_xyzts-0" + fpath.write_bytes(file_bytes) + xf = xyts.XYTSFile(fpath) + assert int(xf.local_nz) == local_nz + assert int(xf.local_ny) == local_ny + assert int(xf.local_nx) == local_nx + assert xf.ncomp == ncomp + assert int(xf.nt) == nt + assert xf.data is not None + assert xf.data.ndim == 5 + assert xf.data.shape == (nt, ncomp, local_nz, local_ny, local_nx) + assert xf.data == pytest.approx(payload) + + +@given(data=xyzts_file_data()) +def test_xyzts_tslice_get_raises(data: tuple) -> None: """tslice_get should raise ValueError for volumetric XYZTS files.""" - fpath = tmp_path / "tslice_xyzts-0" - _make_xyzts_file( - fpath, - endian="<", - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=3, - rng=rng, + endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload = data + header = _make_proc_local_header( + endian, + x0=0, y0=0, z0=0, t0=0, + local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, + nx=nx, ny=ny, nz=local_nz, nt=nt, + dx=0.4, dy=0.4, hh=0.1, dt=0.02, + mrot=0.0, mlat=-43.5, mlon=172.0, ) + file_bytes = header + payload.astype(f"{endian}f4").tobytes() + with tempfile.TemporaryDirectory() as tmpdir: + fpath = Path(tmpdir) / "test_xyzts-0" + fpath.write_bytes(file_bytes) + xf = xyts.XYTSFile(fpath) + with pytest.raises(ValueError, match="tslice_get"): + xf.tslice_get(0) - xf = xyts.XYTSFile(fpath) - - with pytest.raises(ValueError, match="tslice_get"): - xf.tslice_get(0) - -def test_xyzts_pgv_raises( - tmp_path: Path, - rng: np.random.Generator, -) -> None: +@given(data=xyzts_file_data()) +def test_xyzts_pgv_raises(data: tuple) -> None: """pgv() should raise ValueError for volumetric XYZTS files.""" - fpath = tmp_path / "pgv_xyzts-0" - _make_xyzts_file( - fpath, - endian="<", - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=3, - rng=rng, + endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload = data + header = _make_proc_local_header( + endian, + x0=0, y0=0, z0=0, t0=0, + local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, + nx=nx, ny=ny, nz=local_nz, nt=nt, + dx=0.4, dy=0.4, hh=0.1, dt=0.02, + mrot=0.0, mlat=-43.5, mlon=172.0, ) - - xf = xyts.XYTSFile(fpath) - - with pytest.raises(ValueError, match="pgv"): - xf.pgv() + file_bytes = header + payload.astype(f"{endian}f4").tobytes() + with tempfile.TemporaryDirectory() as tmpdir: + fpath = Path(tmpdir) / "test_xyzts-0" + fpath.write_bytes(file_bytes) + xf = xyts.XYTSFile(fpath) + with pytest.raises(ValueError, match="pgv"): + xf.pgv() -def test_xyzts_meta_only( - tmp_path: Path, - rng: np.random.Generator, -) -> None: +@given(data=xyzts_file_data()) +def test_xyzts_meta_only(data: tuple) -> None: """meta_only=True should work for XYZTS files and leave data=None.""" - fpath = tmp_path / "meta_xyzts-0" - _make_xyzts_file( - fpath, - endian="<", - local_nx=_LOCAL_NX, - local_ny=_LOCAL_NY, - local_nz=_LOCAL_NZ, - nx=_GLOBAL_NX, - ny=_GLOBAL_NY, - nt=_NT, - ncomp=3, - rng=rng, + endian, ncomp, local_nx, local_ny, local_nz, nx, ny, nt, payload = data + header = _make_proc_local_header( + endian, + x0=0, y0=0, z0=0, t0=0, + local_nx=local_nx, local_ny=local_ny, local_nz=local_nz, + nx=nx, ny=ny, nz=local_nz, nt=nt, + dx=0.4, dy=0.4, hh=0.1, dt=0.02, + mrot=0.0, mlat=-43.5, mlon=172.0, ) - - xf = xyts.XYTSFile(fpath, meta_only=True) - - assert xf.data is None - assert int(xf.local_nz) == _LOCAL_NZ - assert xf.ncomp == 3 + file_bytes = header + payload.astype(f"{endian}f4").tobytes() + with tempfile.TemporaryDirectory() as tmpdir: + fpath = Path(tmpdir) / "test_xyzts-0" + fpath.write_bytes(file_bytes) + xf = xyts.XYTSFile(fpath, meta_only=True) + assert xf.data is None + assert int(xf.local_nz) == local_nz + assert xf.ncomp == ncomp diff --git a/qcore/xyts.py b/qcore/xyts.py index 7d2b3468..1e475dce 100644 --- a/qcore/xyts.py +++ b/qcore/xyts.py @@ -240,20 +240,22 @@ def __init__( self.xyts_path = xyts_path - # --------------------------------------------------------------- - # Step 1 – determine endianness and whether this is a proc-local - # (72-byte header) file. + # Detect endianness and file variant by inspecting the first 7 i32 words. # - # Layout of the first 7 32-bit integers: - # Standard XYTS (60-byte header): - # [x0, y0, z0, t0, nx, ny, nz] → nz == 1 - # Proc-local XYTS / XYZTS (72-byte header): - # [x0, y0, z0, t0, local_nx, local_ny, local_nz] + # Standard XYTS (60-byte tsheader): + # offset 0: [x0, y0, z0, t0] (4 × i32) + # offset 16: [nx, ny, nz, nt] (4 × i32) ← word 7 = nz == 1 + # offset 32: [dx, dy, hh, dt, mrot, mlat, mlon] (7 × f32) # - # For standard XYTS the 7th word is nz=1, giving a reliable - # endianness probe. For XYZTS files local_nz > 1, so the probe - # fails and we fall through to the proc-local branch below. - # --------------------------------------------------------------- + # Proc-local XYTS / XYZTS (72-byte tsheader_procP / tsheader_procP3): + # offset 0: [x0, y0, z0, t0] (4 × i32) + # offset 16: [local_nx, local_ny, local_nz] (3 × i32) ← word 7 = local_nz + # offset 28: [nx, ny, nz, nt] (4 × i32) + # offset 44: [dx, dy, hh, dt, mrot, mlat, mlon] (7 × f32) + # + # For standard XYTS, word 7 (nz) is always 1, giving a reliable endianness + # probe via the byte-swapped value 0x01000000. For XYZTS files local_nz > 1, + # so the probe fails and we fall through to the endianness tiebreaker below. raw7_be = np.fromfile(xytf, dtype=">i4", count=7) seventh_be = int(raw7_be[-1]) @@ -264,11 +266,10 @@ def __init__( endian = "<" proc_local = proc_local_file else: - # The 7th word is neither 1 nor byte-swapped 1. The only - # known cause is a proc-local XYZTS file where local_nz > 1. - # Determine endianness from local_nx (5th word, index 4): - # small-positive big-endian reads are implausible as - # little-endian because byte-swapping maps e.g. 100 → 1677721600. + # local_nz > 1: proc-local XYZTS file. Determine endianness from + # local_nx (word 5, index 4): byte-swapping a small integer produces + # a value orders of magnitude larger, so only one interpretation will + # be in the plausible range 1…_MAX_GRID_DIM. local_nx_be = int(raw7_be[4]) raw7_le = np.frombuffer(raw7_be.tobytes(), dtype=" 1) : (nt, ncomp, local_nz, local_ny, local_nx) - # --------------------------------------------------------------- if proc_local: if int(self.local_nz) > 1: # Volumetric XYZTS: 5-D tensor diff --git a/qcore_utils.egg-info/PKG-INFO b/qcore_utils.egg-info/PKG-INFO deleted file mode 100644 index 42280cdb..00000000 --- a/qcore_utils.egg-info/PKG-INFO +++ /dev/null @@ -1,38 +0,0 @@ -Metadata-Version: 2.4 -Name: qcore-utils -Version: 2025.12.3.dev1+g93313e926 -Summary: Utils Library -Author: ucgmsim -Requires-Python: >=3.11 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: pandas -Requires-Dist: pyfftw -Requires-Dist: pytest -Requires-Dist: pytest-black -Requires-Dist: alphashape -Requires-Dist: descartes -Requires-Dist: filelock -Requires-Dist: pyproj -Requires-Dist: pooch -Requires-Dist: requests -Requires-Dist: shapely -Requires-Dist: numpy -Requires-Dist: numba -Requires-Dist: hypothesis[numpy] -Requires-Dist: typer -Requires-Dist: docstring_parser -Requires-Dist: xarray -Requires-Dist: pyyaml -Dynamic: license-file - -[![Build Status](https://quakecoresoft.canterbury.ac.nz/jenkins/job/qcore/badge/icon?build=last:${params.ghprbActualCommit=master)](https://quakecoresoft.canterbury.ac.nz/jenkins/job/qcore) - -## Installation: - -To install run `pip install -e .` from the root directory of this repository - -### Downloading data after install - -After installing, if you intend to use GMT for plotting you will need to run "download_data.py" (Located in qcore.data) to download and -unpack the data used for these scripts diff --git a/qcore_utils.egg-info/SOURCES.txt b/qcore_utils.egg-info/SOURCES.txt deleted file mode 100644 index a3b6ae05..00000000 --- a/qcore_utils.egg-info/SOURCES.txt +++ /dev/null @@ -1,88 +0,0 @@ -.gitignore -CHANGELOG.md -Jenkinsfile -LICENSE -MANIFEST.in -README.md -pyproject.toml -requirements.txt -.github/workflows/git-extension.yml -.github/workflows/publish-PyPi.yml -.github/workflows/wiki.yml -qcore/__init__.py -qcore/archive_structure.py -qcore/cli.py -qcore/constants.py -qcore/coordinates.py -qcore/formats.py -qcore/geo.py -qcore/grid.py -qcore/nhm.py -qcore/point_in_polygon.py -qcore/shared.py -qcore/simulation_structure.py -qcore/siteamp_models.py -qcore/src_site_dist.py -qcore/timeseries.py -qcore/utils.py -qcore/xyts.py -qcore/siteamp_coefs_files/Bayless_ModelCoefs.csv -qcore/test/__init__.py -qcore/test/runscript.sh -qcore/test/test_cli/test_cli.py -qcore/test/test_coordinates/test_coordinates.py -qcore/test/test_geo/__init__.py -qcore/test/test_geo/test_geo.py -qcore/test/test_geo/sample1/README.md -qcore/test/test_grid/__init__.py -qcore/test/test_grid/test_grid.py -qcore/test/test_siteamp/amp_bandpass_benchmark.pkl -qcore/test/test_siteamp/cb_2014_test.csv -qcore/test/test_siteamp/interpolate_benchmark.pkl -qcore/test/test_siteamp/test_siteamp.py -qcore/test/test_source_site_dist/__init__.py -qcore/test/test_source_site_dist/test_src_site_dist_calc.py -qcore/test/test_source_site_dist/sample0/input/calc_rrup_rjb_locations.npy -qcore/test/test_source_site_dist/sample0/input/calc_rrup_rjb_srf_points.npy -qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_locations.npy -qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_srf_header.P -qcore/test/test_source_site_dist/sample0/input/calc_rx_ry_srf_points.npy -qcore/test/test_source_site_dist/sample0/output/calc_rrup_rjb_rjb.npy -qcore/test/test_source_site_dist/sample0/output/calc_rrup_rjb_rrup.npy -qcore/test/test_source_site_dist/sample0/output/calc_rx_ry_rx.npy -qcore/test/test_source_site_dist/sample0/output/calc_rx_ry_ry.npy -qcore/test/test_timeseries/R01_seis-00041.e3d -qcore/test/test_timeseries/test_timeseries.py -qcore/test/test_xyts/__init__.py -qcore/test/test_xyts/test_xyts.py -qcore/test/test_xyts/sample1/output/out_tslice-1 -qcore/test/test_xyts/sample1/output/out_tslice0 -qcore/test/test_xyts/sample1/output/out_tslice1 -qcore/test/test_xyts/sample1/output/out_tslice2 -qcore/test/test_xyts/sample1/output/sample_mmiout -qcore/test/test_xyts/sample1/output/sample_pgvout -qcore/test/tool/__init__.py -qcore/test/tool/create_binaryfile.py -qcore/test/tool/utils.py -qcore/uncertainties/__init__.py -qcore/uncertainties/distributions.py -qcore_utils.egg-info/PKG-INFO -qcore_utils.egg-info/SOURCES.txt -qcore_utils.egg-info/dependency_links.txt -qcore_utils.egg-info/requires.txt -qcore_utils.egg-info/top_level.txt -wiki/Bounding-Box.md -wiki/Home.md -wiki/images/alphashape.png -wiki/images/axis_aligned_minimum.png -wiki/images/better_domain.png -wiki/images/bounding_box.png -wiki/images/bounding_box_circle.png -wiki/images/convex_hull.png -wiki/images/domain_bad.png -wiki/images/example_problem.png -wiki/images/point_cluster.png -wiki/images/point_cluster_with_bounding_box.png -wiki/images/point_cluster_with_hull.png -wiki/images/rotated_convex_hull.png -wiki/images/rotated_minimum_boxes.png \ No newline at end of file diff --git a/qcore_utils.egg-info/dependency_links.txt b/qcore_utils.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891..00000000 --- a/qcore_utils.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/qcore_utils.egg-info/requires.txt b/qcore_utils.egg-info/requires.txt deleted file mode 100644 index c5441e1d..00000000 --- a/qcore_utils.egg-info/requires.txt +++ /dev/null @@ -1,18 +0,0 @@ -pandas -pyfftw -pytest -pytest-black -alphashape -descartes -filelock -pyproj -pooch -requests -shapely -numpy -numba -hypothesis[numpy] -typer -docstring_parser -xarray -pyyaml diff --git a/qcore_utils.egg-info/top_level.txt b/qcore_utils.egg-info/top_level.txt deleted file mode 100644 index 4e4eba80..00000000 --- a/qcore_utils.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -qcore