pycsamt.jones#

Jones/J-file parsing, validation, collection objects, headers, blocks, and conversion helpers.

Jones-format transfer functions, blocks, headers, spectra, and utilities.

class pycsamt.jones.Banner(top_lines=None, *, software=None, station=None, date=None, note=None, verbose=0)#

Bases: JComponentBase

Parse and serialize the top provenance comment line.

This helper targets lines such as:

#WRITTEN BY GEOTOOLS: kb0-s001 10/06/95 RAW RECS

It extracts the producer software name, an optional station hint, a free-form date token, and an optional trailing note. The writer defaults the software field to PYSCAMT when none is provided.

Parameters:
  • top_lines (sequence of str, optional) – An initial slice of file lines. The constructor scans these lines and parses the first matching banner.

  • software (str, optional) – Producer software name (e.g., 'GEOTOOLS'). When omitted and the banner is not present, the writer uses 'PYSCAMT' as a default.

  • station (str, optional) – Station identifier hint found in the banner. This does not replace the station found in the Head.

  • date (str, optional) – Free-form date token as found in the banner line.

  • note (str, optional) – Extra text following the date token on the same line.

  • verbose (int, default=0) – Verbosity for warnings during parsing.

Variables:
  • software (str or None) – Producer software parsed from the banner or provided by the user.

  • station_hint (str or None) – Station token parsed from the banner; may differ from the station found in the Head.

  • date (str or None) – Banner date token as text; not parsed into a datetime.

  • note (str or None) – Trailing free-form text after the date token.

  • path (pathlib.Path or None) – Source path when constructed via from_file().

  • encoding (str) – Text encoding used by from_file().

  • verbose (int) – Verbosity level inherited from JComponentBase.

from_file(j_fn, \*, verbose=0)#

Read a file, scan the top lines, and return a parsed Banner.

Parameters:
Return type:

Banner

from_lines(lines, \*, verbose=0)#

Build a Banner from an in-memory sequence of lines.

Parameters:
Return type:

Banner

read(top_lines)#

Parse the first matching banner from the given lines and mark the instance as read.

Parameters:

top_lines (Sequence[str] | None)

Return type:

Banner

write()#

Render a banner line. Defaults the software field to PYSCAMT if missing.

Parameters:
Return type:

list[str]

Notes

The banner parser is intentionally liberal: it ignores leading whitespace, is case-insensitive on the WRITTEN BY marker, and preserves the raw text of the trailing note. It does not validate dates or enforce a specific date format.

Examples

>>> b = Banner().read([
...   '#WRITTEN BY GEOTOOLS: kb0-s001 10/06/95 RAW RECS'
... ])
>>> b.software, b.station_hint, b.date
('GEOTOOLS', 'kb0-s001', '10/06/95')
>>> Banner().write()[0].startswith('#WRITTEN BY PYSCAMT:')
True

See also

Head

Station / data-type / count header triple.

Info

Site information (>KEY=VALUE records).

Heads

Minimal container that includes a Banner.

References

classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

Banner

classmethod from_lines(lines, *, verbose=0)#
Parameters:
Return type:

Banner

read(top_lines=None)#
Parameters:

top_lines (Sequence[str] | None)

Return type:

Banner

write(*, new=True, include_origin=False)#
Parameters:
Return type:

list[str]

property software: str | None#
property date_parsed: datetime | None#
class pycsamt.jones.Head(j_header_list=None, *, verbose=0, **kwargs)#

Bases: JComponentBase

Parse and serialize a single J-format head triple.

This lightweight component represents one data-block header consisting of the station line, the data-type line, and the row count. It provides a consistent constructor and the read / write round-trip expected by the package.

Parameters:
  • j_header_list (sequence of str, optional) – Three logical header lines. The sequence may be a clean triple [station, dtype, n] or a longer slice from a file; the parser will extract the first valid triple.

  • verbose (int, default=0) – Verbosity for warnings during parsing.

  • **kwargs – Accepted for API forwards-compatibility; ignored here.

Variables:
  • station (str or None) – Upper-cased station identifier. Trailing azimuth tokens on the same line are supported and ignored here (but see az_hint).

  • dtype (DataType or None) – Parsed data-type token (e.g., ZXY, RTE) with optional normalized units and a TE/TM tensor hint.

  • n (int or None) – Number of data rows that follow this header.

  • az_hint (float or None) – Optional azimuth extracted from the station line when present (e.g., KB0001  -30). This is not the same as site AZIMUTH from the info block.

  • path (pathlib.Path or None) – Source path when constructed via from_file().

  • encoding (str) – Text encoding used by from_file().

  • verbose (int) – Verbosity level inherited from JComponentBase.

from_file(j_fn, \*, verbose=0)#

Read a file and return a Head. Only the first valid triple is parsed.

Parameters:
Return type:

Head

from_lines(j_header_list, \*, verbose=0)#

Build a Head from an in-memory sequence. If the sequence is longer than three lines, the first valid triple is extracted.

Parameters:
Return type:

Head

read(j_header_list)#

Parse the header triple into attributes and mark the instance as read (see __has_read__).

Parameters:

j_header_list (Sequence[str] | None)

Return type:

Head

write(head_list_infos=None)#

Return a list of three strings representing the header triple. If head_list_infos is given, it is parsed first and then serialized.

Parameters:

head_list_infos (Sequence[str] | None)

Return type:

list[str]

Notes

The station regex accepts common field variants, including hyphens and underscores, and an optional numeric azimuth token after the station id. The data-type parser is liberal with whitespace and recognizes SI (S.I.) and FIELD units.

Examples

>>> Head().read(['KB0001  -30', 'ZXY SI', '29'])
Head(station='KB0001', n=29)
>>> h = Head.from_file('data/j/kb0-s001.txt')
>>> h.station
'KB0001'

See also

Info

Site information (>KEY=VALUE lines).

Heads

Container combining one Head and one Info.

JSiteProperty

Robust latitude/longitude parsing.

DataType

Structured token for kind / comp / units.

References

classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

Head

classmethod from_lines(j_header_list=None, *, verbose=0)#
Parameters:
Return type:

Head

read(j_header_list=None)#
Parameters:

j_header_list (Sequence[str] | None)

Return type:

Head

write(head_list_infos=None)#
Parameters:

head_list_infos (Sequence[str] | None)

Return type:

list[str]

property kind: str | None#
property comp: str | None#
property units: str | None#
property tensor_hint: str | None#
property header: tuple[str, str, int] | None#
class pycsamt.jones.Heads(head=None, info=None, *, verbose=0)#

Bases: JComponentBase

Minimal container for one Head and one Info.

The class provides convenient accessors for station and site-level properties, and a small banner recorder for the top provenance line (#WRITTEN BY ...). It is intended as the lightest useful representation of a single J header section.

Parameters:
  • head (Head, optional) – Existing head to attach. If omitted, an empty Head is created.

  • info (Info, optional) – Existing info to attach. If omitted, an empty Info is created.

  • verbose (int, default=0) – Verbosity for warnings during parsing.

Variables:
  • head (Head) – The parsed header triple.

  • info (Info) – The parsed site information block.

  • banner (Banner) – Parsed top comment provenance. The writer defaults the software field to PYSCAMT if missing.

  • n (int) – 0 or 1 depending on whether a head has been parsed.

  • station (str or None) – Shortcut to head.station.

  • azimuth (latitude, longitude, elevation,) – Shortcuts to values provided by info. azimuth falls back to head.az_hint when the info block does not contain AZIMUTH.

from_file(j_fn, \*, verbose=0)#

Read the file then delegate to read().

Parameters:
Return type:

Heads

from_lines(lines, \*, verbose=0)#

Build from an in-memory line sequence.

Parameters:
Return type:

Heads

read(text_or_lines)#

Extract info + head lists and parse both.

Parameters:

text_or_lines (str | Sequence[str])

Return type:

Heads

write()#

Serialize banner, head and info back-to-back.

Return type:

list[str]

Notes

This class does not parse the subsequent data rows. It is focused on fast, dependency-free header discovery to support scanning tasks and metadata extraction.

Examples

>>> h = Heads.from_file('data/j/kb0-s001.txt')
>>> h.station, h.latitude, h.software
('KB0001', 41.9782, 'GEOTOOLS')

See also

Head

Single data-block header.

Info

Site-level header.

Banner

Top provenance line handler.

References

read(text_or_lines)#
Parameters:

text_or_lines (str | Sequence[str])

Return type:

Heads

write(include_origin=False)#
Return type:

list[str]

classmethod from_lines(lines, *, verbose=0)#
Parameters:
Return type:

Heads

classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

Heads

property n: int#
property station: str | None#
property latitude: float | None#
property longitude: float | None#
property elevation: float | None#
property azimuth: float | None#
property software: str | None#
class pycsamt.jones.HeadMixin#

Bases: object

Mixin that provides a Head on host classes.

The mixin offers class-level and instance-level helpers that delegate to Head while keeping a single copy of the header on the host.

Variables:

head (Head) – Lazily created and cached on first use.

from_file(edi_fn)#

Class method that returns Head.from_file(edi_fn).

Parameters:

edi_fn (str | Path)

Return type:

Head

read(j_header_list=None)#

Ensure a Head exists on the host, parse into it, and return it.

Parameters:

j_header_list (Sequence[str] | None)

Return type:

Head

write(head_list_infos=None)#

Serialize the host’s Head to three header lines.

Parameters:

head_list_infos (Sequence[str] | None)

Return type:

list[str]

Examples

>>> class Host(HeadMixin):
...     pass
>>> Host.from_file('file.j')
Head(...)
head: Head#
classmethod from_file(edi_fn)#
Parameters:

edi_fn (str | Path)

Return type:

Head

read(j_header_list=None)#
Parameters:

j_header_list (Sequence[str] | None)

Return type:

Head

write(head_list_infos=None)#
Parameters:

head_list_infos (Sequence[str] | None)

Return type:

list[str]

class pycsamt.jones.Info(j_info_list=None, *, verbose=0, **kwargs)#

Bases: JComponentBase

Parse and serialize the J-format information block.

This component collects >KEY=VALUE records along with leading comment lines. It exposes a small set of convenience properties derived from JSiteProperty.

Parameters:
  • j_info_list (sequence of str, optional) – A sequence containing the comment and information records. The parser stops at the first non-info, non-comment, non-blank line.

  • verbose (int, default=0) – Verbosity for warnings during parsing.

  • **kwargs – Accepted for API forwards-compatibility; ignored here.

Variables:
  • items (dict of (str -> str)) – Mapping of upper-cased keys to unmodified string values.

  • comments (list of str) – Preserved leading comment lines (starting with #).

  • site (JSiteProperty) – Lazily parsed view providing normalized latitude, longitude, azimuth and elevation (see properties below).

  • latitude (float or None) – Decimal degrees; hemisphere and DMS tolerated.

  • longitude (float or None) – Decimal degrees in [-180, 180).

  • azimuth (float or None) – Site X-axis azimuth (degrees, true north).

  • elevation (float or None) – Elevation in metres.

  • path (pathlib.Path or None) – Source path when constructed via from_file().

  • encoding (str) – Text encoding used by from_file().

  • verbose (int) – Verbosity level inherited from JComponentBase.

from_file(j_fn, \*, verbose=0)#

Read only the comment/info header from a file.

Parameters:
Return type:

Info

from_lines(j_info_list, \*, verbose=0)#

Build from an in-memory sequence.

Parameters:
Return type:

Info

read(j_info_list)#

Parse the header and mark the instance as read.

Parameters:

j_info_list (Sequence[str] | None)

Return type:

Info

write(j_info_list=None)#

Render comments and >KEY = VALUE lines.

Parameters:

j_info_list (Sequence[str] | None)

Return type:

list[str]

Notes

Unknown keys are preserved verbatim. Coordinate and azimuth values are normalized via JSiteProperty, which handles ranges, hemispheres and DMS.

Examples

>>> info = Info.from_file('data/j/kb0-s001.txt')
>>> info.latitude, info.longitude
(41.9782, 140.8958)
>>> lines = info.write()
>>> Info.from_lines(lines).azimuth == info.azimuth
True

See also

Head

One data-block header (station / dtype / count).

Heads

Combined view with convenience properties.

JSiteProperty

Robust parsing used by this class.

References

comments: list[str]#
items: dict[str, str]#
classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

Info

classmethod from_lines(j_info_list=None, *, verbose=0)#
Parameters:
Return type:

Info

write(j_info_list=None)#
Parameters:

j_info_list (Sequence[str] | None)

Return type:

list[str]

read(j_info_list=None)#
Parameters:

j_info_list (Sequence[str] | None)

Return type:

Info

property site: JSiteProperty#
property latitude: float | None#
property longitude: float | None#
property azimuth: float | None#
property elevation: float | None#
get(key, default=None)#
Parameters:
  • key (str)

  • default (str | None)

Return type:

str | None

keys()#
Return type:

tuple[str, …]

values()#
Return type:

tuple[str, …]

items_map()#
Return type:

dict[str, str]

property lat: float | None#
property lon: float | None#
class pycsamt.jones.InfoMixin#

Bases: object

Mixin that provides an Info on host classes.

The mixin mirrors HeadMixin but for the information block. It centralizes parsing and writing of >KEY=VALUE lines.

Variables:

info (Info) – Lazily created and cached on first use.

from_file(edi_fn)#

Class method that returns Info.from_file(edi_fn).

Parameters:

edi_fn (str | Path)

Return type:

Info

read(j_info_list=None)#

Ensure an Info exists on the host, parse into it, and return it.

Parameters:

j_info_list (Sequence[str] | None)

Return type:

Info

write(j_info_list=None)#

Serialize the host’s Info to comment and info lines.

Parameters:

j_info_list (Sequence[str] | None)

Return type:

list[str]

Examples

>>> class Host(InfoMixin):
...     pass
>>> Host().read(['>LATITUDE=10'])
Info(items=1)
info: Info#
classmethod from_file(edi_fn)#
Parameters:

edi_fn (str | Path)

Return type:

Info

read(j_info_list=None)#
Parameters:

j_info_list (Sequence[str] | None)

Return type:

Info

write(j_info_list=None)#
Parameters:

j_info_list (Sequence[str] | None)

Return type:

list[str]

class pycsamt.jones.JSiteProperty(azimuth=None, latitude=None, longitude=None, elevation=None, extra=<factory>, verbose=0, strict=False)#

Bases: object

Container for site properties parsed from J-format info.

This class stores site-level metadata such as latitude, longitude, azimuth, and elevation that are declared in the J-format information block as >KEY=VALUE lines.

Parameters:
  • azimuth (float or None, optional) – Site X-axis azimuth in degrees, referenced to true north. Values are wrapped to [0, 360) when parsed.

  • latitude (float or None, optional) – Latitude in decimal degrees. Inputs may include DMS or hemisphere suffixes and are normalized to [-90, 90].

  • longitude (float or None, optional) – Longitude in decimal degrees. Inputs may include DMS or hemisphere suffixes and are normalized to [-180, 180).

  • elevation (float or None, optional) – Elevation in metres. Missing sentinels are mapped to None.

  • extra (dict of (str -> str), optional) – Unrecognized >KEY=VALUE pairs preserved verbatim.

  • verbose (int or bool, default 0) – Verbosity for non-fatal parsing warnings.

  • strict (bool, default False) – If True, out-of-range coordinates raise errors instead of being coerced to valid bounds.

Variables:
  • location (tuple of (float, float) or None) – Convenience property returning (lat, lon) when both are available, else None.

  • azimuth_rad (float or None) – Azimuth converted to radians when available.

Notes

Parsing leverages robust coordinate helpers that accept DMS, hemisphere letters, and free whitespace. Longitudes are normalized into the half-open interval [-180, 180).

Examples

>>> lines = [\">LATITUDE = 41.9782\", \">LONGITUDE = 140.8958\"]\n
>>> prop = JSiteProperty.from_lines(lines)\n
>>> prop.location\n
(41.9782, 140.8958)

See also

Info

High-level container of the information block which can be used to build a JSiteProperty.

References

azimuth: float | None = None#
latitude: float | None = None#
longitude: float | None = None#
elevation: float | None = None#
extra: dict[str, str]#
verbose: int | bool = 0#
strict: bool = False#
classmethod from_file(obj, *, encoding='utf-8', strict=False, verbose=0)#

Build a JSiteProperty from a J file path or file-like object.

Only the initial information block is consumed. Later station or data sections are ignored by this method.

Parameters:
  • obj (str or pathlib.Path or TextIO) – Path to a J file or an open text stream positioned at the beginning of the file.

  • encoding (str, default 'utf-8') – Text encoding used when reading from a file path.

  • strict (bool, default False) – If True, invalid coordinates raise. If False, out-of-range values are coerced with a warning.

  • verbose (int or bool, default 0) – Verbosity for non-fatal parsing warnings.

Returns:

Parsed site properties.

Return type:

JSiteProperty

Notes

This method stops at the first line that is not a comment, not blank, and not a >KEY=VALUE record.

Examples

>>> prop = JSiteProperty.from_file(\"data/j/kb0-s001.txt\")\n
>>> prop.azimuth is None or 0.0 <= prop.azimuth < 360.0\n
True

See also

from_lines

Parse from an in-memory sequence of lines.

from_mapping

Quick constructor from a dict of keys and values.

References

classmethod from_lines(lines, *, strict=False, verbose=0)#

Build a JSiteProperty from an iterable of lines.

The parser reads sequentially and collects >KEY=VALUE pairs as long as lines are comments, blanks, or info records. It stops at the first non-conforming line.

Parameters:
  • lines (iterable of str) – Lines that include the information block content.

  • strict (bool, default False) – If True, invalid coordinates raise. If False, out-of-range values are coerced with a warning.

  • verbose (int or bool, default 0) – Verbosity for non-fatal parsing warnings.

Returns:

Parsed site properties.

Return type:

JSiteProperty

Notes

Latitude and longitude accept flexible text including DMS and hemisphere tokens. Longitudes are normalized into [-180, 180).

Examples

>>> from pycsamt.
>>> lines = [\n
...   \">AZIMUTH = -30.0\", \">LATITUDE = 41.9782\",\n
...   \">LONGITUDE = 140.8958\", \">ELEVATION = 0.0\",\n
... ]\n
>>> prop = JSiteProperty.from_lines(lines)\n
>>> prop.location[0] == 41.9782\n
True

See also

from_file

Parse from a file path or open stream.

from_mapping

Quick constructor from a dict of keys and values.

References

classmethod from_mapping(mapping, *, strict=False, verbose=0)#

Build a JSiteProperty from a dict of key-value pairs.

Keys can be any case and will be normalized to the upper case tokens used by J files. Values can be strings or numbers. Unknown keys are preserved in extra.

Parameters:
  • mapping (Mapping[str, Any]) – Pairs like {\"latitude\": 41.9, \"longitude\": 140.8}.

  • strict (bool, default False) – If True, invalid coordinates raise. If False, out-of-range values are coerced with a warning.

  • verbose (int or bool, default 0) – Verbosity for non-fatal parsing warnings.

Returns:

Parsed site properties.

Return type:

JSiteProperty

Notes

This is a convenience front-end that converts the mapping to synthetic >KEY=VALUE lines and forwards the work to from_lines().

Examples

>>> prop = JSiteProperty.from_mapping({\n
...   'azimuth': 370, 'latitude': '41:58N',\n
...   'longitude': '140:54E', 'elevation': 0,\n
... })\n
>>> 0.0 <= (prop.azimuth or 0.0) < 360.0\n
True

See also

from_lines

Parse from an in-memory sequence of lines.

from_file

Parse from a file path or open stream.

References

asdict()#
Return type:

dict[str, float | None]

property location: tuple[float, float] | None#
property azimuth_rad: float | None#
class pycsamt.jones.RRow(period, rho, pha, rhomax, rhomin, phamax, phamin, wrho, wpha, rej=False)#

Bases: object

One parsed resistivity/phase row of a J R/S block.

The row stores period (s), apparent resistivity (Ω·m), phase (deg), their 1σ bounds, and per-column weights. A derived boolean flag rej marks a row as rejected according to the J-format rules.

Parameters:
  • period (float) – Period in seconds. If input stored frequency (Hz) as a negative number, it is normalized to a positive period.

  • rho (float) – Apparent resistivity. Values < 0 mark the estimate as rejected.

  • pha (float) – Phase in degrees.

  • rhomax (float) – Upper and lower 1σ bounds of resistivity. May be missing.

  • rhomin (float) – Upper and lower 1σ bounds of resistivity. May be missing.

  • phamax (float) – Upper and lower 1σ bounds of phase. May be missing.

  • phamin (float) – Upper and lower 1σ bounds of phase. May be missing.

  • wrho (float) – Weights. A negative weight marks the estimate as rejected.

  • wpha (float) – Weights. A negative weight marks the estimate as rejected.

  • rej (bool) – Convenience rejection flag derived from the rules above.

Notes

Missing numeric values are often written as -999.0 in J files. The higher-level APIs convert them to NaN for numeric workflows.

Examples

>>> row = RRow(
...     period=1.0, rho=100.0, pha=45.0,
...     rhomax=110.0, rhomin=90.0,
...     phamax=50.0, phamin=40.0,
...     wrho=1.0, wpha=1.0, rej=False,
... )
>>> row.rho, row.rej
(100.0, False)

See also

RBlock

Sequence of RRow with I/O helpers.

TFRow

Row model for transfer-function blocks.

References

period: float#
rho: float#
pha: float#
rhomax: float#
rhomin: float#
phamax: float#
phamin: float#
wrho: float#
wpha: float#
rej: bool = False#
class pycsamt.jones.TFRow(period, real, imag, error, weight, rej=False)#

Bases: object

One parsed transfer-function row of a J Z/Q/C/T block.

The row stores period (s), real/imag parts, a standard error, a row weight, and a derived rej flag based on J-format rules.

Parameters:
  • period (float) – Period in seconds. If input stored frequency (Hz) as a negative number, it is normalized to a positive period.

  • real (float) – Real and imaginary parts of the transfer function.

  • imag (float) – Real and imaginary parts of the transfer function.

  • error (float) – Standard error (format-specific). May be missing.

  • weight (float) – Row weight. Negative values mark the row as rejected.

  • rej (bool) – Convenience rejection flag derived from the rules above.

Notes

The J specification allows several TF families (Z/Q/C/T). The row schema stays the same; only the physical meaning differs.

Examples

>>> tf = TFRow(
...     period=0.1, real=1.0, imag=-2.0,
...     error=0.1, weight=1.0, rej=False,
... )
>>> tf.period, tf.rej
(0.1, False)

See also

TFBlock

Sequence of TFRow with I/O helpers.

RRow

Row model for resistivity/phase blocks.

References

period: float#
real: float#
imag: float#
error: float#
weight: float#
rej: bool = False#
class pycsamt.jones.JBlock(head=None, *, rows=None, verbose=0)#

Bases: JComponentBase

Abstract base for J-format data blocks.

A block ties a parsed header (Head) to a homogeneous sequence of rows (RRow or TFRow). Subclasses implement the row parser, normalization, serialization, and simple QA summaries.

Parameters:
  • head (Head) – Parsed header triple (station, data-type, count).

  • rows (sequence of rows) – Concrete row records for this block family.

  • verbose (int, optional) – Verbosity for warnings during parsing and writing.

Variables:
  • head (Head) – Block header with station, kind, comp, n.

  • nrows (int) – Number of parsed data rows.

  • units (station, kind, comp,) – Convenience views onto head.dtype.

  • columns (tuple of str) – Column names for the structured numeric view.

  • shape ((int, int)) – (nrows, ncols) derived from the current rows.

from_file(j_fn, \*, verbose=0)#

Build a block from a file slice. The concrete subclass is chosen from the header’s kind.

Parameters:
Return type:

JBlock

from_lines(lines, \*, verbose=0)#

Parse from in-memory lines (header + body).

Parameters:
Return type:

JBlock

read((head, body_lines))#

Populate the block from an existing Head and the subsequent body lines. Marks the instance as read.

Parameters:

data (tuple[Head, Sequence[str]] | None)

Return type:

JBlock

write()#

Serialize header and all body rows into text.

Return type:

list[str]

to_numpy()#

Structured array view with numeric normalization (period sign, missing sentinels, rejection flags).

Return type:

dict[str, ndarray]

to_dataframe()#

Optional pandas representation (if available).

qa_summary()#

Small dict of quick QA metrics for this block.

Return type:

dict[str, Any]

Notes

The base class is intentionally minimal to keep the parser light. Subclasses define the row regex, column names, and row-level normalization logic.

Examples

>>> # Pseudocode; subclass chosen from header
>>> blk = JBlock.from_lines(['S01', 'RXY', '1', '...'])
>>> blk.station, blk.nrows
('S01', 1)

See also

RBlock, TFBlock

Heads

Header-only convenience container.

References

head: Head | None#
rows: list[Any]#
classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

JBlock

classmethod from_lines(lines, *, verbose=0)#
Parameters:
Return type:

JBlock

read(data=None)#
Parameters:

data (tuple[Head, Sequence[str]] | None)

Return type:

JBlock

write()#
Return type:

list[str]

normalize()#

Apply row-level normalization:

  • negative period => frequency (Hz) to period (s)

  • missing sentinel (-999) => NaN

  • set rejection flags per rules

Return type:

JBlock

qa_summary()#

Quick QA metrics (counts and basic stats).

Return type:

dict[str, Any]

to_numpy()#
Return type:

dict[str, ndarray]

to_dataframe()#
property nrows: int#
property station: str | None#
property kind: str | None#
property comp: str | None#
property units: str | None#
property has_units: bool#
property columns: tuple[str, ...]#
property shape: tuple[int, int]#
property periods#
class pycsamt.jones.RBlock(head=None, *, rows=None, verbose=0)#

Bases: JBlock

Resistivity/phase (R/S) block implementation.

Parses rows of the form period rho pha rhomax rhomin phamax phamin wrho wpha. Applies J-format rules to normalize period sign and to mark rejected estimates.

Parameters:
  • head (Head) – Header whose kind is 'R' or 'S'. The component encodes the tensor entry or average (e.g. RXY, RDE).

  • rows (sequence of RRow, optional) – Prebuilt rows. Usually left to the parser.

  • verbose (int, optional) – Verbosity for warnings during parsing.

Variables:

columns (tuple of str) – ('period', 'rho', 'pha', 'rhomax', 'rhomin', 'phamax', 'phamin', 'wrho', 'wpha', 'rej').

Notes

Normalization rules:

  • If input period is negative, the value stores frequency in Hz and is converted to period (s).

  • rho < 0 or wrho < 0 marks the row as rejected.

  • -999.0 sentinels are converted to NaN in numeric views.

Examples

>>> lines = [
...   'S01', 'RXY', '2',
...   '-1.0 100 45 110 90 50 40 1 1',
...   ' 2.0 -5  30  35 25 40 20 1 1',
... ]
>>> blk = RBlock.from_lines(lines)
>>> a = blk.to_numpy()
>>> a['period'][0]  # 1/Hz -> s
1.0
>>> a['rej'][1]     # rho < 0
True

See also

TFBlock

Transfer-function block family.

RRow

Single row record used by this block.

References

read(data=None)#
Parameters:

data (tuple[Head, Sequence[str]] | None)

Return type:

RBlock

normalize()#

Apply row-level normalization:

  • negative period => frequency (Hz) to period (s)

  • missing sentinel (-999) => NaN

  • set rejection flags per rules

Return type:

RBlock

to_numpy()#
Return type:

dict[str, ndarray]

qa_summary()#

Quick QA metrics (counts and basic stats).

Return type:

dict[str, Any]

write()#
Return type:

list[str]

property columns: tuple[str, ...]#
class pycsamt.jones.TFBlock(head=None, *, rows=None, verbose=0)#

Bases: JBlock

Transfer-function (Z/Q/C/T) block implementation.

Parses rows of the form period real imag error weight. Applies J-format rules to normalize period sign and to mark rejected estimates.

Parameters:
  • head (Head) – Header whose kind is one of 'Z', 'Q', 'C', or 'T'.

  • rows (sequence of TFRow, optional) – Prebuilt rows. Usually left to the parser.

  • verbose (int, optional) – Verbosity for warnings during parsing.

Variables:

columns (tuple of str) – ('period', 'real', 'imag', 'error', 'weight', 'rej').

Notes

Normalization rules:

  • If input period is negative, the value stores frequency in Hz and is converted to period (s).

  • weight < 0 marks the row as rejected.

  • -999.0 sentinels are converted to NaN in numeric views.

Examples

>>> lines = [
...   'S02', 'ZXY SI', '2',
...   '-1.0e+1 1.0 -2.0 0.1 1.0',
...   ' 5.0    -999 3.0 -999 -1.0',
... ]
>>> blk = TFBlock.from_lines(lines)
>>> a = blk.to_numpy()
>>> round(a['period'][0], 3)
0.1
>>> a['rej'][1]     # weight < 0
True

See also

RBlock

Resistivity/phase block family.

TFRow

Single row record used by this block.

References

read(data=None)#
Parameters:

data (tuple[Head, Sequence[str]] | None)

Return type:

TFBlock

normalize()#

Apply row-level normalization:

  • negative period => frequency (Hz) to period (s)

  • missing sentinel (-999) => NaN

  • set rejection flags per rules

Return type:

TFBlock

to_numpy()#
Return type:

dict[str, ndarray]

qa_summary()#

Quick QA metrics (counts and basic stats).

Return type:

dict[str, Any]

write()#
Return type:

list[str]

property columns: tuple[str, ...]#
class pycsamt.jones.JBlocks(blocks=None, *, verbose=0)#

Bases: JComponentBase

Container for a sequence of parsed J data blocks.

Provides discovery from raw text, iteration, selection by family or component, serialization, and quick QA roll-ups across blocks.

Parameters:
  • blocks (sequence of JBlock, optional) – Prebuilt blocks. Usually created by the parser.

  • verbose (int, optional) – Verbosity for warnings during parsing.

Variables:
  • blocks (list of JBlock) – Parsed blocks in file order.

  • n (int) – Number of blocks.

  • stations (list of str) – All station identifiers seen across blocks.

  • kinds (list of str) – The kind tokens across all blocks (e.g. 'R', 'Z').

from_file(j_fn, \*, verbose=0)#

Parse all blocks found in a file.

Parameters:
Return type:

JBlocks

from_lines(lines, \*, verbose=0)#

Parse blocks from an in-memory sequence of lines.

Parameters:
Return type:

JBlocks

read(lines)#

Replace current content with blocks parsed from lines.

Parameters:

lines (Sequence[str] | None)

Return type:

JBlocks

write()#

Serialize every block back to text.

Return type:

list[str]

select(kind=None, comp=None)#

Return blocks filtered by family and/or component.

Parameters:
  • kind (str | None)

  • comp (str | None)

Return type:

list[JBlock]

period_range()#

Global period min/max across blocks (ignores NaN).

Return type:

tuple[float, float] | None

qa_summary()#

List of QA dicts, one per block.

Return type:

list[dict[str, Any]]

Notes

Header discovery is tolerant to real-world quirks, including optional azimuth on the station line and the count-before-dtype pattern seen in some files.

Examples

>>> col = JBlocks.from_file('data/j/kb0-s001.txt')
>>> col.n >= 1
True
>>> [b.station for b in col.select(kind='R')]
['KB0001', ...]

See also

Head, Heads, RBlock, TFBlock

References

blocks: list[JBlock]#
property n: int#
classmethod from_file(j_fn, *, verbose=0)#
Parameters:
Return type:

JBlocks

classmethod from_lines(lines, *, verbose=0)#
Parameters:
Return type:

JBlocks

read(lines=None)#
Parameters:

lines (Sequence[str] | None)

Return type:

JBlocks

write()#
Return type:

list[str]

to_numpy()#
Return type:

list[dict[str, ndarray]]

to_dataframe()#
qa_summary()#
Return type:

list[dict[str, Any]]

property stations: list[str]#
property station: str | None#

Return the single, unique station name for the block collection. Returns None if no blocks are present.

property kinds: list[str]#
select(*, kind=None, comp=None)#
Parameters:
  • kind (str | None)

  • comp (str | None)

Return type:

list[JBlock]

period_range()#
Return type:

tuple[float, float] | None

class pycsamt.jones.JMixin#

Bases: object

Lightweight helpers shared by J-format readers.

The mixin groups small, allocation-friendly utilities that many parsers need. It keeps math, alignment and token-handling logic out of higher-level classes.

Notes

The helpers are intentionally tiny and avoid importing heavy libraries beyond numpy. They favor pure functions that accept and return arrays.

_complex(re, im)#

Combine real and imaginary parts into a complex vector. Shapes must be broadcast-compatible.

_deg2rad(x)#

Degrees to radians conversion with float return.

_hz_from_period(p)#

Convert period seconds to frequency in Hz. Non- positive entries are mapped to nan.

_align_by_periods(p0, p1)#

Return a tuple (p_common, i0, i1) where p_common are periods present in both sequences, ordered like p0; i0 and i1 are indices to select the matching rows in the original arrays.

Examples

>>> jm = JMixin()
>>> jm._complex([1, -2], [0.5, 3]).dtype.kind == 'c'
True
>>> jm._deg2rad(180.0)
3.141592653589793
>>> jm._hz_from_period([1.0, 0.5])
array([1., 2.])
>>> pc, i0, i1 = jm._align_by_periods([1, 2, 3], [3, 1])
>>> pc.tolist(), i0.tolist(), i1.tolist()
([1, 3], [0, 2], [1, 0])

See also

JIOMixin

Block scanning and object building helpers.

JFile

High-level reader that uses both mixins.

References

class pycsamt.jones.JIOMixin#

Bases: JMixin

Tolerant BLOCK parser and TF/R/Tipper builder.

This mixin concentrates the I/O-oriented parts for J files: scanning blocks, aligning periods, normalizing rows, and assembling higher-level objects (Z, Tipper, and ResPhase).

It aims to be robust against non-canonical header orders and minor format quirks.

Notes

  • Data rows are normalized before assembly. Period sign conventions (negative means Hz) are corrected.

  • Missing sentinels (e.g., -999) are mapped to nan for numeric arrays, but objects are pre- allocated with zeros to keep shapes consistent.

  • When only rho/phi are present, impedance is rebuilt using \(|Z|=\sqrt{\mu_0 \,\omega\, \rho}\) and \(\phi\) for the phase. The vacuum permeability \(\mu_0\) is imported from pycsamt.constants.

_scan_blocks(path, \*, start=None, empty_val=...)#

Parse the file into a component dictionary indexed by tokens like 'ZXY', 'RXX' or 'TZX'. Values include period, real/imag/error (TF) or rho/ phi (+ auxiliary columns for R blocks).

_build_from_comp(comp, \*, z_obj=None, tip_obj=None)#

Assemble Z, Tipper, and ResPhase from the scanned components. Returns a triple (Z|None, Tipper|None, ResPhase|None).

Examples

>>> mix = JIOMixin()
>>> # (typically used via JFile; direct use shown here)
>>> # comp = mix._scan_blocks(Path("data/j/site.j"))
>>> # z, tip, rp = mix._build_from_comp(comp)

See also

JMixin

Mathematical utilities used by this mixin.

JFile

High-level reader/writer that calls these methods.

pycsamt.z.z.Z

Impedance tensor container.

pycsamt.z.tipper.Tipper

Tipper container.

pycsamt.z.resphase.ResPhase

R–φ container.

References

class pycsamt.jones.JFile(path=None, *, verbose=0)#

Bases: JIOMixin

High-level J dispatcher for MT/SEG archives.

The class reads a J file, extracts headers and blocks, and builds analysis-ready objects for impedance (Z), resistivity/phase (Res), and tipper (Tip). It also writes new J files from the in-memory state.

Parameters:
  • path (str or Path, optional) – Input J file. If omitted, call read() later.

  • verbose (int, default=0) – Verbosity level. Non-zero emits informational messages during parsing and writing.

Variables:
  • path (Path or None) – Source path when set via __init__ or from_file().

  • heads (pycsamt.jones.heads.Heads or None) – Parsed banner, info and a single head triple.

  • blocks (pycsamt.jones.blocks.JBlocks or None) – Parsed data blocks (R and/or TF).

  • Z (pycsamt.z.z.Z or None) – Impedance tensor container, possibly rebuilt from rho/phi when TF are absent.

  • Tip (pycsamt.z.tipper.Tipper or None) – Tipper container if ZX/ZY are present.

  • Res (pycsamt.z.resphase.ResPhase or None) – Resistivity/phase view (direct or derived).

  • freq (ndarray or None) – Shared frequency vector inferred from available objects. Periods are available via :pyattr:`periods`.

  • periods (ndarray or None) – Convenience view of 1.0/freq when known.

  • n_freq (int) – Number of frequency samples (0 if unknown).

  • name (str or None) – Friendly site/station name. Precedence is: Z.name -> head.station -> file stem.

  • site (str or None) – Alias for the station code (if known).

  • elev (lat, lon, azimuth, az_hint,) – Geographic metadata proxied from headers.

from_file(path, \*, verbose=0)#

Construct and read in one call.

Parameters:
Return type:

JFile

read(path=None, \*, start=None)#

Parse headers and blocks, then build Z, Tip and Res as available.

Parameters:
Return type:

JFile

write(j_fn=None, new_jfn=None, datatype=None,

savepath=None, *, verbose=None, overwrite=True)

Serialize the current state to a J file. The datatype selector accepts combinations like 'Z', 'R', 'T', 'ZR', or 'ALL'.

compose_headers()#

Render banner, head and info lines only.

Return type:

list[str]

__has_read__()#

Return True once a full read() completed.

Examples

>>> jf = JFile.from_file("data/j/kb0-s001.txt", verbose=0)
>>> jf.n_freq > 0
True
>>> out = jf.write(new_jfn="out.j", datatype="ZR",
...                overwrite=True)
>>> isinstance(out, str)
True
>>> jf.lat, jf.lon  # site coordinates if present
( ... )

Notes

  • write prefers existing uncertainties; missing errors are filled with zeros. Periods are written from the active frequency vector.

  • When only R-blocks exist, Z is rebuilt so that downstream code can still compute QA metrics or plot tensor-based products.

See also

pycsamt.jones.heads.Heads

Header and metadata view.

pycsamt.jones.blocks.JBlocks

Low-level parsed blocks.

pycsamt.z.z.Z

Impedance tensor class.

pycsamt.z.tipper.Tipper

Tipper class.

pycsamt.z.resphase.ResPhase

R–φ class.

References

classmethod from_file(path, *, verbose=0)#

Construct and read a J file in one call.

This convenience constructor mirrors __init__ + read(). It resolves path to a filesystem location, parses headers and data blocks, and builds analysis-ready objects (Z, Tip, Res) when present or derivable.

Parameters:
  • path (str or Path) – Path to a J-format text file (Jones v2.0 style).

  • verbose (int, default=0) – Verbosity flag. When non-zero, progress/info messages may be emitted during parsing.

Returns:

Instance with :pyattr:`heads`, :pyattr:`blocks` and objects (:pyattr:`Z`, :pyattr:`Tip`, :pyattr:`Res`) populated where possible.

Return type:

JFile

Notes

  • Headers (banner + >KEY=VALUE + the first head triple) are parsed via Heads.

  • Blocks are scanned with JBlocks, then assembled into Z/Tip/Res via JIOMixin.

Examples

>>> jf = JFile.from_file("data/j/kb0-s001.txt")
>>> jf.n_freq > 0
True

See also

JFile.read

Lower-level method if you already have an instance.

JBlocks

Low-level block parser.

Heads

Header and site metadata container.

References

read(path=None, *, start=None)#

Parse a J file and build objects in memory.

The method reads the banner, info block and the first head triple, then scans all following data blocks. Transfer functions (Zxx, Zxy, …) and tipper (Tzx, Tzy) are assembled when present. If only resistivity/phase blocks exist, a synthetic impedance is rebuilt from \(\rho\) and \(\phi\).

Parameters:
  • path (str or Path, optional) – If given, set as the source and read from it. If omitted, reuse self.path set at construction.

  • start (int, optional) – Line index hint to start scanning blocks. Most users can leave this as None.

Returns:

The instance itself (for chaining).

Return type:

JFile

Notes

  • Block scanning is tolerant to minor format quirks (blank lines, non-canonical head order where the row count precedes the data-type).

  • Period sign conventions are normalized (negative values mean input was frequency in Hz).

  • Missing sentinels (e.g., -999) are mapped to nan in numeric arrays, while objects are pre- allocated with zeros to keep shapes consistent.

Examples

>>> jf = JFile(verbose=0)
>>> _ = jf.read("data/j/kb0-s001.txt")
>>> jf.Z is not None or jf.Res is not None
True

See also

JFile.from_file

Shortcut that constructs then calls this method.

JBlocks

Underlying block parser.

Z, Tipper, ResPhase

References

write(j_fn=None, new_jfn=None, datatype=None, savepath=None, *, verbose=None, overwrite=True)#

Serialize the current state to a J-format file.

The writer renders a banner, info lines and one or more data blocks selected via datatype. When uncertainties are unavailable, zero-filled error columns are emitted to preserve column layout. Periods are derived from the active frequency vector.

Parameters:
  • j_fn (str, optional) – Base filename to use. If omitted, derive from :pyattr:`path` or default to 'out.j'.

  • new_jfn (str, optional) – Replacement filename. Takes precedence over j_fn when provided.

  • datatype ({'Z','R','T','ZR','RT','ZT','ZRT','ALL'}, optional) – Select families to emit. If None, the writer auto-detects from available objects on the instance.

  • savepath (str or Path, optional) – Folder where to save. Defaults to the parent of :pyattr:`path` or the current directory.

  • verbose (int, optional) – Override verbosity. If None, reuse :pyattr:`verbose`.

  • overwrite (bool, default=True) – If False and the target exists, a numeric suffix is appended to avoid clobbering.

Returns:

out_path – The filesystem path of the written file.

Return type:

str

Notes

  • The station code and optional azimuth hint are taken from the parsed head. Units for transfer functions are written as SI.

  • If only R blocks exist, they can be emitted directly; if only Z is present, synthetic R/φ can be computed for writing when the selector requests it.

  • The banner defaults to PYCSAMT when no producer is known. The original banner (if parsed) can be preserved or referenced by the caller before writing.

Examples

>>> jf = JFile.from_file("data/j/kb0-s001.txt")
>>> out = jf.write(new_jfn="site_out.j",
...                datatype="ZR", overwrite=True)
>>> isinstance(out, str)
True

See also

JFile.compose_headers

Render banner + headers only.

Z, Tipper, ResPhase

References

property freq: ndarray | None#
property periods: ndarray | None#
property n_freq: int#
property station: str | None#
property name: str | None#
property lat: float | None#
property lon: float | None#
property azimuth: float | None#
property az_hint: float | None#
property elev: float | None#
property site#
compose_headers()#
Return type:

list[str]

class pycsamt.jones.IsJ#

Bases: ABC

Abstract base for A.G. Jones J-format validation helpers.

Subclasses implement :pyattr:`is_valid`. The static method _assert_j() provides a robust, file-level validator that accepts either a path or an existing IsJ instance. The check is heuristic, fast and tolerant of minor formatting issues (e.g., non-canonical head order).

abstract property is_valid: bool#

Return True when the instance is structurally valid.

pycsamt.jones.is_j_file(file, *, deep=True)#

Convenience wrapper around IsJ._assert_j().

Parameters:
Return type:

bool

class pycsamt.jones.JParseMixin#

Bases: object

Lightweight helpers for scanning Jones J-format text.

The mixin implements tolerant, file-level utilities used by higher-level parsers and collections. It focuses on small, dependency-free pieces such as path coercion, candidate file discovery, banner and header probing, and quick content reads.

The mixin does not keep state. Methods are small and side-effect free so they can be reused by different classes (e.g., JCoreParser, JCBBase, JCollection).

Notes

Utilities are designed to be permissive. They handle odd encodings, mixed line endings, and common filename patterns. They also accept both pathlib.Path and strings.

The intent is to keep the heavy parsing in dedicated readers, while providing robust file discovery and quick checks here.

Examples

Discover candidate files in a folder:

>>> m = JParseMixin()
>>> root = "data/j"
>>> list(m._iter_j_files([root]))[:1]
[PosixPath('...kb0-s001.txt')]

Coerce user inputs to Path:

>>> p = m._as_path("data/j/kb0-s001.txt")
>>> p.exists()
True

See also

JCoreParser

Adds content probing (station, dtype, counts).

JCBBase

State-holding base for collections.

pycsamt.jones.validation.IsJ

File-level validator for J candidates.

pycsamt.jones.j.JFile

High-level reader that builds Z/Tipper/R blocks.

References

J_SUFFIXES = {'.dat', '.j', '.jones', '.txt'}#
is_j_like(src, *, deep=True)#

Light heuristic to decide if src looks like a Jones file.

Parameters:
  • src (path-like) – File path.

  • deep (bool, default=True) – If False, only extension + existence is checked.

Returns:

True if the file looks like J-format.

Return type:

bool

is_j_file(src, *, deep=True)#

Spec-level check via IsJ. Returns True if the file satisfies the structural requirements; False otherwise. Never raises.

Parameters:
Return type:

bool

is_j_candidate(src, *, deep=True)#

Alias of is_j_like(). Some call-sites prefer this name.

Parameters:
Return type:

bool

class pycsamt.jones.JCoreParser(*, recursive=True, strict=False, on_dup='replace', verbose=0)#

Bases: JParseMixin

Core scanner for J files that extracts light metadata.

Extends JParseMixin with small, read-only probes that inspect the top header and first data head triple. This class can reveal the station code, presence of info keys, encountered data kinds, and the declared row count of the first block. It avoids loading the whole file.

The implementation aims to be fast and safe for directory crawls, where many files are filtered before full parse.

Variables:

encoding (str, default 'utf-8') – Encoding used when reading text. Implementations may choose a tolerant variant such as 'utf-8-sig' with errors='replace'.

Parameters:
_read_text(path)#

Return the file content as a single text string.

_scan_one(path)#

Return a small dict of hints (e.g., station, kinds, nrows) obtained without full parsing.

_looks_like_j(path)#

Heuristic check that a path is a J candidate.

_iter_info_keys(text)#

Yield info keys (>KEY=VALUE) from the header area.

Notes

The scanner is structural. It does not validate numeric content or cross-block consistency. It is designed to be called many times in batch workflows.

Examples

Quick peek of a single file:

>>> p = "data/j/kb0-s001.txt"
>>> core = JCoreParser()
>>> hints = core._scan_one(p)
>>> "station" in hints and "kinds" in hints
True

Filter a folder to J candidates:

>>> paths = list(core._iter_j_files(["data/j"]))
>>> all(core._looks_like_j(p) for p in paths)
True

See also

JParseMixin

Path and discovery helpers used by this scanner.

JCBBase

Collection base that can cache these hints.

pycsamt.jones.heads.Heads

Full header reader (Info + Head + Banner).

pycsamt.jones.blocks.JBlocks

Full data block reader.

References

results: list[_JParseResult]#
parse(sources)#
Parameters:

sources (str | Path | Sequence[str | Path])

Return type:

list[JFile]

errors()#
Return type:

list[tuple[Path, BaseException]]

class pycsamt.jones.JCBBase(items=None, *, verbose=0)#

Bases: object

Minimal stateful base for collections of J files.

The class manages a list of parsed items (usually JFile), keeps light metadata for indexing and filtering, and offers a stable surface for higher-level collection types. It is intentionally small so projects can extend it without tight coupling.

Parameters:
  • verbose (int, default 0) – Verbosity for logs and warnings. Implementations are free to ignore it or to pass it to child readers.

  • items (Iterable[JFile] | None)

Variables:
  • items (list) – Stored per-file objects. The class does not enforce a specific type, but JFile is the natural choice.

  • n (int) – Number of stored items.

  • paths (list of Path) – Convenience view of the underlying file paths (when available on items).

add(obj)#

Append an item. Returns the item for chaining.

Parameters:

jf (JFile)

Return type:

None

parse(paths)#

Build and add items from paths. Uses the light probes from JCoreParser before full parse.

filter(**kws)#

Optional helper that returns a new instance filtered by station, component family, or other metadata.

__len__(), __iter__()#

Python container protocol for lists of items.

Notes

Subclasses are encouraged to keep the API stable while augmenting with domain-specific helpers, like saving index CSV files or computing per-site quality metrics.

The base class uses tolerant discovery, so it can be used on mixed folders where some files are not Jones J-format.

Examples

Build a collection from a folder:

>>> col = JCBBase(verbose=0)
>>> items = col.parse(["data/j"])
>>> len(items) == col.n
True

Iterate over sites and write quick summaries:

>>> for it in col:
...     print(getattr(it, "site", None))

See also

pycsamt.jones.collection.JCollection

Higher-level collection with convenience features.

pycsamt.jones.j.JFile

High-level reader used as per-item object.

JCoreParser

Provides the fast scanning used during parse.

References

add(jf)#
Parameters:

jf (JFile)

Return type:

None

stations()#
Return type:

list[str]

classmethod load(sources, *, parser=None, recursive=True, strict=False, on_dup='replace', verbose=0)#
Parameters:
Return type:

JCBBase

map(fn)#
Parameters:

fn (Callable[[JFile], object])

Return type:

list[object]

write(savepath, *, pattern='{station}.j', **kwargs)#
Parameters:
Return type:

list[str]

summary()#
Return type:

list[dict[str, object]]

property items#

unified iterator over stored items.

Type:

Internal

class pycsamt.jones.JCollectionMixin#

Bases: JParseMixin

Mixin that provides folder/glob expansion and robust parsing orchestration for Jones J-format collections.

The mixin augments a stateful base (e.g., JCBBase) with helpers to normalize user input paths, expand folders and wildcards, deduplicate candidates, and parse items using a tolerant strategy.

Implementations typically use JFile as the per-item reader, but the mixin is agnostic to the concrete class as long as it exposes a compatible from_file constructor.

Notes

The design keeps discovery and parsing separate. First the mixin expands and filters path candidates; then the owning class decides how to instantiate items and how to record failures. This separation avoids tight coupling and keeps error handling clear.

The mixin favors permissive heuristics while still catching obvious mistakes (non-files, unreadable paths, extensions that are unlikely to be J-format, etc.).

Typical Methods#

from_paths(paths, *, strict=False, verbose=0)

Expand and parse paths into items. Returns the created items (usually a list).

_iter_paths(paths)

Yield pathlib.Path objects from strings or paths, ignoring duplicates.

_iter_j_files(paths, *, recursive=True)

Yield J-candidates by expanding folders and glob patterns (e.g., "*.j", "**/*.txt").

_is_j_candidate(path)

Light heuristic that recognizes J-format candidates.

Examples

Expand a folder and parse all candidates:

>>> mix = JCollectionMixin()
>>> # usually inherited together with JCBBase
>>> list(mix._iter_j_files(["data/j"]))[:1]
[PosixPath('...kb0-s001.txt')]

See also

JCBBase

Minimal stateful base for collections (stores items).

JCollection

High-level collection that mixes in this helper and provides user-facing APIs.

pycsamt.jones.j.JFile

High-level J reader used as default item type.

References

add_from(sources, *, recursive=True, strict=False, on_dup='replace', verbose=None)#
Parameters:
Return type:

JCollectionMixin

select(stations)#
Parameters:

stations (Sequence[str])

Return type:

JCollection

where(fn)#
Parameters:

fn (Callable[[JFile], bool])

Return type:

JCollection

sort(key='station', *, reverse=False)#
Parameters:
Return type:

JCollection

property paths: list[str]#
nf_stats()#
Return type:

dict

class pycsamt.jones.JCollection(items=None, *, verbose=0)#

Bases: JCBBase, JCollectionMixin

High-level collection of Jones J-format files.

Combines JCBBase (state container) with JCollectionMixin (discovery/orchestration) to offer a convenient interface for batch loading, quick metadata browsing, and simple filtering over many J files.

The default per-item object is JFile, which exposes parsed headers (Heads) and data blocks (JBlocks) as well as MT objects (pycsamt.z.z.Z, pycsamt.z.tipper.Tipper, pycsamt.z.resphase.ResPhase) when available.

Parameters:
  • verbose (int, default 0) – Verbosity for logging and warnings during discovery and parsing.

  • items (Iterable[JFile] | None)

Variables:
  • items (list of JFile) – Parsed items in insertion order. The class follows Python’s container protocol (__len__, __iter__).

  • n (int) – Number of items in the collection (len(self)).

  • paths (list of Path) – Convenience view of the associated file paths.

  • stations (list of str) – Station codes when available on items (best-effort).

parse(paths, \*, strict=False, verbose=None)#

Expand paths (file, folder, glob), parse J files, and append items to the collection. Returns the new items.

where(**query)#

Optional, return a filtered view (e.g., by station or by component family has_Z/has_R/has_T).

summary()#

Optional, return a compact text or dataframe summary.

Parameters:

fields (Sequence[str])

Return type:

list[dict]

write_index(path, \*, overwrite=True)#

Optional, serialize a CSV/TSV inventory for the collection.

Notes

The collection is intentionally lightweight. It does not enforce a database schema, and it avoids implicitly reading large arrays until needed. This makes it suitable for quick exploration and CI tests.

Error handling is conservative: unreadable paths or parse errors are usually skipped with a warning (unless strict=True is requested).

Examples

Parse a folder and browse basic metadata:

>>> col = JCollection(verbose=0)
>>> _ = col.parse(["data/j"])
>>> len(col) >= 1
True
>>> sorted(set(getattr(x, "site", None) for x in col))[:3]
[...]

Filter by station (if where is provided):

>>> sub = getattr(col, "where", lambda **k: col)(station="KB0001")
>>> len(sub) >= 1
True

See also

JCBBase

Underlying state container.

JCollectionMixin

Path expansion and tolerant orchestration.

pycsamt.jones.j.JFile

Per-item high-level J reader.

References

classmethod from_sources(sources, *, recursive=True, strict=False, on_dup='replace', verbose=0)#
Parameters:
Return type:

JCollection

merge(other, *, on_dup='replace')#
Parameters:
Return type:

JCollection

get(site, what, default=None)#
Quick extractor. ‘what’ supports:
  • ‘freq’

  • ‘z’,’zxx’,’zxy’,’zyx’,’zyy’

  • ‘tip’,’tx’,’ty’

  • ‘rxy’,’ryx’,’rxx’,’ryy’ (rho)

  • ‘phixy’,’phiyx’,’phixx’,’phiyy’

  • ‘station’/’site’,’lat’,’lon’,’elev’,’az’,’name’

  • ‘path’,’filename’

Parameters:
Return type:

object | None

set(site, *, jfile=None, update=None)#

Replace or mutate a site’s JFile.

  • If ‘jfile’ is given, replace the stored object.

  • Else apply ‘update’ keys on the existing object: ‘station’/’site’,’lat’,’lon’,’elev’,’az’, ‘freq’,’z’,’tip’,’resphase’

Parameters:
Return type:

JFile

adjust(site, *, dlat=None, dlon=None, lat=None, lon=None, elev=None, rename=None)#

Shift or set position and/or rename station.

Parameters:
Return type:

JFile

summary(fields=('station', 'n_freq', 'has_z', 'has_r', 'has_t', 'lat', 'lon', 'az'))#
Parameters:

fields (Sequence[str])

Return type:

list[dict]

property sites: list[str]#

Best-effort station names (one per item).

property latitude: ndarray#

Vector of latitudes (np.nan for missing).

property longitude: ndarray#

Vector of longitudes (np.nan for missing).

export(output_dir, *, file_pattern='{station}.j', export_summary=False, summary_filename='summary.csv', **jfile_write_kwargs)#

Exports all JFile items to a directory with advanced options.

This method orchestrates the writing of each JFile in the collection to a specified directory, with flexible naming, error handling, and an optional summary CSV file.

Parameters:
  • output_dir (Pathish) – The path to the directory where files will be saved. It will be created if it does not exist.

  • file_pattern (str, default="{station}.j") – A format string for output filenames. Can use attributes of JFile like {station}, {name}, {site}.

  • export_summary (bool, default=False) – If True, a summary of the collection will also be saved as a CSV file in the output directory.

  • summary_filename (str, default="summary.csv") – The name of the summary file if export_summary is True.

  • **jfile_write_kwargs – Keyword arguments to be passed directly to each JFile.write() call (e.g., datatype=”ZRT”, overwrite=True).

Returns:

A dictionary with two keys: - ‘successful’: A list of paths to successfully written files. - ‘failed’: A list of tuples, where each tuple contains the

station name and the error that occurred.

Return type:

dict

fetch(site=None, lat=None, lon=None, tol=0.001, first=False, **kwargs)#

Fetches JFile objects from the collection based on specified criteria.

This method provides a flexible way to search for J-format files by site name, geographic coordinates, or any other attribute of the JFile object or its nested Heads sections.

Parameters:
  • site (str, optional) – The site or station name to search for. The comparison is case-insensitive.

  • lat (float, optional) – The latitude to search for, in decimal degrees.

  • lon (float, optional) – The longitude to search for, in decimal degrees.

  • tol (float, default=0.001) – The tolerance in decimal degrees for geographic coordinate searches. A match is found if the absolute difference is within this tolerance.

  • first (bool, default=False) – If True, returns only the first matching JFile object found, or None if no match is found. If False, returns a list of all matching objects.

  • **kwargs (Any) – Additional keyword arguments to match against attributes of the JFile object or its nested Heads object (e.g., acqby=’Contractor’). The attribute name is case-insensitive.

Returns:

  • If first=True, returns the first matching JFile or None.

  • If first=False, returns a list of all matching JFile objects. An empty list is returned if no matches are found.

Return type:

JFile or list of JFile or None

Examples

>>> # Fetch a single site by its name
>>> jfile_obj = jcollection.fetch(site='S01', first=True)
>>> # Fetch all sites where the azimuth is 0
>>> zero_az_files = jcollection.fetch(azimuth=0)
>>> # Fetch all sites within a small geographic area
>>> area_files = jcollection.fetch(
...     lat=26.05,
...     lon=-10.33,
...     tol=0.1
... )
class pycsamt.jones.JComponentMixin#

Bases: object

Lightweight facade to manage Jones (J-format) components on a host object. The host is expected to expose a mapping-like container (self.sections or self.components). Keys are normalized to lowercase for stable lookups.

The mixin centralizes small CRUD helpers (cget/cset/chas/ cdrop/snapshot) and offers typed accessors for frequent J parts such as banner, info, head, heads, blocks, and derived data objects (z, tip, res).

It also provides compose_headers which serializes the header portion of a J file by calling write() on available components. If a combined heads component is present, it takes precedence over separate banner/head/info parts to avoid duplication.

cget(key, default=None)#
Parameters:
Return type:

Any

cset(key, obj)#
Parameters:
Return type:

None

chas(key)#
Parameters:

key (str)

Return type:

bool

cdrop(key)#
Parameters:

key (str)

Return type:

None

snapshot(keys=None)#
Parameters:

keys (Iterable[str] | None)

Return type:

dict[str, Any]

get_banner()#
Return type:

Any

set_banner(obj)#
Parameters:

obj (Any)

Return type:

None

get_info()#
Return type:

Any

set_info(obj)#
Parameters:

obj (Any)

Return type:

None

get_head()#
Return type:

Any

set_head(obj)#
Parameters:

obj (Any)

Return type:

None

get_heads()#
Return type:

Any

set_heads(obj)#
Parameters:

obj (Any)

Return type:

None

get_blocks()#
Return type:

Any

set_blocks(obj)#
Parameters:

obj (Any)

Return type:

None

get_z()#
Return type:

Any

set_z(obj)#
Parameters:

obj (Any)

Return type:

None

get_tip()#
Return type:

Any

set_tip(obj)#
Parameters:

obj (Any)

Return type:

None

get_res()#
Return type:

Any

set_res(obj)#
Parameters:

obj (Any)

Return type:

None

compose_headers(*, prefer_heads=True, join=False)#

Serialize header lines by querying available components. If prefer_heads is True and a heads component is present, it is used exclusively. Otherwise the mixin attempts banner + head + info in that order.

When join is True, returns a single string joined with newlines. Otherwise returns a list of lines.

Parameters:
Return type:

list[str] | str

pycsamt.jones.iter_lines(obj, *, encoding='utf-8', keepends=False)#

Yield lines from a path, file‑like, or a sequence of strings.

Parameters:
  • obj (file‑like | str | Path | sequence of str) – Source to read from. Paths are opened in text mode.

  • encoding (str, default="utf-8") – Text encoding used for paths.

  • keepends (bool, default=False) – Whether to keep line endings in yielded strings.

Yields:

str – One line at a time.

Return type:

Iterator[str]

pycsamt.jones.parse_datatype_units(line, *, lineno=None)#

Parse a data‑type line like ZXY SI or RTE.

The result contains the kind, component, optional units, and a tensor_hint for TE/TM modes.

Parameters:
  • line (str)

  • lineno (int | None)

Return type:

DataType

Jones Modules#

pycsamt.jones.base

Minimal bases for the Jones (J-format) subsystem.

pycsamt.jones.blocks

pycsamt.jones.cbase

pycsamt.jones.collection

pycsamt.jones.components

pycsamt.jones.config

Configuration and canonical constants for the A.G.

pycsamt.jones.heads

pycsamt.jones.j

pycsamt.jones.property

Site‑level properties parsed from the J‑format information block.

pycsamt.jones.utils

Lightweight parsing utilities for A.G.

pycsamt.jones.validation

pycsamt.jones.xa