Skip to main content

Quantity and Quality

PyPI Python CI License: MIT

A lightweight Python library and CLI for reporting energy quantity together with energy quality.

Try it in your browser · Paper · Adoption cookbook · Changelog

Instead of writing:

1 MWh

write:

1 MWh, fx = 0.170

where fx is the Exergy Factor: accessible useful work potential per unit of energy.

For example:

1 MWh_th, fx = 0.170 [Th = 80 C, T0 = 20 C]

means that 1 MWh of 80 °C heat carries about:

0.170 MWh_ex

of accessible work potential relative to a 20 °C reference sink.

This framework is designed for make the full thermodynamic energy picture visible for energy analysts, engineers, consultants, researchers, software teams, and workflows that need a simple way to add energy-quality reporting to existing energy data.

It does not replace detailed exergy analysis, process simulation, ISO 50001, IPMVP, LCA, cost accounting, or engineering judgment. It adds one useful quality field to existing energy records so electricity, fuels, heat, cooling, storage, and savings can be compared more honestly.


What You Can Do With It

Use this framework to:

  • calculate Exergy Factor for electricity, heat, cooling, fuels, and solar radiation
  • convert ordinary energy records into quantity-plus-quality notation
  • clean CSV, JSON, JSONL, Excel, DataFrame, SQL, stream, or URL records
  • compare energy options using MWh_ex, cost/MWh_ex, and CO2/MWh_ex
  • add auditable context such as reference sink, boundary, basis, assumptions, and warnings
  • export canonical reference data for web calculators, dashboards, APIs, and reports

The package is designed to start simple: use reference defaults for screening, then replace them with site-specific values when accuracy matters.


Install

From PyPI:

python -m pip install quantity-and-quality

The installed command is quantity-quality (no "and"), and the import name is quantity_quality.

For local development:

python -m pip install -e ".[all,dev]"

YAML scenario files require the optional scenario extra, and the HTTP API requires the api extra:

python -m pip install "quantity-and-quality[scenario]"
python -m pip install "quantity-and-quality[api]"

To install the unreleased development version directly from GitHub:

python -m pip install git+https://github.com/cdimurro/quantity-and-quality.git

The Three Main Workflows

1. Calculate One Stream

Use this when you know the energy form and want a quick quantity-plus-quality record.

quantity-quality calc thermal --quantity 1 --unit MWh_th --source-c 80 --sink-c 20

Example output:

80 C heat to 20 C sink
report: 1 MWh_th, fx = 0.170 [Th = 80 C, T0 = 20 C]
accessible exergy: 0.169899 MWh_ex

Other common calculations:

quantity-quality calc electricity --quantity 1 --unit MWh
quantity-quality calc fuel --quantity 1 --fuel "natural gas" --basis HHV
quantity-quality calc cooling --quantity 1 --unit MWh_cooling --cold-service-c 7 --ambient-sink-c 30
quantity-quality calc custom --quantity 1 --unit MWh --fx 0.73

2. Clean Existing Energy Records

Use this when you already have energy records in a file or data source.

quantity-quality clean examples/adoption_records.csv --output clean.csv

The cleaner accepts messy field names such as:

energy_kwh
supply_temp_f
fuel_type
reference_id
fx
exergy_factor

It adds:

  • notation
  • accessible exergy
  • normalized MWh_ex where possible
  • reference context
  • assumptions
  • warnings
  • validation issues

Example:

import quantity_quality as qq

records = qq.clean_records([
    {"asset": "Grid meter", "energy_kwh": 845, "reference_id": "electricity-delivered"},
    {"asset": "Kiln exhaust", "energy_kwh": 2738, "supply_temp_f": 1005.8},
    {"asset": "Unknown stream", "quantity": 2.738, "unit": "kWh_th", "fx": 0.64},
])

for record in records:
    print(record["full_notation"], record["missing_context"])

3. Compare Energy Options

Use this when you want to compare fuels, heat, electricity, waste heat, cooling, storage, or project scenarios.

quantity-quality compare examples/process_heat_comparison.json

Example output:

Option                Energy         fx       MWh_ex  Cost/MWh_ex  CO2/MWh_ex
--------------------  -------------  -------  ------  -----------  ----------
Natural gas HHV       10000 MWh_HHV  0.93     9300    34.4086      194.624
Hydrogen HHV          10000 MWh_HHV  0.83     8300    114.458      0
Electric resistance   10000 MWh      1        10000   70           0
Recovered 500 C heat  10000 MWh_th   0.61437  6143.7  19.5322      0

Markdown and JSON reports are also available:

quantity-quality compare examples/process_heat_comparison.json --format markdown --output report.md
quantity-quality compare examples/process_heat_comparison.json --format json

Python API

import quantity_quality as qq

record = qq.thermal(1, "MWh_th", source_c=80, sink_c=20)

print(record.full_notation)
# 1 MWh_th, fx = 0.170 [Th = 80 C, T0 = 20 C]

print(record.accessible_exergy, record.accessible_exergy_unit)
# 0.169899... MWh_ex

Create a custom record:

record = qq.report(1, "MWh", fx=0.73)

print(record.notation)
# 1 MWh, fx = 0.730

Use a bundled reference example:

record = qq.lookup("heat-80c-standard", quantity=1.8)

print(record.full_notation)
# 1.8 MWh_th, fx = 0.170 [Th = 80 C, T0 = 20 C]

Compare scenario files:

result = qq.compare_scenario_file("examples/process_heat_comparison.json")
print(qq.scenario_to_markdown(result))

Core Formula

The reporting layer normalizes different energy carriers into one quality field:

accessible exergy = energy quantity * Exergy Factor

or:

X_A = E * fx

For power:

accessible exergy rate = power * Exergy Factor

or:

Xdot_A = P * fx

For heat, the default thermal Exergy Factor uses the Carnot factor:

fx = 1 - T0 / Th

Temperatures are converted to kelvin internally. Public examples use:

T0 = 20 C

unless another sink or reference condition is declared.

Fuel examples must declare their energy basis. HHV is recommended for broad public comparison because it avoids confusing fx > 1 values for common fuels. LHV is supported when explicitly labeled.


Why This Matters

One MWh of electricity, one MWh of 80 °C heat, one MWh of 40 °C heat, and one MWh of fuel are equal under first-law energy accounting.

They are not equal as useful work resources.

Examples with a 20 °C reference sink:

Stream Conventional Report Quantity + Exergy Factor
Electricity 1 MWh 1 MWh, fx = 1.0
Heat at 150 °C 1 MWh_th 1 MWh_th, fx = 0.307
Heat at 80 °C 1 MWh_th 1 MWh_th, fx = 0.170
Heat at 40 °C 1 MWh_th 1 MWh_th, fx = 0.064
Methane, HHV basis 1 MWh_HHV 1 MWh_HHV, fx = 0.930
Hydrogen, HHV basis 1 MWh_HHV 1 MWh_HHV, fx = 0.830

The Exergy Factor helps reveal:

  • when high-grade resources are used for low-grade services
  • when low-grade heat can be productively cascaded
  • when heat pumps act as work-potential matching devices
  • when fuels, electricity, heat, cooling, and storage are not directly comparable by MWh alone
  • when savings should be reported as both avoided energy and avoided accessible exergy

Data Contract

The minimum direct record is:

{
  "quantity": 1,
  "unit": "MWh",
  "exergy_factor": 0.73
}

For auditable records, add context:

{
  "quantity": 1,
  "unit": "MWh_th",
  "exergy_factor": 0.170,
  "source_c": 80,
  "sink_c": 20,
  "reference": "20 C thermal sink",
  "boundary": "delivery point",
  "basis": "Carnot factor"
}

Bundled reference examples can be used with reference_id:

{
  "quantity": 1,
  "unit": "MWh_th",
  "reference_id": "heat-80c-standard"
}

The JSON Schema is packaged and available at:

data/quantity_quality_record.schema.json

CLI:

quantity-quality schema --json-schema

Python:

schema = qq.load_record_schema()

Reference Data

The package includes reference examples for:

  • electricity
  • mechanical work
  • thermal streams
  • cooling
  • fuels
  • solar radiation
  • storage
  • measurement and reporting use cases
quantity-quality list
quantity-quality list --category thermal
quantity-quality lookup heat-80c-standard

Reference data files:

data/reference_examples.json
data/reference_examples.csv

Each reference example declares:

  • boundary
  • basis
  • source
  • confidence class
  • carrier
  • reference condition
  • structured context such as temperatures or fuel basis where relevant

Reference examples are starting assumptions, not universal constants. Use them for screening, teaching, first-pass comparison, and software integration. Replace them with site-specific values when making project decisions.


Website Data Export

The static exergyfactor.com calculator can consume reference data generated from this Python package:

quantity-quality export-web-data \
  --output ../exergy-factor/data/reference_examples.json \
  --js-output ../exergy-factor/data/reference_examples.js

The JavaScript bundle is synchronous and small, so the website calculator can load canonical values immediately without waiting for a runtime fetch.

This keeps the Python library and public calculator aligned around one source of truth.


Reporting Notation

A computed Exergy Factor keeps its trailing zeros: 0.170, not 0.17, and 0.730, not 0.73. Those digits state the precision being claimed, and they make the published figure look like the value a reader recomputes.

An exact factor is not padded. Electricity is 1 by definition, not 1 measured to three decimals, so it reads fx = 1.0. The quantity is never padded either — 1 MWh, not 1.000 MWh.

Short notation

Use this when the reference convention is already known, the carrier is unambiguous, or the value is being used in a compact dashboard, invoice, spreadsheet, or chart.

1 MWh, fx = 1.0

A short-form record is not verifiable from itself. That is a legitimate choice for electricity, where fx = 1.0 regardless of the sink — but it is a choice, and the reader should be able to tell that it was made.

Full notation

Use this for thermal streams, non-default references, technical reports, datasets, audits, and any case where another person needs to verify the value from the notation itself.

1 MWh_th, fx = 0.170 [Th = 80 C, T0 = 20 C]

This is the point of the notation. The bracket declares the source and reference temperatures, so whoever receives the record can re-derive the factor themselves — in one division, without trusting the sender or this library:

fx = 1 - T0/Th = 1 - 293.15/353.15 = 0.170

From the shell, on any record — including ones this package did not produce:

quantity-quality verify "1 MWh, fx = 0.170 [Th = 80 C, T0 = 20 C]"
# 1 MWh, fx = 0.170 [Th = 80 C, T0 = 20 C]
#   fx = 1 - T0/Th = 1 - 293.15/353.15 = 0.170  [OK]

It exits non-zero when a verifiable record disagrees with its own bracket, so it can gate a pipeline: a report whose stated factors no longer match the temperatures printed beside them fails the build instead of being published. A record with no bracket exits zero — it has not been contradicted.

From Python:

>>> import quantity_quality as qq
>>> print(qq.verify_notation("1 MWh, fx = 0.170 [Th = 80 C, T0 = 20 C]"))
fx = 1 - T0/Th = 1 - 293.15/353.15 = 0.170  [OK]

>>> check = qq.verify_notation("1 MWh_th, fx = 0.900 [Th = 80 C, T0 = 20 C]")
>>> check.agrees, round(check.difference, 3)
(False, 0.73)

A record with no declaration bracket is reported as not verifiable, which is not the same as wrong — nothing has been contradicted, there is simply nothing to check against.

The bracket also round-trips, so a record can be read back out of a report, a CSV cell, or an email:

>>> parsed = qq.parse_energy_notation("1 MWh, fx = 0.170 [Th = 80°C, T0 = 20°C]")
>>> parsed.source_c, parsed.sink_c, parsed.is_fully_specified
(80.0, 20.0, True)

°C is accepted but never required, and a bracket temperature may state K or F explicitly — [Th = 353.15 K, T0 = 293.15 K] parses to the same record. The canonical written form stays ASCII so the notation survives a spreadsheet, a plain-text log, and an email without an encoding step.

Cooling services declare their own bracket and verify against the service equation:

1 MWh_cooling, fx = 0.082 [Tcold = 7 C, T0 = 30 C]
fx = T0/Tcold - 1 = 303.15/280.15 - 1 = 0.082

Structured data

Use this in APIs, databases, telemetry, invoices, procurement data, and standards templates where records should be machine-readable.

{
  "quantity": 1.0,
  "unit": "MWh_th",
  "exergy_factor": 0.170,
  "source_c": 80,
  "sink_c": 20,
  "reference": "20 C thermal sink",
  "boundary": "delivery point",
  "basis": "Carnot factor"
}

The practical standard is:

quantity, fx = value

plus enough declared context to make the value interpretable.


Supply-Demand Matching

The framework becomes most useful when both supply and demand are reported with Exergy Factor.

Supply:

(P_s, fx_s)

Demand:

(P_d, fx_d)

Good match:

P_s ~= P_d
fx_s ~= fx_d

Wasteful match:

fx_s >> fx_d

This means a high-exergy source is being used for a low-exergy service.

Insufficient match:

fx_s < fx_d

This means the supply must be upgraded by a heat pump, compressor, reactor, electrolyzer, or another conversion process.

A simple mismatch index is:

Delta_fx = fx_s - fx_d

For a matched energy quantity:

X_mismatch = E_matched * max(0, fx_s - fx_d)

Stream Quality vs. Process Efficiency

The framework keeps stream reporting separate from process performance.

Stream descriptor:

(E, fx)

or:

(P, fx)

Process descriptor:

eta_x
Xdot_dest

where:

eta_x = useful exergy output / accessible exergy input
Xdot_dest = T0 * Sdot_gen

A stream can have high fx and still be wasted in an irreversible device.

A stream can have low fx and still be valuable if it is well matched to a low-fx demand.


Machine-Readable Input Patterns

The library accepts incomplete records immediately, computes what it can, and returns:

  • capabilities
  • missing context
  • assumptions
  • warnings
  • validation issues

This lets records improve over time instead of forcing every user through a fixed checklist.

The simplest machine-readable record only needs:

quantity or power
unit
fx or exergy_factor

For declared context, add:

reference
boundary
basis

For thermal streams, include source temperature and reference sink temperature when possible:

source_c
sink_c

For chemical carriers, declare the energy basis:

HHV
LHV
tabulated chemical exergy

Project Contents

src/quantity_quality/                  Python package
data/reference_examples.json           Canonical reference examples
data/reference_examples.csv            Spreadsheet export
data/quantity_quality_record.schema.json
                                       JSON Schema for interoperable records
examples/adoption_records.csv          Cleaning example
examples/process_heat_comparison.json  Scenario comparison example
docs/adoption-cookbook.md              Practical adoption recipes
paper/                                 Framework paper

Development

python -m pip install -e ".[all,dev]"
python -m pytest -q
python -m build

The package is typed:

py.typed

and built as a pure Python wheel.


Citation

If you use this framework, examples, or code, please cite:

@misc{dimurro2026quantityquality,
  title  = {Quantity and Quality: A Standard Reporting Framework for Energy Systems},
  author = {DiMurro, Christopher},
  year   = {2026},
  note   = {Independent Researcher, Exergy Lab}
}

After the arXiv version is available, replace this with the arXiv citation.

Machine-readable citation metadata is in CITATION.cff. GitHub renders a formatted citation from it via the Cite this repository button in the repository sidebar.


Contributing

Issues and pull requests are welcome, particularly:

  • Reference examples for carriers or processes not yet covered, with a stated boundary, basis, and source. New examples belong in data/reference_examples.json and should come with a test.
  • Corrections to any published number. If a reference value here is wrong, that is the most valuable issue you can file — please include the working, not just the corrected value.
  • Adoption reports: what broke when you pointed this at a real dataset.

Before opening a pull request:

python -m pip install -e ".[all,dev]"
python -m pytest -q

CI runs the test suite and a package build on Python 3.9 through 3.13.


Related

exergyfactor.com Browser calculator built on this package's reference data. No install required.
cdimurro/exergy-factor Source for that site.

License

MIT © 2026 Christopher DiMurro

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quantity_and_quality-0.7.0.tar.gz (71.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quantity_and_quality-0.7.0-py3-none-any.whl (71.6 kB view details)

Uploaded Python 3

File details

Details for the file quantity_and_quality-0.7.0.tar.gz.

File metadata

  • Download URL: quantity_and_quality-0.7.0.tar.gz
  • Upload date:
  • Size: 71.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for quantity_and_quality-0.7.0.tar.gz
Algorithm Hash digest
SHA256 4c8651513b30ec5cc80d8c24855a1fa4cdcbec02fea581ff4a8f46f7fff8cf00
MD5 adfef9289203942275b1cc52de361e16
BLAKE2b-256 4c3750f886e0b93143651b96cd510762b5824e7bc4b2adb4fc655551c2b980fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for quantity_and_quality-0.7.0.tar.gz:

Publisher: publish.yml on cdimurro/quantity-and-quality

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file quantity_and_quality-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for quantity_and_quality-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9d95c6ce1e7e748404bc8c8415292e09c40e4bc798aecc3c45da71a1378fca58
MD5 5af80f70f55be517bb1ed77cd658b654
BLAKE2b-256 137f61c5818cc7121bafeee3024dd61b43a63160a141ac617415073fffcb89be

See more details on using hashes here.

Provenance

The following attestation bundles were made for quantity_and_quality-0.7.0-py3-none-any.whl:

Publisher: publish.yml on cdimurro/quantity-and-quality

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page