import logging
from typing import List
import numpy as np
-from scipy.optimize import fsolve
from abc import abstractmethod
import matplotlib.pyplot as plt
@@ -151,35 +145,6 @@ Source code for vclibpy.flowsheets.base
[docs] def get_all_components(self) -> List[BaseComponent]:
return [self.condenser, self.evaporator]
-[docs] def get_start_condensing_pressure(self, inputs: Inputs):
-
T_3_start = inputs.T_con_in + inputs.dT_con_subcooling
-
p_2_start = self.med_prop.calc_state("TQ", T_3_start, 0).p
-
return p_2_start
-
-[docs] def improve_first_condensing_guess(self, inputs: Inputs, m_flow_guess, p_2_guess, dT_pinch_assumption=0):
-
self.condenser.m_flow_secondary = inputs.m_flow_con # [kg/s]
-
self.condenser.calc_secondary_cp(T=inputs.T_con_in)
-
-
def nonlinear_func(p_2, *args):
-
_flowsheet, _inputs, _m_flow_ref, _dT_pinch = args
-
state_q0 = _flowsheet.med_prop.calc_state("PQ", p_2, 0)
-
state_q1 = _flowsheet.med_prop.calc_state("PQ", p_2, 1)
-
state_3 = _flowsheet.med_prop.calc_state("PT", p_2, state_q0.T - _inputs.dT_con_subcooling)
-
Q_water_till_q1 = (state_q1.h - state_3.h) * _m_flow_ref
-
T_water_q1 = _inputs.T_con_in + Q_water_till_q1 / _flowsheet.condenser.m_flow_secondary_cp
-
return T_water_q1 + _dT_pinch - state_q1.T
-
-
p_2_guess_optimized = fsolve(
-
func=nonlinear_func,
-
x0=p_2_guess,
-
args=(self, inputs, m_flow_guess, dT_pinch_assumption)
-
)[0]
-
return p_2_guess_optimized
-
-[docs] def get_start_evaporating_pressure(self, inputs: Inputs, dT_pinch: float = 0):
-
T_1_start = inputs.T_eva_in - inputs.dT_eva_superheating - dT_pinch
-
return self.med_prop.calc_state("TQ", T_1_start, 1).p
-
[docs] def calc_steady_state(self, inputs: Inputs, fluid: str = None, **kwargs):
"""
Calculate the steady-state performance of a vapor compression cycle
@@ -235,22 +200,15 @@
Source code for vclibpy.flowsheets.base
# Settings
min_iteration_step = kwargs.pop("min_iteration_step", 1)
save_path_plots = kwargs.get("save_path_plots", None)
+ input_name = ";".join([k + "=" + str(np.round(v.value, 3)).replace(".", "_")
+ for k, v in inputs.get_variables().items()])
show_iteration = kwargs.get("show_iteration", False)
use_quick_solver = kwargs.pop("use_quick_solver", True)
err_ntu = kwargs.pop("max_err_ntu", 0.5)
err_dT_min = kwargs.pop("max_err_dT_min", 0.1)
max_num_iterations = kwargs.pop("max_num_iterations", 1e5)
- dT_pinch_con_guess = kwargs.pop("dT_pinch_con_guess", 0)
- dT_pinch_eva_guess = kwargs.pop("dT_pinch_eva_guess", 0)
- improve_first_condensing_guess = kwargs.pop("improve_first_condensing_guess", False)
p_1_history = []
p_2_history = []
- error_con_history = []
- error_eva_history = []
- dT_eva_history = []
- dT_con_history = []
- error_con, dT_min_eva, dT_min_con, error_eva = np.NAN, np.NAN, np.NAN, np.NAN
- plot_last = -100
if use_quick_solver:
step_p1 = kwargs.get("step_max", 10000)
@@ -265,15 +223,19 @@ Source code for vclibpy.flowsheets.base
self.setup_new_fluid(fluid)
# First: Iterate with given conditions to get the 4 states and the mass flow rate:
- p_1_next = self.get_start_evaporating_pressure(inputs=inputs, dT_pinch=dT_pinch_eva_guess)
- p_2_next = self.get_start_condensing_pressure(inputs=inputs)
+ T_1_start = inputs.T_eva_in - inputs.dT_eva_superheating
+ T_3_start = inputs.T_con_in + inputs.dT_con_subcooling
+ p_1_start = self.med_prop.calc_state("TQ", T_1_start, 1).p
+ p_2_start = self.med_prop.calc_state("TQ", T_3_start, 0).p
+ p_1_next = p_1_start
+ p_2_next = p_2_start
fs_state = FlowsheetState() # Always log what is happening in the whole flowsheet
fs_state.set(name="Q_con", value=1, unit="W", description="Condenser heat flow rate")
fs_state.set(name="COP", value=0, unit="-", description="Coefficient of performance")
if show_iteration:
- fig_iterations, ax_iterations = plt.subplots(3, 2, sharex=True)
+ fig_iterations, ax_iterations = plt.subplots(2)
num_iterations = 0
@@ -290,29 +252,13 @@ Source code for vclibpy.flowsheets.base
p_1 = p_1_next
p_2 = p_2_next
- p_1_history.append(p_1 / 1e5)
- p_2_history.append(p_2 / 1e5)
- error_con_history.append(error_con)
- error_eva_history.append(error_eva)
- dT_con_history.append(dT_min_con)
- dT_eva_history.append(dT_min_eva)
-
+ p_1_history.append(p_1)
+ p_2_history.append(p_2)
if show_iteration:
- for ax in ax_iterations.flatten():
- ax.clear()
- iterations = list(range(len(p_1_history)))[plot_last:]
- ax_iterations[0, 0].set_ylabel("error_eva in %")
- ax_iterations[0, 1].set_ylabel("error_con in %")
- ax_iterations[1, 0].set_ylabel("$\Delta T_\mathrm{Min}$ in K")
- ax_iterations[1, 1].set_ylabel("$\Delta T_\mathrm{Min}$ in K")
- ax_iterations[2, 0].set_ylabel("$p_1$ in bar")
- ax_iterations[2, 1].set_ylabel("$p_2$ in bar")
- ax_iterations[0, 0].scatter(iterations, error_eva_history[plot_last:])
- ax_iterations[0, 1].scatter(iterations, error_con_history[plot_last:])
- ax_iterations[1, 0].scatter(iterations, dT_eva_history[plot_last:])
- ax_iterations[1, 1].scatter(iterations, dT_con_history[plot_last:])
- ax_iterations[2, 0].scatter(iterations, p_1_history[plot_last:])
- ax_iterations[2, 1].scatter(iterations, p_2_history[plot_last:])
+ ax_iterations[0].cla()
+ ax_iterations[1].cla()
+ ax_iterations[0].scatter(list(range(len(p_1_history))), p_1_history)
+ ax_iterations[1].scatter(list(range(len(p_2_history))), p_2_history)
plt.draw()
plt.pause(1e-5)
@@ -334,31 +280,18 @@ Source code for vclibpy.flowsheets.base
step_p1 /= 10
continue
+ # Calculate the states based on the given flowsheet
try:
- error_eva, dT_min_eva, error_con, dT_min_con = self.calculate_cycle_for_pressures(
- p_1=p_1, p_2=p_2, inputs=inputs, fs_state=fs_state
- )
+ self.calc_states(p_1, p_2, inputs=inputs, fs_state=fs_state)
except ValueError as err:
logger.error("An error occurred while calculating states. "
"Can't guess next pressures, thus, exiting: %s", err)
return
+ if save_path_plots is not None and num_iterations == 1 and show_iteration:
+ self.plot_cycle(save_path=save_path_plots.joinpath(f"{input_name}_initialization.png"), inputs=inputs)
- if num_iterations == 1:
- if improve_first_condensing_guess:
- p_2_next = self.improve_first_condensing_guess(
- inputs=inputs,
- m_flow_guess=self.condenser.m_flow,
- p_2_guess=p_2,
- dT_pinch_assumption=dT_pinch_con_guess
- )
-
- if save_path_plots is not None and show_iteration:
- input_name = inputs.get_name()
- self.plot_cycle(
- save_path=save_path_plots.joinpath(f"{input_name}_initialization.png"),
- inputs=inputs
- )
-
+ # Check heat exchangers:
+ error_eva, dT_min_eva = self.evaporator.calc(inputs=inputs, fs_state=fs_state)
if not isinstance(error_eva, float):
print(error_eva)
if error_eva < 0:
@@ -374,6 +307,7 @@ Source code for vclibpy.flowsheets.base
p_1_next = p_1 + step_p1
continue
+ error_con, dT_min_con = self.condenser.calc(inputs=inputs, fs_state=fs_state)
if error_con < 0:
p_2_next = p_2 + step_p2
continue
@@ -413,92 +347,13 @@ Source code for vclibpy.flowsheets.base
if show_iteration:
plt.close(fig_iterations)
- return self.calculate_outputs_for_valid_pressures(
- p_1=p_1, p_2=p_2, inputs=inputs, fs_state=fs_state,
- save_path_plots=save_path_plots
- )
-
-[docs] def calc_steady_state_fsolve(self, inputs: Inputs, fluid: str = None, **kwargs):
-
# Settings
-
max_err = kwargs.pop("max_err_ntu", 0.5)
-
-
save_path_plots = kwargs.get("save_path_plots", None)
-
dT_pinch_eva_guess = kwargs.pop("dT_pinch_eva_guess", 0)
-
-
# Setup fluid:
-
if fluid is None:
-
fluid = self.fluid
-
self.setup_new_fluid(fluid)
-
-
# First: Iterate with given conditions to get the 4 states and the mass flow rate:
-
p_1_next = self.get_start_evaporating_pressure(inputs=inputs, dT_pinch=dT_pinch_eva_guess)
-
p_2_next = self.get_start_condensing_pressure(inputs=inputs)
-
-
def nonlinear_func(x, *args):
-
_flowsheet, _inputs, _fs_state, _max_err = args
-
_p_1, _p_2 = x
-
if not (_p_1 < _p_2 < self._p_max):
-
return 1000, 1000
-
if not (self._p_min < _p_1 < _p_2):
-
return 1000, 1000
-
_error_eva, dT_min_eva, _error_con, dT_min_con = _flowsheet.calculate_cycle_for_pressures(
-
p_1=x[0], p_2=x[1], inputs=_inputs, fs_state=_fs_state
-
)
-
-
if 0 <= _error_eva < _max_err:
-
_error_eva = 0
-
if 0 <= _error_con < _max_err:
-
_error_con = 0
-
if 0 > _error_eva:
-
_error_eva *= 5
-
if 0 > _error_con:
-
_error_con *= 5
-
return _error_eva, _error_con
-
-
fs_state = FlowsheetState() # Always log what is happening in the whole flowsheet
-
try:
-
args = (self, inputs, fs_state, max_err)
-
p_optimized = fsolve(
-
func=nonlinear_func,
-
x0=np.array([p_1_next, p_2_next]),
-
args=args
-
)
-
except Exception as err:
-
logger.error("An error occurred while calculating states using fsolve: %s", err)
-
return
-
error_con, error_eva = nonlinear_func(p_optimized, *args)
-
print(f"{error_con=}, {error_eva=}")
-
-
p_1, p_2 = p_optimized
-
return self.calculate_outputs_for_valid_pressures(
-
p_1=p_1, p_2=p_2, inputs=inputs, fs_state=fs_state,
-
save_path_plots=save_path_plots
-
)
-
-[docs] def calculate_cycle_for_pressures(self, p_1: float, p_2: float, inputs: Inputs, fs_state: FlowsheetState):
-
# Calculate the states based on the given flowsheet
-
self.calc_states(p_1, p_2, inputs=inputs, fs_state=fs_state)
-
# Check heat exchangers:
-
error_eva, dT_min_eva = self.evaporator.calc(inputs=inputs, fs_state=fs_state)
-
error_con, dT_min_con = self.condenser.calc(inputs=inputs, fs_state=fs_state)
-
return error_eva, dT_min_eva, error_con, dT_min_con
-
-[docs] def calculate_outputs_for_valid_pressures(
-
self,
-
p_1,
-
p_2,
-
fs_state: FlowsheetState,
-
inputs: Inputs,
-
save_path_plots
-
):
-
self.calc_states(p_1, p_2, inputs=inputs, fs_state=fs_state)
# Calculate the heat flow rates for the selected states.
Q_con = self.condenser.calc_Q_flow()
Q_con_outer = self.condenser.calc_secondary_Q_flow(Q_con)
Q_eva = self.evaporator.calc_Q_flow()
Q_eva_outer = self.evaporator.calc_secondary_Q_flow(Q_eva)
-
error_con, dT_min_con = self.condenser.calc(inputs=inputs, fs_state=fs_state)
-
error_eva, dT_min_eva = self.evaporator.calc(inputs=inputs, fs_state=fs_state)
+
self.evaporator.calc(inputs=inputs, fs_state=fs_state)
+
self.condenser.calc(inputs=inputs, fs_state=fs_state)
P_el = self.calc_electrical_power(fs_state=fs_state, inputs=inputs)
T_con_out = inputs.T_con_in + Q_con_outer / self.condenser.m_flow_secondary_cp
@@ -538,24 +393,8 @@
Source code for vclibpy.flowsheets.base
name="COP_outer", value=COP_outer,
unit="-", description="Outer COP, including heat losses"
)
- fs_state.set(
- name="error_con", value=error_con,
- unit="%", description="Error in condenser heat exchanger model"
- )
- fs_state.set(
- name="error_eva", value=error_eva,
- unit="%", description="Error in evaporator heat exchanger model"
- )
- fs_state.set(
- name="dT_min_eva", value=dT_min_eva,
- unit="K", description="Evaporator pinch temperature"
- )
- fs_state.set(
- name="dT_min_con", value=dT_min_con,
- unit="K", description="Condenser pinch temperature"
- )
+
if save_path_plots is not None:
- input_name = inputs.get_name()
self.plot_cycle(save_path=save_path_plots.joinpath(f"{input_name}_final_result.png"), inputs=inputs)
return fs_state
diff --git a/docs/4-add-validation-based-on-optihorst/docs/_modules/vclibpy/flowsheets/standard.html b/docs/10_jupyter_notebook_compressor_model/docs/_modules/vclibpy/flowsheets/standard.html
similarity index 97%
rename from docs/4-add-validation-based-on-optihorst/docs/_modules/vclibpy/flowsheets/standard.html
rename to docs/10_jupyter_notebook_compressor_model/docs/_modules/vclibpy/flowsheets/standard.html
index fbc3267..556864a 100644
--- a/docs/4-add-validation-based-on-optihorst/docs/_modules/vclibpy/flowsheets/standard.html
+++ b/docs/10_jupyter_notebook_compressor_model/docs/_modules/vclibpy/flowsheets/standard.html
@@ -1,3 +1,5 @@
+
+
@@ -9,15 +11,11 @@
-
-
-
-
-
-
-
+
+
+
+
+
@@ -34,9 +32,6 @@
vclibpy
-
- 0.1
-