Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add solar still ZLD unit model, costing model, test file #131

Merged
merged 49 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
5c752f8
create initial version of solar still model
kurbansitterley Jul 3, 2024
c0dde53
initial solar still costing model
kurbansitterley Jul 3, 2024
66cd2c7
Merge branch 'main' of https://github.com/kurbansitterley/watertap-se…
kurbansitterley Sep 30, 2024
23e15ec
add initial version of water_yield_calculation for solar still
kurbansitterley Sep 30, 2024
acbeac9
move to unit_models
kurbansitterley Sep 30, 2024
ec41747
initial ss test
kurbansitterley Sep 30, 2024
6e41c7d
rename costing pkg
kurbansitterley Sep 30, 2024
0028dc1
move and rename unit model file
kurbansitterley Oct 1, 2024
3f13d21
update ss costing pkg
kurbansitterley Oct 1, 2024
7ba5fb9
add ss test data
kurbansitterley Oct 1, 2024
9c2bfee
update ss test file, passing tests
kurbansitterley Oct 1, 2024
009ec07
black; add header
kurbansitterley Oct 1, 2024
542c0a1
stash
kurbansitterley Oct 7, 2024
6f0b4e1
Merge branch 'main' into solar_still
kurbansitterley Oct 8, 2024
bdcc6bb
Merge branch 'main' into solar_still
kurbansitterley Oct 9, 2024
e3a1b4b
Merge branch 'main' into solar_still
kurbansitterley Nov 15, 2024
db0d828
Merge branch 'solar_still' of https://github.com/kurbansitterley/wate…
kurbansitterley Nov 15, 2024
789a26c
create SS ZLD water yield calc
kurbansitterley Nov 15, 2024
48a40f6
fix test
kurbansitterley Nov 15, 2024
d97545c
clean up; create prop funcs
kurbansitterley Nov 15, 2024
7798330
checkpoint
kurbansitterley Nov 16, 2024
ab7361f
create sw_props utility file
kurbansitterley Nov 16, 2024
50e07d0
clean up water yield calcs
kurbansitterley Nov 16, 2024
de22bb1
blackification
kurbansitterley Nov 16, 2024
e85b6d7
zld checkpoint
kurbansitterley Nov 17, 2024
ddb5304
use ZLD water yield calc
kurbansitterley Nov 17, 2024
c3a9874
update water yield to ZLD
kurbansitterley Nov 17, 2024
687f57f
update tests
kurbansitterley Nov 17, 2024
be9a688
update err msg
kurbansitterley Nov 18, 2024
660f0d5
add cost per still eq
kurbansitterley Nov 18, 2024
3b101a4
updated water yield calc
kurbansitterley Nov 18, 2024
f9afc04
updated for new costing and water yield calc
kurbansitterley Nov 18, 2024
0df7d16
black
kurbansitterley Nov 19, 2024
6604a34
rename test data
kurbansitterley Nov 20, 2024
cff59de
add data with diff col name test
kurbansitterley Nov 20, 2024
d8ad9a6
update to scaled approach
kurbansitterley Nov 20, 2024
643f2bf
clean up
kurbansitterley Nov 20, 2024
40ab976
Merge branch 'main' into solar_still
kurbansitterley Nov 21, 2024
d666426
add to blk
kurbansitterley Nov 21, 2024
1c04667
Merge branch 'main' into solar_still
kurbansitterley Nov 22, 2024
a6b5d7d
Merge branch 'solar_still' of https://github.com/kurbansitterley/wate…
kurbansitterley Nov 22, 2024
b14aa18
remove print
kurbansitterley Nov 22, 2024
83a819b
black
kurbansitterley Dec 4, 2024
ef8e809
fix negative amb temp > sky temp issue
kurbansitterley Dec 6, 2024
7dddcf9
everything as array
kurbansitterley Dec 6, 2024
1bf85f1
initialize arr; cleanup
kurbansitterley Dec 6, 2024
71eca22
add length_zld_cycle Expression
kurbansitterley Dec 6, 2024
5eb6179
more checking for negatives
kurbansitterley Dec 6, 2024
71a748d
remove arrays :(
kurbansitterley Dec 6, 2024
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
397 changes: 397 additions & 0 deletions src/watertap_contrib/reflo/costing/units/solar_still.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,397 @@
#################################################################################
# WaterTAP Copyright (c) 2020-2024, The Regents of the University of California,
# through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory,
# National Renewable Energy Laboratory, and National Energy Technology
# Laboratory (subject to receipt of any required approvals from the U.S. Dept.
# of Energy). All rights reserved.
#
# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license
# information, respectively. These files are also available online at the URL
# "https://github.com/watertap-org/watertap/"
#################################################################################

import pyomo.environ as pyo
from watertap.costing.util import register_costing_parameter_block
from watertap_contrib.reflo.costing.util import (
make_capital_cost_var,
make_fixed_operating_cost_var,
)


def build_solar_still_cost_param_block(blk):

blk.cost_solar_still = pyo.Var(
initialize=40,
units=pyo.units.USD_2020 / pyo.units.m**2,
bounds=(0, None),
doc="Cost of solar still per unit area",
)

blk.cost_saltwater_pump = pyo.Var(
initialize=750,
units=pyo.units.USD_2020,
bounds=(0, None),
doc="Cost of single saltwater pump",
)

blk.cost_freshwater_pump = pyo.Var(
initialize=150,
units=pyo.units.USD_2020,
bounds=(0, None),
doc="Cost of single freshwater pump",
)

blk.cost_piping = pyo.Var(
initialize=1.5,
bounds=(0, None),
units=pyo.units.USD_2020 / pyo.units.ft,
doc="CPVC pipe per linear foot",
)

blk.pipe_length_param = pyo.Var(
initialize=1.5,
bounds=(0, None),
units=pyo.units.dimensionless,
doc="Pipe length equation parameter",
)
blk.cost_feed_tank_base = pyo.Var(
initialize=1601.1,
bounds=(0, None),
units=pyo.units.USD_2020,
doc="Feed tank capital equation base",
)

blk.cost_feed_tank_exp = pyo.Var(
initialize=0.6373,
units=pyo.units.dimensionless,
doc="Feed tank capital equation exponent",
)

blk.cost_dist_tank_base = pyo.Var(
initialize=1680.8,
units=pyo.units.USD_2020,
doc="Distillate tank capital equation base",
)

blk.cost_dist_tank_exp = pyo.Var(
initialize=0.6085,
units=pyo.units.dimensionless,
doc="Distillate tank capital equation exponent",
)

blk.cost_underground_tank_base = pyo.Var(
initialize=411.78,
units=pyo.units.USD_2020,
doc="Underground tank capital equation base",
)

blk.cost_underground_tank_exp = pyo.Var(
initialize=0.8693,
units=pyo.units.dimensionless,
doc="Underground tank capital equation exponent",
)

blk.cost_excavation_base = pyo.Var(
initialize=646.33,
bounds=(0, None),
units=pyo.units.USD_2020,
doc="Cost excavation base",
)

blk.cost_excavation_exp = pyo.Var(
initialize=0.624,
bounds=(0, None),
units=pyo.units.dimensionless,
doc="Cost excavation exponent",
)

blk.fixed_opex_factor = pyo.Var(
initialize=0.035,
bounds=(0, None),
units=pyo.units.year**-1,
doc="Factor for calculating fixed operating costs as a fraction of CAPEX",
)
blk.fix_all_vars()


@register_costing_parameter_block(
build_rule=build_solar_still_cost_param_block,
parameter_block_name="solar_still",
)
def cost_solar_still(blk):
ss_params = blk.costing_package.solar_still
ss = blk.unit_model
base_currency = blk.config.flowsheet_costing_block.base_currency
base_period = blk.config.flowsheet_costing_block.base_period
make_capital_cost_var(blk)
make_fixed_operating_cost_var(blk)

dimensionless_water_yield = pyo.units.convert(
ss.annual_water_yield * pyo.units.m**-1,
to_units=pyo.units.dimensionless,
)

blk.pressure_drop = pyo.Param(
initialize=1,
mutable=True,
units=pyo.units.bar,
doc="Pressure drop for pumps",
)

blk.max_sw_flow = pyo.Param(
initialize=1728,
mutable=True,
units=pyo.units.m**3 / pyo.units.day,
doc="Saltwater pump flow rate",
)

blk.max_fw_flow = pyo.Param(
initialize=86.4,
mutable=True,
units=pyo.units.m**3 / pyo.units.day,
doc="Freshwater pump flow rate",
)

blk.sw_pump_efficiency = pyo.Param(
initialize=0.8,
mutable=True,
units=pyo.units.dimensionless,
doc="Saltwater pump efficiency",
)

blk.fw_pump_efficiency = pyo.Param(
initialize=0.8,
mutable=True,
units=pyo.units.dimensionless,
doc="Freshwater pump efficiency",
)

blk.number_sw_pumps = pyo.Param(
initialize=1,
mutable=True,
units=pyo.units.dimensionless,
doc="Number saltwater pumps",
)

blk.number_fw_pumps = pyo.Param(
initialize=1,
mutable=True,
units=pyo.units.dimensionless,
doc="Number freshwater pumps",
)

blk.sw_pump_power = pyo.Var(
initialize=1,
bounds=(0, None),
units=pyo.units.kilowatt,
doc="Saltwater pumping power per pump",
)

blk.fw_pump_power = pyo.Var(
initialize=1,
bounds=(0, None),
units=pyo.units.kilowatt,
doc="Freshwater pumping power per pump",
)

blk.pumping_power_required = pyo.Var(
initialize=1,
bounds=(0, None),
units=pyo.units.kilowatt,
doc="Total pumping power required",
)

blk.length_piping = pyo.Var(
initialize=1,
bounds=(0, None),
units=pyo.units.ft,
doc="Length of CPVC piping",
)

blk.capital_cost_solar_still = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of solar stills",
)

blk.capital_cost_sw_pumps = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of saltwater pumps",
)

blk.capital_cost_fw_pumps = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of freshwater pumps",
)

blk.capital_cost_feed_tank = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of feed tank",
)

blk.capital_cost_distillate_tank = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of distillate tank",
)

blk.capital_cost_underground_tank = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of underground tank",
)

blk.capital_cost_excavation = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of excavation",
)

blk.capital_cost_piping = pyo.Var(
initialize=1,
bounds=(0, None),
units=base_currency,
doc="Capital cost of piping",
)

blk.sw_pump_power_constraint = pyo.Constraint(
expr=blk.sw_pump_power
== pyo.units.convert(
(blk.pressure_drop * blk.max_sw_flow) / blk.sw_pump_efficiency,
to_units=pyo.units.kilowatt,
)
)

blk.fw_pump_power_constraint = pyo.Constraint(
expr=blk.fw_pump_power
== pyo.units.convert(
(blk.pressure_drop * blk.max_fw_flow) / blk.fw_pump_efficiency,
to_units=pyo.units.kilowatt,
)
)

blk.pumping_power_required_constraint = pyo.Constraint(
expr=blk.pumping_power_required
== blk.number_sw_pumps
* pyo.units.convert(blk.sw_pump_power, to_units=pyo.units.kilowatt)
+ blk.number_fw_pumps
* pyo.units.convert(blk.fw_pump_power, to_units=pyo.units.kilowatt)
)

blk.length_piping_constraint = pyo.Constraint(
expr=blk.length_piping
== pyo.units.convert(
ss_params.pipe_length_param * ss.number_stills * ss.length_basin,
to_units=pyo.units.ft,
)
)

capital_cost_expr = 0

blk.capital_cost_solar_still_constraint = pyo.Constraint(
expr=blk.capital_cost_solar_still
== pyo.units.convert(
ss.total_area * ss_params.cost_solar_still, to_units=base_currency
)
)

capital_cost_expr += blk.capital_cost_solar_still

blk.capital_cost_sw_pumps_constraint = pyo.Constraint(
expr=blk.capital_cost_sw_pumps
== pyo.units.convert(
blk.number_sw_pumps * ss_params.cost_saltwater_pump, to_units=base_currency
)
)

capital_cost_expr += blk.capital_cost_sw_pumps

blk.capital_cost_fw_pumps_constraint = pyo.Constraint(
expr=blk.capital_cost_fw_pumps
== pyo.units.convert(
blk.number_fw_pumps * ss_params.cost_freshwater_pump, to_units=base_currency
)
)

capital_cost_expr += blk.capital_cost_fw_pumps

blk.capital_cost_feed_tank_constraint = pyo.Constraint(
expr=blk.capital_cost_feed_tank
== pyo.units.convert(
ss_params.cost_feed_tank_base
* dimensionless_water_yield**ss_params.cost_feed_tank_exp,
to_units=base_currency,
)
)

capital_cost_expr += blk.capital_cost_feed_tank

blk.capital_cost_distillate_tank_constraint = pyo.Constraint(
expr=blk.capital_cost_distillate_tank
== pyo.units.convert(
ss_params.cost_dist_tank_base
* dimensionless_water_yield**ss_params.cost_dist_tank_exp,
to_units=base_currency,
)
)

capital_cost_expr += blk.capital_cost_distillate_tank

blk.capital_cost_underground_tank_constraint = pyo.Constraint(
expr=blk.capital_cost_underground_tank
== pyo.units.convert(
ss_params.cost_underground_tank_base
* dimensionless_water_yield**ss_params.cost_underground_tank_exp,
to_units=base_currency,
)
)

capital_cost_expr += blk.capital_cost_underground_tank

blk.capital_cost_excavation_constraint = pyo.Constraint(
expr=blk.capital_cost_excavation
== pyo.units.convert(
ss_params.cost_excavation_base
* dimensionless_water_yield**ss_params.cost_excavation_exp,
to_units=base_currency,
)
)

capital_cost_expr += blk.capital_cost_excavation

blk.capital_cost_piping_constraint = pyo.Constraint(
expr=blk.capital_cost_piping
== pyo.units.convert(
blk.length_piping * ss_params.cost_piping,
to_units=base_currency,
)
)

capital_cost_expr += blk.capital_cost_piping

blk.costing_package.add_cost_factor(blk, "TIC")

blk.capital_cost_constraint = pyo.Constraint(
expr=blk.capital_cost
== pyo.units.convert(capital_cost_expr, to_units=base_currency)
)

blk.fixed_operating_cost_constraint = pyo.Constraint(
expr=blk.fixed_operating_cost
== pyo.units.convert(
blk.capital_cost * ss_params.fixed_opex_factor,
to_units=base_currency / base_period,
)
)

blk.costing_package.cost_flow(blk.pumping_power_required, "electricity")
Loading