-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 28b8fba
Showing
19 changed files
with
1,067 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Setup and Test | ||
|
||
on: push | ||
|
||
jobs: | ||
build: | ||
name: Setup | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
python-version: ["3.8", "3.9"] | ||
defaults: | ||
run: | ||
shell: bash | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v1 | ||
- name: Setup python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v1 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Upgrade pip | ||
run: python -m pip install --upgrade pip | ||
- name: Install Poetry | ||
uses: snok/[email protected] | ||
- name: Install project | ||
run: poetry install | ||
- name: Test | ||
run: poetry run doit | ||
- name: Upload output | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: output-${{ matrix.os }}-py${{ matrix.python-version }} | ||
path: output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
*.egg-info/ | ||
.doit.* | ||
.pytest_cache/ | ||
.vscode/ | ||
__pycache__/ | ||
dist/ | ||
build/ | ||
output/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Copyright (c) 2022 Big Ladder Software, LLC | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
|
||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
chiller | ||
======= | ||
|
||
A python package for modeling chillers. | ||
|
||
Purposes: | ||
|
||
1. Comparing models | ||
2. Generating ASHRAE 205 compliant representations | ||
3. Calculating standard efficiency ratings (e.g., for AHRI 510/550) | ||
|
||
Development setup | ||
----------------- | ||
|
||
Requirements: | ||
|
||
1. Python 3.8+ | ||
2. [Poetry](https://python-poetry.org/) | ||
|
||
Project setup: `poetry install` | ||
|
||
Testing: `poetry run doit` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .chiller import Chiller | ||
from .units import fr_u, to_u |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
from chiller.fluid_properties import FluidState | ||
from .conditions import AHRI_550_590_WATER_COOLED_CONDITIONS, AHRI_550_590_WATER_COOLED_CONDENSER_OUTLET, AHRI_550_590_WATER_COOLED_EVAPORATOR_INLET, OperatingConditions | ||
from .models.energyplus_eir import EnergyPlusEIR | ||
from .units import fr_u | ||
from numpy import linspace | ||
|
||
class Chiller: | ||
def __init__( | ||
self, | ||
model=EnergyPlusEIR(), | ||
rated_net_evaporator_capacity=fr_u(100.0,"ton_ref"), | ||
rated_cop=2.0, | ||
cycling_degradation_coefficient=0.0, | ||
standby_power=0.0, | ||
number_of_compressor_speeds=None, | ||
minimum_evaporator_leaving_temperature=fr_u(39.0,"°F"), | ||
maximum_evaporator_leaving_temperature=fr_u(60.0,"°F"), | ||
minimum_condenser_entering_temperature=fr_u(55.0,"°F"), | ||
maximum_condenser_entering_temperature=fr_u(104.0,"°F"), | ||
**kwargs): | ||
|
||
self.kwargs = kwargs | ||
|
||
self.model = model | ||
|
||
self.number_of_compressor_speeds = number_of_compressor_speeds | ||
|
||
self.model.set_system(self) | ||
|
||
self.rated_net_evaporator_capacity = rated_net_evaporator_capacity | ||
self.rated_cop = rated_cop | ||
self.cycling_degradation_coefficient = cycling_degradation_coefficient | ||
self.standby_power = standby_power | ||
|
||
self.minimum_evaporator_leaving_temperature = minimum_evaporator_leaving_temperature | ||
self.maximum_evaporator_leaving_temperature = maximum_evaporator_leaving_temperature | ||
self.minimum_condenser_entering_temperature = minimum_condenser_entering_temperature | ||
self.maximum_condenser_entering_temperature = maximum_condenser_entering_temperature | ||
|
||
self.set_rated_evaporator_volumetric_flow_rate() | ||
self.set_rated_condenser_volumetric_flow_rate() | ||
|
||
def net_evaporator_capacity(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return self.model.net_evaporator_capacity(conditions) | ||
|
||
def input_power(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return self.model.input_power(conditions) | ||
|
||
def net_condenser_capacity(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return self.model.net_condenser_capacity(conditions) | ||
|
||
def oil_cooler_heat(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return self.model.oil_cooler_heat(conditions) | ||
|
||
def auxiliary_heat(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return self.model.auxiliary_heat(conditions) | ||
|
||
def cop(self, conditions=None): | ||
return self.net_evaporator_capacity(conditions)/self.input_power(conditions) | ||
|
||
def condenser_liquid_leaving_temperature(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return conditions.condenser_inlet.T + self.net_condenser_capacity(conditions)/(conditions.condenser_inlet.get_cp()*conditions.condenser_inlet.m_dot) | ||
|
||
def evaporator_liquid_entering_temperature(self, conditions=None): | ||
if conditions == None: | ||
conditions = AHRI_550_590_WATER_COOLED_CONDITIONS | ||
return conditions.evaporator_outlet.T + self.net_evaporator_capacity(conditions)/(conditions.evaporator_outlet.get_cp()*conditions.evaporator_outlet.m_dot) | ||
|
||
def space_loss_heat(self, conditions=None): | ||
return (self.input_power(conditions) + self.net_evaporator_capacity(conditions)) - (self.net_condenser_capacity(conditions) + self.oil_cooler_heat(conditions) + self.auxiliary_heat(conditions)) | ||
|
||
def set_rated_evaporator_volumetric_flow_rate(self): | ||
delta_T = AHRI_550_590_WATER_COOLED_EVAPORATOR_INLET.T - AHRI_550_590_WATER_COOLED_CONDITIONS.evaporator_outlet.T | ||
m_dot = self.net_evaporator_capacity()/(AHRI_550_590_WATER_COOLED_CONDITIONS.evaporator_outlet.get_cp()*delta_T) | ||
AHRI_550_590_WATER_COOLED_CONDITIONS.evaporator_outlet.set_m_dot(m_dot) | ||
AHRI_550_590_WATER_COOLED_EVAPORATOR_INLET.set_m_dot(m_dot) | ||
self.rated_evaporator_volumetric_flow_rate = AHRI_550_590_WATER_COOLED_CONDITIONS.evaporator_outlet.V_dot | ||
|
||
def set_rated_condenser_volumetric_flow_rate(self): | ||
delta_T = AHRI_550_590_WATER_COOLED_CONDENSER_OUTLET.T - AHRI_550_590_WATER_COOLED_CONDITIONS.condenser_inlet.T | ||
m_dot = self.net_condenser_capacity()/(AHRI_550_590_WATER_COOLED_CONDITIONS.condenser_inlet.get_cp()*delta_T) | ||
AHRI_550_590_WATER_COOLED_CONDITIONS.condenser_inlet.set_m_dot(m_dot) | ||
AHRI_550_590_WATER_COOLED_CONDENSER_OUTLET.set_m_dot(m_dot) | ||
self.rated_condenser_volumetric_flow_rate = AHRI_550_590_WATER_COOLED_CONDITIONS.condenser_inlet.V_dot | ||
|
||
def generate_205_performance(self): | ||
# Create conditions | ||
evaporator_liquid_volumetric_flow_rates = [self.rated_evaporator_volumetric_flow_rate] | ||
evaporator_liquid_leaving_temperatures = linspace(self.minimum_evaporator_leaving_temperature, self.maximum_evaporator_leaving_temperature, 4).tolist() | ||
condenser_liquid_volumetric_flow_rates = [self.rated_condenser_volumetric_flow_rate] | ||
condenser_liquid_entering_temperatures = linspace(self.minimum_condenser_entering_temperature, self.maximum_condenser_entering_temperature, 4).tolist() | ||
compressor_sequence_numbers = list(range(1,self.number_of_compressor_speeds + 1)) | ||
|
||
grid_variables = { | ||
"evaporator_liquid_volumetric_flow_rate": | ||
evaporator_liquid_volumetric_flow_rates, | ||
"evaporator_liquid_leaving_temperature": | ||
evaporator_liquid_leaving_temperatures, | ||
"condenser_liquid_volumetric_flow_rate": | ||
condenser_liquid_volumetric_flow_rates, | ||
"condenser_liquid_entering_temperature": | ||
condenser_liquid_entering_temperatures, | ||
"compressor_sequence_number": | ||
compressor_sequence_numbers | ||
} | ||
|
||
input_powers = [] | ||
net_evaporator_capacities = [] | ||
net_condenser_capacities = [] | ||
evaporator_liquid_entering_temperatures = [] | ||
condenser_liquid_leaving_temperatures = [] | ||
evaporator_liquid_differential_pressures = [] | ||
condenser_liquid_differential_pressures = [] | ||
oil_cooler_heats = [] | ||
auxiliary_heats = [] | ||
|
||
for v_evap in evaporator_liquid_volumetric_flow_rates: | ||
for t_evap in evaporator_liquid_leaving_temperatures: | ||
for v_cond in condenser_liquid_volumetric_flow_rates: | ||
for t_cond in condenser_liquid_entering_temperatures: | ||
for speed in [self.number_of_compressor_speeds - n for n in compressor_sequence_numbers]: | ||
conditions = OperatingConditions( | ||
evaporator_outlet=FluidState(temperature=t_evap, volumetric_flow_rate=v_evap), | ||
condenser_inlet=FluidState(temperature=t_cond, volumetric_flow_rate=v_cond), | ||
compressor_speed=speed) | ||
|
||
input_powers.append(self.input_power(conditions)) | ||
net_evaporator_capacities.append(self.net_evaporator_capacity(conditions)) | ||
net_condenser_capacities.append(self.net_condenser_capacity(conditions)) | ||
evaporator_liquid_entering_temperatures.append(self.evaporator_liquid_entering_temperature(conditions)) | ||
condenser_liquid_leaving_temperatures.append(self.condenser_liquid_leaving_temperature(conditions)) | ||
evaporator_liquid_differential_pressures.append(fr_u(15.,"kPa")) | ||
condenser_liquid_differential_pressures.append(fr_u(15.,"kPa")) | ||
oil_cooler_heats.append(self.oil_cooler_heat(conditions)) | ||
auxiliary_heats.append(self.auxiliary_heat(conditions)) | ||
|
||
performance_map_cooling = { | ||
"grid_variables": grid_variables, | ||
"lookup_variables": { | ||
"input_power": | ||
input_powers, | ||
"net_evaporator_capacity": | ||
net_evaporator_capacities, | ||
"net_condenser_capacity": | ||
net_condenser_capacities, | ||
"evaporator_liquid_entering_temperature": | ||
evaporator_liquid_entering_temperatures, | ||
"condenser_liquid_leaving_temperature": | ||
condenser_liquid_leaving_temperatures, | ||
"evaporator_liquid_differential_pressure": | ||
evaporator_liquid_differential_pressures, | ||
"condenser_liquid_differential_pressure": | ||
condenser_liquid_differential_pressures, | ||
"oil_cooler_heat": | ||
oil_cooler_heats, | ||
"auxiliary_heat": | ||
auxiliary_heats | ||
} | ||
} | ||
performance = { | ||
"evaporator_liquid_type": { # TODO: Make consistent with model | ||
"liquid_components": [ | ||
{ | ||
"liquid_constituent": "WATER", | ||
"concentration": 1.0, | ||
} | ||
], | ||
"concentration_type": "BY_VOLUME" | ||
}, | ||
"condenser_liquid_type": { # TODO: Make consistent with model | ||
"liquid_components": [ | ||
{ | ||
"liquid_constituent": "WATER", | ||
"concentration": 1.0, | ||
} | ||
], | ||
"concentration_type": "BY_VOLUME" | ||
}, | ||
"evaporator_fouling_factor": 0.0, | ||
"condenser_fouling_factor": 0.0, | ||
"compressor_speed_control_type": "CONTINUOUS", | ||
"maximum_power": max(input_powers), # Do something else? | ||
"cycling_degradation_coefficient": self.cycling_degradation_coefficient, | ||
"performance_map_cooling": performance_map_cooling, | ||
"performance_map_standby": { | ||
"grid_variables": { | ||
"environment_dry_bulb_temperature": [fr_u(20.0, "°C")], | ||
}, | ||
"lookup_variables": { | ||
"input_power": [self.standby_power], | ||
}, | ||
} | ||
} | ||
return performance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from .fluid_properties import FluidState | ||
from .units import fr_u | ||
|
||
class OperatingConditions: | ||
def __init__(self, condenser_inlet, evaporator_outlet, compressor_speed=0): | ||
self.condenser_inlet = condenser_inlet | ||
self.evaporator_outlet = evaporator_outlet | ||
self.compressor_speed = compressor_speed | ||
|
||
AHRI_550_590_WATER_COOLED_CONDITIONS = OperatingConditions(condenser_inlet=FluidState(fr_u(85.0,"°F")), evaporator_outlet=FluidState(fr_u(44.0,"°F"))) | ||
|
||
AHRI_550_590_WATER_COOLED_CONDENSER_OUTLET = FluidState(fr_u(94.3,"°F")) | ||
|
||
AHRI_550_590_WATER_COOLED_EVAPORATOR_INLET = FluidState(fr_u(54.0,"°F")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from re import S | ||
import CoolProp.CoolProp as CP | ||
from .units import fr_u | ||
|
||
class FluidState: | ||
def __init__(self, temperature, pressure=fr_u(1.0,"atm"), volumetric_flow_rate=None, fluid_name="Water"): | ||
self.fluid_name = fluid_name | ||
self.T = temperature | ||
self.p = pressure | ||
self.rho_set = False | ||
self.cp_set = False | ||
self.V_dot_set = False | ||
if volumetric_flow_rate is None: | ||
self.V_dot = None | ||
else: | ||
self.set_V_dot(volumetric_flow_rate) | ||
|
||
def get_rho(self): | ||
if not self.rho_set: | ||
self.rho = CP.PropsSI("D", "P", self.p, "T", self.T, self.fluid_name) | ||
self.rho_set = True | ||
return self.rho | ||
|
||
def get_cp(self): | ||
if not self.cp_set: | ||
self.cp = CP.PropsSI("C", "P", self.p, "T", self.T, self.fluid_name) | ||
self.cp_set = True | ||
return self.cp | ||
|
||
def set_V_dot(self, volumetric_flow_rate): | ||
self.V_dot = volumetric_flow_rate | ||
self.m_dot = self.V_dot*self.get_rho() | ||
self.V_dot_set = True | ||
|
||
def set_m_dot(self, mass_flow_rate): | ||
self.m_dot = mass_flow_rate | ||
self.V_dot = self.m_dot/self.get_rho() | ||
self.V_dot_set = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .energyplus_eir import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
class ChillerModel: | ||
def __init__(self): | ||
self.system = None | ||
self.allowed_kwargs = [] | ||
|
||
def set_system(self, system): | ||
self.system = system | ||
for kwarg in system.kwargs: | ||
if kwarg not in self.allowed_kwargs: | ||
raise Exception(f"Unrecognized key word argument: {kwarg}") | ||
|
||
def net_evaporator_capacity(self, conditions): | ||
raise NotImplementedError() | ||
|
||
def input_power(self, conditions): | ||
raise NotImplementedError | ||
|
||
def net_condenser_capacity(self, conditions): | ||
raise NotImplementedError() | ||
|
||
def oil_cooler_heat(self, conditions): | ||
raise NotImplementedError() | ||
|
||
def auxiliary_heat(self, conditions): | ||
raise NotImplementedError() |
Oops, something went wrong.