def _set_geometry(self): """ Define the geometry of the unit as necessary, and link to holdup volume """ # UA (product of overall heat transfer coefficient and area) # between side 1 and side 2 self.ua_side_2 = Var(self.flowsheet().config.time, initialize=10.0, doc='UA between side 1 and side 2') # UA (product of overall heat transfer coefficient and area) # between side 1 and side 3 self.ua_side_3 = Var(self.flowsheet().config.time, initialize=10.0, doc='UA between side 1 and side 3') # fraction of heat from hot stream as heat loss to ambient self.frac_heatloss = Var(initialize=0.05, doc='Fraction of heat loss to ambient') if self.config.has_holdup is True: self.volume_side_1 = Reference(self.side_1.volume) self.volume_side_2 = Reference(self.side_2.volume) self.volume_side_3 = Reference(self.side_3.volume)
def test_flat_model(self): m = ConcreteModel() m.T = ContinuousSet(bounds=(0, 1)) m.x = Var() m.y = Var([1, 2]) m.a = Var(m.T) m.b = Var(m.T, [1, 2]) m.c = Var([3, 4], m.T) regular, time = flatten_dae_variables(m, m.T) regular_id = set(id(_) for _ in regular) self.assertEqual(len(regular), 3) self.assertIn(id(m.x), regular_id) self.assertIn(id(m.y[1]), regular_id) self.assertIn(id(m.y[2]), regular_id) # Output for debugging #for v in time: # v.pprint() # for _ in v.values(): # print" -> ", _.name ref_data = { self._hashRef(Reference(m.a[:])), self._hashRef(Reference(m.b[:, 1])), self._hashRef(Reference(m.b[:, 2])), self._hashRef(Reference(m.c[3, :])), self._hashRef(Reference(m.c[4, :])), } self.assertEqual(len(time), len(ref_data)) for ref in time: self.assertIn(self._hashRef(ref), ref_data)
def test_get_violated_bounds_at_time(): m = ConcreteModel() m.time = Set(initialize=[1, 2, 3]) m.v = Var(m.time, ['a', 'b', 'c'], initialize=5) varlist = [ Reference(m.v[:, 'a']), Reference(m.v[:, 'b']), Reference(m.v[:, 'c']) ] group = NMPCVarGroup(varlist, m.time) group.set_lb(0, 0) group.set_lb(1, 6) group.set_lb(2, 0) group.set_ub(0, 4) group.set_ub(1, 10) group.set_ub(2, 10) violated = get_violated_bounds_at_time(group, [1, 2, 3], tolerance=1e-8) violated_set = ComponentSet(violated) for t in m.time: assert m.v[t, 'a'] in violated_set assert m.v[t, 'b'] in violated_set violated = get_violated_bounds_at_time(group, 2, tolerance=1e-8) violated_set = ComponentSet(violated) assert m.v[2, 'a'] in violated_set assert m.v[2, 'b'] in violated_set
def build(self): """ Begin building model (pre-DAE transformation) Args: None Returns: None """ # Call UnitModel.build to setup dynamics super().build() # Build Control Volume self.control_volume = ControlVolume0DBlock(default={ "dynamic": self.config.dynamic, "has_holdup": self.config.has_holdup, "property_package": self.config.property_package, "property_package_args": self.config.property_package_args}) self.control_volume.add_geometry() # This model requires the IAPWS95 property package with the mixed phase # option, therefore, phase equilibrium calculations are handled by # the property package. self.control_volume.add_state_blocks(has_phase_equilibrium=False) self.control_volume.add_material_balances( balance_type=self.config.material_balance_type) self.control_volume.add_energy_balances( balance_type=self.config.energy_balance_type, has_heat_transfer=self.config.has_heat_transfer) self.control_volume.add_momentum_balances( balance_type=self.config.momentum_balance_type, has_pressure_change=True) # Add Ports self.add_inlet_port() self.add_outlet_port() # Add object references self.volume = Reference(self.control_volume.volume) # Set references to balance terms at unit level if (self.config.has_heat_transfer is True and self.config.energy_balance_type != EnergyBalanceType.none): self.heat_duty = Reference(self.control_volume.heat) if (self.config.has_pressure_change is True and self.config.momentum_balance_type != 'none'): self.deltaP = Reference(self.control_volume.deltaP) # Set Unit Geometry and Holdup Volume self._set_geometry() # Construct performance equations self._make_performance()
def test_initialize_by_element_in_range(): mod = make_model(horizon=2, ntfe=20) assert degrees_of_freedom(mod) == 0 scalar_vars, dae_vars = flatten_dae_variables(mod.fs, mod.fs.time) diff_vars = [ Reference(mod.fs.cstr.control_volume.energy_holdup[:, 'aq']), Reference(mod.fs.cstr.control_volume.material_holdup[:, 'aq', 'S']), Reference(mod.fs.cstr.control_volume.material_holdup[:, 'aq', 'E']), Reference(mod.fs.cstr.control_volume.material_holdup[:, 'aq', 'C']), Reference(mod.fs.cstr.control_volume.material_holdup[:, 'aq', 'P']) ] initialize_by_element_in_range(mod.fs, mod.fs.time, 0, 1, solver=solver, dae_vars=dae_vars, time_linking_variables=diff_vars, outlvl=idaeslog.DEBUG, solve_initial_conditions=True) assert degrees_of_freedom(mod.fs) == 0 assert mod.fs.cstr.outlet.conc_mol[1, 'S'].value == approx(10.189, abs=1e-3) assert mod.fs.cstr.outlet.conc_mol[1, 'C'].value == approx(0.4275, abs=1e-4) assert mod.fs.cstr.outlet.conc_mol[1, 'E'].value == approx(0.0541, abs=1e-4) assert mod.fs.cstr.outlet.conc_mol[1, 'P'].value == approx(0.3503, abs=1e-4) initialize_by_element_in_range(mod.fs, mod.fs.time, 1, 2, solver=solver, dae_vars=dae_vars, outlvl=idaeslog.DEBUG) assert degrees_of_freedom(mod.fs) == 0 for con in activated_equalities_generator(mod.fs): assert value(con.body) - value(con.upper) < 1e-5 assert mod.fs.cstr.outlet.conc_mol[2, 'S'].value == approx(11.263, abs=1e-3) assert mod.fs.cstr.outlet.conc_mol[2, 'C'].value == approx(0.4809, abs=1e-4) assert mod.fs.cstr.outlet.conc_mol[2, 'E'].value == approx(0.0538, abs=1e-4) assert mod.fs.cstr.outlet.conc_mol[2, 'P'].value == approx(0.4372, abs=1e-4)
def build(self): """ Begin building model (pre-DAE transformation). Args: None Returns: None """ # Call UnitModel.build to setup dynamics super(StoichiometricReactorData, self).build() # Build Control Volume self.control_volume = ControlVolume0DBlock( default={ "dynamic": self.config.dynamic, "property_package": self.config.property_package, "property_package_args": self.config.property_package_args, "reaction_package": self.config.reaction_package, "reaction_package_args": self.config.reaction_package_args }) self.control_volume.add_state_blocks(has_phase_equilibrium=False) self.control_volume.add_reaction_blocks(has_equilibrium=False) self.control_volume.add_material_balances( balance_type=self.config.material_balance_type, has_rate_reactions=True) self.control_volume.add_energy_balances( balance_type=self.config.energy_balance_type, has_heat_transfer=self.config.has_heat_transfer, has_heat_of_reaction=self.config.has_heat_of_reaction) self.control_volume.add_momentum_balances( balance_type=self.config.momentum_balance_type, has_pressure_change=self.config.has_pressure_change) # Add Ports self.add_inlet_port() self.add_outlet_port() # Add performance equations self.rate_reaction_extent = Reference( self.control_volume.rate_reaction_extent[...]) # Set references to balance terms at unit level if (self.config.has_heat_transfer is True and self.config.energy_balance_type != EnergyBalanceType.none): self.heat_duty = Reference(self.control_volume.heat[:]) if (self.config.has_pressure_change is True and self.config.momentum_balance_type != MomentumBalanceType.none): self.deltaP = Reference(self.control_volume.deltaP[:])
def build(self): """ Begin building model """ # Call UnitModel.build to setup dynamics super(WaterPipeData, self).build() # Build Control Volume self.control_volume = ControlVolume0DBlock( default={ "dynamic": self.config.dynamic, "has_holdup": self.config.has_holdup, "property_package": self.config.property_package, "property_package_args": self.config.property_package_args }) self.control_volume.add_geometry() self.control_volume.add_state_blocks(has_phase_equilibrium=False) self.control_volume.add_material_balances( balance_type=self.config.material_balance_type, ) self.control_volume.add_energy_balances( balance_type=self.config.energy_balance_type, has_heat_transfer=self.config.has_heat_transfer) self.control_volume.add_momentum_balances( balance_type=self.config.momentum_balance_type, has_pressure_change=True) # Add Ports self.add_inlet_port() self.add_outlet_port() # Add object references self.volume = Reference(self.control_volume.volume) # Set references to balance terms at unit level if (self.config.has_heat_transfer is True and self.config.energy_balance_type != EnergyBalanceType.none): self.heat_duty = Reference(self.control_volume.heat) if (self.config.has_pressure_change is True and self.config.momentum_balance_type != 'none'): self.deltaP = Reference(self.control_volume.deltaP) # Set Unit Geometry and Volume self._set_geometry() # Construct performance equations self._make_performance()
def test_2dim_set(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 1)) m.v = Var(m.time, [('a', 1), ('b', 2)]) scalar, dae = flatten_dae_variables(m, m.time) self.assertEqual(len(scalar), 0) ref_data = { self._hashRef(Reference(m.v[:, 'a', 1])), self._hashRef(Reference(m.v[:, 'b', 2])), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def build(self): super().build() self._tech_type = "deep_well_injection" build_pt(self) self._Q = Reference(self.properties[:].flow_vol) pump_electricity(self, self._Q) self.pipe_distance = Var(self.flowsheet().config.time, units=pyunits.miles, doc="Piping distance") self.pipe_diameter = Var(self.flowsheet().config.time, units=pyunits.inches, doc="Pipe diameter") self.flow_basis = Var(self.flowsheet().time, units=pyunits.m**3 / pyunits.hour, doc="flow basis") self._fixed_perf_vars.append(self.pipe_distance) self._fixed_perf_vars.append(self.pipe_diameter) self._fixed_perf_vars.append(self.flow_basis) self._perf_var_dict["Pipe Distance (miles)"] = self.pipe_distance self._perf_var_dict["Pipe Diameter (inches)"] = self.pipe_diameter
def build(self): super().build() self._tech_type = "sw_onshore_intake" build_pt(self) self._Q = Reference(self.properties[:].flow_vol) pump_electricity(self, self._Q)
def build(self): super().build() self._tech_type = "backwash_solids_handling" build_sido(self) self._Q = Reference(self.properties_in[:].flow_vol) pump_electricity(self, self._Q)
def build(self): """ Begin building model. Args: None Returns: None """ # Call UnitModel.build to setup dynamics super(FeedFlashData, self).build() # Build Control Volume self.control_volume = ControlVolume0DBlock( default={ "dynamic": self.config.dynamic, "has_holdup": self.config.has_holdup, "property_package": self.config.property_package, "property_package_args": self.config.property_package_args }) # No need for control volume geometry self.control_volume.add_state_blocks(has_phase_equilibrium=True) self.control_volume.add_material_balances( balance_type=self.config.material_balance_type, has_phase_equilibrium=True) # Add isothermal constraint @self.Constraint(self.flowsheet().config.time, doc="Isothermal constraint") def isothermal(b, t): return (b.control_volume.properties_in[t].temperature == b.control_volume.properties_out[t].temperature) self.control_volume.add_momentum_balances( balance_type=MomentumBalanceType.pressureTotal) # Add references to all feed state vars s_vars = self.control_volume.properties_in[ self.flowsheet().config.time.first()].define_state_vars() for s in s_vars: l_name = s_vars[s].local_name if s_vars[s].is_indexed(): slicer = (self.control_volume.properties_in[:].component( l_name)[...]) else: slicer = self.control_volume.properties_in[:].component(l_name) r = Reference(slicer) setattr(self, s, r) # Add Ports self.add_outlet_port()
def build(self): super().build() self._tech_type = "gac" build_sido(self) self._Q = Reference(self.properties_in[:].flow_vol) # TODO: incorporate a*Q**b relationship for electricity consumption based on EPA data fitting; # apply pump electricity consumption in the meantime pump_electricity(self, self._Q)
def test_NMPCVarLocator(): m = ConcreteModel() m.time = Set(initialize=[1, 2, 3]) m.v = Var(m.time, ['a', 'b', 'c']) varlist = [ Reference(m.v[:, 'a']), Reference(m.v[:, 'b']), Reference(m.v[:, 'b']) ] group = NMPCVarGroup(varlist, m.time) categ = VariableCategory.DIFFERENTIAL locator = NMPCVarLocator(categ, group, 0, is_ic=True) assert locator.category == VariableCategory.DIFFERENTIAL assert locator.group is group assert locator.location == 0 assert locator.is_ic == True
def build(self): super().build() self._tech_type = "fixed_bed" build_siso(self) self._Q = Reference(self.properties_in[:].flow_vol) # TODO: incorporate a*Q**b relationship for electricity consumption based on EPA data fitting; # apply pump electricity consumption in the meantime pump_electricity(self, self._Q) self.recovery_frac_mass_H2O.fix(1)
def build(self): super().build() self._tech_type = "municipal_drinking" build_pt(self) self._Q = Reference(self.properties[:].flow_vol) pump_electricity(self, self._Q) # mutable parameter; default value found in WT3 self.lift_height.set_value(300 * pyunits.feet)
def build(self): """Building model Args: None Returns: None """ # Call UnitModel.build to setup dynamics super(HeaterData, self).build() # Add Control Volume _make_heater_control_volume(self, "control_volume", self.config) # Add Ports self.add_inlet_port() self.add_outlet_port() # Add a convienient reference to heat duty. self.heat_duty = Reference(self.control_volume.heat) if (self.config.has_pressure_change is True and self.config.momentum_balance_type != MomentumBalanceType.none): self.deltaP = Reference(self.control_volume.deltaP)
def test_indexed_block(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0,1)) m.comp = Set(initialize=['a', 'b']) def bb_rule(bb, t): bb.dae_var = Var() def b_rule(b, c): b.bb = Block(m.time, rule=bb_rule) m.b = Block(m.comp, rule=b_rule) scalar, dae = flatten_dae_variables(m, m.time) self.assertEqual(len(scalar), 0) ref_data = { self._hashRef(Reference(m.b['a'].bb[:].dae_var)), self._hashRef(Reference(m.b['b'].bb[:].dae_var)), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def build(self): super().build() self._tech_type = "ion_exchange" build_siso(self) self._Q = Reference(self.properties_in[:].flow_vol) pump_electricity(self, self._Q) # mutable parameter; default value found in WT3 for anion exchange self.eta_pump.set_value(0.8) # mutable parameter; default value of 2 bar converted to feet head self.lift_height.set_value(69.91052 * pyunits.feet) self.recovery_frac_mass_H2O.fix(1) # Add variables and constraints for material requirements self.NaCl_flowrate = Var(self.flowsheet().time, initialize=1, units=pyunits.kg / pyunits.s, bounds=(0, None), doc="Flowrate of NaCl addition") self.NaCl_dose = Var(units=pyunits.kg / pyunits.m**3, bounds=(0, None), doc="Dosage of NaCl addition") self._fixed_perf_vars.append(self.NaCl_dose) self._perf_var_dict["NaCl Addition"] = self.NaCl_flowrate @self.Constraint(self.flowsheet().time) def NaCl_constraint(blk, t): return (blk.NaCl_flowrate[t] == blk.NaCl_dose * blk.properties_in[t].flow_vol) self.resin_demand = Var(self.flowsheet().time, initialize=1, units=pyunits.kg / pyunits.s, bounds=(0, None), doc="Replacement rate of ion exchange resin") self.resin_replacement = Var( units=pyunits.kg / pyunits.m**3, bounds=(0, None), doc="Resin replacement as a fuction of flow") self._fixed_perf_vars.append(self.resin_replacement) self._perf_var_dict["Resin Demand"] = self.resin_demand @self.Constraint(self.flowsheet().time) def resin_constraint(blk, t): return (blk.resin_demand[t] == blk.resin_replacement * blk.properties_in[t].flow_vol)
def build(self): """Building model Args: None Returns: None """ # Call UnitModel.build to setup dynamics super().build() # Add Control Volume make_balance_control_volume(self, "control_volume", self.config) # Add Ports self.add_inlet_port() self.add_outlet_port() # Add convienient references to control volume quantities deltaP. if (self.config.has_pressure_change is True and self.config.momentum_balance_type != MomentumBalanceType.none): self.deltaP = Reference(self.control_volume.deltaP) if self.config.has_heat_transfer is True: self.heat_duty = Reference(self.control_volume.heat) if self.config.has_work_transfer is True: self.work = Reference(self.control_volume.work)
def test_1level_model(self): m = ConcreteModel() m.T = ContinuousSet(bounds=(0,1)) @m.Block([1,2],m.T) def B(b, i, t): b.x = Var(list(range(2*i, 2*i+2))) regular, time = flatten_dae_variables(m, m.T) self.assertEqual(len(regular), 0) # Output for debugging #for v in time: # v.pprint() # for _ in v.values(): # print" -> ", _.name ref_data = { self._hashRef(Reference(m.B[1,:].x[2])), self._hashRef(Reference(m.B[1,:].x[3])), self._hashRef(Reference(m.B[2,:].x[4])), self._hashRef(Reference(m.B[2,:].x[5])), } self.assertEqual(len(time), len(ref_data)) for ref in time: self.assertIn(self._hashRef(ref), ref_data)
def test_constraint(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 1)) m.comp = Set(initialize=['a', 'b']) m.v0 = Var() m.v1 = Var(m.time) m.v2 = Var(m.time, m.comp) def c0_rule(m): return m.v0 == 1 m.c0 = Constraint(rule=c0_rule) def c1_rule(m, t): return m.v1[t] == 3 m.c1 = Constraint(m.time, rule=c1_rule) @m.Block(m.time) def b(b, t): def c2_rule(b, j): return b.model().v2[t, j] == 5 b.c2 = Constraint(m.comp, rule=c2_rule) scalar, dae = flatten_dae_components(m, m.time, Constraint) hash_scalar = {id(s) for s in scalar} self.assertIn(id(m.c0), hash_scalar) ref_data = { self._hashRef(Reference(m.c1[:])), self._hashRef(Reference(m.b[:].c2['a'])), self._hashRef(Reference(m.b[:].c2['b'])), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def test_cuid_from_slice_errors(self): # two getitem m = self._slice_model() m.b.comp = Reference(m.b.b1[:].v1) _slice = m.b[:].comp[1][1.1] with self.assertRaisesRegex(ValueError, r'.*Two `get_item` calls.*'): cuid = ComponentUID(_slice) _slice = IndexedComponent_slice(m.b[:].component('v'), (IndexedComponent_slice.del_attribute, ('foo', ))) with self.assertRaisesRegex( ValueError, "Cannot create a CUID from a slice that " "contains `set` or `del` calls: got call %s " r"with argument \('foo',\)" % (IndexedComponent_slice.del_attribute, )): cuid = ComponentUID(_slice)
def add_port(blk, name=None, block=None, doc=None): """ This is a method to build Port objects in a unit model and connect these to a specified StateBlock. Keyword Args: name : name to use for Port object. block : an instance of a StateBlock to use as the source to populate the Port object doc : doc string for Port object Returns: A Pyomo Port object and associated components. """ # Validate block object if not isinstance(block, StateBlock): raise ConfigurationError("{} block object provided to add_port " "method is not an instance of a " "StateBlock object. IDAES port objects " "should only be associated with " "StateBlocks.".format(blk.name)) # Create empty Port p = Port(noruleinit=True, doc=doc) setattr(blk, name, p) p._state_block = (block, ) # Get dict of Port members and names member_list = block[ blk.flowsheet().config.time.first()].define_port_members() # Create References for port members for s in member_list: if not member_list[s].is_indexed(): slicer = block[:].component(member_list[s].local_name) else: slicer = block[:].component(member_list[s].local_name)[...] r = Reference(slicer) setattr(blk, "_" + s + "_" + name + "_ref", r) # Add Reference to Port p.add(r, s) return p
def _add_category_references(self): """ Create a "time-indexed vector" for each category of variables. """ category_dict = self.category_dict # Add a deactivated block to store all my `_NmpcVector`s # These be will vars, named by category, indexed by the index # into the list of that category and by time. E.g. # self.vectors.differential self.add_component(self._vectors_name, Block()) self.vectors.deactivate() for categ in category_dict: ctype = CATEGORY_TYPE_MAP[categ] # Get the block that holds this category of var, # and the name of the attribute that holds the # custom-ctype var (this attribute is the same # for all blocks). block_name = self.get_category_block_name(categ) var_name = self._var_name # Get a slice of the block, e.g. self.DIFFERENTIAL_BLOCK[:] _slice = getattr(self, block_name)[:] #_slice = self.__getattribute__(block_name)[:] # Why does this work when self.__getattr__(block_name) does not? # __getattribute__ appears to work just fine... # Get a slice of the block and var, e.g. # self.DIFFERENTIAL_BLOCK[:].var[:] _slice = getattr(_slice, var_name)[:] # Add a reference to this slice to the `vectors` block. # This will be, e.g. `self.vectors.differential` and # can be accessed with its two indices, e.g. # `self.vectors.differential[i,t0]` # to get the "ith coordinate" of the vector of differential # variables at time t0. self.vectors.add_component( ctype._attr, # ^ I store the name I want this attribute to have, # e.g. 'differential', on the custom ctype. Reference(_slice, ctype=_NmpcVector), )
def test_constraint_skip(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 1)) m.v = Var(m.time) def c_rule(m, t): if t == m.time.first(): return Constraint.Skip return m.v[t] == 1. m.c = Constraint(m.time, rule=c_rule) scalar, dae = flatten_dae_components(m, m.time, Constraint) ref_data = { self._hashRef(Reference(m.c[:])), } self.assertEqual(len(dae), len(ref_data)) for ref in dae: self.assertIn(self._hashRef(ref), ref_data)
def build(self): """ Begin building model. Args: None Returns: None """ # Call UnitModel.build to setup dynamics super(ProductData, self).build() # Add State Block self.properties = self.config.property_package.state_block_class( self.flowsheet().config.time, doc="Material properties in product", default={ "defined_state": True, "parameters": self.config.property_package, "has_phase_equilibrium": False, **self.config.property_package_args, }, ) # Add references to all state vars s_vars = self.properties[ self.flowsheet().config.time.first()].define_state_vars() for s in s_vars: l_name = s_vars[s].local_name if s_vars[s].is_indexed(): slicer = self.properties[:].component(l_name)[...] else: slicer = self.properties[:].component(l_name) r = Reference(slicer) setattr(self, s, r) # Add outlet port self.add_port(name="inlet", block=self.properties, doc="Inlet Port")
def build(self): """ Callable method for Block construction """ super(VaporStateBlockData, self).build() # Object reference for molecular weight if needed by CV1D # Molecular weights self.mw_comp = Reference(self.params.mw_comp) self.flow_mol = Var(initialize=1.0, domain=NonNegativeReals, units=pyunits.mol / pyunits.s, doc='Total molar flowrate') self.mole_frac_comp = Var(self.component_list, domain=NonNegativeReals, bounds=(0, 1), units=None, initialize=1 / len(self.component_list), doc='Component mole fractions [-]') self.pressure = Var(initialize=101325, domain=NonNegativeReals, units=pyunits.Pa, doc='Pressure [Pa]') self.temperature = Var(initialize=298.15, domain=NonNegativeReals, units=pyunits.K, doc='Temperature [K]') # Sum mole fractions if not inlet block if self.config.defined_state is False: def sum_component_eqn(b): return b.flow_mol == sum(b.flow_mol_comp[j] for j in b._params.component_list) self.sum_component_eqn = Constraint(rule=sum_component_eqn)
def build(self): super().build() self._tech_type = "surface_discharge" build_pt(self) self._Q = Reference(self.properties[:].flow_vol) pump_electricity(self, self._Q) self.pipe_distance = Var(self.flowsheet().config.time, units=pyunits.miles, doc="Piping distance") self.pipe_diameter = Var(self.flowsheet().config.time, units=pyunits.inches, doc="Pipe diameter") self._fixed_perf_vars.append(self.pipe_distance) self._fixed_perf_vars.append(self.pipe_diameter) self._perf_var_dict["Pipe Distance"] = self.pipe_distance self._perf_var_dict["Pipe Diameter"] = self.pipe_diameter
def _add_category_blocks(self): """ Adds an indexed block for each category of variable and attach a reference to each variable to one of the BlockDatas. """ category_dict = self.category_dict var_name = self._var_name for categ, varlist in category_dict.items(): ctype = CATEGORY_TYPE_MAP.get(categ, NmpcVar) # These names are e.g. 'DIFFERENTIAL_BLOCK', 'DIFFERENTIAL_SET' # They serve as a way to access all the "differential variables" block_name = self.get_category_block_name(categ) set_name = self.get_category_set_name(categ) set_range = range(len(varlist)) # Construct a set that indexes, eg, the "differential variables" category_set = Set(initialize=set_range) self.add_component(set_name, category_set) # Construct an IndexedBlock, each data object of which # will contain a single reference-to-timeslice of that # category, and with the corresponding custom ctype category_block = Block(category_set) self.add_component(block_name, category_block) # Don't want these blocks sent to any solver. category_block.deactivate() for i, var in enumerate(varlist): # Add reference-to-timeslices to new blocks: # # Create a new reference if var is not a reference or # it has the wrong ctype... # We may want to reconsider overriding the user's ctype... # We may also want to make sure these references are not # attached to anything. Otherwise we will fail here. ref = var if var.is_reference() and var.ctype is ctype \ else Reference(var, ctype=ctype) category_block[i].add_component(var_name, ref)