Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f52db5e
add crystallizer flowsheet
ElmiraShamlou Aug 20, 2024
2b16d2e
modifications
ElmiraShamlou Aug 21, 2024
bd85f8a
modifies costig
ElmiraShamlou Aug 22, 2024
deef8f9
modifies steam heater
ElmiraShamlou Aug 22, 2024
f4d56c0
modifies chiller
ElmiraShamlou Aug 22, 2024
b790eab
add revised crystallizer model
ElmiraShamlou Sep 11, 2024
45d86d0
add purge to MVR config
ElmiraShamlou Sep 12, 2024
2358454
add chiller for crystallizer vapor condensation
ElmiraShamlou Oct 1, 2024
eb4acd6
transfer revised crystallizer model to the original crystallizer mode…
ElmiraShamlou Oct 1, 2024
1dbff4e
Merge branch 'main' into cryst_flowsheet
ElmiraShamlou Dec 11, 2024
06b28b1
Merge branch 'main' into cryst_flowsheet
ElmiraShamlou Jan 15, 2025
700ceba
add TVC flowsheet
ElmiraShamlou Mar 25, 2025
2f194b9
Merge branch 'main' into cryst_flowsheet
ksbeattie May 1, 2025
cda4538
Running black
ksbeattie May 1, 2025
c371077
Merge branch 'main' of https://github.com/watertap-org/watertap into …
ElmiraShamlou Aug 27, 2025
70eebef
add notebook
ElmiraShamlou Sep 1, 2025
cdc11c1
add sweep analysis and modifies notebook distillate and steam calcula…
ElmiraShamlou Sep 2, 2025
6790efc
use steam cost on global param block in costing package
adam-a-a Sep 3, 2025
a69ba45
change steam costing to match watertap conventions for other material…
kurbansitterley Sep 12, 2025
79a1d0c
Merge branch 'main' into cryst_flowsheet
kurbansitterley Sep 12, 2025
fd2c875
black
kurbansitterley Sep 12, 2025
3d2a9ab
Merge branch 'cryst_flowsheet' of https://github.com/elmirashamlou/wa…
kurbansitterley Sep 12, 2025
7bfd853
change sweep variables to match changes
kurbansitterley Sep 12, 2025
2a277de
black
kurbansitterley Dec 8, 2025
461199f
Merge branch 'main' into cryst_flowsheet
kurbansitterley Dec 8, 2025
3823dbf
fix linting
kurbansitterley Dec 9, 2025
46d3057
linting
kurbansitterley Dec 9, 2025
4297103
linting
kurbansitterley Dec 9, 2025
92a8dac
linting and add header
kurbansitterley Dec 9, 2025
297c953
clean up display
kurbansitterley Dec 9, 2025
caa4582
test main for crystallizer_live_steam_with_condenser_chiller
kurbansitterley Dec 9, 2025
db3e9d4
clean up display
kurbansitterley Dec 9, 2025
7543db6
rename
kurbansitterley Dec 9, 2025
ab83ae1
rename
kurbansitterley Dec 9, 2025
98fe627
test main on crystallizer_MVR
kurbansitterley Dec 9, 2025
c84db42
clean up display func
kurbansitterley Dec 9, 2025
e067503
test crystallizer TVC main
kurbansitterley Dec 9, 2025
139deb1
convert capital_cost to base_currency
kurbansitterley Dec 9, 2025
c8e251d
fs and test mods necessary from changing compressor costing method
kurbansitterley Dec 9, 2025
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
39 changes: 21 additions & 18 deletions watertap/costing/unit_models/compressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@


def build_compressor_cost_param_block(blk):
blk.unit_cost = pyo.Var(
initialize=7364,
doc="Compressor unit cost (El-Sayed et al., 2001)",
units=pyo.units.USD_2001,
blk.unit_cost_intercept = pyo.Param(
initialize=580000,
doc="Compressor cost intercept for centrifugal compressors (USD)",
units=pyo.units.USD_2010,
)

blk.exponent = pyo.Var(
initialize=0.7,
doc="Compressor exponent (El-Sayed et al., 2001)",
units=pyo.units.dimensionless,
blk.unit_cost_slope = pyo.Param(
initialize=20000,
doc="Compressor cost slope for centrifugal compressors (USD/kW^0.6)",
units=pyo.units.USD_2010 / pyo.units.kW**0.6,
)


Expand All @@ -35,21 +35,24 @@ def build_compressor_cost_param_block(blk):
def cost_compressor(blk, cost_electricity_flow=True):
make_capital_cost_var(blk)
blk.costing_package.add_cost_factor(blk, "TIC")

compressor_power_kW = pyo.units.convert(
blk.unit_model.control_volume.work[0], to_units=pyo.units.kW
)

blk.capital_cost_constraint = pyo.Constraint(
expr=blk.capital_cost
== blk.cost_factor
* pyo.units.convert(
blk.costing_package.compressor.unit_cost
* blk.unit_model.control_volume.properties_in[0].flow_mass_phase_comp[
"Vap", "H2O"
] # Add a convert to kg/s
/ (pyo.units.kg / pyo.units.s)
* blk.unit_model.pressure_ratio
* (blk.unit_model.efficiency / (1 - blk.unit_model.efficiency))
** blk.costing_package.compressor.exponent,
== pyo.units.convert(
blk.cost_factor
* (
blk.costing_package.compressor.unit_cost_intercept
+ blk.costing_package.compressor.unit_cost_slope
* compressor_power_kW**0.6
),
to_units=blk.costing_package.base_currency,
)
)

if cost_electricity_flow:
blk.costing_package.cost_flow(
pyo.units.convert(
Expand Down
53 changes: 15 additions & 38 deletions watertap/costing/unit_models/crystallizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ class CrystallizerCostType(StrEnum):
volume_basis = "volume_basis"


def build_nacl_recovered_cost_param_block(blk):

blk.cost = pyo.Var(
initialize=0,
units=pyo.units.USD_2018 / pyo.units.kg,
doc="Unit recovery value of NaCl",
)
blk.parent_block().register_flow_type("NaCl_recovered", blk.cost)


def build_crystallizer_cost_param_block(blk):

blk.steam_pressure = pyo.Var(
Expand Down Expand Up @@ -80,22 +90,6 @@ def build_crystallizer_cost_param_block(blk):
units=pyo.units.dimensionless,
)

blk.steam_cost = pyo.Var(
initialize=0.004,
units=pyo.units.USD_2018 / (pyo.units.meter**3),
doc="Steam cost, Panagopoulos (2019)",
)

blk.NaCl_recovery_value = pyo.Var(
initialize=0,
units=pyo.units.USD_2018 / pyo.units.kg,
doc="Unit recovery value of NaCl",
)

costing = blk.parent_block()
costing.register_flow_type("steam", blk.steam_cost)
costing.register_flow_type("NaCl", blk.NaCl_recovery_value)


def cost_crystallizer(blk, cost_type=CrystallizerCostType.default):
"""
Expand All @@ -120,34 +114,17 @@ def cost_crystallizer(blk, cost_type=CrystallizerCostType.default):


def _cost_crystallizer_flows(blk):
blk.costing_package.cost_flow(
pyo.units.convert(
(
blk.unit_model.magma_circulation_flow_vol
* blk.unit_model.dens_mass_slurry
* Constants.acceleration_gravity
* blk.costing_package.crystallizer.pump_head_height
/ blk.costing_package.crystallizer.efficiency_pump
),
to_units=pyo.units.kW,
),
"electricity",
)

blk.costing_package.cost_flow(
pyo.units.convert(
(blk.unit_model.work_mechanical[0] / _compute_steam_properties(blk)),
to_units=pyo.units.m**3 / pyo.units.s,
),
"steam",
)
Comment on lines -123 to -143
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious about why these lines are being deleted. I probably didn't look closely enough, but have they been moved elsewhere or completely removed? And why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@adam-a-a They are removed as we integrate the steam heater, pump, and other essential components into the full FC crystallizer flowsheet. Therefore, the flow rates of the steam and recycle streams, along with their associated costs, are incorporated within the cost calculations of the steam heater and pump unit models.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ElmiraShamlou but removing this hinders whoever wants to use the combined unit we had previously.

Maybe what we need is a configuration argument that determines the mode the user wants (broken down or combined), and then adds the necessary equations for each case?


blk.costing_package.cost_flow(
blk.unit_model.solids.flow_mass_phase_comp[0, "Sol", "NaCl"],
"NaCl",
"NaCl_recovered",
)


@register_costing_parameter_block(
build_rule=build_nacl_recovered_cost_param_block,
parameter_block_name="NaCl_recovered",
)
@register_costing_parameter_block(
build_rule=build_crystallizer_cost_param_block,
parameter_block_name="crystallizer",
Expand Down
23 changes: 15 additions & 8 deletions watertap/costing/unit_models/heat_exchanger.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
from ..util import register_costing_parameter_block, make_capital_cost_var


def build_steam_cost_param_block(blk):

blk.cost = pyo.Var(
initialize=0.00,
units=pyo.units.USD_2018 / (pyo.units.kg),
doc="Steam cost per kg",
)

blk.parent_block().register_flow_type("steam", blk.cost)


def build_heat_exchanger_cost_param_block(blk):

blk.unit_cost = pyo.Var(
Expand All @@ -28,15 +39,11 @@ def build_heat_exchanger_cost_param_block(blk):
units=pyo.units.dimensionless,
)

blk.steam_cost = pyo.Var(
initialize=0.008,
units=pyo.units.USD_2018 / (pyo.units.kg),
doc="steam cost per kg",
)

blk.parent_block().register_flow_type("steam", blk.steam_cost)


@register_costing_parameter_block(
build_rule=build_steam_cost_param_block,
parameter_block_name="steam",
)
@register_costing_parameter_block(
build_rule=build_heat_exchanger_cost_param_block,
parameter_block_name="heat_exchanger",
Expand Down
14 changes: 4 additions & 10 deletions watertap/costing/unit_models/steam_ejector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,14 @@ def build_steam_ejector_cost_param_block(blk):
blk.base_cost = pyo.Var(
initialize=1949,
doc="Base cost coefficient for steam ejector",
units=pyo.units.USD_2020,
units=pyo.units.USD_2018,
)
blk.cost_exponent = pyo.Var(
initialize=0.3,
doc="Cost scaling exponent",
units=pyo.units.dimensionless,
)

blk.steam_cost = pyo.Var(
initialize=0.008,
units=pyo.units.USD_2018 / pyo.units.kg,
doc="Steam cost per kg",
)

blk.parent_block().register_flow_type("steam", blk.steam_cost)


@register_costing_parameter_block(
build_rule=build_steam_ejector_cost_param_block,
Expand Down Expand Up @@ -57,12 +49,14 @@ def cost_steam_ejector(blk, cost_steam_flow=False):
to_units=pyo.units.kg / pyo.units.hour,
)

dimensionless_flow = (S + EV) / (pyo.units.kg / pyo.units.hour)

blk.capital_cost_constraint = pyo.Constraint(
expr=blk.capital_cost
== blk.cost_factor
* pyo.units.convert(
blk.costing_package.steam_ejector.base_cost
* (S + EV) ** blk.costing_package.steam_ejector.cost_exponent,
* dimensionless_flow**blk.costing_package.steam_ejector.cost_exponent,
to_units=blk.costing_package.base_currency,
)
)
Expand Down
24 changes: 15 additions & 9 deletions watertap/costing/unit_models/surrogate_crystallizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@
)


def build_steam_cost_param_block(blk):

blk.cost = pyo.Var(
initialize=0.004,
units=pyo.units.USD_2018 / pyo.units.m**3,
doc="Steam cost per m^3",
)

blk.parent_block().register_flow_type("steam", blk.cost)


def build_surrogate_crystallizer_cost_param_block(blk):

blk.steam_pressure = pyo.Var(
Expand Down Expand Up @@ -62,15 +73,6 @@ def build_surrogate_crystallizer_cost_param_block(blk):
units=pyo.units.dimensionless,
)

blk.steam_cost = pyo.Var(
initialize=0.004,
units=pyo.units.USD_2018 / (pyo.units.meter**3),
doc="Steam cost, Panagopoulos (2019)",
)

costing = blk.parent_block()
costing.register_flow_type("steam", blk.steam_cost)


def cost_surrogate_crystallizer(blk):
"""
Expand All @@ -90,6 +92,10 @@ def _cost_crystallizer_flows(blk):
)


@register_costing_parameter_block(
build_rule=build_steam_cost_param_block,
parameter_block_name="steam",
)
@register_costing_parameter_block(
build_rule=build_surrogate_crystallizer_cost_param_block,
parameter_block_name="surrogate_crystallizer",
Expand Down
Loading
Loading