Source code for idaes.models_extra.power_generation.unit_models.helm.turbine_multistage

#################################################################################
# The Institute for the Design of Advanced Energy Systems Integrated Platform
# Framework (IDAES IP) was produced under the DOE Institute for the
# Design of Advanced Energy Systems (IDAES).
#
# Copyright (c) 2018-2024 by the software owners: The Regents of the
# University of California, through Lawrence Berkeley National Laboratory,
# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon
# University, West Virginia University Research Corporation, et al.
# All rights reserved.  Please see the files COPYRIGHT.md and LICENSE.md
# for full copyright and license information.
#################################################################################
"""
Multistage steam turbine for power generation.

Liese, (2014). "Modeling of a Steam Turbine Including Partial Arc Admission
    for Use in a Process Simulation Software Environment." Journal of Engineering
    for Gas Turbines and Power. v136, November
"""
# TODO: Missing docstrings
# pylint: disable=missing-class-docstring

import copy

import pyomo.environ as pyo
from pyomo.network import Arc
from pyomo.common.config import ConfigBlock, ConfigValue, ConfigList, In

from idaes.core import declare_process_block_class, UnitModelBlockData, useDefault
from idaes.models_extra.power_generation.unit_models.helm import (
    HelmSplitter,
    HelmMixer,
    MomentumMixingType,
    HelmTurbineInletStage,
    HelmTurbineStage,
    HelmTurbineOutletStage,
    ValveFunctionType,
)
from idaes.models_extra.power_generation.unit_models.helm import HelmValve as SteamValve

from idaes.core.util.config import is_physical_parameter_block
from idaes.core.util import from_json, to_json, StoreSpec
from idaes.core.util.initialization import propagate_state
import idaes.core.util.scaling as iscale

import idaes.logger as idaeslog

_log = idaeslog.getLogger(__name__)


def _define_turbine_multistage_config(config):
    config.declare(
        "dynamic",
        ConfigValue(
            domain=In([False]),
            default=False,
            description="Dynamic model flag",
            doc="Only False, in a dynamic flowsheet this is pseudo-steady-state.",
        ),
    )
    config.declare(
        "has_holdup",
        ConfigValue(
            default=False,
            domain=In([False]),
            description="Holdup construction flag",
            doc="Only False, in a dynamic flowsheet this is pseudo-steady-state.",
        ),
    )
    config.declare(
        "property_package",
        ConfigValue(
            default=useDefault,
            domain=is_physical_parameter_block,
            description="Property package to use for control volume",
            doc="""Property parameter object used to define property calculations,
**default** - useDefault.
**Valid values:** {
**useDefault** - use default package from parent model or flowsheet,
**PropertyParameterObject** - a PropertyParameterBlock object.}""",
        ),
    )
    config.declare(
        "property_package_args",
        ConfigBlock(
            implicit=True,
            description="Arguments to use for constructing property packages",
            doc="""A ConfigBlock with arguments to be passed to a property block(s)
and used when constructing these,
**default** - None.
**Valid values:** {
see property package for documentation.}""",
        ),
    )
    config.declare(
        "num_parallel_inlet_stages",
        ConfigValue(
            default=4,
            domain=int,
            description="Number of parallel inlet stages to simulate partial arc "
            "admission.  Default=4",
        ),
    )
    config.declare(
        "throttle_valve_function",
        ConfigValue(
            default=ValveFunctionType.linear,
            domain=In(ValveFunctionType),
            description="Valve function type, if custom provide an expression rule",
            doc="""The type of valve function, if custom provide an expression rule
with the valve_function_rule argument.
**default** - ValveFunctionType.linear
**Valid values** - {
ValveFunctionType.linear,
ValveFunctionType.quick_opening,
ValveFunctionType.equal_percentage,
ValveFunctionType.custom}""",
        ),
    )
    config.declare(
        "throttle_valve_function_callback",
        ConfigValue(
            default=None,
            description="A callback to add a custom valve function to the "
            "throttle valves or None.  If a callback is provided, it should "
            "take the valve block data as an argument and add a "
            "valve_function expressions to it. Default=None",
        ),
    )
    config.declare(
        "num_hp",
        ConfigValue(
            default=2,
            domain=int,
            description="Number of high pressure stages not including inlet stage",
            doc="Number of high pressure stages not including inlet stage",
        ),
    )
    config.declare(
        "num_ip",
        ConfigValue(
            default=10,
            domain=int,
            description="Number of intermediate pressure stages",
            doc="Number of intermediate pressure stages",
        ),
    )
    config.declare(
        "num_lp",
        ConfigValue(
            default=5,
            domain=int,
            description="Number of low pressure stages not including outlet stage",
            doc="Number of low pressure stages not including outlet stage",
        ),
    )
    config.declare(
        "hp_split_locations",
        ConfigList(
            default=[],
            domain=int,
            description="Locations of splitters in HP section",
            doc="A list of index locations of splitters in the HP section. The "
            "indexes indicate after which stage to include splitters.  0 is "
            "between the inlet stage and the first regular HP stage.",
        ),
    )
    config.declare(
        "ip_split_locations",
        ConfigList(
            default=[],
            domain=int,
            description="Locations of splitters in IP section",
            doc="A list of index locations of splitters in the IP section. The "
            "indexes indicate after which stage to include splitters.",
        ),
    )
    config.declare(
        "lp_split_locations",
        ConfigList(
            default=[],
            domain=int,
            description="Locations of splitter in LP section",
            doc="A list of index locations of splitters in the LP section. The "
            "indexes indicate after which stage to include splitters.",
        ),
    )
    config.declare(
        "hp_disconnect",
        ConfigList(
            default=[],
            domain=int,
            description="HP Turbine stages to not connect to next with an arc.",
            doc="HP Turbine stages to not connect to next with an arc. This is "
            "usually used to insert additional units between stages on a "
            "flowsheet, such as a reheater",
        ),
    )
    config.declare(
        "ip_disconnect",
        ConfigList(
            default=[],
            domain=int,
            description="IP Turbine stages to not connect to next with an arc.",
            doc="IP Turbine stages to not connect to next with an arc. This is "
            "usually used to insert additional units between stages on a "
            "flowsheet, such as a reheater",
        ),
    )
    config.declare(
        "lp_disconnect",
        ConfigList(
            default=[],
            domain=int,
            description="LP Turbine stages to not connect to next with an arc.",
            doc="LP Turbine stages to not connect to next with an arc. This is "
            "usually used to insert additional units between stages on a "
            "flowsheet, such as a reheater",
        ),
    )
    config.declare(
        "hp_split_num_outlets",
        ConfigValue(
            default={},
            domain=dict,
            description="Dict, hp split index: number of splitter outlets, if not 2",
        ),
    )
    config.declare(
        "ip_split_num_outlets",
        ConfigValue(
            default={},
            domain=dict,
            description="Dict, ip split index: number of splitter outlets, if not 2",
        ),
    )
    config.declare(
        "lp_split_num_outlets",
        ConfigValue(
            default={},
            domain=dict,
            description="Dict, lp split index: number of splitter outlets, if not 2",
        ),
    )


[docs] @declare_process_block_class( "HelmTurbineMultistage", doc="Multistage steam turbine with optional reheat and extraction", ) class HelmTurbineMultistageData(UnitModelBlockData): CONFIG = ConfigBlock() _define_turbine_multistage_config(CONFIG)
[docs] def build(self): super().build() config = self.config unit_cfg = { # general unit model config "dynamic": config.dynamic, "has_holdup": config.has_holdup, "property_package": config.property_package, "property_package_args": config.property_package_args, } ni = self.config.num_parallel_inlet_stages inlet_idx = self.inlet_stage_idx = pyo.RangeSet(ni) thrtl_cfg = unit_cfg.copy() thrtl_cfg["valve_function"] = self.config.throttle_valve_function thrtl_cfg["valve_function_callback"] = ( self.config.throttle_valve_function_callback ) # Adding unit models # ------------------------ # Splitter to inlet that splits main flow into parallel flows for # partial arc admission to the turbine self.inlet_split = HelmSplitter(**self._split_cfg(unit_cfg, ni)) self.throttle_valve = SteamValve(inlet_idx, **thrtl_cfg) self.inlet_stage = HelmTurbineInletStage(inlet_idx, **unit_cfg) # mixer to combine the parallel flows back together self.inlet_mix = HelmMixer(**self._mix_cfg(unit_cfg, ni)) # add turbine sections. # inlet stage -> hp stages -> ip stages -> lp stages -> outlet stage self.hp_stages = HelmTurbineStage(pyo.RangeSet(config.num_hp), **unit_cfg) self.ip_stages = HelmTurbineStage(pyo.RangeSet(config.num_ip), **unit_cfg) self.lp_stages = HelmTurbineStage(pyo.RangeSet(config.num_lp), **unit_cfg) self.outlet_stage = HelmTurbineOutletStage(**unit_cfg) for i in self.hp_stages: self.hp_stages[i].ratioP.fix() self.hp_stages[i].efficiency_isentropic.fix() for i in self.ip_stages: self.ip_stages[i].ratioP.fix() self.ip_stages[i].efficiency_isentropic.fix() for i in self.lp_stages: self.lp_stages[i].ratioP.fix() self.lp_stages[i].efficiency_isentropic.fix() # Then make splitter config. If number of outlets is specified # make a specific config, otherwise use default with 2 outlets s_sfg_default = self._split_cfg(unit_cfg, 2) hp_splt_cfg = {} ip_splt_cfg = {} lp_splt_cfg = {} # Now to finish up if there are more than two outlets, set that for i, v in config.hp_split_num_outlets.items(): hp_splt_cfg[i] = self._split_cfg(unit_cfg, v) for i, v in config.ip_split_num_outlets.items(): ip_splt_cfg[i] = self._split_cfg(unit_cfg, v) for i, v in config.lp_split_num_outlets.items(): lp_splt_cfg[i] = self._split_cfg(unit_cfg, v) # put in splitters for turbine steam extractions if config.hp_split_locations: self.hp_split = HelmSplitter( config.hp_split_locations, **s_sfg_default, initialize=hp_splt_cfg ) else: self.hp_split = {} if config.ip_split_locations: self.ip_split = HelmSplitter( config.ip_split_locations, **s_sfg_default, initialize=ip_splt_cfg ) else: self.ip_split = {} if config.lp_split_locations: self.lp_split = HelmSplitter( config.lp_split_locations, **s_sfg_default, initialize=lp_splt_cfg ) else: self.lp_split = {} # Done with unit models. Adding Arcs (streams). # ------------------------------------------------ # First up add streams in the inlet section def _split_to_rule(b, i): return { "source": getattr(self.inlet_split, "outlet_{}".format(i)), "destination": self.throttle_valve[i].inlet, } def _valve_to_rule(b, i): return { "source": self.throttle_valve[i].outlet, "destination": self.inlet_stage[i].inlet, } def _inlet_to_rule(b, i): return { "source": self.inlet_stage[i].outlet, "destination": getattr(self.inlet_mix, "inlet_{}".format(i)), } self.stream_throttle_inlet = Arc(inlet_idx, rule=_split_to_rule) self.stream_throttle_outlet = Arc(inlet_idx, rule=_valve_to_rule) self.stream_inlet_mix_inlet = Arc(inlet_idx, rule=_inlet_to_rule) # There are three sections HP, IP, and LP which all have the same sort # of internal connections, so the functions below provide some generic # capcbilities for adding the internal Arcs (streams). def _arc_indexes(nstages, index_set, discon, splits): """ This takes the index set of all possible streams in a turbine section and throws out arc indexes for stages that are disconnected and arc indexes that are not needed because there is no splitter after a stage. Args: nstages (int): Number of stages in section index_set (Set): Index set for arcs in the section discon (list): Disconnected stages in the section splits (list): Splitter locations """ sr = set() # set of things to remove from the Arc index set for i in index_set: if (i[0] in discon or i[0] == nstages) and i[0] in splits: # don't connect stage i to next remove stream after split sr.add((i[0], 2)) elif (i[0] in discon or i[0] == nstages) and i[0] not in splits: # no splitter and disconnect so remove both streams sr.add((i[0], 1)) sr.add((i[0], 2)) elif i[0] not in splits: # no splitter and not disconnected so just second stream sr.add((i[0], 2)) else: # has splitter so need both streams don't remove anything pass for i in sr: # remove the unneeded Arc indexes index_set.remove(i) def _arc_rule(turbines, splitters): """ This creates a rule function for arcs in a turbine section. When this is used, the indexes for nonexistent stream will have already been removed, so any indexes the rule will get should have a stream associated. Args: turbines (TurbineStage): Indexed block with turbine section stages splitters (Separator): Indexed block of splitters """ def _rule(b, i, j): if i in splitters and j == 1: # stage to splitter return { "source": turbines[i].outlet, "destination": splitters[i].inlet, } elif j == 2: # splitter to next stage return { "source": splitters[i].outlet_1, "destination": turbines[i + 1].inlet, } else: # no splitter, stage to next stage return { "source": turbines[i].outlet, "destination": turbines[i + 1].inlet, } return _rule # Create initial arcs index sets with all possible streams self.hp_stream_idx = pyo.Set(initialize=self.hp_stages.index_set() * [1, 2]) self.ip_stream_idx = pyo.Set(initialize=self.ip_stages.index_set() * [1, 2]) self.lp_stream_idx = pyo.Set(initialize=self.lp_stages.index_set() * [1, 2]) # Throw out unneeded streams for disconnected stages or no splitter _arc_indexes( config.num_hp, self.hp_stream_idx, config.hp_disconnect, config.hp_split_locations, ) _arc_indexes( config.num_ip, self.ip_stream_idx, config.ip_disconnect, config.ip_split_locations, ) _arc_indexes( config.num_lp, self.lp_stream_idx, config.lp_disconnect, config.lp_split_locations, ) # Create connections internal to each turbine section (hp, ip, and lp) self.hp_stream = Arc( self.hp_stream_idx, rule=_arc_rule(self.hp_stages, self.hp_split) ) self.ip_stream = Arc( self.ip_stream_idx, rule=_arc_rule(self.ip_stages, self.ip_split) ) self.lp_stream = Arc( self.lp_stream_idx, rule=_arc_rule(self.lp_stages, self.lp_split) ) # Connect hp section to ip section unless its a disconnect location last_hp = config.num_hp if 0 not in config.ip_disconnect and last_hp not in config.hp_disconnect: # Not disconnected stage so add stream, depending on splitter existence if last_hp in config.hp_split_locations: # connect splitter to ip self.hp_to_ip_stream = Arc( source=self.hp_split[last_hp].outlet_1, destination=self.ip_stages[1].inlet, ) else: # connect last hp to ip self.hp_to_ip_stream = Arc( source=self.hp_stages[last_hp].outlet, destination=self.ip_stages[1].inlet, ) # Connect ip section to lp section unless its a disconnect location last_ip = config.num_ip if 0 not in config.lp_disconnect and last_ip not in config.ip_disconnect: if last_ip in config.ip_split_locations: # connect splitter to ip self.ip_to_lp_stream = Arc( source=self.ip_split[last_ip].outlet_1, destination=self.lp_stages[1].inlet, ) else: # connect last hp to ip self.ip_to_lp_stream = Arc( source=self.ip_stages[last_ip].outlet, destination=self.lp_stages[1].inlet, ) # Connect inlet stage to hp section # not allowing disconnection of inlet and first regular hp stage if 0 in config.hp_split_locations: # connect inlet mix to splitter and splitter to hp section self.inlet_to_splitter_stream = Arc( source=self.inlet_mix.outlet, destination=self.hp_split[0].inlet ) self.splitter_to_hp_stream = Arc( source=self.hp_split[0].outlet_1, destination=self.hp_stages[1].inlet ) else: # connect mixer to first hp turbine stage self.inlet_to_hp_stream = Arc( source=self.inlet_mix.outlet, destination=self.hp_stages[1].inlet ) self.power = pyo.Var( self.flowsheet().time, initialize=-1e8, doc="total turbine power", units=pyo.units.W, ) @self.Constraint(self.flowsheet().time) def power_eqn(b, t): return b.power[t] == b.outlet_stage.control_volume.work[ t ] * b.outlet_stage.efficiency_mech + sum( b.inlet_stage[i].control_volume.work[t] * b.inlet_stage[i].efficiency_mech for i in b.inlet_stage ) + sum( b.hp_stages[i].control_volume.work[t] * b.hp_stages[i].efficiency_mech for i in b.hp_stages ) + sum( b.ip_stages[i].control_volume.work[t] * b.ip_stages[i].efficiency_mech for i in b.ip_stages ) + sum( b.lp_stages[i].control_volume.work[t] * b.lp_stages[i].efficiency_mech for i in b.lp_stages ) # Connect lp section to outlet stage, not allowing outlet stage to be # disconnected last_lp = config.num_lp if last_lp in config.lp_split_locations: # connect splitter to outlet self.lp_to_outlet_stream = Arc( source=self.lp_split[last_lp].outlet_1, destination=self.outlet_stage.inlet, ) else: # connect last lpstage to outlet self.lp_to_outlet_stream = Arc( source=self.lp_stages[last_lp].outlet, destination=self.outlet_stage.inlet, ) pyo.TransformationFactory("network.expand_arcs").apply_to(self)
def _split_cfg(self, unit_cfg, no=2): """ This creates a configuration dictionary for a splitter. Args: unit_cfg: The base unit config dict. no: Number of outlets, default=2 """ # Create a dict for splitter config args cfg = copy.copy(unit_cfg) cfg.update(num_outlets=no) return cfg def _mix_cfg(self, unit_cfg, ni=2): """ This creates a configuration dictionary for a mixer. Args: unit_cfg: The base unit config dict. ni: Number of inlets, default=2 """ cfg = copy.copy(unit_cfg) cfg.update( num_inlets=ni, momentum_mixing_type=MomentumMixingType.minimize_and_equality ) return cfg
[docs] def throttle_cv_fix(self, value): """ Fix the thottle valve coefficients. These are generally the same for each of the parallel stages so this provides a convenient way to set them. Args: value: The value to fix the turbine inlet flow coefficients at """ for i in self.throttle_valve: self.throttle_valve[i].Cv.fix(value)
[docs] def turbine_inlet_cf_fix(self, value): """ Fix the inlet turbine stage flow coefficient. These are generally the same for each of the parallel stages so this provides a convenient way to set them. Args: value: The value to fix the turbine inlet flow coefficients at """ for i in self.inlet_stage: self.inlet_stage[i].flow_coeff.fix(value)
def _init_section( self, stages, splits, disconnects, prev_port, outlvl, solver, optarg, copy_disconnected_flow, copy_disconnected_pressure, ): """Reuse the initialization for HP, IP and, LP sections.""" if 0 in splits: propagate_state(splits[0].inlet, prev_port) splits[0].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = splits[0].outlet_1 for i in stages: if i - 1 not in disconnects: propagate_state(stages[i].inlet, prev_port) else: if copy_disconnected_flow: for t in stages[i].inlet.flow_mol: stages[i].inlet.flow_mol[t] = pyo.value(prev_port.flow_mol[t]) if copy_disconnected_pressure: for t in stages[i].inlet.pressure: stages[i].inlet.pressure[t] = pyo.value(prev_port.pressure[t]) stages[i].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = stages[i].outlet if i in splits: propagate_state(splits[i].inlet, prev_port) splits[i].initialize(outlvl=outlvl, solver=solver, optarg=optarg) prev_port = splits[i].outlet_1 return prev_port
[docs] def turbine_outlet_cf_fix(self, value): """ Fix the inlet turbine stage flow coefficient. These are generally the same for each of the parallel stages so this provides a convenient way to set them. Args: value: The value to fix the turbine inlet flow coefficients at """ self.outlet_stage.flow_coeff.fix(value)
[docs] def initialize_build( self, outlvl=idaeslog.NOTSET, solver=None, flow_iterate=2, optarg=None, copy_disconnected_flow=True, copy_disconnected_pressure=True, calculate_outlet_cf=False, calculate_inlet_cf=False, ): """ Initialize Args: outlvl: logging level default is NOTSET, which inherits from the parent logger solver: the NL solver flow_iterate: If not calculating flow coefficients, this is the number of times to update the flow and repeat initialization (1 to 5 where 1 does not update the flow guess) optarg: solver arguments, default is None copy_disconnected_flow: Copy the flow through the disconnected stages default is True copy_disconnected_pressure: Copy the pressure through the disconnected stages default is True calculate_outlet_cf: Use the flow initial flow guess to calculate the outlet stage flow coefficient, default is False, calculate_inlet_cf: Use the inlet stage ratioP to calculate the flow coefficient for the inlet stage default is False Returns: None """ # Setup loggers # Store initial model specs, restored at the end of initialization, so # the problem is not altered. This can restore fixed/free vars, # active/inactive constraints, and fixed variable values. sp = StoreSpec.value_isfixed_isactive(only_fixed=True) istate = to_json(self, return_dict=True, wts=sp) for it_count in range(flow_iterate): self.inlet_split.initialize(outlvl=outlvl, solver=solver, optarg=optarg) # Initialize valves for i in self.inlet_stage_idx: u = self.throttle_valve[i] propagate_state( u.inlet, getattr(self.inlet_split, "outlet_{}".format(i)) ) u.initialize(outlvl=outlvl, solver=solver, optarg=optarg) # Initialize turbine for i in self.inlet_stage_idx: u = self.inlet_stage[i] propagate_state(u.inlet, self.throttle_valve[i].outlet) u.initialize( outlvl=outlvl, solver=solver, optarg=optarg, calculate_cf=calculate_inlet_cf, ) # Initialize Mixer self.inlet_mix.use_minimum_inlet_pressure_constraint() for i in self.inlet_stage_idx: propagate_state( getattr(self.inlet_mix, "inlet_{}".format(i)), self.inlet_stage[i].outlet, ) getattr(self.inlet_mix, "inlet_{}".format(i)).fix() self.inlet_mix.initialize(outlvl=outlvl, solver=solver, optarg=optarg) for i in self.inlet_stage_idx: getattr(self.inlet_mix, "inlet_{}".format(i)).unfix() self.inlet_mix.use_equal_pressure_constraint() prev_port = self.inlet_mix.outlet prev_port = self._init_section( self.hp_stages, self.hp_split, self.config.hp_disconnect, prev_port, outlvl, solver, optarg, copy_disconnected_flow=copy_disconnected_flow, copy_disconnected_pressure=copy_disconnected_pressure, ) if len(self.hp_stages) in self.config.hp_disconnect: self.config.ip_disconnect.append(0) prev_port = self._init_section( self.ip_stages, self.ip_split, self.config.ip_disconnect, prev_port, outlvl, solver, optarg, copy_disconnected_flow=copy_disconnected_flow, copy_disconnected_pressure=copy_disconnected_pressure, ) if len(self.ip_stages) in self.config.ip_disconnect: self.config.lp_disconnect.append(0) prev_port = self._init_section( self.lp_stages, self.lp_split, self.config.lp_disconnect, prev_port, outlvl, solver, optarg, copy_disconnected_flow=copy_disconnected_flow, copy_disconnected_pressure=copy_disconnected_pressure, ) propagate_state(self.outlet_stage.inlet, prev_port) self.outlet_stage.initialize( outlvl=outlvl, solver=solver, optarg=optarg, calculate_cf=calculate_outlet_cf, ) if calculate_outlet_cf: break if it_count < flow_iterate - 1: for t in self.inlet_split.inlet.flow_mol: self.inlet_split.inlet.flow_mol[t].value = ( self.outlet_stage.inlet.flow_mol[t].value ) for s in self.hp_split.values(): for i, o in enumerate(s.outlet_list): if i == 0: continue o = getattr(s, o) self.inlet_split.inlet.flow_mol[t].value += o.flow_mol[ t ].value for s in self.ip_split.values(): for i, o in enumerate(s.outlet_list): if i == 0: continue o = getattr(s, o) self.inlet_split.inlet.flow_mol[t].value += o.flow_mol[ t ].value for s in self.lp_split.values(): for i, o in enumerate(s.outlet_list): if i == 0: continue o = getattr(s, o) self.inlet_split.inlet.flow_mol[t].value += o.flow_mol[ t ].value if calculate_inlet_cf: # cf was probably fixed, so will have to set the value again here # if you ask for it to be calculated. icf = {} for i in self.inlet_stage: for t in self.inlet_stage[i].flow_coeff: icf[i, t] = pyo.value(self.inlet_stage[i].flow_coeff[t]) if calculate_outlet_cf: ocf = pyo.value(self.outlet_stage.flow_coeff) from_json(self, sd=istate, wts=sp) if calculate_inlet_cf: # cf was probably fixed, so will have to set the value again here # if you ask for it to be calculated. for t in self.inlet_stage[i].flow_coeff: for i in self.inlet_stage: self.inlet_stage[i].flow_coeff[t] = icf[i, t] if calculate_outlet_cf: self.outlet_stage.flow_coeff = ocf
def calculate_scaling_factors(self): super().calculate_scaling_factors() # Add a default power scale # pretty safe to say power is around 100 to 1000 MW for t in self.power: if iscale.get_scaling_factor(self.power[t]) is None: iscale.set_scaling_factor(self.power[t], 1e-8) for t, c in self.power_eqn.items(): power_scale = iscale.get_scaling_factor( self.power[t], default=1, warning=True ) # Set power equation scale factor iscale.constraint_scaling_transform(c, power_scale, overwrite=False) def _get_stream_table_contents(self, time_point=0): raise NotImplementedError( "The multi-stage turbine model has not implemented the code necessary to " "construct a stream table." )