Skip to content

Assessment (cost and LCA)

The assessment layer computes cost and life-cycle impact as functions of a solved, verified state (see Cost estimation and LCA). It is a Python library layer: the CLI, HTTP and MCP interfaces do not offer it yet. A typical sequence, as in the cost and climate impact example:

from openflowsheet.application.revision_binding import bind_revision_flowsheet
from openflowsheet.assessment.program import AssessmentProgram
from openflowsheet.assessment.spec import load_assessment
from openflowsheet.assessment.views import view_of
from openflowsheet.canonical import state_sha256

binding = bind_revision_flowsheet(revision)          # the solved revision document
program = AssessmentProgram.build(
    view_of(binding.flowsheet), binding.spec, load_assessment(document), state
)
report = program.report(state, state_sha256=state_sha256(state, binding.spec.variable_ids))

revision and state are the revision.json and solution-state.json of the run's replay bundle. Unsupported requests come back as a typed Refusal; they are not raised.

The document

load_assessment

load_assessment(
    source: Mapping[str, Any] | str | Path,
) -> AssessmentSpec

An AssessmentSpec from a document or a JSON file; AssessmentDocumentError otherwise.

Parameters:

Name Type Description Default
source Mapping[str, Any] | str | Path

The assessment document (schemas/assessment.schema.json), or the path of a JSON file holding it. A mapping is deep-copied; the caller's object is never kept.

required

Returns:

Type Description
AssessmentSpec

The validated document and its identity, assessment_sha256 (the canonical hash).

Raises:

Type Description
AssessmentDocumentError

When the document has no canonical JSON form or does not validate against the schema; errors lists every reason.

AssessmentSpec dataclass

AssessmentSpec(
    document: Mapping[str, Any], assessment_sha256: str
)

A validated assessment document and its identity. The document is a private deep copy.

section

section(name: str) -> Any

A top-level section, or None when the document does not have it.

AssessmentDocumentError

AssessmentDocumentError(errors: list[str])

Bases: ValueError

The document is not a valid, canonical assessment; errors lists every reason.

The flowsheet's view

view_of

view_of(
    flowsheet: RevisionFlowsheet | Syn001Flowsheet,
) -> FlowsheetView

The assessment's view of a bound flowsheet.

Parameters:

Name Type Description Default
flowsheet RevisionFlowsheet | Syn001Flowsheet

A bound revision flowsheet (bind_revision_flowsheet(document).flowsheet) or the SYN-001 flowsheet.

required

Returns:

Type Description
FlowsheetView

The components, the property provider, the units with their ports and connections, and the molar masses: everything the contributors read, and nothing they could change.

Raises:

Type Description
TypeError

For any other kind of flowsheet.

The program

AssessmentProgram

AssessmentProgram(
    *,
    ctx: BuildContext,
    contributors: tuple[Contributor, ...],
    rows: tuple[_Row, ...],
    output_count: int,
    theta: tuple[Theta, ...],
    blocks: tuple[
        tuple[PropertyBlock, tuple[str, ...]], ...
    ],
    entries: tuple[RegimeEntry, ...],
    plans: Mapping[str, ContributionPlan],
)

One assessment over one host at one held regime (§4.1, §4.2.1).

The outputs (sizes, costs, inventory, impacts, derived ratios) are rows of one functional ProblemSpec over the host's variables, compiled by the existing compiler and never part of the host's CompiledProblem. Build one with AssessmentProgram.build; then evaluate, linearize and report it at a state.

build classmethod

build(
    view: FlowsheetView,
    host_spec: ProblemSpec,
    spec: AssessmentSpec,
    state: Mapping[str, float],
    regime: Regime | None = None,
    *,
    contributors: Sequence[Contributor] | None = None,
) -> AssessmentProgram | Refusal

Plan every contributor at state and compile the functional spec (§4.2.1).

regime=None selects by the rule at state. A given regime is held: every one of its entries must be one the program has, and every admissibility row must be ≥ −τ_feas at state, else ASSESSMENT_REGIME_INADMISSIBLE. contributors defaults to the three of CONTRIBUTOR_ORDER; a document section whose contributor is not among them is refused ASSESSMENT_CONTRIBUTOR_MISSING(<section>), never silently ignored (R-869).

Parameters:

Name Type Description Default
view FlowsheetView

The flowsheet's view, view_of(flowsheet).

required
host_spec ProblemSpec

The host's problem specification (a revision binding's spec).

required
spec AssessmentSpec

The assessment document, load_assessment(...).

required
state Mapping[str, float]

The solved state by variable id, normally a certified solution.

required
regime Regime | None

A regime to hold, or None to select one by the rule at state.

None
contributors Sequence[Contributor] | None

The contributors to plan; by default the registered cost, LCA and derived ones.

None

Returns:

Type Description
AssessmentProgram or Refusal

The program, or a typed refusal; an unsupported request is never raised.

evaluate

evaluate(
    x: Mapping[str, float],
    decisions: Mapping[str, float] = MappingProxyType({}),
    *,
    domain_guard: bool = True,
) -> Mapping[str, float] | Refusal

Every output and admissibility row at (x, d) on the float path (§4.2.1).

Raises TwinEvaluationError where a value cannot be evaluated (§4.2.3), including a domain row ≤ 0: METRIC_UNDEFINED(<output_id>) at every state (§4.7.5 erratum, R-868). domain_guard=False is the report's alone: it nulls each undefined output itself and reports the others (§4.9).

Parameters:

Name Type Description Default
x Mapping[str, float]

The state by host variable id.

required
decisions Mapping[str, float]

Host pinned inputs at other values than the program's; an assessment parameter is refused UNSUPPORTED(ASSESSMENT_PARAMETER_DECISION).

MappingProxyType({})
domain_guard bool

Raise on an undefined output (see above); True except in the report.

True

Returns:

Type Description
Mapping[str, float] or Refusal

Every output and every admissibility row (adm.*) by id; units in units.

linearize

linearize(
    x: Mapping[str, float],
    decisions: Mapping[str, float],
    outputs: Sequence[str],
    symbolic: Sequence[str] = (),
) -> Linearization | Refusal

Values (twin) of every row, and ∂(outputs)/∂x (outputs x host variable ids) and ∂(outputs)/∂p (outputs x symbolic), at (x, d). The decisions are symbols of the twin whether or not they are requested, so the graph is the one the NLP differentiates.

Parameters:

Name Type Description Default
x Mapping[str, float]

The state by host variable id.

required
decisions Mapping[str, float]

Host pinned inputs at other values than the program's (may be empty).

required
outputs Sequence[str]

The output ids to differentiate.

required
symbolic Sequence[str]

Host pinned inputs or assessment parameters (theta ids) to differentiate by.

()

Returns:

Type Description
Linearization or Refusal

values (every row), d_dx and d_dp as sparse matrices; a refusal for an unknown or unavailable output, or for an assessment parameter given as a decision.

report

report(
    x: Mapping[str, float],
    *,
    state_sha256: str,
    uncertainty: bool = True,
) -> dict[str, Any]

The assessment report at x (§4.2.1, §4.9, §4.11): a document valid against assessment-report.schema.json. Built by assessment.report.build_report.

Parameters:

Name Type Description Default
x Mapping[str, float]

The state by host variable id.

required
state_sha256 str

The state's identity (openflowsheet.canonical.state_sha256), recorded in the report.

required
uncertainty bool

Whether to propagate the declared input ranges (first-order interval and σ).

True

Returns:

Type Description
dict

The report: status, regime, items, capital, operating and annual figures, LCA inventory and impacts, uncertainty, limitations, refusals and the evidence statement.

select

select(
    x: Mapping[str, float],
    decisions: Mapping[str, float] = MappingProxyType({}),
    *,
    release: Sequence[str] = (),
) -> Regime

The regime at x (§4.3.2): the held choice of every entry whose admissibility rows are ≥ −τ_feas at x, the rule for the others. A held regime that cannot be evaluated at x is released whole.

decisions are host pins at other values than the program's (a study's candidate, §4.10.3 V7): the rows and the rule then read them. release gives entries to the rule whatever their rows — V7's dormancy entries, which have none (§4.3.1).

Refusal dataclass

Refusal(
    code: str,
    target: str = "",
    detail: str = "",
    kind: Literal["refusal", "unsupported"] = "refusal",
)

A typed refusal (or an unsupported result): never an exception to the caller (§4.12).

Limitation dataclass

Limitation(
    code: str,
    target: str = "",
    detail: Mapping[str, Any] = dict(),
)

A typed limitation of a computed result (§4.12).

build_report

build_report(
    program: AssessmentProgram,
    x: Mapping[str, float],
    *,
    state_sha256: str,
    uncertainty: bool = True,
) -> dict[str, Any]

The report at x (§4.11); provenance is outside every hash.

Parameters:

Name Type Description Default
program AssessmentProgram

The assessment program.

required
x Mapping[str, float]

The state by host variable id.

required
state_sha256 str

The state's identity, recorded in the report.

required
uncertainty bool

Whether to propagate the declared input ranges.

True

Returns:

Type Description
dict

A document valid against schemas/assessment-report.schema.json.

Sensitivities

assessment_sensitivity

assessment_sensitivity(
    program: AssessmentProgram,
    host: SensitivityHost,
    request: SensitivityRequest,
    state: NDArray[float64],
    outputs: Sequence[str],
    certificate: CertificateEvidence | None = None,
    *,
    scales: Mapping[str, float] | None = None,
    splits: Sequence[SplitRegime] = (),
) -> AssessmentSensitivity

§4.10.1: dy/dp of the assessment outputs (ids without the prefix) at the certified state (in host.spec.variable_ids order) for request's parameters and mode.

scales gives an output's scale; by default max(|y(x*)|, 1) (§4.10.2's output scale). A refusal of program.linearize (an unavailable or unknown output) is returned with no host run. Raises ValueError when the program's host variables are not the host's.

Parameters:

Name Type Description Default
program AssessmentProgram

The assessment program, built over the same host problem.

required
host SensitivityHost

The sensitivity host, e.g. revision_sensitivity_host(flowsheet, state).

required
request SensitivityRequest

The parameters, the host outputs and the mode (forward, adjoint or both).

required
state NDArray[float64]

The certified state, in host.spec.variable_ids order.

required
outputs Sequence[str]

The assessment output ids, without the assessment: prefix.

required
certificate CertificateEvidence | None

The certificate's evidence, passed to the host's qualification.

None
scales Mapping[str, float] | None

Output scales; by default max(|y(x*)|, 1).

None
splits Sequence[SplitRegime]

Split regimes, passed to the host's evaluation.

()

Returns:

Type Description
AssessmentSensitivity

dy/dp per output (rows) and parameter (columns), the host's own result, refusals, active regime bounds and limitations.

Raises:

Type Description
ValueError

When the program was built over a different host problem.

AssessmentSensitivity dataclass

AssessmentSensitivity(
    outputs: tuple[str, ...],
    parameter_ids: tuple[str, ...],
    scales: Mapping[str, float],
    dependence: Mapping[str, Dependence],
    forward: SensitivityBlock | None,
    adjoint: SensitivityBlock | None,
    base: SensitivityResult | None,
    refusals: tuple[Refusal, ...] = (),
    regime_bounds_active: tuple[
        tuple[str, float], ...
    ] = (),
    regime_slack: Mapping[str, float | None] = dict(),
    limitations: tuple[Limitation, ...] = (),
)

dy/dp of the requested assessment outputs (rows) over the request's parameters (columns), forward and/or adjoint as the request's mode; None where the host's column, or the whole request, is refused. base is the host's result for the augmented request (its own outputs first, then assessment:<id> for every state-dependent output).

revision_sensitivity_host

revision_sensitivity_host(
    flowsheet: Any, state: Mapping[str, float]
) -> SensitivityHost

syn001.host_of for a RevisionFlowsheet: flowsheet.spec(), its compiled problem, K03 scales from the spec's declared kinds, and the alias rows eliminate_alias_rows removes at state with the pressure-shifted second state of the certificate (verify/certificate.py; without a second state the elimination is structural, as there).

trf_objective_from_assessment

trf_objective_from_assessment(
    program: AssessmentProgram, output_id: str
) -> Refusal

The only route from an assessment output to a trust-region objective (§4.10.4). Day one: UNSUPPORTED(ASSESSMENT_OUTPUT_IN_TRF), before anything is built or solved (A37; §7 Q1).

Building unit-score tables (the lca extra)

These functions run only where bw2data and bw2calc are installed; without them each returns UNSUPPORTED(LCA_ENGINE_UNAVAILABLE). They never run inside a solve, an optimisation or a replay.

available

available() -> bool

Whether bw2data and bw2calc import (no project is touched).

build_unit_score_table

build_unit_score_table(
    project: str,
    activities: Sequence[tuple[str, Sequence[str]]],
    categories: Sequence[tuple[str, Sequence[str]]],
    rights: Mapping[str, str],
    *,
    table_id: str,
    si_per_unit: Mapping[str, float] | None = None,
) -> dict[str, Any] | Refusal

A unit-score-table-v1 of q_{m,k} for activities [(activity_id, key)] and categories [(category_id, method)] in project (§4.8.4).

si_per_unit gives an activity's unit in SI where SI_PER_UNIT does not know its unit. A key or a method the project lacks is refused LCA_ACTIVITY_UNKNOWN (never raised).

Parameters:

Name Type Description Default
project str

The Brightway project, prepared by the user (no database is downloaded).

required
activities Sequence[tuple[str, Sequence[str]]]

(activity_id, key) pairs: the id the assessment document uses, and the activity's Brightway key.

required
categories Sequence[tuple[str, Sequence[str]]]

(category_id, method) pairs: the id the document uses, and the LCIA method tuple.

required
rights Mapping[str, str]

The table's rights: class (open or user-licensed), licence, redistribution (allowed or forbidden) and notice.

required
table_id str

The new table's id.

required
si_per_unit Mapping[str, float] | None

SI amount per activity unit, for units the adapter does not know.

None

Returns:

Type Description
dict or Refusal

A unit-score-table-v1 document; UNSUPPORTED(LCA_ENGINE_UNAVAILABLE) without the lca extra.

build_direct_factor_table

build_direct_factor_table(
    project: str,
    method: tuple[str, Sequence[str]],
    flows: Sequence[tuple[str, Sequence[str]]],
    rights: Mapping[str, str],
    *,
    table_id: str,
    source: Mapping[str, Any] | None = None,
) -> dict[str, Any] | Refusal

A direct-factor-table-v1 of method (category_id, method)'s characterisation factors for flows [(flow_id, biosphere key)]; a flow the method does not characterise gets 0.0.

foreground_check

foreground_check(
    project: str,
    exchanges: Sequence[tuple[Sequence[str], float]],
    emissions: Sequence[tuple[Sequence[str], float]],
    method: Sequence[str],
) -> float | Refusal

Brightway's score of one foreground activity that consumes exchanges [(key, a_k)] (activity units; negative for generation or substitution) and emits emissions [(biosphere key, kg)], characterised by method (A25). Runs in a scratch copy of project, which is deleted afterwards.