Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c80c5d8
Migrate costing metrics from valorization_costing_block
Apr 21, 2026
4245fd4
Update watertap/costing/watertap_costing_package.py
luohezhiming May 5, 2026
3f5b256
Update watertap/costing/watertap_costing_package.py
luohezhiming May 5, 2026
4a697a7
Update watertap/costing/watertap_costing_package.py
luohezhiming May 5, 2026
13b5060
Update watertap/costing/watertap_costing_package.py
luohezhiming May 5, 2026
95034fe
add general metrics
luohezhiming May 14, 2026
e4df958
Merge branch 'main' into migrate_valorization_costing_block
luohezhiming May 14, 2026
3796227
delete redundant comments
luohezhiming May 14, 2026
c1ad3f8
delete redundant comment
luohezhiming May 14, 2026
f7565b7
Merge branch 'main' into migrate_valorization_costing_block
tristantc Jul 2, 2026
58df86b
Refactor flow component breakdown methods and enhance documentation f…
tristantc Jul 2, 2026
d834d32
Keep `add_LCOW` as a thin wrapper around the generic helper `add_leve…
tristantc Jul 2, 2026
5d280a4
Refactor levelized-cost helper: rename for reuse, improve docs
tristantc Jul 2, 2026
040f3d5
Refactor flow component breakdown: update flow units and improve meth…
tristantc Jul 2, 2026
612ecbc
Refactor flow unit calculations
tristantc Jul 2, 2026
a3e3c27
Refactor annual water production calculation: replace expression with…
tristantc Jul 2, 2026
6caae27
Refactor `add_specific_electrical_carbon_intensity`: enhance flow bas…
tristantc Jul 2, 2026
97a6db4
Refactor `add_flow_component`: improve documentation and add validati…
tristantc Jul 2, 2026
14eda46
Add unit-consistency checks for `flow_rate` vs `flow_basis` in costin…
tristantc Jul 16, 2026
69d1a1b
add valueeffor for mismatch
luohezhiming Jul 16, 2026
773d0f9
Merge branch 'main' into migrate_valorization_costing_block
luohezhiming Jul 16, 2026
c07ff13
Merge branch 'migrate_valorization_costing_block' of https://github.c…
luohezhiming Jul 16, 2026
a08dbb5
Fix method name for flow component breakdowns in WaterTAPCostingBlock…
tristantc Jul 16, 2026
e41f96e
Refactor flow component breakdown methods in WaterTAPCostingBlockData…
tristantc Jul 16, 2026
da8a317
Fix argument order in add_flow_component_breakdown for NaCl usage in …
tristantc Jul 16, 2026
55830d0
docs: fix argument order in `add_flow_component_breakdown` examples a…
tristantc Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/how_to_guides/how_to_use_watertap_costing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,13 @@ Additional details on the WaterTAP costing package, including equations and defa
m.fs.product.properties[0].flow_vol_phase["Liq"], name="SEC"
)
m.fs.costing.add_flow_component_breakdown(
"bazchem",
"bazchem",
m.fs.product.properties[0].flow_vol_phase["Liq"],
period=pyunits.hr,
)
m.fs.costing.add_flow_component_breakdown(
"electricity",
"electricity",
m.fs.product.properties[0].flow_vol_phase["Liq"],
period=pyunits.hr,
Expand Down
6 changes: 3 additions & 3 deletions docs/technical_reference/costing/costing_base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ The total operating cost is the sum of the fixed and variable operating costs:

C_{op,tot} = C_{op,fix} + C_{op,var}

The total fixed operating cost :math:`C_{op,fix}` is the sum of the maintence, labor, and chemical operating costs, :math:`C_{mlc}`, and the total fixed operating costs from the unit models, :math:`C_{fop,u}`:
The total fixed operating cost :math:`C_{op,fix}` is the sum of the maintenance, labor, and chemical operating costs, :math:`C_{mlc}`, and the total fixed operating costs from the unit models, :math:`C_{fop,u}`:

.. math::

Expand Down Expand Up @@ -492,7 +492,7 @@ For a given registered flow type :math:`x` the flow component breakdown :math:`\
\text{FCB}_{u} = \frac{F_{x,u} M_f}{Q_p}

Where :math:`F_{x,u}` is the flow of :math:`x` from source :math:`u`, :math:`M_f` is an optional multiplier, and :math:`Q_p` is a specified volumetric flow rate.
:math:`M_f` must have units that, when multipled with the units for :math:`F_{x,u}`, result in a rate (i.e., units per time). For example, if the flow rate was electricity (units of kW),
:math:`M_f` must have units that, when multiplied with the units for :math:`F_{x,u}`, result in a rate (i.e., units per time). For example, if the flow rate was electricity (units of kW),
the multiplier could be a electrical carbon intensity (units of kg/kWh) and the resulting units would be kg/hr.

The method has two required arguments and three optional arguments:
Expand All @@ -509,7 +509,7 @@ an expression ``m.fs.costing.bazchem_flow_component`` indexed to every unit that
.. code-block:: python

m.fs.costing.add_flow_component_breakdown(
"bazchem", flow_rate, name="bazchem_flow", period=pyunits.hour
"bazchem", "bazchem_flow", flow_rate, period=pyunits.hour
)

.. note::
Expand Down
102 changes: 81 additions & 21 deletions watertap/costing/tests/test_costing_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,36 @@ def test_breakdowns():
m.fs.costing.add_specific_electrical_carbon_intensity(
m.fs.product.properties[0].flow_vol
)
# Tests for performance indices introduced from valorization_costing_block
m.fs.costing.add_levelized_cost(
sum(
m.fs.product.properties[0].flow_mass_phase_comp["Liq", comp]
for comp in m.fs.properties.component_list
),
flow_basis="mass",
name="LCOP",
)
m.fs.costing.add_levelized_cost(
m.fs.product.properties[0].flow_vol,
flow_basis="volumetric",
Comment on lines +161 to +162

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add test to check what happens when flow basis is different from actual variable supplied (e.g., flow_vol, flow_basis="mass")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

name="LCOT",
)
m.fs.costing.add_specific_energy_consumption(
sum(
m.fs.product.properties[0].flow_mass_phase_comp["Liq", comp]
for comp in m.fs.properties.component_list
),
flow_basis="mass",
name="specific_energy_consumption_with_product",
)
m.fs.costing.add_annual_total(
sum(
m.fs.product.properties[0].flow_mass_phase_comp["Liq", comp]
for comp in m.fs.properties.component_list
),
flow_basis="mass",
name="annual_product_generation",
)

assert_units_consistent(m)

Expand Down Expand Up @@ -188,31 +218,61 @@ def test_breakdowns():


@pytest.mark.component
def test_breakdowns_with_no_unit():
def test_flow_basis_mismatch():
m = lsrro.build()

m.fs.BoosterPumps[:].control_volume.work[0.0].value = 42e6
m.fs.EnergyRecoveryDevices[:].control_volume.work[0.0].value = -42e6
m.fs.electricity_flow_with_no_unit = pyo.Var(units=pyo.units.kW, initialize=1234)
comp = next(iter(m.fs.properties.component_list))

m.fs.costing.cost_flow(m.fs.electricity_flow_with_no_unit, "electricity")
# flow_vol supplied but flow_basis says "mass"
with pytest.raises(
ValueError,
match=r"flow_basis was set to 'mass', but the supplied flow_rate "
r".*flow_vol.* appears to be a 'volumetric' flow \(matched on "
r"'flow_vol'\)\. Please check that flow_basis matches the flow_rate "
r"provided\.",
):
m.fs.costing.add_levelized_cost(
m.fs.product.properties[0].flow_vol,
flow_basis="mass",
name="LCOW_mismatch",
)

m.fs.costing.add_flow_component_breakdown(
"electricity",
m.fs.product.properties[0].flow_vol,
period=pyo.units.year,
)
assert hasattr(m.fs.costing, "electricity_component")
assert (
"fs.electricity_flow_with_no_unit"
in m.fs.costing.electricity_component.index_set()
)
# flow_mass_phase_comp supplied but flow_basis says "volumetric"
with pytest.raises(
ValueError,
match=r"flow_basis was set to 'volumetric', but the supplied flow_rate "
r".*flow_mass_phase_comp.* appears to be a 'mass' flow \(matched on "
r"'flow_mass'\)\. Please check that flow_basis matches the flow_rate "
r"provided\.",
):
m.fs.costing.add_specific_energy_consumption(
m.fs.product.properties[0].flow_mass_phase_comp["Liq", comp],
flow_basis="volumetric",
name="specific_energy_consumption_mismatch",
)

m.fs.costing.add_flow_component_breakdown(
"electricity",
# flow_vol supplied but flow_basis says "energy"
with pytest.raises(
ValueError,
match=r"flow_basis was set to 'energy', but the supplied flow_rate "
r".*flow_vol.* appears to be a 'volumetric' flow \(matched on "
r"'flow_vol'\)\. Please check that flow_basis matches the flow_rate "
r"provided\.",
):
m.fs.costing.add_annual_total(
m.fs.product.properties[0].flow_vol,
flow_basis="energy",
name="annual_total_mismatch",
)

# matching flow_basis and flow_rate should not raise
m.fs.costing.add_levelized_cost(
m.fs.product.properties[0].flow_vol,
name="biff",
period=pyo.units.millisecond,
flow_basis="volumetric",
name="LCOW_ok",
)
m.fs.costing.add_annual_total(
m.fs.product.properties[0].flow_mass_phase_comp["Liq", comp],
flow_basis="mass",
name="annual_total_ok",
)
assert hasattr(m.fs.costing, "biff_component")
assert "fs.electricity_flow_with_no_unit" in m.fs.costing.biff_component.index_set()
Loading
Loading