Skip to content

postfile

postfile

PyAERMOD POSTFILE Parser

Parses AERMOD POSTFILE output files containing concentration grids for each averaging period and source group.

Supports both formatted (PLOT) and unformatted (UNFORM/binary) POSTFILE output.

AERMOD formatted POSTFILE (PLOT): - Header lines start with '*' and contain metadata such as AERMOD version, AVERTIME, POLLUTID, and SRCGROUP. - Data lines contain columns: X, Y, CONC, ZELEV, ZHILL, ZFLAG, AVE, GRP, DATE (YYMMDDHH). - Concentrations may use scientific notation (e.g. 1.23456E+01).

AERMOD unformatted POSTFILE (UNFORM): - Fortran unformatted sequential records. - Each record contains: KURDAT (int32), IANHRS (int32), GRPID (char*8), ANNVAL (float64 x num_receptors). - Receptor coordinates are NOT stored in the binary file; they must be supplied externally or default to index-based values.

Based on AERMOD version 24142 POSTFILE specifications.

PostfileHeader dataclass

Metadata parsed from POSTFILE header lines.

Each field corresponds to a '*'-prefixed header line in the POSTFILE.

PostfileResult dataclass

Parsed data for a single POSTFILE (one source group / averaging period).

Attributes:

Name Type Description
header PostfileHeader

Metadata extracted from the file header.

data DataFrame

Concentration data with columns: x, y, concentration, zelev, zhill, zflag, ave, grp, date.

max_concentration property

max_concentration: float

Return the maximum concentration value in the dataset.

max_location property

max_location: Tuple[float, float]

Return (x, y) coordinates of the maximum concentration.

get_timestep

get_timestep(date: str) -> pd.DataFrame

Get all data rows for a specific date/time.

Parameters:

Name Type Description Default
date str

Date string in YYMMDDHH format (e.g. '26010101').

required

Returns:

Type Description
DataFrame

Subset of data matching the requested date.

get_receptor

get_receptor(x: float, y: float, tolerance: float = 1.0) -> pd.DataFrame

Get all data rows for a specific receptor location.

Parameters:

Name Type Description Default
x float

X coordinate of the receptor.

required
y float

Y coordinate of the receptor.

required
tolerance float

Distance tolerance for matching receptor coordinates.

1.0

Returns:

Type Description
DataFrame

Subset of data within tolerance of the requested location.

get_max_by_receptor

get_max_by_receptor() -> pd.DataFrame

Get the maximum concentration at each unique receptor location.

Returns:

Type Description
DataFrame

DataFrame with columns x, y, concentration (max at each receptor).

to_dataframe

to_dataframe() -> pd.DataFrame

Return a copy of the full data DataFrame.

Returns:

Type Description
DataFrame

Copy of the concentration data.

PostfileParser

Parser for AERMOD POSTFILE output files.

Parameters:

Name Type Description Default
filepath str or Path

Path to the POSTFILE to parse.

required

Raises:

Type Description
FileNotFoundError

If the specified file does not exist.

parse

parse() -> PostfileResult

Read and parse the POSTFILE.

Returns:

Type Description
PostfileResult

Parsed header metadata and concentration data.

UnformattedPostfileParser

Parser for AERMOD unformatted (binary) POSTFILE output files.

AERMOD writes unformatted POSTFILE records using Fortran sequential unformatted I/O. Each record has the layout::

[4-byte record-length marker]
KURDAT    — int32    (date in YYMMDDHH format)
IANHRS    — int32    (hours in averaging period, or NUMYRS for ANNUAL)
GRPID     — char*8   (source group ID, space-padded)
ANNVAL()  — float64 × num_receptors  (concentration per receptor)
[4-byte record-length marker]

For deposition runs the ANNVAL array contains three contiguous blocks: CONC(1:N), DRY_DEP(1:N), WET_DEP(1:N) — i.e. 3×N float64 values per record.

Parameters:

Name Type Description Default
filepath str or Path

Path to the unformatted POSTFILE.

required
num_receptors int

Number of receptors. If None, inferred from the first record size.

None
receptor_coords list of (float, float)

(x, y) coordinate pairs for each receptor index. If None, receptors are assigned index-based coordinates (i, 0).

None
has_deposition bool

If True, each record is assumed to contain 3×N float64 values (concentration, dry deposition, wet deposition). If None (default), deposition is auto-detected when num_receptors is given and the record contains exactly 3×N values. If False, deposition columns are never produced.

None

Raises:

Type Description
FileNotFoundError

If the specified file does not exist.

parse

parse() -> PostfileResult

Read all records from the unformatted POSTFILE.

Returns:

Type Description
PostfileResult

Parsed header metadata and concentration data. Header fields are populated from the first record's source group and averaging info; version, title, model_options, and pollutant_id are set to None (not present in binary format).

When the file contains deposition data (3×N floats per record), the DataFrame includes dry_depo and wet_depo columns in addition to concentration.

read_postfile

read_postfile(filepath: Union[str, Path], *, num_receptors: Optional[int] = None, receptor_coords: Optional[List[Tuple[float, float]]] = None, has_deposition: Optional[bool] = None) -> PostfileResult

Parse an AERMOD POSTFILE and return the result.

Automatically detects whether the file is in formatted (PLOT/text) or unformatted (UNFORM/binary) format.

Parameters:

Name Type Description Default
filepath str or Path

Path to the POSTFILE.

required
num_receptors int

Number of receptors (binary files only). Ignored for text files. If None, inferred from the first record.

None
receptor_coords list of (float, float)

Receptor (x, y) coordinates (binary files only). Ignored for text files.

None
has_deposition bool

Whether the binary file contains deposition data (3×N floats per record). Ignored for text files. If None, auto-detection is attempted when num_receptors is provided.

None

Returns:

Type Description
PostfileResult

Parsed header metadata and concentration data.