From 63fd509a3fbfcc714a64bd556ed88735bc52b61e Mon Sep 17 00:00:00 2001 From: ljz <425868052@qq.com> Date: Mon, 22 Jun 2026 15:40:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B4=A8=E9=87=8F=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brayton_cycle/__init__.py | 2 + brayton_cycle/components.py | 89 ++++++++++++++++++++++++++++++++++--- brayton_cycle/cycles.py | 49 ++++++++++++++++++++ 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/brayton_cycle/__init__.py b/brayton_cycle/__init__.py index f809fdf..6cdbf65 100644 --- a/brayton_cycle/__init__.py +++ b/brayton_cycle/__init__.py @@ -1,6 +1,7 @@ """Tools for CO2 Brayton cycle simulation and optimization.""" from .components import ( + ComponentMassMixin, Compressor, Concentrator, Condenser, @@ -26,6 +27,7 @@ from .sensitivity import ( __all__ = [ "BraytonCycle", + "ComponentMassMixin", "CO2PropertyCalculator", "Compressor", "Concentrator", diff --git a/brayton_cycle/components.py b/brayton_cycle/components.py index a89ddbb..8e0fe1a 100644 --- a/brayton_cycle/components.py +++ b/brayton_cycle/components.py @@ -1,8 +1,74 @@ # -*- coding: utf-8 -*- """Component models used by Brayton cycle simulations.""" -class Compressor(): + +class ComponentMassMixin: + """Shared mass-calculation interface for cycle components.""" + + component_type = "component" + + def _init_mass_interface(self): + self.mass = None + self.mass_variables = None + + def calculate_mass(self, mass_model=None, **kwargs): + """Calculate and store component mass. + + The future mass model can be provided as either a callable accepting + ``(component, **kwargs)`` or an object exposing ``calculate_mass`` or + ``calculate__mass``. + """ + if self.variables is None: + raise ValueError("Run component calculator before mass calculation") + + if mass_model is None: + result = self._calculate_mass(**kwargs) + else: + result = self._run_external_mass_model(mass_model, **kwargs) + + return self._store_mass_result(result) + + def mass_calculator(self, mass_model=None, **kwargs): + return self.calculate_mass(mass_model=mass_model, **kwargs) + + def _calculate_mass(self, **kwargs): + raise NotImplementedError( + f"{self.__class__.__name__} mass model is not implemented yet. " + "Pass a mass_model or override _calculate_mass()." + ) + + def _run_external_mass_model(self, mass_model, **kwargs): + method_name = f"calculate_{self.component_type}_mass" + if hasattr(mass_model, method_name): + return getattr(mass_model, method_name)(self, **kwargs) + if hasattr(mass_model, "calculate_mass"): + return mass_model.calculate_mass(self, **kwargs) + if callable(mass_model): + return mass_model(self, **kwargs) + raise TypeError("mass_model must be callable or expose a supported method") + + def _store_mass_result(self, result): + if isinstance(result, dict): + if "mass" in result: + mass = result["mass"] + elif "total_mass" in result: + mass = result["total_mass"] + else: + raise ValueError("Mass result dictionary must include 'mass'") + mass_variables = dict(result) + else: + mass = result + mass_variables = {"mass": result} + + self.mass = mass + self.mass_variables = mass_variables + self.variables["mass"] = self.mass + self.variables["mass_variables"] = self.mass_variables + return self.mass + +class Compressor(ComponentMassMixin): """压缩机类""" + component_type = "compressor" def __init__(self, name, eff): """ 初始化参数 @@ -18,6 +84,7 @@ class Compressor(): self.name = name self.eff = eff self.variables = None + self._init_mass_interface() def calculator(self, p_in, T_in, p_out, property_calculator): # 先计算熵值 @@ -51,8 +118,9 @@ class Compressor(): 'pi': p_out / p_in } -class Turbine(): +class Turbine(ComponentMassMixin): """透平类""" + component_type = "turbine" def __init__(self, name, eff): """ 初始化参数 @@ -62,6 +130,7 @@ class Turbine(): self.name = name self.eff = eff self.variables = None + self._init_mass_interface() def calculator(self, p_in, T_in, p_out, property_calculator): """涡轮参数计算""" @@ -94,8 +163,9 @@ class Turbine(): 'pi': p_in / p_out } -class Recuperator(): +class Recuperator(ComponentMassMixin): """换热器类""" + component_type = "recuperator" def __init__(self, name, eff, x=0): """ 初始化参数 @@ -107,6 +177,7 @@ class Recuperator(): self.Q_ex = None self.variables = None self.x = x + self._init_mass_interface() def calculator(self, cold_inlet_state, hot_inlet_state, bypass_info, ploss=0.0, property_calculator=None): """ @@ -254,11 +325,13 @@ class Recuperator(): return True -class Heater(): +class Heater(ComponentMassMixin): """加热器类""" + component_type = "heater" def __init__(self, name): self.name = name self.variables = None + self._init_mass_interface() def calculator(self, inlet_state, outlet_state): h_in = inlet_state['h'] h_out = outlet_state['h'] @@ -280,11 +353,13 @@ class Heater(): 'Q_in': Q_input, } -class Condenser(): +class Condenser(ComponentMassMixin): """冷凝器类""" + component_type = "condenser" def __init__(self, name): self.name = name self.variables = None + self._init_mass_interface() def calculator(self, inlet_state, outlet_state): h_in = inlet_state['h'] h_out = outlet_state['h'] @@ -306,11 +381,13 @@ class Condenser(): 'Q_out': Q_output, } -class Concentrator(): +class Concentrator(ComponentMassMixin): """汇流组件""" + component_type = "concentrator" def __init__(self, name): self.name = name self.variables = None + self._init_mass_interface() def calculator(self, inlet_state_bypass, inlet_state_mroad, x, property_calculator): h_in_bypass = inlet_state_bypass['h'] h_in_mroad = inlet_state_mroad['h'] diff --git a/brayton_cycle/cycles.py b/brayton_cycle/cycles.py index 43e5f9c..9a718e1 100644 --- a/brayton_cycle/cycles.py +++ b/brayton_cycle/cycles.py @@ -23,6 +23,8 @@ class BraytonCycle: self.heater = None self.condenser = None self.concentrator = None + self.component_masses = None + self.total_mass = None self.refprop_path = refprop_path self.property_calculator = CO2PropertyCalculator(self.refprop_path) @@ -36,6 +38,53 @@ class BraytonCycle: Q_input = self.heater.variables["Q_in"] return (Wt - Wc) / Q_input + def iter_components(self): + """Yield initialized component objects in the current cycle.""" + for value in ( + self.compressor, + self.turbine, + self.recuperator, + self.heater, + self.condenser, + self.concentrator, + ): + if value is None: + continue + if isinstance(value, list): + for component in value: + if component is not None: + yield component + else: + yield value + + def calculate_component_masses(self, mass_model=None, **kwargs): + """Calculate mass for each initialized component.""" + component_masses = {} + for component in self.iter_components(): + mass = component.calculate_mass(mass_model=mass_model, **kwargs) + key = component.variables.get("name", component.name) + component_masses[key] = { + "component_type": component.component_type, + "mass": mass, + "mass_variables": component.mass_variables, + } + + self.component_masses = component_masses + return self.component_masses + + def cycle_mass_calculator(self, mass_model=None, **kwargs): + """Calculate and return total cycle component mass.""" + component_masses = self.calculate_component_masses( + mass_model=mass_model, + **kwargs, + ) + self.total_mass = sum(item["mass"] for item in component_masses.values()) + return self.total_mass + + def calculate_total_mass(self, mass_model=None, **kwargs): + """Compatibility alias for cycle_mass_calculator.""" + return self.cycle_mass_calculator(mass_model=mass_model, **kwargs) + def SC(self, T_low, T_high, p_low, p_high, param=None): """Simple Brayton cycle.""" defaults = {